mirror of
https://github.com/TigerVNC/tigervnc.git
synced 2024-08-21 17:54:34 +02:00
![Constantin Kaplinsky](/assets/img/avatar_default.png)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2 3789f03b-4d11-0410-bbf8-ca57d06f2519
448 lines
13 KiB
C++
448 lines
13 KiB
C++
/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
|
|
*
|
|
* This is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*/
|
|
|
|
// Win32Util.cxx
|
|
|
|
#include <rfb_win32/Win32Util.h>
|
|
#include <rdr/Exception.h>
|
|
#include <rdr/HexOutStream.h>
|
|
|
|
|
|
namespace rfb {
|
|
namespace win32 {
|
|
|
|
LogicalPalette::LogicalPalette() : palette(0), numEntries(0) {
|
|
BYTE buf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
|
|
LOGPALETTE* logpal = (LOGPALETTE*)buf;
|
|
logpal->palVersion = 0x300;
|
|
logpal->palNumEntries = 256;
|
|
for (int i=0; i<256;i++) {
|
|
logpal->palPalEntry[i].peRed = 0;
|
|
logpal->palPalEntry[i].peGreen = 0;
|
|
logpal->palPalEntry[i].peBlue = 0;
|
|
logpal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
palette = CreatePalette(logpal);
|
|
if (!palette)
|
|
throw rdr::SystemException("failed to CreatePalette", GetLastError());
|
|
}
|
|
|
|
LogicalPalette::~LogicalPalette() {
|
|
if (palette)
|
|
if (!DeleteObject(palette))
|
|
throw rdr::SystemException("del palette failed", GetLastError());
|
|
}
|
|
|
|
void LogicalPalette::setEntries(int start, int count, const Colour* cols) {
|
|
if (numEntries < count) {
|
|
ResizePalette(palette, start+count);
|
|
numEntries = start+count;
|
|
}
|
|
PALETTEENTRY* logpal = new PALETTEENTRY[count];
|
|
for (int i=0; i<count; i++) {
|
|
logpal[i].peRed = cols[i].r >> 8;
|
|
logpal[i].peGreen = cols[i].g >> 8;
|
|
logpal[i].peBlue = cols[i].b >> 8;
|
|
logpal[i].peFlags = 0;
|
|
}
|
|
UnrealizeObject(palette);
|
|
SetPaletteEntries(palette, start, count, logpal);
|
|
delete [] logpal;
|
|
}
|
|
|
|
|
|
static LogWriter dcLog("DeviceContext");
|
|
|
|
PixelFormat DeviceContext::getPF() const {
|
|
return getPF(dc);
|
|
}
|
|
|
|
PixelFormat DeviceContext::getPF(HDC dc) {
|
|
PixelFormat format;
|
|
CompatibleBitmap bitmap(dc, 1, 1);
|
|
|
|
// -=- Get the bitmap format information
|
|
BitmapInfo bi;
|
|
memset(&bi, 0, sizeof(bi));
|
|
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biBitCount = 0;
|
|
|
|
if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
|
|
throw rdr::SystemException("unable to determine device pixel format", GetLastError());
|
|
}
|
|
if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
|
|
throw rdr::SystemException("unable to determine pixel shifts/palette", GetLastError());
|
|
}
|
|
|
|
// -=- Munge the bitmap info here
|
|
switch (bi.bmiHeader.biBitCount) {
|
|
case 1:
|
|
case 4:
|
|
bi.bmiHeader.biBitCount = 8;
|
|
break;
|
|
case 24:
|
|
bi.bmiHeader.biBitCount = 32;
|
|
break;
|
|
}
|
|
bi.bmiHeader.biPlanes = 1;
|
|
|
|
format.trueColour = bi.bmiHeader.biBitCount > 8;
|
|
format.bigEndian = 0;
|
|
format.bpp = format.depth = bi.bmiHeader.biBitCount;
|
|
|
|
if (format.trueColour) {
|
|
DWORD rMask=0, gMask=0, bMask=0;
|
|
|
|
// Which true colour format is the DIB section using?
|
|
switch (bi.bmiHeader.biCompression) {
|
|
case BI_RGB:
|
|
// Default RGB layout
|
|
switch (bi.bmiHeader.biBitCount) {
|
|
case 16:
|
|
// RGB 555 - High Colour
|
|
dcLog.info("16-bit High Colour");
|
|
rMask = 0x7c00;
|
|
bMask = 0x001f;
|
|
gMask = 0x03e0;
|
|
format.depth = 15;
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
// RGB 888 - True Colour
|
|
dcLog.info("24/32-bit High Colour");
|
|
rMask = 0xff0000;
|
|
gMask = 0x00ff00;
|
|
bMask = 0x0000ff;
|
|
format.depth = 24;
|
|
break;
|
|
default:
|
|
dcLog.error("bits per pixel %u not supported", bi.bmiHeader.biBitCount);
|
|
throw rdr::Exception("unknown bits per pixel specified");
|
|
};
|
|
break;
|
|
case BI_BITFIELDS:
|
|
// Custom RGB layout
|
|
rMask = bi.mask.red;
|
|
gMask = bi.mask.green;
|
|
bMask = bi.mask.blue;
|
|
dcLog.info("BitFields format: %lu, (%lx, %lx, %lx)",
|
|
bi.bmiHeader.biBitCount, rMask, gMask, bMask);
|
|
if (format.bpp == 32)
|
|
format.depth = 24; // ...probably
|
|
break;
|
|
};
|
|
|
|
// Convert the data we just retrieved
|
|
initMaxAndShift(rMask, &format.redMax, &format.redShift);
|
|
initMaxAndShift(gMask, &format.greenMax, &format.greenShift);
|
|
initMaxAndShift(bMask, &format.blueMax, &format.blueShift);
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
|
|
WindowDC::WindowDC(HWND wnd) : hwnd(wnd) {
|
|
dc = GetDC(wnd);
|
|
if (!dc)
|
|
throw rdr::SystemException("GetDC failed", GetLastError());
|
|
}
|
|
WindowDC::~WindowDC() {
|
|
if (dc)
|
|
ReleaseDC(hwnd, dc);
|
|
}
|
|
|
|
|
|
CompatibleDC::CompatibleDC(HDC existing) {
|
|
dc = CreateCompatibleDC(existing);
|
|
if (!dc)
|
|
throw rdr::SystemException("CreateCompatibleDC failed", GetLastError());
|
|
}
|
|
CompatibleDC::~CompatibleDC() {
|
|
if (dc)
|
|
DeleteDC(dc);
|
|
}
|
|
|
|
|
|
BitmapDC::BitmapDC(HDC hdc, HBITMAP hbitmap) : CompatibleDC(hdc){
|
|
oldBitmap = (HBITMAP)SelectObject(dc, hbitmap);
|
|
if (!oldBitmap)
|
|
throw rdr::SystemException("SelectObject to CompatibleDC failed",
|
|
GetLastError());
|
|
}
|
|
BitmapDC::~BitmapDC() {
|
|
SelectObject(dc, oldBitmap);
|
|
}
|
|
|
|
|
|
CompatibleBitmap::CompatibleBitmap(HDC hdc, int width, int height) {
|
|
hbmp = CreateCompatibleBitmap(hdc, width, height);
|
|
if (!hbmp)
|
|
throw rdr::SystemException("CreateCompatibleBitmap() failed",
|
|
GetLastError());
|
|
}
|
|
CompatibleBitmap::~CompatibleBitmap() {
|
|
if (hbmp) DeleteObject(hbmp);
|
|
}
|
|
|
|
|
|
PaletteSelector::PaletteSelector(HDC dc, HPALETTE pal) : device(dc), redrawRequired(false) {
|
|
oldPal = SelectPalette(dc, pal, FALSE);
|
|
redrawRequired = RealizePalette(dc) > 0;
|
|
}
|
|
PaletteSelector::~PaletteSelector() {
|
|
if (oldPal) SelectPalette(device, oldPal, TRUE);
|
|
}
|
|
|
|
|
|
IconInfo::IconInfo(HICON icon) {
|
|
if (!GetIconInfo(icon, this))
|
|
throw rdr::SystemException("GetIconInfo() failed", GetLastError());
|
|
}
|
|
IconInfo::~IconInfo() {
|
|
if (hbmColor)
|
|
DeleteObject(hbmColor);
|
|
if (hbmMask)
|
|
DeleteObject(hbmMask);
|
|
}
|
|
|
|
|
|
ModuleFileName::ModuleFileName(HMODULE module) : TCharArray(MAX_PATH) {
|
|
if (!module) module = GetModuleHandle(0);
|
|
if (!GetModuleFileName(module, buf, MAX_PATH))
|
|
buf[0] = 0;
|
|
}
|
|
|
|
|
|
FileVersionInfo::FileVersionInfo(const TCHAR* filename) {
|
|
// Get executable name
|
|
ModuleFileName exeName;
|
|
if (!filename) filename = exeName.buf;
|
|
|
|
// Get version info size
|
|
DWORD handle;
|
|
int size = GetFileVersionInfoSize((TCHAR*)filename, &handle);
|
|
if (!size)
|
|
throw rdr::SystemException("GetVersionInfoSize failed", GetLastError());
|
|
|
|
// Get version info
|
|
buf = new TCHAR[size];
|
|
if (!GetFileVersionInfo((TCHAR*)filename, handle, size, buf))
|
|
throw rdr::SystemException("GetVersionInfo failed", GetLastError());
|
|
}
|
|
|
|
const TCHAR* FileVersionInfo::getVerString(const TCHAR* name, DWORD langId) {
|
|
char langIdBuf[sizeof(langId)];
|
|
for (int i=sizeof(langIdBuf)-1; i>=0; i--) {
|
|
langIdBuf[i] = langId & 0xff;
|
|
langId = langId >> 8;
|
|
}
|
|
|
|
TCharArray langIdStr = rdr::HexOutStream::binToHexStr(langIdBuf, sizeof(langId));
|
|
TCharArray infoName(_tcslen(_T("StringFileInfo")) + 4 + _tcslen(name) + _tcslen(langIdStr.buf));
|
|
_stprintf(infoName.buf, _T("\\StringFileInfo\\%s\\%s"), langIdStr.buf, name);
|
|
|
|
// Locate the required version string within the version info
|
|
TCHAR* buffer = 0;
|
|
UINT length = 0;
|
|
if (!VerQueryValue(buf, infoName.buf, (void**)&buffer, &length)) {
|
|
printf("unable to find %s version string", CStr(infoName.buf));
|
|
throw rdr::Exception("VerQueryValue failed");
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
|
|
bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file) {
|
|
return tstrSplit(path, '\\', dir, file, true);
|
|
}
|
|
|
|
|
|
static LogWriter dfbLog("DynamicFn");
|
|
|
|
DynamicFnBase::DynamicFnBase(const TCHAR* dllName, const char* fnName) : dllHandle(0), fnPtr(0) {
|
|
dllHandle = LoadLibrary(dllName);
|
|
if (!dllHandle) {
|
|
dfbLog.info("DLL %s not found (%d)", (const char*)CStr(dllName), GetLastError());
|
|
return;
|
|
}
|
|
fnPtr = GetProcAddress(dllHandle, fnName);
|
|
if (!fnPtr)
|
|
dfbLog.info("proc %s not found in %s (%d)", fnName, (const char*)CStr(dllName), GetLastError());
|
|
}
|
|
|
|
DynamicFnBase::~DynamicFnBase() {
|
|
if (dllHandle)
|
|
FreeLibrary(dllHandle);
|
|
}
|
|
|
|
|
|
static LogWriter miLog("MonitorInfo");
|
|
|
|
MonitorInfo::MonitorInfo(HWND window) {
|
|
#if (WINVER >= 0x0500)
|
|
typedef HMONITOR (WINAPI *_MonitorFromWindow_proto)(HWND,DWORD);
|
|
rfb::win32::DynamicFn<_MonitorFromWindow_proto> _MonitorFromWindow(_T("user32.dll"), "MonitorFromWindow");
|
|
typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
|
|
rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
|
|
|
|
// Can we dynamically link to the monitor functions?
|
|
if (_MonitorFromWindow.isValid()) {
|
|
if (_GetMonitorInfo.isValid()) {
|
|
HMONITOR monitor = (*_MonitorFromWindow)(window, MONITOR_DEFAULTTONEAREST);
|
|
miLog.debug("monitor=%lx", monitor);
|
|
if (monitor) {
|
|
memset(this, 0, sizeof(MONITORINFOEXA));
|
|
cbSize = sizeof(MONITORINFOEXA);
|
|
if ((*_GetMonitorInfo)(monitor, this)) {
|
|
miLog.debug("monitor is %d,%d-%d,%d", rcMonitor.left, rcMonitor.top, rcMonitor.right, rcMonitor.bottom);
|
|
miLog.debug("work area is %d,%d-%d,%d", rcWork.left, rcWork.top, rcWork.right, rcWork.bottom);
|
|
miLog.debug("device is \"%s\"", szDevice);
|
|
return;
|
|
}
|
|
miLog.error("failed to get monitor info: %ld", GetLastError());
|
|
}
|
|
} else {
|
|
miLog.debug("GetMonitorInfo not found");
|
|
}
|
|
} else {
|
|
miLog.debug("MonitorFromWindow not found");
|
|
}
|
|
#else
|
|
#pragma message ("not building in GetMonitorInfo")
|
|
cbSize = sizeof(MonitorInfo);
|
|
szDevice[0] = 0;
|
|
#endif
|
|
|
|
// Legacy fallbacks - just return the desktop settings
|
|
miLog.debug("using legacy fall-backs");
|
|
HWND desktop = GetDesktopWindow();
|
|
GetWindowRect(desktop, &rcMonitor);
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
|
|
dwFlags = 0;
|
|
}
|
|
|
|
|
|
#if (WINVER >= 0x0500)
|
|
|
|
struct moveToMonitorData {
|
|
HWND window;
|
|
const char* monitorName;
|
|
};
|
|
|
|
typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
|
|
static rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
|
|
|
|
static BOOL CALLBACK moveToMonitorEnumProc(HMONITOR monitor,
|
|
HDC dc,
|
|
LPRECT pos,
|
|
LPARAM d) {
|
|
moveToMonitorData* data = (moveToMonitorData*)d;
|
|
MONITORINFOEXA info;
|
|
memset(&info, 0, sizeof(info));
|
|
info.cbSize = sizeof(info);
|
|
|
|
if ((*_GetMonitorInfo)(monitor, &info)) {
|
|
if (stricmp(data->monitorName, info.szDevice) == 0) {
|
|
SetWindowPos(data->window, 0,
|
|
info.rcMonitor.left, info.rcMonitor.top,
|
|
info.rcMonitor.right, info.rcMonitor.bottom,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
void moveToMonitor(HWND handle, const char* device) {
|
|
miLog.debug("moveToMonitor %s", device);
|
|
|
|
#if (WINVER >= 0x500)
|
|
typedef BOOL (WINAPI *_EnumDisplayMonitors_proto)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
|
|
rfb::win32::DynamicFn<_EnumDisplayMonitors_proto> _EnumDisplayMonitors(_T("user32.dll"), "EnumDisplayMonitors");
|
|
if (!_EnumDisplayMonitors.isValid()) {
|
|
miLog.debug("EnumDisplayMonitors not found");
|
|
return;
|
|
}
|
|
|
|
moveToMonitorData data;
|
|
data.window = handle;
|
|
data.monitorName = device;
|
|
|
|
(*_EnumDisplayMonitors)(0, 0, &moveToMonitorEnumProc, (LPARAM)&data);
|
|
#endif
|
|
}
|
|
|
|
|
|
void centerWindow(HWND handle, HWND parent, bool clipToParent) {
|
|
RECT r;
|
|
if (parent && IsWindowVisible(parent)) {
|
|
if (!GetWindowRect(parent, &r)) return;
|
|
} else {
|
|
MonitorInfo mi(handle);
|
|
r=mi.rcWork;
|
|
}
|
|
centerWindow(handle, r, clipToParent);
|
|
}
|
|
|
|
void centerWindow(HWND handle, const RECT& r, bool clipToRect) {
|
|
RECT wr;
|
|
if (!GetWindowRect(handle, &wr)) return;
|
|
int w = wr.right-wr.left;
|
|
int h = wr.bottom-wr.top;
|
|
if (clipToRect) {
|
|
w = min(r.right-r.left, w);
|
|
h = min(r.bottom-r.top, h);
|
|
}
|
|
int x = (r.left + r.right - w)/2;
|
|
int y = (r.top + r.bottom - h)/2;
|
|
UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | (clipToRect ? 0 : SWP_NOSIZE);
|
|
SetWindowPos(handle, 0, x, y, w, h, flags);
|
|
}
|
|
|
|
|
|
int MsgBox(HWND parent, const TCHAR* msg, UINT flags) {
|
|
const TCHAR* msgType = 0;
|
|
UINT tflags = flags & 0x70;
|
|
if (tflags == MB_ICONHAND)
|
|
msgType = _T("Error");
|
|
else if (tflags == MB_ICONQUESTION)
|
|
msgType = _T("Question");
|
|
else if (tflags == MB_ICONEXCLAMATION)
|
|
msgType = _T("Warning");
|
|
else if (tflags == MB_ICONASTERISK)
|
|
msgType = _T("Information");
|
|
flags |= MB_TOPMOST | MB_SETFOREGROUND;
|
|
int len = _tcslen(AppName.buf) + 1;
|
|
if (msgType) len += _tcslen(msgType) + 3;
|
|
TCharArray title = new TCHAR[len];
|
|
_tcscpy(title.buf, AppName.buf);
|
|
if (msgType) {
|
|
_tcscat(title.buf, _T(" : "));
|
|
_tcscat(title.buf, msgType);
|
|
}
|
|
return MessageBox(parent, msg, title.buf, flags);
|
|
}
|
|
|
|
|
|
};
|
|
};
|