tigervnc/rfb_win32/Win32Util.cxx
Constantin Kaplinsky 47ed8d321c Initial revision
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2 3789f03b-4d11-0410-bbf8-ca57d06f2519
2004-10-08 09:43:57 +00:00

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);
}
};
};