diff options
Diffstat (limited to 'hw')
73 files changed, 5357 insertions, 3235 deletions
diff --git a/hw/dmx/config/scanner.l b/hw/dmx/config/scanner.l index e527d6df5..b75a440a8 100644 --- a/hw/dmx/config/scanner.l +++ b/hw/dmx/config/scanner.l @@ -109,7 +109,7 @@ void yyerror(const char *message) }; fprintf(stderr, "parse error on line %d at token \"%*.*s\"\n", - lineno, yyleng, yyleng, yytext); + lineno, (int)yyleng, (int)yyleng, yytext); end = message + strlen(message); for (pt = message; *pt; pt++) { if (pt[0] == 'T' && pt[1] == '_') { diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index b6f258313..360b3c61c 100644 --- a/hw/xwin/InitOutput.c +++ b/hw/xwin/InitOutput.c @@ -35,12 +35,10 @@ from The Open Group. #include "winmsg.h" #include "winconfig.h" #include "winprefs.h" -#ifdef XWIN_CLIPBOARD -#include "X11/Xlocale.h" -#endif #ifdef DPMSExtension #include "dpmsproc.h" #endif +#include <locale.h> #ifdef __CYGWIN__ #include <mntent.h> #endif @@ -66,6 +64,7 @@ typedef WINAPI HRESULT(*SHGETFOLDERPATHPROC) (HWND hwndOwner, #include "glx_extinit.h" #ifdef XWIN_GLX_WINDOWS #include "glx/glwindows.h" +#include "dri/windowsdri.h" #endif /* @@ -76,9 +75,6 @@ typedef WINAPI HRESULT(*SHGETFOLDERPATHPROC) (HWND hwndOwner, * Function prototypes */ -static Bool - winCheckDisplayNumber(void); - void winLogCommandLine(int argc, char *argv[]); @@ -92,6 +88,11 @@ Bool const char *winGetBaseDir(void); #endif +static void winCheckMount(void); + +extern Bool XSupportsLocale(void); +extern Status XInitThreads(void); + /* * For the depth 24 pixmap we default to 32 bits per pixel, but * we change this pixmap format later if we detect that the display @@ -120,6 +121,9 @@ const int NUMFORMATS = sizeof(g_PixmapFormats) / sizeof(g_PixmapFormats[0]); static const ExtensionModule xwinExtensions[] = { #ifdef GLXEXT { GlxExtensionInit, "GLX", &noGlxExtension }, +#ifdef XWIN_WINDOWS_DRI + { WindowsDRIExtensionInit, "Windows-DRI", &noDriExtension }, +#endif #endif }; @@ -162,6 +166,8 @@ main(int argc, char *argv[], char *envp[]) { int iReturn; + xorg_crashreport_init(NULL); + /* Create & acquire the termination mutex */ iReturn = pthread_mutex_init(&g_pmTerminating, NULL); if (iReturn != 0) { @@ -173,6 +179,8 @@ main(int argc, char *argv[], char *envp[]) ErrorF("ddxMain - pthread_mutex_lock () failed: %d\n", iReturn); } + winCheckMount(); + return dix_main(argc, argv, envp); } @@ -212,10 +220,6 @@ ddxGiveUp(enum ExitCode error) } #endif - if (!g_fLogInited) { - g_pszLogFile = LogInit(g_pszLogFile, NULL); - g_fLogInited = TRUE; - } LogClose(error); /* @@ -259,6 +263,8 @@ AbortDDX(enum ExitCode error) } #ifdef __CYGWIN__ +extern Bool nolock; + /* hasmntopt is currently not implemented for cygwin */ static const char * winCheckMntOpt(const struct mntent *mnt, const char *opt) @@ -283,6 +289,9 @@ winCheckMntOpt(const struct mntent *mnt, const char *opt) return NULL; } +/* + Check mounts and issue warnings/activate workarounds as needed + */ static void winCheckMount(void) { @@ -292,6 +301,7 @@ winCheckMount(void) enum { none = 0, sys_root, user_root, sys_tmp, user_tmp } level = none, curlevel; BOOL binary = TRUE; + BOOL fat = TRUE; mnt = setmntent("/etc/mtab", "r"); if (mnt == NULL) { @@ -330,6 +340,12 @@ winCheckMount(void) binary = FALSE; else binary = TRUE; + + if ((strcmp(ent->mnt_type, "vfat") == 0) || + (strcmp(ent->mnt_type, "exfat") == 0)) + fat = TRUE; + else + fat = FALSE; } if (endmntent(mnt) != 1) { @@ -339,6 +355,12 @@ winCheckMount(void) if (!binary) winMsg(X_WARNING, "/tmp mounted in textmode\n"); + + if (fat) { + winMsg(X_WARNING, + "/tmp mounted on FAT filesystem, activating -nolock\n"); + nolock = TRUE; + } } #else static void @@ -594,13 +616,13 @@ winFixupPaths(void) winMsg(X_ERROR, "Can not determine HOME directory\n"); } } - if (!g_fLogFileChanged) { + if (!g_fLogFile) { static char buffer[MAX_PATH]; DWORD size = GetTempPath(sizeof(buffer), buffer); if (size && size < sizeof(buffer)) { snprintf(buffer + size, sizeof(buffer) - size, - "XWin.%s.log", display); + g_pszLogFileFormat, display); buffer[sizeof(buffer) - 1] = 0; g_pszLogFile = buffer; winMsg(X_DEFAULT, "Logfile set to \"%s\"\n", g_pszLogFile); @@ -631,15 +653,16 @@ OsVendorInit(void) OsVendorVErrorFProc = OsVendorVErrorF; #endif - if (!g_fLogInited) { - /* keep this order. If LogInit fails it calls Abort which then calls - * ddxGiveUp where LogInit is called again and creates an infinite - * recursion. If we set g_fLogInited to TRUE before the init we - * avoid the second call - */ - g_fLogInited = TRUE; - g_pszLogFile = LogInit(g_pszLogFile, NULL); + if (serverGeneration == 1) { + if (g_pszLogFile) + g_pszLogFile = LogInit(g_pszLogFile, ".old"); + else + g_pszLogFile = LogInit(g_pszLogFileFormat, ".old"); + + /* Tell crashreporter logfile name */ + xorg_crashreport_init(g_pszLogFile); } + LogSetParameter(XLOG_FLUSH, 1); LogSetParameter(XLOG_VERBOSITY, g_iLogVerbose); LogSetParameter(XLOG_FILE_VERBOSITY, g_iLogVerbose); @@ -692,6 +715,20 @@ OsVendorInit(void) } } } + + /* Work out what the default resize setting should be, and apply it if it + was not explicitly specified */ + { + int j; + for (j = 0; j < g_iNumScreens; j++) { + if (g_ScreenInfo[j].iResizeMode == resizeDefault) { + if (g_ScreenInfo[j].fFullScreen) + g_ScreenInfo[j].iResizeMode = resizeNotAllowed; + else + g_ScreenInfo[j].iResizeMode = resizeWithRandr; + } + } + } } static void @@ -748,10 +785,6 @@ winUseMsg(void) ErrorF("-ignoreinput\n" "\tIgnore keyboard and mouse input.\n"); -#ifdef XWIN_MULTIWINDOWEXTWM - ErrorF("-internalwm\n" "\tRun the internal window manager.\n"); -#endif - #ifdef XWIN_XF86CONFIG ErrorF("-keyboard\n" "\tSpecify a keyboard device from the configuration file.\n"); @@ -870,24 +903,7 @@ winUseMsg(void) void ddxUseMsg(void) { - /* Set a flag so that FatalError won't give duplicate warning message */ - g_fSilentFatalError = TRUE; - winUseMsg(); - - /* Log file will not be opened for UseMsg unless we open it now */ - if (!g_fLogInited) { - g_pszLogFile = LogInit(g_pszLogFile, NULL); - g_fLogInited = TRUE; - } - LogClose(EXIT_NO_ERROR); - - /* Notify user where UseMsg text can be found. */ - if (!g_fNoHelpMessageBox) - winMessageBoxF("The " PROJECT_NAME " help text has been printed to " - "%s.\n" - "Please open %s to read the help text.\n", - MB_ICONINFORMATION, g_pszLogFile, g_pszLogFile); } /* See Porting Layer Definition - p. 20 */ @@ -918,14 +934,6 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) "Exiting.\n"); } - /* Check for duplicate invocation on same display number. */ - if (serverGeneration == 1 && !winCheckDisplayNumber()) { - if (g_fSilentDupError) - g_fSilentFatalError = TRUE; - FatalError("InitOutput - Duplicate invocation on display " - "number: %s. Exiting.\n", display); - } - #ifdef XWIN_XF86CONFIG /* Try to read the xorg.conf-style configuration file */ if (!winReadConfigfile()) @@ -1038,11 +1046,27 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) /* Perform some one time initialization */ if (1 == serverGeneration) { + const char *locale; + + /* Allow multiple threads to access Xlib */ + if (XInitThreads() == 0) { + ErrorF("XInitThreads failed.\n"); + } + /* * setlocale applies to all threads in the current process. * Apply locale specified in LANG environment variable. */ - setlocale(LC_ALL, ""); + locale = setlocale(LC_ALL, ""); + if (!locale) { + ErrorF("setlocale failed.\n"); + } + + /* See if X supports the current locale */ + if (XSupportsLocale() == FALSE) { + ErrorF("Warning: Locale '%s' not supported by X, falling back to 'C' locale.\n", locale); + setlocale(LC_ALL, "C"); + } } #endif @@ -1050,70 +1074,3 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) winDebug("InitOutput - Returning.\n"); #endif } - -/* - * winCheckDisplayNumber - Check if another instance of Cygwin/X is - * already running on the same display number. If no one exists, - * make a mutex to prevent new instances from running on the same display. - * - * return FALSE if the display number is already used. - */ - -static Bool -winCheckDisplayNumber(void) -{ - int nDisp; - HANDLE mutex; - char name[MAX_PATH]; - const char *pszPrefix = '\0'; - OSVERSIONINFO osvi = { 0 }; - - /* Check display range */ - nDisp = atoi(display); - if (nDisp < 0 || nDisp > 65535) { - ErrorF("winCheckDisplayNumber - Bad display number: %d\n", nDisp); - return FALSE; - } - - /* Set first character of mutex name to null */ - name[0] = '\0'; - - /* Get operating system version information */ - osvi.dwOSVersionInfoSize = sizeof(osvi); - GetVersionEx(&osvi); - - /* Want a mutex shared among all terminals on NT > 4.0 */ - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 5) { - pszPrefix = "Global\\"; - } - - /* Setup Cygwin/X specific part of name */ - snprintf(name, sizeof(name), "%sCYGWINX_DISPLAY:%d", pszPrefix, nDisp); - - /* Windows automatically releases the mutex when this process exits */ - mutex = CreateMutex(NULL, FALSE, name); - if (!mutex) { - LPVOID lpMsgBuf; - - /* Display a fancy error message */ - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, 0, NULL); - ErrorF("winCheckDisplayNumber - CreateMutex failed: %s\n", - (LPSTR) lpMsgBuf); - LocalFree(lpMsgBuf); - - return FALSE; - } - if (GetLastError() == ERROR_ALREADY_EXISTS) { - ErrorF("winCheckDisplayNumber - " - PROJECT_NAME " is already running on display %d\n", nDisp); - return FALSE; - } - - return TRUE; -} diff --git a/hw/xwin/Makefile.am b/hw/xwin/Makefile.am index 4da3d12a4..ceadd9d20 100644 --- a/hw/xwin/Makefile.am +++ b/hw/xwin/Makefile.am @@ -9,9 +9,17 @@ CLIPBOARD_LIBS = $(top_builddir)/hw/xwin/winclipboard/libXWinclipboard.la endif if XWIN_GLX_WINDOWS -GLX_DIR = glx -DEFS_GLX_WINDOWS = -DXWIN_GLX_WINDOWS -XWIN_GLX_LIBS = $(top_builddir)/hw/xwin/glx/libXwinGLX.la +GLX_DIR = +DEFS_GLX_WINDOWS = +XWIN_GLX_LIBS = +if XWIN_WINDOWS_DRI +GLX_DIR += dri +DEFS_GLX_WINDOWS += -DXWIN_WINDOWS_DRI +XWIN_GLX_LIBS += $(top_builddir)/hw/xwin/dri/libWindowsDRI.la +endif +GLX_DIR += glx +DEFS_GLX_WINDOWS += -DXWIN_GLX_WINDOWS +XWIN_GLX_LIBS += $(top_builddir)/hw/xwin/glx/libXwinGLX.la XWIN_GLX_SYS_LIBS = -lopengl32 endif @@ -25,6 +33,7 @@ SRCS_MULTIWINDOW = \ winSetAppUserModelID.c DEFS_MULTIWINDOW = -DXWIN_MULTIWINDOW MULTIWINDOW_SYS_LIBS = -lshlwapi -lole32 +MULTIWINDOW_LIBS = $(top_builddir)/hw/xwin/wmutil/libXWinWMUtil.la endif if XWIN_MULTIWINDOWEXTWM @@ -89,8 +98,6 @@ SRCS = InitInput.c \ winconfig.h \ win.h \ winglobals.h \ - winkeybd.h \ - winkeynames.h \ winlayouts.h \ winmessages.h \ winmonitors.h \ @@ -134,6 +141,7 @@ XWIN_LIBS += \ $(top_builddir)/Xi/libXistubs.la XWin_DEPENDENCIES = \ + $(MULTIWINDOW_LIBS) \ $(MULTIWINDOWEXTWM_LIBS) \ $(XWIN_GLX_LIBS) \ $(XWIN_LIBS) \ @@ -142,6 +150,7 @@ XWin_DEPENDENCIES = \ XWin_LDADD = \ + $(MULTIWINDOW_LIBS) \ $(MULTIWINDOWEXTWM_LIBS) \ $(XWIN_GLX_LIBS) \ $(XWIN_LIBS) \ @@ -156,7 +165,7 @@ XWin_LDFLAGS = -mwindows -Wl,--disable-stdcall-fixup $(LD_EXPORT_SYMBOLS_FLAG) .rc.o: - $(AM_V_GEN)$(WINDRES) --use-temp-file -i $< --input-format=rc -o $@ -O coff -I $(top_builddir)/include + $(AM_V_GEN)$(WINDRES) --use-temp-file -i $< --input-format=rc -o $@ -O coff -I $(top_builddir)/include -DHOST_TRIPLET=\"$(host)\" XWin.o: XWin.rc XWin.exe.manifest X.ico @@ -188,5 +197,5 @@ EXTRA_DIST = \ relink: $(AM_V_at)rm -f XWin$(EXEEXT) && $(MAKE) XWin$(EXEEXT) -SUBDIRS = man $(GLX_DIR) winclipboard . -DIST_SUBDIRS = man glx winclipboard . +SUBDIRS = man $(GLX_DIR) winclipboard wmutil . +DIST_SUBDIRS = man glx winclipboard wmutil . diff --git a/hw/xwin/XWin.rc b/hw/xwin/XWin.rc index a54e0fdbb..e74a9a5ef 100644 --- a/hw/xwin/XWin.rc +++ b/hw/xwin/XWin.rc @@ -46,7 +46,7 @@ FONT 8, "MS Shell Dlg 2" BEGIN CONTROL IDI_XWIN, IDC_STATIC, "Static", SS_ICON, 8, 8, 32, 32 LTEXT XVENDORNAMESHORT " X Server ", IDC_STATIC, 36, 8, 220, 8 - LTEXT VENDOR_MAN_VERSION, IDC_STATIC, 36, 18, 220, 8 + LTEXT VENDOR_MAN_VERSION " (" HOST_TRIPLET ")", IDC_STATIC, 36, 18, 220, 8 LTEXT BUILDERSTRING, IDC_STATIC, 36, 28, 220, 8 LTEXT "This software is licensed under the terms of the MIT/X11 License.", IDC_STATIC, 36, 48, 220, 20 CONTROL __VENDORDWEBSUPPORT__, ID_ABOUT_WEBSITE, "Button", diff --git a/hw/xwin/dri/Makefile.am b/hw/xwin/dri/Makefile.am new file mode 100644 index 000000000..bdcd48aae --- /dev/null +++ b/hw/xwin/dri/Makefile.am @@ -0,0 +1,8 @@ +noinst_LTLIBRARIES = libWindowsDRI.la + +libWindowsDRI_la_SOURCES = \ + windowsdri.c \ + windowsdri.h + +AM_CFLAGS = $(DIX_CFLAGS) \ + -I$(top_srcdir)/hw/xwin/ diff --git a/hw/xwin/dri/windowsdri.c b/hw/xwin/dri/windowsdri.c new file mode 100644 index 000000000..ab18a4691 --- /dev/null +++ b/hw/xwin/dri/windowsdri.c @@ -0,0 +1,274 @@ +/* + * Copyright © 2014 Jon TURNEY + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/extensions/windowsdristr.h> + +#include "dixstruct.h" +#include "extnsionst.h" +#include "scrnintstr.h" +#include "swaprep.h" +#include "protocol-versions.h" +#include "windowsdri.h" +#include "glx/dri_helpers.h" + +static int WindowsDRIErrorBase = 0; +static unsigned char WindowsDRIReqCode = 0; +static int WindowsDRIEventBase = 0; + +static void +WindowsDRIResetProc(ExtensionEntry* extEntry) +{ +} + +static int +ProcWindowsDRIQueryVersion(ClientPtr client) +{ + xWindowsDRIQueryVersionReply rep; + + REQUEST_SIZE_MATCH(xWindowsDRIQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_WINDOWSDRI_MAJOR_VERSION; + rep.minorVersion = SERVER_WINDOWSDRI_MINOR_VERSION; + rep.patchVersion = SERVER_WINDOWSDRI_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.majorVersion); + swaps(&rep.minorVersion); + swapl(&rep.patchVersion); + } + WriteToClient(client, sizeof(xWindowsDRIQueryVersionReply), &rep); + return Success; +} + +static int +ProcWindowsDRIQueryDirectRenderingCapable(ClientPtr client) +{ + xWindowsDRIQueryDirectRenderingCapableReply rep; + + REQUEST(xWindowsDRIQueryDirectRenderingCapableReq); + REQUEST_SIZE_MATCH(xWindowsDRIQueryDirectRenderingCapableReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!client->local) + rep.isCapable = 0; + else + rep.isCapable = glxWinGetScreenAiglxIsActive(screenInfo.screens[stuff->screen]); + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + } + + WriteToClient(client, + sizeof(xWindowsDRIQueryDirectRenderingCapableReply), + &rep); + return Success; +} + +static int +ProcWindowsDRIQueryDrawable(ClientPtr client) +{ + xWindowsDRIQueryDrawableReply rep; + int rc; + + REQUEST(xWindowsDRIQueryDrawableReq); + REQUEST_SIZE_MATCH(xWindowsDRIQueryDrawableReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = glxWinQueryDrawable(client, stuff->drawable, &(rep.drawable_type), &(rep.handle)); + + if (rc) + return rc; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.handle); + swapl(&rep.drawable_type); + } + + WriteToClient(client, sizeof(xWindowsDRIQueryDrawableReply), &rep); + return Success; +} + +static int +ProcWindowsDRIFBConfigToPixelFormat(ClientPtr client) +{ + xWindowsDRIFBConfigToPixelFormatReply rep; + + REQUEST(xWindowsDRIFBConfigToPixelFormatReq); + REQUEST_SIZE_MATCH(xWindowsDRIFBConfigToPixelFormatReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rep.pixelFormatIndex = glxWinFBConfigIDToPixelFormatIndex(stuff->screen, stuff->fbConfigID); + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.pixelFormatIndex); + } + + WriteToClient(client, sizeof(xWindowsDRIFBConfigToPixelFormatReply), &rep); + return Success; +} + +/* dispatch */ + +static int +ProcWindowsDRIDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_WindowsDRIQueryVersion: + return ProcWindowsDRIQueryVersion(client); + + case X_WindowsDRIQueryDirectRenderingCapable: + return ProcWindowsDRIQueryDirectRenderingCapable(client); + } + + if (!client->local) + return WindowsDRIErrorBase + WindowsDRIClientNotLocal; + + switch (stuff->data) { + case X_WindowsDRIQueryDrawable: + return ProcWindowsDRIQueryDrawable(client); + + case X_WindowsDRIFBConfigToPixelFormat: + return ProcWindowsDRIFBConfigToPixelFormat(client); + + default: + return BadRequest; + } +} + +static void +SNotifyEvent(xWindowsDRINotifyEvent *from, + xWindowsDRINotifyEvent *to) +{ + to->type = from->type; + to->kind = from->kind; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->time, to->time); +} + +static int +SProcWindowsDRIQueryVersion(ClientPtr client) +{ + REQUEST(xWindowsDRIQueryVersionReq); + swaps(&stuff->length); + return ProcWindowsDRIQueryVersion(client); +} + +static int +SProcWindowsDRIQueryDirectRenderingCapable(ClientPtr client) +{ + REQUEST(xWindowsDRIQueryDirectRenderingCapableReq); + swaps(&stuff->length); + swapl(&stuff->screen); + return ProcWindowsDRIQueryDirectRenderingCapable(client); +} + +static int +SProcWindowsDRIQueryDrawable(ClientPtr client) +{ + REQUEST(xWindowsDRIQueryDrawableReq); + swaps(&stuff->length); + swapl(&stuff->screen); + swapl(&stuff->drawable); + return ProcWindowsDRIQueryDrawable(client); +} + +static int +SProcWindowsDRIFBConfigToPixelFormat(ClientPtr client) +{ + REQUEST(xWindowsDRIFBConfigToPixelFormatReq); + swaps(&stuff->length); + swapl(&stuff->screen); + swapl(&stuff->fbConfigID); + return ProcWindowsDRIFBConfigToPixelFormat(client); +} + +static int +SProcWindowsDRIDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_WindowsDRIQueryVersion: + return SProcWindowsDRIQueryVersion(client); + + case X_WindowsDRIQueryDirectRenderingCapable: + return SProcWindowsDRIQueryDirectRenderingCapable(client); + } + + if (!client->local) + return WindowsDRIErrorBase + WindowsDRIClientNotLocal; + + switch (stuff->data) { + case X_WindowsDRIQueryDrawable: + return SProcWindowsDRIQueryDrawable(client); + + case X_WindowsDRIFBConfigToPixelFormat: + return SProcWindowsDRIFBConfigToPixelFormat(client); + + default: + return BadRequest; + } +} + +void +WindowsDRIExtensionInit(void) +{ + ExtensionEntry* extEntry; + + if ((extEntry = AddExtension(WINDOWSDRINAME, + WindowsDRINumberEvents, + WindowsDRINumberErrors, + ProcWindowsDRIDispatch, + SProcWindowsDRIDispatch, + WindowsDRIResetProc, + StandardMinorOpcode))) { + size_t i; + WindowsDRIReqCode = (unsigned char)extEntry->base; + WindowsDRIErrorBase = extEntry->errorBase; + WindowsDRIEventBase = extEntry->eventBase; + for (i = 0; i < WindowsDRINumberEvents; i++) + EventSwapVector[WindowsDRIEventBase + i] = (EventSwapPtr)SNotifyEvent; + } +} diff --git a/hw/xwin/dri/windowsdri.h b/hw/xwin/dri/windowsdri.h new file mode 100644 index 000000000..a48c72b04 --- /dev/null +++ b/hw/xwin/dri/windowsdri.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2014 Jon TURNEY + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef windowsdri_h +#define windowsdri_h + +void WindowsDRIExtensionInit(void); +Bool noDriExtension; + +#endif /* windowsdri_h */ diff --git a/hw/xwin/glx/Makefile.am b/hw/xwin/glx/Makefile.am index f2dffbffb..599ec37cc 100644 --- a/hw/xwin/glx/Makefile.am +++ b/hw/xwin/glx/Makefile.am @@ -7,9 +7,16 @@ libXwinGLX_la_SOURCES = \ glwindows.h \ glshim.c \ indirect.c \ + indirect.h \ wgl_ext_api.c \ wgl_ext_api.h +if XWIN_WINDOWS_DRI +libXwinGLX_la_SOURCES += \ + dri_helpers.c \ + dri_helpers.h +endif + libnativeGLthunk_la_SOURCES = \ glthunk.c diff --git a/hw/xwin/glx/dri_helpers.c b/hw/xwin/glx/dri_helpers.c new file mode 100644 index 000000000..7ed9c9532 --- /dev/null +++ b/hw/xwin/glx/dri_helpers.c @@ -0,0 +1,119 @@ +/* + * Copyright © 2014 Jon TURNEY + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + +#include <glx/glxserver.h> +#include <glx/glxutil.h> +#include <X11/extensions/windowsdriconst.h> + +#include "indirect.h" +#include "winpriv.h" +#include "dri_helpers.h" +#include "win.h" + +extern int validGlxDrawable(ClientPtr client, XID id, int type, int access_mode, + __GLXdrawable ** drawable, int *err); + +int +glxWinQueryDrawable(ClientPtr client, XID drawId, unsigned int *type, unsigned int *handle) +{ + __GLXWinDrawable *pDrawable; + int err; + + if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY, + DixReadAccess, (__GLXdrawable **)&pDrawable, &err)) { + + switch (pDrawable->base.type) + { + case GLX_DRAWABLE_WINDOW: + { + HWND h = winGetWindowInfo((WindowPtr)(pDrawable->base.pDraw)); + *handle = (uintptr_t)h; + *type = WindowsDRIDrawableWindow; + } + break; + + case GLX_DRAWABLE_PIXMAP: + glxWinDeferredCreateDrawable(pDrawable, pDrawable->base.config); + *handle = pDrawable->base.pDraw->id; + // XXX: We could use DuplicateHandle to make pDrawble->hSection + // available to the requesting process... ? + *type = WindowsDRIDrawablePixmap; + break; + + case GLX_DRAWABLE_PBUFFER: + glxWinDeferredCreateDrawable(pDrawable, pDrawable->base.config); + *handle = (uintptr_t)(pDrawable->hPbuffer); + *type = WindowsDRIDrawablePbuffer; + break; + + default: + assert(FALSE); + *handle = 0; + } + } + else { + HWND h; + /* The drawId XID doesn't identify a GLX drawable. The only other valid + alternative is that it is the XID of a window drawable that is being + used by the pre-GLX 1.3 interface */ + DrawablePtr pDraw; + int rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); + if (rc != Success || pDraw->type != DRAWABLE_WINDOW) { + return err; + } + + h = winGetWindowInfo((WindowPtr)(pDraw)); + *handle = (uintptr_t)h; + *type = WindowsDRIDrawableWindow; + } + + winDebug("glxWinQueryDrawable: type %d, handle %p\n", *type, (void *)(uintptr_t)*handle); + return Success; +} + +int +glxWinFBConfigIDToPixelFormatIndex(int scr, int fbConfigID) +{ + __GLXscreen *screen = glxGetScreen(screenInfo.screens[scr]); + __GLXconfig *c; + + for (c = screen->fbconfigs; + c != NULL; + c = c->next) { + if (c->fbconfigID == fbConfigID) + return ((GLXWinConfig *)c)->pixelFormatIndex; + } + + return 0; +} + +Bool +glxWinGetScreenAiglxIsActive(ScreenPtr pScreen) +{ + winPrivScreenPtr pWinScreen = winGetScreenPriv(pScreen); + return pWinScreen->fNativeGlActive; +} diff --git a/hw/xwin/glx/dri_helpers.h b/hw/xwin/glx/dri_helpers.h new file mode 100644 index 000000000..05bc9bc93 --- /dev/null +++ b/hw/xwin/glx/dri_helpers.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2014 Jon TURNEY + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef dri_helpers_h +#define dri_helpers_h + +#include "dixstruct.h" + +int +glxWinQueryDrawable(ClientPtr client, XID drawId, unsigned int *type, unsigned int *handle); + +int +glxWinFBConfigIDToPixelFormatIndex(int scr, int fbConfigID); + +Bool +glxWinGetScreenAiglxIsActive(ScreenPtr pScreen); + +#endif /* dri_helpers_h */ diff --git a/hw/xwin/glx/indirect.c b/hw/xwin/glx/indirect.c index e4be64228..b9881426c 100644 --- a/hw/xwin/glx/indirect.c +++ b/hw/xwin/glx/indirect.c @@ -81,12 +81,13 @@ #include "glwindows.h" #include <glx/glxserver.h> #include <glx/glxutil.h> -#include <glx/extension_string.h> #include <GL/glxtokens.h> #include <winpriv.h> #include <wgl_ext_api.h> #include <winglobals.h> +#include <indirect.h> +#include <setjmp.h> #define NUM_ELEMENTS(x) (sizeof(x)/ sizeof(x[1])) @@ -101,59 +102,13 @@ #define PFD_SUPPORT_COMPOSITION 0x00008000 #endif -/* ---------------------------------------------------------------------- */ -/* - * structure definitions - */ - -typedef struct __GLXWinContext __GLXWinContext; -typedef struct __GLXWinDrawable __GLXWinDrawable; -typedef struct __GLXWinScreen glxWinScreen; -typedef struct __GLXWinConfig GLXWinConfig; - -struct __GLXWinContext { - __GLXcontext base; - HGLRC ctx; /* Windows GL Context */ - __GLXWinContext *shareContext; /* Context with which we will share display lists and textures */ - HWND hwnd; /* For detecting when HWND has changed */ -}; - -struct __GLXWinDrawable { - __GLXdrawable base; - __GLXWinContext *drawContext; - __GLXWinContext *readContext; - - /* If this drawable is GLX_DRAWABLE_PBUFFER */ - HPBUFFERARB hPbuffer; - - /* If this drawable is GLX_DRAWABLE_PIXMAP */ - HDC dibDC; - HBITMAP hDIB; - HBITMAP hOldDIB; /* original DIB for DC */ - void *pOldBits; /* original pBits for this drawable's pixmap */ -}; - -struct __GLXWinScreen { - __GLXscreen base; - - /* Supported GLX extensions */ - unsigned char glx_enable_bits[__GLX_EXT_BYTES]; - - Bool has_WGL_ARB_multisample; - Bool has_WGL_ARB_pixel_format; - Bool has_WGL_ARB_pbuffer; - Bool has_WGL_ARB_render_texture; - - /* wrapped screen functions */ - RealizeWindowProcPtr RealizeWindow; - UnrealizeWindowProcPtr UnrealizeWindow; - CopyWindowProcPtr CopyWindow; -}; - -struct __GLXWinConfig { - __GLXconfig base; - int pixelFormatIndex; -}; +typedef struct { + int notOpenGL; + int rgbaFloat; + int unsignedRgbaFloat; + int unknownPixelType; + int unaccelerated; +} PixelFormatRejectStats; /* ---------------------------------------------------------------------- */ /* @@ -340,13 +295,16 @@ swap_method_name(int mthd) } static void -fbConfigsDump(unsigned int n, __GLXconfig * c) +fbConfigsDump(unsigned int n, __GLXconfig * c, PixelFormatRejectStats *rejects) { LogMessage(X_INFO, "%d fbConfigs\n", n); + LogMessage(X_INFO, "ignored pixel formats: %d not OpenGL, %d RBGA float, %d RGBA unsigned float, %d unknown pixel type, %d unaccelerated\n", + rejects->notOpenGL, rejects->rgbaFloat, rejects->unsignedRgbaFloat, + rejects->unknownPixelType, rejects->unaccelerated); if (g_iLogVerbose < 3) return; - ErrorF("%d fbConfigs\n", n); + ErrorF ("pxf vis fb render Ste aux accum MS drawable Group/\n"); ErrorF @@ -419,13 +377,15 @@ static Bool glxWinRealizeWindow(WindowPtr pWin); static Bool glxWinUnrealizeWindow(WindowPtr pWin); static void glxWinCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc); - +static Bool glxWinSetPixelFormat(HDC hdc, int bppOverride, int drawableTypeOverride, + __GLXscreen *screen, __GLXconfig *config); static HDC glxWinMakeDC(__GLXWinContext * gc, __GLXWinDrawable * draw, HDC * hdc, HWND * hwnd); static void glxWinReleaseDC(HWND hwnd, HDC hdc, __GLXWinDrawable * draw); static void glxWinCreateConfigs(HDC dc, glxWinScreen * screen); -static void glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen); +static void glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen, + PixelFormatRejectStats * rejects); static int fbConfigToPixelFormat(__GLXconfig * mode, PIXELFORMATDESCRIPTOR * pfdret, int drawableTypeOverride); @@ -520,6 +480,30 @@ glxLogExtensions(const char *prefix, const char *extensions) free(str); } +static jmp_buf jmp_sig; +static struct sigaction old_act; +extern Bool install_os_signal_handler; + +static void +glxWinScreenProbeSigHandler(int signo, siginfo_t * sip, void *context) +{ + // log a message + ErrorFSigSafe("segfault in WGL during glxWinScreenProbe()\n"); + + // show a messagebox + MessageBox(NULL, + "Windows OpenGL has been disabled as a crash occurred during initialization.\n" + "\n" + "Please try updating the display driver.\n" + "\n" + "You can disable the use of Windows OpenGL by starting the X server using the -nowgl option.", + XVENDORNAMESHORT, + MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); + + // continue via longjmp() + longjmp(jmp_sig, 1); +} + /* This is called by GlxExtensionInit() asking the GLX provider if it can handle the screen... */ static __GLXscreen * glxWinScreenProbe(ScreenPtr pScreen) @@ -531,6 +515,7 @@ glxWinScreenProbe(ScreenPtr pScreen) HWND hwnd; HDC hdc; HGLRC hglrc; + PixelFormatRejectStats rejects; GLWIN_DEBUG_MSG("glxWinScreenProbe"); @@ -551,8 +536,11 @@ glxWinScreenProbe(ScreenPtr pScreen) return NULL; // Select the native GL implementation (WGL) - if (glWinSelectImplementation(1)) + if (glWinSelectImplementation(1)) { + LogMessage(X_ERROR, "AIGLX: WGL not available\n"); + free(screen); return NULL; + } // create window class #define WIN_GL_TEST_WINDOW_CLASS "XWinGLTest" @@ -563,7 +551,7 @@ glxWinScreenProbe(ScreenPtr pScreen) WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_HREDRAW | CS_VREDRAW; + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -578,22 +566,79 @@ glxWinScreenProbe(ScreenPtr pScreen) } } + // The following tests seem particularly prone to crashing somewhere in the + // display driver's OpenGL implementation. So temporarily install a special + // SIGSEGV handler so can catch that and offer some remedial advice... + if (install_os_signal_handler) + { + struct sigaction act; + sigemptyset(&act.sa_mask); + act.sa_sigaction = glxWinScreenProbeSigHandler; + act.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &act, &old_act); + + if (setjmp(jmp_sig)) { + LogMessage(X_ERROR, "AIGLX: Not using WGL due to SEGV\n"); + goto error; + } + } + // create an invisible window for a scratch DC hwnd = CreateWindowExA(0, WIN_GL_TEST_WINDOW_CLASS, "XWin GL Renderer Capabilities Test Window", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL); - if (hwnd == NULL) + if (hwnd == NULL) { LogMessage(X_ERROR, "AIGLX: Couldn't create a window for render capabilities testing\n"); + goto error; + } hdc = GetDC(hwnd); + if (!hdc) { + LogMessage(X_ERROR, "AIGLX: Couldn't create a DC for render capabilities testing\n"); + goto error; + } + + // we must set a pixel format before we can create a context + { + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DEPTH_DONTCARE | PFD_DOUBLEBUFFER_DONTCARE | PFD_STEREO_DONTCARE, + PFD_TYPE_RGBA, + 24, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 0, + 0, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + int iPixelFormat = ChoosePixelFormat(hdc, &pfd); + if (iPixelFormat == 0) { + LogMessage(X_ERROR, "AIGLX: ChoosePixelFormat failed\n"); + goto error; + } + + if (!SetPixelFormat(hdc, iPixelFormat, NULL)) { + LogMessage(X_ERROR, "AIGLX: SetPixelFormat %d failed\n", iPixelFormat); + goto error; + } + LogMessage(X_INFO, "AIGLX: Testing pixelFormatIndex %d\n",iPixelFormat); + } - // we must set a pixel format before we can create a context, just use the first one... - SetPixelFormat(hdc, 1, NULL); hglrc = wglCreateContext(hdc); - wglMakeCurrent(hdc, hglrc); + if (!wglMakeCurrent(hdc, hglrc)) { + ErrorF("glxWinScreenProbe: wglMakeCurrent error: %08x dc %p ctx %p\n", + (unsigned)GetLastError(), hdc, hglrc); + } // initialize wgl extension proc pointers (don't call them before here...) // (but we need to have a current context for them to be resolvable) @@ -605,6 +650,8 @@ glxWinScreenProbe(ScreenPtr pScreen) gl_renderer = (const char *) glGetString(GL_RENDERER); ErrorF("GL_RENDERER: %s\n", gl_renderer); gl_extensions = (const char *) glGetString(GL_EXTENSIONS); + if (!gl_extensions) + gl_extensions = ""; wgl_extensions = wglGetExtensionsStringARBWrapper(hdc); if (!wgl_extensions) wgl_extensions = ""; @@ -614,10 +661,15 @@ glxWinScreenProbe(ScreenPtr pScreen) glxLogExtensions("WGL_EXTENSIONS: ", wgl_extensions); } + if (!gl_renderer) { + LogMessage(X_ERROR, + "AIGLX: Native renderer not identified\n"); + goto error; + } + if (strcasecmp(gl_renderer, "GDI Generic") == 0) { - free(screen); LogMessage(X_ERROR, - "AIGLX: Won't use generic native renderer as it is not accelerated\n"); + "AIGLX: Won't use the generic native renderer as it is not accelerated\n"); goto error; } @@ -704,8 +756,9 @@ glxWinScreenProbe(ScreenPtr pScreen) screen->base.pScreen = pScreen; // Creating the fbConfigs initializes screen->base.fbconfigs and screen->base.numFBConfigs + memset(&rejects, 0, sizeof(rejects)); if (strstr(wgl_extensions, "WGL_ARB_pixel_format")) { - glxWinCreateConfigsExt(hdc, screen); + glxWinCreateConfigsExt(hdc, screen, &rejects); /* Some graphics drivers appear to advertise WGL_ARB_pixel_format, @@ -718,6 +771,7 @@ glxWinScreenProbe(ScreenPtr pScreen) } if (screen->base.numFBConfigs <= 0) { + memset(&rejects, 0, sizeof(rejects)); glxWinCreateConfigs(hdc, screen); screen->has_WGL_ARB_pixel_format = FALSE; } @@ -726,7 +780,6 @@ glxWinScreenProbe(ScreenPtr pScreen) If we still didn't get any fbConfigs, we can't provide GLX for this screen */ if (screen->base.numFBConfigs <= 0) { - free(screen); LogMessage(X_ERROR, "AIGLX: No fbConfigs could be made from native OpenGL pixel formats\n"); goto error; @@ -778,7 +831,7 @@ glxWinScreenProbe(ScreenPtr pScreen) DestroyWindow(hwnd); // dump out fbConfigs now fbConfigIds and visualIDs have been assigned - fbConfigsDump(screen->base.numFBConfigs, screen->base.fbconfigs); + fbConfigsDump(screen->base.numFBConfigs, screen->base.fbconfigs, &rejects); /* Wrap RealizeWindow, UnrealizeWindow and CopyWindow on this screen */ screen->RealizeWindow = pScreen->RealizeWindow; @@ -788,9 +841,20 @@ glxWinScreenProbe(ScreenPtr pScreen) screen->CopyWindow = pScreen->CopyWindow; pScreen->CopyWindow = glxWinCopyWindow; + // Note that WGL is active on this screen + winSetScreenAiglxIsActive(pScreen); + + // Restore the previous sighandler + sigaction(SIGSEGV, &old_act, NULL); + return &screen->base; error: + // Restore the previous sighandler + sigaction(SIGSEGV, &old_act, NULL); + + free(screen); + // Something went wrong and we can't use the native GL implementation // so make sure the mesa GL implementation is selected instead glWinSelectImplementation(0); @@ -934,6 +998,10 @@ glxWinDrawableDestroy(__GLXdrawable * base) } if (glxPriv->hDIB) { + if (!CloseHandle(glxPriv->hSection)) { + ErrorF("CloseHandle failed: %s\n", glxWinErrorMessage()); + } + if (!DeleteObject(glxPriv->hDIB)) { ErrorF("DeleteObject failed: %s\n", glxWinErrorMessage()); } @@ -977,6 +1045,179 @@ glxWinCreateDrawable(ClientPtr client, return &glxPriv->base; } +void +glxWinDeferredCreateDrawable(__GLXWinDrawable *draw, __GLXconfig *config) +{ + switch (draw->base.type) { + case GLX_DRAWABLE_WINDOW: + { + WindowPtr pWin = (WindowPtr) draw->base.pDraw; + + if (!(config->drawableType & GLX_WINDOW_BIT)) { + ErrorF + ("glxWinDeferredCreateDrawable: tried to create a GLX_DRAWABLE_WINDOW drawable with a fbConfig which doesn't have drawableType GLX_WINDOW_BIT\n"); + } + + if (pWin == NULL) { + GLWIN_DEBUG_MSG("Deferring until X window is created"); + return; + } + + GLWIN_DEBUG_MSG("glxWinDeferredCreateDrawable: pWin %p", pWin); + + if (winGetWindowInfo(pWin) == NULL) { + GLWIN_DEBUG_MSG("Deferring until native window is created"); + return; + } + } + break; + + case GLX_DRAWABLE_PBUFFER: + { + if (draw->hPbuffer == NULL) { + __GLXscreen *screen; + glxWinScreen *winScreen; + int pixelFormat; + + // XXX: which DC are we supposed to use??? + HDC screenDC = GetDC(NULL); + + if (!(config->drawableType & GLX_PBUFFER_BIT)) { + ErrorF + ("glxWinDeferredCreateDrawable: tried to create a GLX_DRAWABLE_PBUFFER drawable with a fbConfig which doesn't have drawableType GLX_PBUFFER_BIT\n"); + } + + screen = glxGetScreen(screenInfo.screens[draw->base.pDraw->pScreen->myNum]); + winScreen = (glxWinScreen *) screen; + + pixelFormat = + fbConfigToPixelFormatIndex(screenDC, config, + GLX_PBUFFER_BIT, winScreen); + if (pixelFormat == 0) { + return; + } + + draw->hPbuffer = + wglCreatePbufferARBWrapper(screenDC, pixelFormat, + draw->base.pDraw->width, + draw->base.pDraw->height, NULL); + ReleaseDC(NULL, screenDC); + + if (draw->hPbuffer == NULL) { + ErrorF("wglCreatePbufferARBWrapper error: %s\n", + glxWinErrorMessage()); + return; + } + + GLWIN_DEBUG_MSG + ("glxWinDeferredCreateDrawable: pBuffer %p created for drawable %p", + draw->hPbuffer, draw); + } + } + break; + + case GLX_DRAWABLE_PIXMAP: + { + if (draw->dibDC == NULL) { + BITMAPINFOHEADER bmpHeader; + void *pBits; + __GLXscreen *screen; + DWORD size; + char name[MAX_PATH]; + + memset(&bmpHeader, 0, sizeof(BITMAPINFOHEADER)); + bmpHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpHeader.biWidth = draw->base.pDraw->width; + bmpHeader.biHeight = draw->base.pDraw->height; + bmpHeader.biPlanes = 1; + bmpHeader.biBitCount = draw->base.pDraw->bitsPerPixel; + bmpHeader.biCompression = BI_RGB; + + if (!(config->drawableType & GLX_PIXMAP_BIT)) { + ErrorF + ("glxWinDeferredCreateDrawable: tried to create a GLX_DRAWABLE_PIXMAP drawable with a fbConfig which doesn't have drawableType GLX_PIXMAP_BIT\n"); + } + + draw->dibDC = CreateCompatibleDC(NULL); + if (draw->dibDC == NULL) { + ErrorF("CreateCompatibleDC error: %s\n", glxWinErrorMessage()); + return; + } + +#define RASTERWIDTHBYTES(bmi) (((((bmi)->biWidth*(bmi)->biBitCount)+31)&~31)>>3) + size = bmpHeader.biHeight * RASTERWIDTHBYTES(&bmpHeader); + ErrorF("shared memory region size %zu + %u\n", sizeof(BITMAPINFOHEADER), size); + + // Create unique name for mapping based on XID + // + // XXX: not quite unique as potentially this name could be used in + // another server instance. Not sure how to deal with that. + snprintf(name, sizeof(name), "Local\\CYGWINX_WINDOWSDRI_%08x", draw->base.pDraw->id); + ErrorF("shared memory region name %s\n", name); + + // Create a file mapping backed by the pagefile + draw->hSection = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(BITMAPINFOHEADER) + size, name); + if (draw->hSection == NULL) { + ErrorF("CreateFileMapping error: %s\n", glxWinErrorMessage()); + return; + } + + draw->hDIB = + CreateDIBSection(draw->dibDC, (BITMAPINFO *) &bmpHeader, + DIB_RGB_COLORS, &pBits, draw->hSection, sizeof(BITMAPINFOHEADER)); + if (draw->dibDC == NULL) { + ErrorF("CreateDIBSection error: %s\n", glxWinErrorMessage()); + return; + } + + // Store a copy of the BITMAPINFOHEADER at the start of the shared + // memory for the information of the receiving process + { + LPVOID pData = MapViewOfFile(draw->hSection, FILE_MAP_WRITE, 0, 0, 0); + memcpy(pData, (void *)&bmpHeader, sizeof(BITMAPINFOHEADER)); + UnmapViewOfFile(pData); + } + + // XXX: CreateDIBSection insists on allocating the bitmap memory for us, so we're going to + // need some jiggery pokery to point the underlying X Drawable's bitmap at the same set of bits + // so that they can be read with XGetImage as well as glReadPixels, assuming the formats are + // even compatible ... + draw->pOldBits = ((PixmapPtr) draw->base.pDraw)->devPrivate.ptr; + ((PixmapPtr) draw->base.pDraw)->devPrivate.ptr = pBits; + + // Select the DIB into the DC + draw->hOldDIB = SelectObject(draw->dibDC, draw->hDIB); + if (!draw->hOldDIB) { + ErrorF("SelectObject error: %s\n", glxWinErrorMessage()); + } + + screen = glxGetScreen(screenInfo.screens[draw->base.pDraw->pScreen->myNum]); + + // Set the pixel format of the bitmap + glxWinSetPixelFormat(draw->dibDC, + draw->base.pDraw->bitsPerPixel, + GLX_PIXMAP_BIT, + screen, + config); + + GLWIN_DEBUG_MSG + ("glxWinDeferredCreateDrawable: DIB bitmap %p created for drawable %p", + draw->hDIB, draw); + } + } + break; + + default: + { + ErrorF + ("glxWinDeferredCreateDrawable: tried to attach unhandled drawable type %d\n", + draw->base.type); + return; + } + } +} + /* ---------------------------------------------------------------------- */ /* * Texture functions @@ -1020,13 +1261,10 @@ glxWinReleaseTexImage(__GLXcontext * baseContext, */ static Bool -glxWinSetPixelFormat(__GLXWinContext * gc, HDC hdc, int bppOverride, - int drawableTypeOverride) +glxWinSetPixelFormat(HDC hdc, int bppOverride, int drawableTypeOverride, + __GLXscreen *screen, __GLXconfig *config) { - __GLXscreen *screen = gc->base.pGlxScreen; glxWinScreen *winScreen = (glxWinScreen *) screen; - - __GLXconfig *config = gc->base.config; GLXWinConfig *winConfig = (GLXWinConfig *) config; GLWIN_DEBUG_MSG("glxWinSetPixelFormat: pixelFormatIndex %d", @@ -1072,12 +1310,35 @@ glxWinSetPixelFormat(__GLXWinContext * gc, HDC hdc, int bppOverride, (config->redBits + config->greenBits + config->blueBits), bppOverride, config->drawableType, drawableTypeOverride); - if (!winScreen->has_WGL_ARB_pixel_format) { + if (winScreen->has_WGL_ARB_pixel_format) { + int pixelFormat = + fbConfigToPixelFormatIndex(hdc, config, + drawableTypeOverride, winScreen); + if (pixelFormat != 0) { + GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d", + pixelFormat); + ErrorF + ("wglChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n", + pixelFormat, winConfig->pixelFormatIndex); + + if (!SetPixelFormat(hdc, pixelFormat, NULL)) { + ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); + return FALSE; + } + } + } + + /* + For some drivers, wglChoosePixelFormatARB() can fail when the provided + DC doesn't belong to the driver (e.g. it's a compatible DC for a bitmap, + so allow fallback to ChoosePixelFormat() + */ + { PIXELFORMATDESCRIPTOR pfd; int pixelFormat; /* convert fbConfig to PFD */ - if (fbConfigToPixelFormat(gc->base.config, &pfd, drawableTypeOverride)) { + if (fbConfigToPixelFormat(config, &pfd, drawableTypeOverride)) { ErrorF("glxWinSetPixelFormat: fbConfigToPixelFormat failed\n"); return FALSE; } @@ -1108,25 +1369,6 @@ glxWinSetPixelFormat(__GLXWinContext * gc, HDC hdc, int bppOverride, return FALSE; } } - else { - int pixelFormat = - fbConfigToPixelFormatIndex(hdc, gc->base.config, - drawableTypeOverride, winScreen); - if (pixelFormat == 0) { - return FALSE; - } - - GLWIN_DEBUG_MSG("wglChoosePixelFormat: chose pixelFormatIndex %d", - pixelFormat); - ErrorF - ("wglChoosePixelFormat: chose pixelFormatIndex %d (rather than %d as originally planned)\n", - pixelFormat, winConfig->pixelFormatIndex); - - if (!SetPixelFormat(hdc, pixelFormat, NULL)) { - ErrorF("SetPixelFormat error: %s\n", glxWinErrorMessage()); - return FALSE; - } - } return TRUE; } @@ -1178,7 +1420,7 @@ glxWinMakeDC(__GLXWinContext * gc, __GLXWinDrawable * draw, HDC * hdc, gc->hwnd = *hwnd; /* We must select a pixelformat, but SetPixelFormat can only be called once for a window... */ - if (!glxWinSetPixelFormat(gc, *hdc, 0, GLX_WINDOW_BIT)) { + if (!glxWinSetPixelFormat(*hdc, 0, GLX_WINDOW_BIT, gc->base.pGlxScreen, gc->base.config)) { ErrorF("glxWinSetPixelFormat error: %s\n", glxWinErrorMessage()); ReleaseDC(*hwnd, *hdc); @@ -1264,140 +1506,7 @@ glxWinDeferredCreateContext(__GLXWinContext * gc, __GLXWinDrawable * draw) ("glxWinDeferredCreateContext: attach context %p to drawable %p", gc, draw); - switch (draw->base.type) { - case GLX_DRAWABLE_WINDOW: - { - WindowPtr pWin = (WindowPtr) draw->base.pDraw; - - if (!(gc->base.config->drawableType & GLX_WINDOW_BIT)) { - ErrorF - ("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_WINDOW_BIT to a GLX_DRAWABLE_WINDOW drawable\n"); - } - - if (pWin == NULL) { - GLWIN_DEBUG_MSG("Deferring until X window is created"); - return; - } - - GLWIN_DEBUG_MSG("glxWinDeferredCreateContext: pWin %p", pWin); - - if (winGetWindowInfo(pWin) == NULL) { - GLWIN_DEBUG_MSG("Deferring until native window is created"); - return; - } - } - break; - - case GLX_DRAWABLE_PBUFFER: - { - if (draw->hPbuffer == NULL) { - __GLXscreen *screen; - glxWinScreen *winScreen; - int pixelFormat; - - // XXX: which DC are we supposed to use??? - HDC screenDC = GetDC(NULL); - - if (!(gc->base.config->drawableType & GLX_PBUFFER_BIT)) { - ErrorF - ("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_PBUFFER_BIT to a GLX_DRAWABLE_PBUFFER drawable\n"); - } - - screen = gc->base.pGlxScreen; - winScreen = (glxWinScreen *) screen; - - pixelFormat = - fbConfigToPixelFormatIndex(screenDC, gc->base.config, - GLX_PBUFFER_BIT, winScreen); - if (pixelFormat == 0) { - return; - } - - draw->hPbuffer = - wglCreatePbufferARBWrapper(screenDC, pixelFormat, - draw->base.pDraw->width, - draw->base.pDraw->height, NULL); - ReleaseDC(NULL, screenDC); - - if (draw->hPbuffer == NULL) { - ErrorF("wglCreatePbufferARBWrapper error: %s\n", - glxWinErrorMessage()); - return; - } - - GLWIN_DEBUG_MSG - ("glxWinDeferredCreateContext: pBuffer %p created for drawable %p", - draw->hPbuffer, draw); - } - } - break; - - case GLX_DRAWABLE_PIXMAP: - { - if (draw->dibDC == NULL) { - BITMAPINFOHEADER bmpHeader; - void *pBits; - - memset(&bmpHeader, 0, sizeof(BITMAPINFOHEADER)); - bmpHeader.biSize = sizeof(BITMAPINFOHEADER); - bmpHeader.biWidth = draw->base.pDraw->width; - bmpHeader.biHeight = draw->base.pDraw->height; - bmpHeader.biPlanes = 1; - bmpHeader.biBitCount = draw->base.pDraw->bitsPerPixel; - bmpHeader.biCompression = BI_RGB; - - if (!(gc->base.config->drawableType & GLX_PIXMAP_BIT)) { - ErrorF - ("glxWinDeferredCreateContext: tried to attach a context whose fbConfig doesn't have drawableType GLX_PIXMAP_BIT to a GLX_DRAWABLE_PIXMAP drawable\n"); - } - - draw->dibDC = CreateCompatibleDC(NULL); - if (draw->dibDC == NULL) { - ErrorF("CreateCompatibleDC error: %s\n", glxWinErrorMessage()); - return; - } - - draw->hDIB = - CreateDIBSection(draw->dibDC, (BITMAPINFO *) &bmpHeader, - DIB_RGB_COLORS, &pBits, 0, 0); - if (draw->dibDC == NULL) { - ErrorF("CreateDIBSection error: %s\n", glxWinErrorMessage()); - return; - } - - // XXX: CreateDIBSection insists on allocating the bitmap memory for us, so we're going to - // need some jiggery pokery to point the underlying X Drawable's bitmap at the same set of bits - // so that they can be read with XGetImage as well as glReadPixels, assuming the formats are - // even compatible ... - draw->pOldBits = ((PixmapPtr) draw->base.pDraw)->devPrivate.ptr; - ((PixmapPtr) draw->base.pDraw)->devPrivate.ptr = pBits; - - // Select the DIB into the DC - draw->hOldDIB = SelectObject(draw->dibDC, draw->hDIB); - if (!draw->hOldDIB) { - ErrorF("SelectObject error: %s\n", glxWinErrorMessage()); - } - - // Set the pixel format of the bitmap - glxWinSetPixelFormat(gc, draw->dibDC, - draw->base.pDraw->bitsPerPixel, - GLX_PIXMAP_BIT); - - GLWIN_DEBUG_MSG - ("glxWinDeferredCreateContext: DIB bitmap %p created for drawable %p", - draw->hDIB, draw); - } - } - break; - - default: - { - ErrorF - ("glxWinDeferredCreateContext: tried to attach unhandled drawable type %d\n", - draw->base.type); - return; - } - } + glxWinDeferredCreateDrawable(draw, gc->base.config); dc = glxWinMakeDC(gc, draw, &dc, &hwnd); gc->ctx = wglCreateContext(dc); @@ -1913,6 +2022,8 @@ glxWinCreateConfigs(HDC hdc, glxWinScreen * screen) /* EXT_visual_rating / GLX 1.2 */ if (pfd.dwFlags & PFD_GENERIC_FORMAT) { c->base.visualRating = GLX_SLOW_VISUAL_EXT; + GLWIN_DEBUG_MSG("pixelFormat %d is un-accelerated, skipping", i + 1); + continue; } else { // PFD_GENERIC_ACCELERATED is not considered, so this may be MCD or ICD acclerated... @@ -2047,7 +2158,7 @@ getAttrValue(const int attrs[], int values[], unsigned int num, int attr, // Create the GLXconfigs using wglGetPixelFormatAttribfvARB() extension // static void -glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen) +glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen, PixelFormatRejectStats * rejects) { GLXWinConfig *c, *result, *prev = NULL; int i = 0; @@ -2159,6 +2270,7 @@ glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen) #define ATTR_VALUE(a, d) getAttrValue(attrs, values, num_attrs, (a), (d)) if (!ATTR_VALUE(WGL_SUPPORT_OPENGL_ARB, 0)) { + rejects->notOpenGL++; GLWIN_DEBUG_MSG ("pixelFormat %d isn't WGL_SUPPORT_OPENGL_ARB, skipping", i + 1); @@ -2195,11 +2307,13 @@ glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen) break; case WGL_TYPE_RGBA_FLOAT_ARB: + rejects->rgbaFloat++; GLWIN_DEBUG_MSG ("pixelFormat %d is WGL_TYPE_RGBA_FLOAT_ARB, skipping", i + 1); continue; case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT: + rejects->unsignedRgbaFloat++; GLWIN_DEBUG_MSG ("pixelFormat %d is WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT, skipping", i + 1); @@ -2212,6 +2326,7 @@ glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen) break; default: + rejects->unknownPixelType++; ErrorF ("wglGetPixelFormatAttribivARB returned unknown value 0x%x for WGL_PIXEL_TYPE_ARB\n", ATTR_VALUE(WGL_PIXEL_TYPE_ARB, 0)); @@ -2252,7 +2367,10 @@ glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen) ATTR_VALUE(WGL_ACCELERATION_ARB, 0)); case WGL_NO_ACCELERATION_ARB: + rejects->unaccelerated++; c->base.visualRating = GLX_SLOW_VISUAL_EXT; + GLWIN_DEBUG_MSG("pixelFormat %d is un-accelerated, skipping", i + 1); + continue; break; case WGL_GENERIC_ACCELERATION_ARB: @@ -2324,11 +2442,16 @@ glxWinCreateConfigsExt(HDC hdc, glxWinScreen * screen) /* SGIX_pbuffer / GLX 1.3 */ if (screen->has_WGL_ARB_pbuffer) { - c->base.maxPbufferWidth = ATTR_VALUE(WGL_MAX_PBUFFER_WIDTH_ARB, -1); - c->base.maxPbufferHeight = - ATTR_VALUE(WGL_MAX_PBUFFER_HEIGHT_ARB, -1); - c->base.maxPbufferPixels = - ATTR_VALUE(WGL_MAX_PBUFFER_PIXELS_ARB, -1); + // mesa libGL "can't handle the truth" about max pbuffer size. + // We must report 0, which exactly matches what it expects + // + // ATTR_VALUE(WGL_MAX_PBUFFER_WIDTH_ARB, -1); + // ATTR_VALUE(WGL_MAX_PBUFFER_PIXELS_ARB, -1); + // ATTR_VALUE(WGL_MAX_PBUFFER_HEIGHT_ARB, -1); + // + c->base.maxPbufferWidth = 0; + c->base.maxPbufferHeight = 0; + c->base.maxPbufferPixels = 0; } else { c->base.maxPbufferWidth = -1; diff --git a/hw/xwin/glx/indirect.h b/hw/xwin/glx/indirect.h new file mode 100644 index 000000000..163375556 --- /dev/null +++ b/hw/xwin/glx/indirect.h @@ -0,0 +1,94 @@ +/* + * Copyright © 2014 Jon TURNEY + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef indirect_h +#define indirect_h + +#include <X11/Xwindows.h> +#include <GL/wglext.h> +#include <glx/extension_string.h> + +/* ---------------------------------------------------------------------- */ +/* + * structure definitions + */ + +typedef struct __GLXWinContext __GLXWinContext; +typedef struct __GLXWinDrawable __GLXWinDrawable; +typedef struct __GLXWinScreen glxWinScreen; +typedef struct __GLXWinConfig GLXWinConfig; + +struct __GLXWinContext { + __GLXcontext base; + HGLRC ctx; /* Windows GL Context */ + __GLXWinContext *shareContext; /* Context with which we will share display lists and textures */ + HWND hwnd; /* For detecting when HWND has changed */ +}; + +struct __GLXWinDrawable { + __GLXdrawable base; + __GLXWinContext *drawContext; + __GLXWinContext *readContext; + + /* If this drawable is GLX_DRAWABLE_PBUFFER */ + HPBUFFERARB hPbuffer; + + /* If this drawable is GLX_DRAWABLE_PIXMAP */ + HDC dibDC; + HANDLE hSection; /* file mapping handle */ + HBITMAP hDIB; + HBITMAP hOldDIB; /* original DIB for DC */ + void *pOldBits; /* original pBits for this drawable's pixmap */ +}; + +struct __GLXWinScreen { + __GLXscreen base; + + /* Supported GLX extensions */ + unsigned char glx_enable_bits[__GLX_EXT_BYTES]; + + Bool has_WGL_ARB_multisample; + Bool has_WGL_ARB_pixel_format; + Bool has_WGL_ARB_pbuffer; + Bool has_WGL_ARB_render_texture; + + /* wrapped screen functions */ + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + CopyWindowProcPtr CopyWindow; +}; + +struct __GLXWinConfig { + __GLXconfig base; + int pixelFormatIndex; +}; + +/* ---------------------------------------------------------------------- */ +/* + * function prototypes + */ + +void +glxWinDeferredCreateDrawable(__GLXWinDrawable *draw, __GLXconfig *config); + +#endif /* indirect_h */ diff --git a/hw/xwin/glx/winpriv.c b/hw/xwin/glx/winpriv.c index e6afbff01..4bb2b3104 100644 --- a/hw/xwin/glx/winpriv.c +++ b/hw/xwin/glx/winpriv.c @@ -14,6 +14,41 @@ void winCreateWindowsWindow(WindowPtr pWin); +static void +winCreateWindowsWindowHierarchy(WindowPtr pWin) +{ + winWindowPriv(pWin); + + winDebug("winCreateWindowsWindowHierarchy - pWin:%p XID:0x%x \n", pWin, + pWin->drawable.id); + + if (!pWin) + return; + + /* stop recursion at root window */ + if (pWin == pWin->drawable.pScreen->root) + return; + + /* recursively ensure parent window exists */ + if (pWin->parent) + winCreateWindowsWindowHierarchy(pWin->parent); + + /* ensure this window exists */ + if (pWinPriv->hWnd == NULL) { + winCreateWindowsWindow(pWin); + + /* ... and if it's already been mapped, make sure it's visible */ + if (pWin->mapped) { + /* Display the window without activating it */ + if (pWin->drawable.class != InputOnly) + ShowWindow(pWinPriv->hWnd, SW_SHOWNOACTIVATE); + + /* Send first paint message */ + UpdateWindow(pWinPriv->hWnd); + } + } +} + /** * Return size and handles of a window. * If pWin is NULL, then the information for the root window is requested. @@ -50,7 +85,7 @@ winGetWindowInfo(WindowPtr pWin) } if (pWinPriv->hWnd == NULL) { - winCreateWindowsWindow(pWin); + winCreateWindowsWindowHierarchy(pWin); winDebug("winGetWindowInfo: forcing window to exist\n"); } @@ -119,3 +154,10 @@ winCheckScreenAiglxIsSupported(ScreenPtr pScreen) return FALSE; } + +void +winSetScreenAiglxIsActive(ScreenPtr pScreen) +{ + winPrivScreenPtr pWinScreen = winGetScreenPriv(pScreen); + pWinScreen->fNativeGlActive = TRUE; +} diff --git a/hw/xwin/glx/winpriv.h b/hw/xwin/glx/winpriv.h index dce1edf48..6f695a971 100644 --- a/hw/xwin/glx/winpriv.h +++ b/hw/xwin/glx/winpriv.h @@ -9,3 +9,4 @@ HWND winGetWindowInfo(WindowPtr pWin); Bool winCheckScreenAiglxIsSupported(ScreenPtr pScreen); +void winSetScreenAiglxIsActive(ScreenPtr pScreen); diff --git a/hw/xwin/layout_mapping_check.c b/hw/xwin/layout_mapping_check.c new file mode 100644 index 000000000..429be9821 --- /dev/null +++ b/hw/xwin/layout_mapping_check.c @@ -0,0 +1,51 @@ +/* + * Copyright © 2015 Jon TURNEY + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "winlayouts.h" + +int main() +{ + WinKBLayoutPtr pLayout; + for (pLayout = winKBLayouts; pLayout->winlayout != -1; pLayout++) { + char cmd[1024]; + strcpy(cmd, "setxkbmap "); + strcat(cmd, "-layout "); + strcat(cmd, pLayout->xkblayout); + strcat(cmd, " -model "); + strcat(cmd, pLayout->xkbmodel); + if (pLayout->xkbvariant) { + strcat(cmd, " -variant "); + strcat(cmd, pLayout->xkbvariant); + } + if (pLayout->xkboptions) { + strcat(cmd, " -options "); + strcat(cmd, pLayout->xkboptions); + } + if (system(cmd)) { + printf("'%s' failed\n", cmd); + } + } +} diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man index d68ee2a41..d28fb3dbc 100644 --- a/hw/xwin/man/XWin.man +++ b/hw/xwin/man/XWin.man @@ -124,7 +124,8 @@ Alternative name for \fB\-resize=scrollbars\fP. .SH OPTIONS CONTROLLING RESIZE BEHAVIOUR .TP 8 .B \-resize[=none|scrollbars|randr] -Select the resize mode of an X screen. The default is randr. +Select the resize mode of an X screen. +The default is \fBnone\fP if \fB\-fullscreen\fP is used, \fBrandr\fP otherwise. .RS .IP \fB\-resize=none\fP 8 @@ -174,6 +175,12 @@ on its own is equivalent to \fB\-resize=randr\fP Add the host name to the window title for X applications which are running on remote hosts, when that information is available and it's useful to do so. The default is enabled. +.TP 8 +.B \-compositewm +Experimental. +Use Composite extension redirection to maintain a bitmap image of each top-level +X window, so window contents which are occluded show correctly in task bar and +task switcher previews. .SH OPTIONS CONTROLLING WINDOWS INTEGRATION .TP 8 @@ -350,9 +357,6 @@ Color map manipulation is not supported, so the PseudoColor visual will not have the correct colors. This option is intended to allow applications which only work with a depth 8 visual to operate in TrueColor modes. -.TP 8 -.B \-internalwm -Run the internal window manager. .SH LOG FILE As it runs \fIXWin\fP writes messages indicating the most relevant events diff --git a/hw/xwin/man/XWinrc.man b/hw/xwin/man/XWinrc.man index 71d8dad23..60b8ce1ec 100644 --- a/hw/xwin/man/XWinrc.man +++ b/hw/xwin/man/XWinrc.man @@ -54,6 +54,35 @@ There are four kinds of instructions: miscellaneous, menu, icon and style. .SH Miscellaneous instruction .TP 8 +.B DPI \fIresolution\fP +Sets the resolution for all screens, in dots per inch. To be used when +the server cannot determine the screen size(s) from the hardware. + +.TP 8 +.B XKBLayout \fIlayout\fP +.TP 8 +.B XKBModel \fImodel\fP +.TP 8 +.B XKBOptions \fIoption\fP +.TP 8 +.B XKBRules \fIrule\fP +.TP 8 +.B XKBVariant \fIvariant\fp +These options configure the xkeyboard extension to load a particular +keyboard map as the X server starts. The behavior is similar to the +\fIsetxkbmap\fP(1) program. + +See the \fIxkeyboard-config\fP(__miscmansuffix__) manual page for a list of +keyboard configurations. + +Alternatively, you can use \fIsetxkbmap\fP(1) program after \fIXWin\fP +is running. + +The default is to select a keyboard configuration matching your current +layout as reported by \fIWindows\fP, if known, or the default X server +configuration if no matching keyboard configuration was found. + +.TP 8 .B DEBUG \fIString\fP The \fIString\fP is printed to the XWin log file. @@ -171,7 +200,7 @@ will be used. .SH Style Instructions .TP 8 .B STYLES { -\fIclass-or-name-of-window\fP \fIstyle-keyword-1\fP \fIstyle-keyword-2\fP +\fIclass-or-name-of-window\fP \fIstyle-keyword-1\fP \fIstyle-keyword-2\fP \fIstyle-keyword-3\fP .br \fI...\fP .br @@ -216,8 +245,14 @@ No Windows title bar and just a thin-line border, for the class or name. .br No Windows title bar or border, for the class or name. -One keyword in \fIstyle-keyword-1\fP can be used with one keyword in \fIstyle-keyword-2\fP, -or any keyword can be used singly. +\fIstyle-keyword-3\fP + +\fBSKIPTASKBAR\fP +.br +Omit the class or name from being listed in the Windows taskbar. + +Up to one keyword from each of these three groups can be used. Not all +groups need be used, and the keywords can be given in any order. .SH EXAMPLE diff --git a/hw/xwin/system.XWinrc b/hw/xwin/system.XWinrc index f0771c610..87d714a68 100644 --- a/hw/xwin/system.XWinrc +++ b/hw/xwin/system.XWinrc @@ -81,38 +81,46 @@ // own configuration file. // Make some menus... -menu apps { - xterm exec "xterm" - "Emacs" exec "emacs" - notepad exec notepad - xload exec "xload -display %display%" # Comment -} +# menu apps { +# xterm exec "xterm" +# "Emacs" exec "emacs" +# notepad exec notepad +# xload exec "xload -display %display%" # Comment +# } menu root { +// "Applications" menu apps // Comments fit here, too... - "Reload .XWinrc" RELOAD - "Applications" menu apps - SEParATOR -} +// SEPARATOR -menu aot { - Separator - "Always on Top" alwaysontop -} + FAQ EXEC "cygstart http://x.cygwin.com/docs/faq/cygwin-x-faq.html" + "User's Guide" EXEC "cygstart http://x.cygwin.com/docs/ug/cygwin-x-ug.html" + SEPARATOR + "View logfile" EXEC "xterm -title $XWINLOGFILE -e less +F $XWINLOGFILE" + SEPARATOR -menu xtermspecial { - "Emacs" exec "emacs" - "Always on Top" alwaysontop - SepArAtor + "Reload .XWinrc" RELOAD + SEParATOR } RootMenu root -DefaultSysMenu aot atend - -SysMenu { - "xterm" xtermspecial atstart -} +# menu aot { +# Separator +# "Always on Top" alwaysontop +# } +# +# menu xtermspecial { +# "Emacs" exec "emacs" +# "Always on Top" alwaysontop +# SepArAtor +# } +# +# DefaultSysMenu aot atend +# +# SysMenu { +# "xterm" xtermspecial atstart +# } # IconDirectory "c:\winnt\" diff --git a/hw/xwin/win.h b/hw/xwin/win.h index 5710ea852..eac91bd7c 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -162,7 +162,6 @@ #include "mipointer.h" #include "X11/keysym.h" #include "micoord.h" -#include "dix.h" #include "miline.h" #include "shadow.h" #include "fb.h" @@ -272,6 +271,8 @@ typedef Bool (*winFinishScreenInitProcPtr) (int, ScreenPtr, int, char **); typedef Bool (*winBltExposedRegionsProcPtr) (ScreenPtr); +typedef Bool (*winBltExposedWindowRegionProcPtr) (ScreenPtr, WindowPtr); + typedef Bool (*winActivateAppProcPtr) (ScreenPtr); typedef Bool (*winRedrawScreenProcPtr) (ScreenPtr pScreen); @@ -287,38 +288,13 @@ typedef Bool (*winCreateColormapProcPtr) (ColormapPtr pColormap); typedef Bool (*winDestroyColormapProcPtr) (ColormapPtr pColormap); -typedef Bool (*winHotKeyAltTabProcPtr) (ScreenPtr); - typedef Bool (*winCreatePrimarySurfaceProcPtr) (ScreenPtr); typedef Bool (*winReleasePrimarySurfaceProcPtr) (ScreenPtr); -typedef Bool (*winFinishCreateWindowsWindowProcPtr) (WindowPtr pWin); - typedef Bool (*winCreateScreenResourcesProc) (ScreenPtr); /* - * GC (graphics context) privates - */ - -typedef struct { - HDC hdc; - HDC hdcMem; -} winPrivGCRec, *winPrivGCPtr; - -/* - * Pixmap privates - */ - -typedef struct { - HDC hdcSelected; - HBITMAP hBitmap; - BYTE *pbBits; - DWORD dwScanlineBytes; - BITMAPINFOHEADER *pbmih; -} winPrivPixmapRec, *winPrivPixmapPtr; - -/* * Colormap privates */ @@ -329,6 +305,7 @@ typedef struct { PALETTEENTRY peColors[WIN_NUM_PALETTE_ENTRIES]; } winPrivCmapRec, *winPrivCmapPtr; + /* * Windows Cursor handling. */ @@ -348,7 +325,8 @@ typedef struct { * Resize modes */ typedef enum { - notAllowed, + resizeDefault = -1, + resizeNotAllowed, resizeWithScrollbars, resizeWithRandr } winResizeMode; @@ -404,12 +382,11 @@ typedef struct { Bool fDecoration; #ifdef XWIN_MULTIWINDOWEXTWM Bool fMWExtWM; - Bool fInternalWM; - Bool fAnotherWMRunning; #endif Bool fRootless; #ifdef XWIN_MULTIWINDOW Bool fMultiWindow; + Bool fCompositeWM; #endif #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) Bool fMultiMonitorOverride; @@ -517,6 +494,7 @@ typedef struct _winPrivScreenRec { winCreateBoundingWindowProcPtr pwinCreateBoundingWindow; winFinishScreenInitProcPtr pwinFinishScreenInit; winBltExposedRegionsProcPtr pwinBltExposedRegions; + winBltExposedWindowRegionProcPtr pwinBltExposedWindowRegion; winActivateAppProcPtr pwinActivateApp; winRedrawScreenProcPtr pwinRedrawScreen; winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette; @@ -524,17 +502,10 @@ typedef struct _winPrivScreenRec { winStoreColorsProcPtr pwinStoreColors; winCreateColormapProcPtr pwinCreateColormap; winDestroyColormapProcPtr pwinDestroyColormap; - winHotKeyAltTabProcPtr pwinHotKeyAltTab; winCreatePrimarySurfaceProcPtr pwinCreatePrimarySurface; winReleasePrimarySurfaceProcPtr pwinReleasePrimarySurface; - winCreateScreenResourcesProc pwinCreateScreenResources; -#ifdef XWIN_MULTIWINDOW - /* Window Procedures for MultiWindow mode */ - winFinishCreateWindowsWindowProcPtr pwinFinishCreateWindowsWindow; -#endif - /* Window Procedures for Rootless mode */ CreateWindowProcPtr CreateWindow; DestroyWindowProcPtr DestroyWindow; @@ -554,6 +525,8 @@ typedef struct _winPrivScreenRec { SetShapeProcPtr SetShape; winCursorRec cursor; + + Bool fNativeGlActive; } winPrivScreenRec; #ifdef XWIN_MULTIWINDOWEXTWM @@ -828,9 +801,6 @@ void */ int - winTranslateKey(WPARAM wParam, LPARAM lParam); - -int winKeybdProc(DeviceIntPtr pDeviceInt, int iState); void @@ -839,20 +809,6 @@ void void winRestoreModeKeyStates(void); -Bool - winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam); - -void - winKeybdReleaseKeys(void); - -void - winSendKeyEvent(DWORD dwKey, Bool fDown); - -BOOL winCheckKeyPressed(WPARAM wParam, LPARAM lParam); - -void - winFixShiftKeys(int iScanCode); - /* * winkeyhook.c */ @@ -881,14 +837,7 @@ int winMouseProc(DeviceIntPtr pDeviceInt, int iState); int - winMouseWheel(int *iTotalDeltaZ, int iDeltaZ, int iButtonUp, int iButtonDown); - -void - winMouseButtonsSendEvent(int iEventType, int iButton); - -int - -winMouseButtonsHandle(ScreenPtr pScreen, + winMouseButtonsHandle(ScreenPtr pScreen, int iEventType, int iButton, WPARAM wParam); void @@ -1027,6 +976,8 @@ int LRESULT CALLBACK winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK +winChildWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); #endif /* @@ -1137,9 +1088,6 @@ winMWExtWMUpdateWindowDecoration(win32RootlessWindowPtr pRLWinPriv, wBOOL CALLBACK winMWExtWMDecorateWindow(HWND hwnd, LPARAM lParam); -Bool - winIsInternalWMRunning(winScreenInfoPtr pScreenInfo); - void winMWExtWMRestackWindows(ScreenPtr pScreen); #endif diff --git a/hw/xwin/winallpriv.c b/hw/xwin/winallpriv.c index 816b030ca..d73fc96cd 100644 --- a/hw/xwin/winallpriv.c +++ b/hw/xwin/winallpriv.c @@ -79,20 +79,6 @@ winAllocatePrivates(ScreenPtr pScreen) /* Save the screen private pointer */ winSetScreenPriv(pScreen, pScreenPriv); - /* Reserve GC memory for our privates */ - if (!dixRegisterPrivateKey - (g_iGCPrivateKey, PRIVATE_GC, sizeof(winPrivGCRec))) { - ErrorF("winAllocatePrivates - AllocateGCPrivate () failed\n"); - return FALSE; - } - - /* Reserve Pixmap memory for our privates */ - if (!dixRegisterPrivateKey - (g_iPixmapPrivateKey, PRIVATE_PIXMAP, sizeof(winPrivPixmapRec))) { - ErrorF("winAllocatePrivates - AllocatePixmapPrivates () failed\n"); - return FALSE; - } - /* Reserve Window memory for our privates */ if (!dixRegisterPrivateKey (g_iWindowPrivateKey, PRIVATE_WINDOW, sizeof(winPrivWinRec))) { diff --git a/hw/xwin/winauth.c b/hw/xwin/winauth.c index 7efa1c00f..fcad49e9f 100644 --- a/hw/xwin/winauth.c +++ b/hw/xwin/winauth.c @@ -38,6 +38,16 @@ #include "securitysrv.h" #include "os/osdep.h" +#include <xcb/xcb.h> + +/* Need to get this from Xlib.h */ +extern void XSetAuthorization( + const char * /* name */, + int /* namelen */, + const char * /* data */, + int /* datalen */ +); + /* * Constants */ @@ -51,6 +61,7 @@ static XID g_authId = 0; static unsigned int g_uiAuthDataLen = 0; static char *g_pAuthData = NULL; +static xcb_auth_info_t auth_info; /* * Code to generate a MIT-MAGIC-COOKIE-1, copied from under XCSECURITY @@ -132,6 +143,11 @@ winGenerateAuthorization(void) g_uiAuthDataLen, g_pAuthData); } + auth_info.name = AUTH_NAME; + auth_info.namelen = strlen(AUTH_NAME); + auth_info.data = g_pAuthData; + auth_info.datalen = g_uiAuthDataLen; + #ifdef XCSECURITY /* Allocate structure for additional auth information */ pAuth = (SecurityAuthorizationPtr) @@ -179,3 +195,12 @@ winSetAuthorization(void) XSetAuthorization(AUTH_NAME, strlen(AUTH_NAME), g_pAuthData, g_uiAuthDataLen); } + +xcb_auth_info_t * +winGetXcbAuthInfo(void) +{ + if (g_pAuthData) + return &auth_info; + + return NULL; +} diff --git a/hw/xwin/winblock.c b/hw/xwin/winblock.c index 07e907828..8b846520c 100644 --- a/hw/xwin/winblock.c +++ b/hw/xwin/winblock.c @@ -70,7 +70,7 @@ winBlockHandler(ScreenPtr pScreen, if (pScreenPriv != NULL && !pScreenPriv->fServerStarted) { int iReturn; - ErrorF("winBlockHandler - pthread_mutex_unlock()\n"); + winDebug("winBlockHandler - pthread_mutex_unlock()\n"); /* Flag that modules are to be started */ pScreenPriv->fServerStarted = TRUE; diff --git a/hw/xwin/winclipboard/internal.h b/hw/xwin/winclipboard/internal.h index 6c26caf2e..d0d8fbda1 100644 --- a/hw/xwin/winclipboard/internal.h +++ b/hw/xwin/winclipboard/internal.h @@ -77,6 +77,14 @@ typedef struct Atom atomTargets; } ClipboardAtoms; +/* Modern clipboard API functions */ +typedef wBOOL WINAPI (*ADDCLIPBOARDFORMATLISTENERPROC)(HWND hwnd); +typedef wBOOL WINAPI (*REMOVECLIPBOARDFORMATLISTENERPROC)(HWND hwnd); + +extern Bool g_fHasModernClipboardApi; +extern ADDCLIPBOARDFORMATLISTENERPROC g_fpAddClipboardFormatListener; +extern REMOVECLIPBOARDFORMATLISTENERPROC g_fpRemoveClipboardFormatListener; + /* * winclipboardwndproc.c */ diff --git a/hw/xwin/winclipboard/thread.c b/hw/xwin/winclipboard/thread.c index 50e1e8cb5..58b3bf74d 100644 --- a/hw/xwin/winclipboard/thread.c +++ b/hw/xwin/winclipboard/thread.c @@ -84,6 +84,10 @@ static pthread_t g_winClipboardProcThread; int xfixes_event_base; int xfixes_error_base; +Bool g_fHasModernClipboardApi = FALSE; +ADDCLIPBOARDFORMATLISTENERPROC g_fpAddClipboardFormatListener; +REMOVECLIPBOARDFORMATLISTENERPROC g_fpRemoveClipboardFormatListener; + /* * Local function prototypes */ @@ -127,16 +131,10 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay) winDebug("winClipboardProc - Hello\n"); - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winClipboardProc - XInitThreads failed.\n"); - goto winClipboardProc_Exit; - } - - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winClipboardProc - Warning: Locale not supported by X.\n"); - } + g_fpAddClipboardFormatListener = (ADDCLIPBOARDFORMATLISTENERPROC)GetProcAddress(GetModuleHandle("user32"),"AddClipboardFormatListener"); + g_fpRemoveClipboardFormatListener = (REMOVECLIPBOARDFORMATLISTENERPROC)GetProcAddress(GetModuleHandle("user32"),"RemoveClipboardFormatListener"); + g_fHasModernClipboardApi = g_fpAddClipboardFormatListener && g_fpRemoveClipboardFormatListener; + ErrorF("OS maintains clipboard viewer chain: %s\n", g_fHasModernClipboardApi ? "yes" : "no"); g_winClipboardProcThread = pthread_self(); @@ -165,7 +163,7 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay) "successfully opened the display.\n"); /* Get our connection number */ - iConnectionNumber = ConnectionNumber(pDisplay); + iConnectionNumber = XConnectionNumber(pDisplay); #ifdef HAS_DEVWINDOWS /* Open a file descriptor for the windows message queue */ @@ -193,12 +191,12 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay) /* Create a messaging window */ iWindow = XCreateSimpleWindow(pDisplay, - DefaultRootWindow(pDisplay), + XDefaultRootWindow(pDisplay), 1, 1, 500, 500, 0, - BlackPixel(pDisplay, 0), - BlackPixel(pDisplay, 0)); + XBlackPixel(pDisplay, 0), + XBlackPixel(pDisplay, 0)); if (iWindow == 0) { ErrorF("winClipboardProc - Could not create an X window.\n"); goto winClipboardProc_Done; @@ -344,7 +342,6 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay) #endif } - winClipboardProc_Exit: /* broke out of while loop on a shutdown message */ fShutdown = TRUE; @@ -382,7 +379,7 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay) XSync(pDisplay, TRUE); /* Select event types to watch */ - XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None); + XSelectInput(pDisplay, XDefaultRootWindow(pDisplay), None); /* Close our X display */ if (pDisplay) { diff --git a/hw/xwin/winclipboard/wndproc.c b/hw/xwin/winclipboard/wndproc.c index d17cf2e86..91f874f61 100644 --- a/hw/xwin/winclipboard/wndproc.c +++ b/hw/xwin/winclipboard/wndproc.c @@ -58,6 +58,9 @@ #define WIN_POLL_TIMEOUT 1 +#ifndef WM_CLIPBOARDUPDATE +#define WM_CLIPBOARDUPDATE 0x031D +#endif /* * Process X events up to specified timeout @@ -76,7 +79,7 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay, iTimeoutSec); /* Get our connection number */ - iConnNumber = ConnectionNumber(pDisplay); + iConnNumber = XConnectionNumber(pDisplay); /* Loop for X events */ while (1) { @@ -151,8 +154,16 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { winDebug("winClipboardWindowProc - WM_DESTROY\n"); - /* Remove ourselves from the clipboard chain */ - ChangeClipboardChain(hwnd, s_hwndNextViewer); + if (g_fHasModernClipboardApi) + { + /* Remove clipboard listener */ + g_fpRemoveClipboardFormatListener(hwnd); + } + else + { + /* Remove ourselves from the clipboard chain */ + ChangeClipboardChain(hwnd, s_hwndNextViewer); + } s_hwndNextViewer = NULL; } @@ -168,8 +179,6 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_CREATE: { - HWND first, next; - DWORD error_code = 0; ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams; winDebug("winClipboardWindowProc - WM_CREATE\n"); @@ -179,16 +188,26 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) atoms = cwcp->atoms; fRunning = TRUE; - first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ - if (first == hwnd) - return 0; /* Make sure it's not us! */ - /* Add ourselves to the clipboard viewer chain */ - next = SetClipboardViewer(hwnd); - error_code = GetLastError(); - if (SUCCEEDED(error_code) && (next == first)) /* SetClipboardViewer must have succeeded, and the handle */ - s_hwndNextViewer = next; /* it returned must have been the first window in the chain */ + if (g_fHasModernClipboardApi) + { + g_fpAddClipboardFormatListener(hwnd); + } else - s_fCBCInitialized = FALSE; + { + HWND first, next; + DWORD error_code = 0; + + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ + if (first == hwnd) + return 0; /* Make sure it's not us! */ + /* Add ourselves to the clipboard viewer chain */ + next = SetClipboardViewer(hwnd); + error_code = GetLastError(); + if (SUCCEEDED(error_code) && (next == first)) /* SetClipboardViewer must have succeeded, and the handle */ + s_hwndNextViewer = next; /* it returned must have been the first window in the chain */ + else + s_fCBCInitialized = FALSE; + } } return 0; @@ -233,6 +252,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) winDebug("winClipboardWindowProc - WM_WM_REINIT: Enter\n"); + if (g_fHasModernClipboardApi) + { + return 0; + } + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ if (first == hwnd) return 0; /* Make sure it's not us! */ @@ -257,38 +281,45 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) return 0; case WM_DRAWCLIPBOARD: + case WM_CLIPBOARDUPDATE: { static Bool s_fProcessingDrawClipboard = FALSE; int iReturn; - winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n"); + if (message == WM_DRAWCLIPBOARD) + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n"); + else + winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Enter\n"); - /* - * We've occasionally seen a loop in the clipboard chain. - * Try and fix it on the first hint of recursion. - */ - if (!s_fProcessingDrawClipboard) { - s_fProcessingDrawClipboard = TRUE; - } - else { - /* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */ - s_fCBCInitialized = FALSE; - ChangeClipboardChain(hwnd, s_hwndNextViewer); - winFixClipboardChain(); - ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "Nested calls detected. Re-initing.\n"); - winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); - s_fProcessingDrawClipboard = FALSE; - return 0; - } + if (!g_fHasModernClipboardApi) + { + /* + * We've occasionally seen a loop in the clipboard chain. + * Try and fix it on the first hint of recursion. + */ + if (!s_fProcessingDrawClipboard) { + s_fProcessingDrawClipboard = TRUE; + } + else { + /* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */ + s_fCBCInitialized = FALSE; + ChangeClipboardChain(hwnd, s_hwndNextViewer); + winFixClipboardChain(); + ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Nested calls detected. Re-initing.\n"); + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); + s_fProcessingDrawClipboard = FALSE; + return 0; + } - /* Bail on first message */ - if (!s_fCBCInitialized) { - s_fCBCInitialized = TRUE; - s_fProcessingDrawClipboard = FALSE; - winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); - return 0; - } + /* Bail on first message */ + if (!s_fCBCInitialized) { + s_fCBCInitialized = TRUE; + s_fProcessingDrawClipboard = FALSE; + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); + return 0; + } + } /* * NOTE: We cannot bail out when NULL == GetClipboardOwner () diff --git a/hw/xwin/winconfig.c b/hw/xwin/winconfig.c index d26cc9376..488171b8a 100644 --- a/hw/xwin/winconfig.c +++ b/hw/xwin/winconfig.c @@ -70,6 +70,7 @@ WinCmdlineRec g_cmdline = { #ifdef XWIN_XF86CONFIG NULL, /* keyboard */ #endif + FALSE, /* customDPI */ NULL, /* xkbRules */ NULL, /* xkbModel */ NULL, /* xkbLayout */ @@ -224,7 +225,8 @@ winConfigKeyboard(DeviceIntPtr pDevice) { char layoutName[KL_NAMELENGTH]; unsigned char layoutFriendlyName[256]; - static unsigned int layoutNum = 0; + unsigned int layoutNum = 0; + unsigned int deviceIdentifier = 0; int keyboardType; #ifdef XWIN_XF86CONFIG @@ -263,8 +265,9 @@ winConfigKeyboard(DeviceIntPtr pDevice) break; } g_winInfo.keyboard.rate = (kbd_speed > 0) ? kbd_speed : 1; - winMsgVerb(X_PROBED, 1, "Setting autorepeat to delay=%ld, rate=%ld\n", - g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); + winMsg(X_PROBED, "Setting autorepeat to delay=%ld, rate=%ld\n", + g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); + } } @@ -272,15 +275,10 @@ winConfigKeyboard(DeviceIntPtr pDevice) if (keyboardType > 0 && GetKeyboardLayoutName(layoutName)) { WinKBLayoutPtr pLayout; Bool bfound = FALSE; + int pass; - if (!layoutNum) - layoutNum = strtoul(layoutName, (char **) NULL, 16); + layoutNum = strtoul(layoutName, (char **) NULL, 16); if ((layoutNum & 0xffff) == 0x411) { - /* The japanese layouts know a lot of different IMEs which all have - different layout numbers set. Map them to a single entry. - Same might apply for chinese, korean and other symbol languages - too */ - layoutNum = (layoutNum & 0xffff); if (keyboardType == 7) { /* Japanese layouts have problems with key event messages such as the lack of WM_KEYUP for Caps Lock key. @@ -318,31 +316,47 @@ winConfigKeyboard(DeviceIntPtr pDevice) "Windows keyboard layout: \"%s\" (%08x) \"%s\", type %d\n", layoutName, layoutNum, layoutFriendlyName, keyboardType); - for (pLayout = winKBLayouts; pLayout->winlayout != -1; pLayout++) { - if (pLayout->winlayout != layoutNum) - continue; - if (pLayout->winkbtype > 0 && pLayout->winkbtype != keyboardType) - continue; - - bfound = TRUE; - winMsg(X_PROBED, - "Found matching XKB configuration \"%s\"\n", - pLayout->layoutname); - - winMsg(X_PROBED, - "Model = \"%s\" Layout = \"%s\"" - " Variant = \"%s\" Options = \"%s\"\n", - pLayout->xkbmodel ? pLayout->xkbmodel : "none", - pLayout->xkblayout ? pLayout->xkblayout : "none", - pLayout->xkbvariant ? pLayout->xkbvariant : "none", - pLayout->xkboptions ? pLayout->xkboptions : "none"); + deviceIdentifier = layoutNum >> 16; + for (pass = 0; pass < 2; pass++) { + /* If we didn't find an exact match for the input locale identifer, + try to find an match on the language identifier part only */ + if (pass == 1) + layoutNum = (layoutNum & 0xffff); + + for (pLayout = winKBLayouts; pLayout->winlayout != -1; pLayout++) { + if (pLayout->winlayout != layoutNum) + continue; + if (pLayout->winkbtype > 0 && pLayout->winkbtype != keyboardType) + continue; + + bfound = TRUE; + winMsg(X_PROBED, + "Found matching XKB configuration \"%s\"\n", + pLayout->layoutname); + + winMsg(X_PROBED, + "Model = \"%s\" Layout = \"%s\"" + " Variant = \"%s\" Options = \"%s\"\n", + pLayout->xkbmodel ? pLayout->xkbmodel : "none", + pLayout->xkblayout ? pLayout->xkblayout : "none", + pLayout->xkbvariant ? pLayout->xkbvariant : "none", + pLayout->xkboptions ? pLayout->xkboptions : "none"); + + g_winInfo.xkb.model = pLayout->xkbmodel; + g_winInfo.xkb.layout = pLayout->xkblayout; + g_winInfo.xkb.variant = pLayout->xkbvariant; + g_winInfo.xkb.options = pLayout->xkboptions; + + if (deviceIdentifier == 0xa000) { + winMsg(X_PROBED, "Windows keyboard layout device identifier indicates Macintosh, setting Model = \"macintosh\""); + g_winInfo.xkb.model = "macintosh"; + } - g_winInfo.xkb.model = pLayout->xkbmodel; - g_winInfo.xkb.layout = pLayout->xkblayout; - g_winInfo.xkb.variant = pLayout->xkbvariant; - g_winInfo.xkb.options = pLayout->xkboptions; + break; + } - break; + if (bfound) + break; } if (!bfound) { diff --git a/hw/xwin/winconfig.h b/hw/xwin/winconfig.h index f079368c7..2edaf4df2 100644 --- a/hw/xwin/winconfig.h +++ b/hw/xwin/winconfig.h @@ -159,6 +159,7 @@ typedef struct { #ifdef XWIN_XF86CONFIG char *keyboard; #endif + Bool customDPI; char *xkbRules; char *xkbModel; char *xkbLayout; @@ -199,7 +200,7 @@ typedef union { unsigned long num; char *str; double realnum; - Bool bool; + Bool bool_; OptFrequency freq; } ValueUnion; diff --git a/hw/xwin/wincreatewnd.c b/hw/xwin/wincreatewnd.c index b2f797c51..e6e587f9f 100644 --- a/hw/xwin/wincreatewnd.c +++ b/hw/xwin/wincreatewnd.c @@ -171,7 +171,7 @@ winCreateBoundingWindowWindowed(ScreenPtr pScreen) fForceShowWindow = TRUE; } dwWindowStyle |= WS_CAPTION; - if (pScreenInfo->iResizeMode != notAllowed) + if (pScreenInfo->iResizeMode != resizeNotAllowed) dwWindowStyle |= WS_THICKFRAME | WS_MAXIMIZEBOX; } else @@ -226,7 +226,7 @@ winCreateBoundingWindowWindowed(ScreenPtr pScreen) ) && (pScreenInfo->iResizeMode == resizeWithScrollbars)) { /* We cannot have scrollbars if we do not have a window border */ - pScreenInfo->iResizeMode = notAllowed; + pScreenInfo->iResizeMode = resizeNotAllowed; } /* Did the user specify a height and width? */ @@ -253,7 +253,7 @@ winCreateBoundingWindowWindowed(ScreenPtr pScreen) #endif /* Are we resizable */ - if (pScreenInfo->iResizeMode != notAllowed) { + if (pScreenInfo->iResizeMode != resizeNotAllowed) { #if CYGDEBUG winDebug ("winCreateBoundingWindowWindowed - Window is resizable\n"); diff --git a/hw/xwin/wincursor.c b/hw/xwin/wincursor.c index bddd6b7ed..285da3b6f 100644 --- a/hw/xwin/wincursor.c +++ b/hw/xwin/wincursor.c @@ -34,14 +34,14 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + #include "win.h" #include "winmsg.h" #include <cursorstr.h> #include <mipointrst.h> #include <servermd.h> #include "misc.h" - -#define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114) +#include "wmutil/cursor_convert.h" #if 0 #define WIN_DEBUG_MSG winDebug @@ -128,296 +128,30 @@ winCrossScreen(ScreenPtr pScreen, Bool fEntering) { } -static unsigned char -reverse(unsigned char c) -{ - int i; - unsigned char ret = 0; - - for (i = 0; i < 8; ++i) { - ret |= ((c >> i) & 1) << (7 - i); - } - return ret; -} - /* * Convert X cursor to Windows cursor - * FIXME: Perhaps there are more smart code */ static HCURSOR winLoadCursor(ScreenPtr pScreen, CursorPtr pCursor, int screen) { - winScreenPriv(pScreen); - HCURSOR hCursor = NULL; - unsigned char *pAnd; - unsigned char *pXor; - int nCX, nCY; - int nBytes; - double dForeY, dBackY; - BOOL fReverse; - HBITMAP hAnd, hXor; - ICONINFO ii; - unsigned char *pCur; - unsigned char bit; - HDC hDC; - BITMAPV4HEADER bi; - BITMAPINFO *pbmi; - uint32_t *lpBits; - - WIN_DEBUG_MSG("winLoadCursor: Win32: %dx%d X11: %dx%d hotspot: %d,%d\n", - pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, - pCursor->bits->width, pCursor->bits->height, - pCursor->bits->xhot, pCursor->bits->yhot); - - /* We can use only White and Black, so calc brightness of color - * Also check if the cursor is inverted */ - dForeY = BRIGHTNESS(pCursor->fore); - dBackY = BRIGHTNESS(pCursor->back); - fReverse = dForeY < dBackY; - - /* Check wether the X11 cursor is bigger than the win32 cursor */ - if (pScreenPriv->cursor.sm_cx < pCursor->bits->width || - pScreenPriv->cursor.sm_cy < pCursor->bits->height) { - winErrorFVerb(3, - "winLoadCursor - Windows requires %dx%d cursor but X requires %dx%d\n", - pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, - pCursor->bits->width, pCursor->bits->height); - } - - /* Get the number of bytes required to store the whole cursor image - * This is roughly (sm_cx * sm_cy) / 8 - * round up to 8 pixel boundary so we can convert whole bytes */ - nBytes = - bits_to_bytes(pScreenPriv->cursor.sm_cx) * pScreenPriv->cursor.sm_cy; - - /* Get the effective width and height */ - nCX = min(pScreenPriv->cursor.sm_cx, pCursor->bits->width); - nCY = min(pScreenPriv->cursor.sm_cy, pCursor->bits->height); - - /* Allocate memory for the bitmaps */ - pAnd = malloc(nBytes); - memset(pAnd, 0xFF, nBytes); - pXor = calloc(1, nBytes); - - /* Convert the X11 bitmap to a win32 bitmap - * The first is for an empty mask */ - if (pCursor->bits->emptyMask) { - int x, y, xmax = bits_to_bytes(nCX); - - for (y = 0; y < nCY; ++y) - for (x = 0; x < xmax; ++x) { - int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x; - int nXPix = BitmapBytePad(pCursor->bits->width) * y + x; - - pAnd[nWinPix] = 0; - if (fReverse) - pXor[nWinPix] = reverse(~pCursor->bits->source[nXPix]); - else - pXor[nWinPix] = reverse(pCursor->bits->source[nXPix]); - } - } - else { - int x, y, xmax = bits_to_bytes(nCX); - - for (y = 0; y < nCY; ++y) - for (x = 0; x < xmax; ++x) { - int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x; - int nXPix = BitmapBytePad(pCursor->bits->width) * y + x; - - unsigned char mask = pCursor->bits->mask[nXPix]; - - pAnd[nWinPix] = reverse(~mask); - if (fReverse) - pXor[nWinPix] = - reverse(~pCursor->bits->source[nXPix] & mask); - else - pXor[nWinPix] = - reverse(pCursor->bits->source[nXPix] & mask); - } - } - - /* prepare the pointers */ - hCursor = NULL; - lpBits = NULL; - - /* We have a truecolor alpha-blended cursor and can use it! */ - if (pCursor->bits->argb) { - WIN_DEBUG_MSG("winLoadCursor: Trying truecolor alphablended cursor\n"); - memset(&bi, 0, sizeof(BITMAPV4HEADER)); - bi.bV4Size = sizeof(BITMAPV4HEADER); - bi.bV4Width = pScreenPriv->cursor.sm_cx; - bi.bV4Height = -(pScreenPriv->cursor.sm_cy); /* right-side up */ - bi.bV4Planes = 1; - bi.bV4BitCount = 32; - bi.bV4V4Compression = BI_BITFIELDS; - bi.bV4RedMask = 0x00FF0000; - bi.bV4GreenMask = 0x0000FF00; - bi.bV4BlueMask = 0x000000FF; - bi.bV4AlphaMask = 0xFF000000; - - lpBits = calloc(pScreenPriv->cursor.sm_cx * pScreenPriv->cursor.sm_cy, - sizeof(uint32_t)); - - if (lpBits) { - int y; - for (y = 0; y < nCY; y++) { - void *src, *dst; - src = &(pCursor->bits->argb[y * pCursor->bits->width]); - dst = &(lpBits[y * pScreenPriv->cursor.sm_cx]); - memcpy(dst, src, 4 * nCX); - } - } - } /* End if-truecolor-icon */ - - if (!lpBits) { - RGBQUAD *pbmiColors; - /* Bicolor, use a palettized DIB */ - WIN_DEBUG_MSG("winLoadCursor: Trying two color cursor\n"); - pbmi = (BITMAPINFO *) &bi; - pbmiColors = &(pbmi->bmiColors[0]); - - memset(pbmi, 0, sizeof(BITMAPINFOHEADER)); - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biWidth = pScreenPriv->cursor.sm_cx; - pbmi->bmiHeader.biHeight = -abs(pScreenPriv->cursor.sm_cy); /* right-side up */ - pbmi->bmiHeader.biPlanes = 1; - pbmi->bmiHeader.biBitCount = 8; - pbmi->bmiHeader.biCompression = BI_RGB; - pbmi->bmiHeader.biSizeImage = 0; - pbmi->bmiHeader.biClrUsed = 3; - pbmi->bmiHeader.biClrImportant = 3; - - pbmiColors[0].rgbRed = 0; /* Empty */ - pbmiColors[0].rgbGreen = 0; - pbmiColors[0].rgbBlue = 0; - pbmiColors[0].rgbReserved = 0; - pbmiColors[1].rgbRed = pCursor->backRed >> 8; /* Background */ - pbmiColors[1].rgbGreen = pCursor->backGreen >> 8; - pbmiColors[1].rgbBlue = pCursor->backBlue >> 8; - pbmiColors[1].rgbReserved = 0; - pbmiColors[2].rgbRed = pCursor->foreRed >> 8; /* Foreground */ - pbmiColors[2].rgbGreen = pCursor->foreGreen >> 8; - pbmiColors[2].rgbBlue = pCursor->foreBlue >> 8; - pbmiColors[2].rgbReserved = 0; - - lpBits = calloc(pScreenPriv->cursor.sm_cx * pScreenPriv->cursor.sm_cy, 1); - - pCur = (unsigned char *) lpBits; - if (lpBits) { - int x, y; - for (y = 0; y < pScreenPriv->cursor.sm_cy; y++) { - for (x = 0; x < pScreenPriv->cursor.sm_cx; x++) { - if (x >= nCX || y >= nCY) /* Outside of X11 icon bounds */ - (*pCur++) = 0; - else { /* Within X11 icon bounds */ - - int nWinPix = - bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + - (x / 8); - - bit = pAnd[nWinPix]; - bit = bit & (1 << (7 - (x & 7))); - if (!bit) { /* Within the cursor mask? */ - int nXPix = - BitmapBytePad(pCursor->bits->width) * y + - (x / 8); - bit = - ~reverse(~pCursor->bits-> - source[nXPix] & pCursor->bits-> - mask[nXPix]); - bit = bit & (1 << (7 - (x & 7))); - if (bit) /* Draw foreground */ - (*pCur++) = 2; - else /* Draw background */ - (*pCur++) = 1; - } - else /* Outside the cursor mask */ - (*pCur++) = 0; - } - } /* end for (x) */ - } /* end for (y) */ - } /* end if (lpbits) */ - } - - /* If one of the previous two methods gave us the bitmap we need, make a cursor */ - if (lpBits) { - WIN_DEBUG_MSG("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n", - pCursor->bits->xhot, pCursor->bits->yhot); - - hAnd = NULL; - hXor = NULL; - - hAnd = - CreateBitmap(pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, - 1, 1, pAnd); - - hDC = GetDC(NULL); - if (hDC) { - hXor = - CreateCompatibleBitmap(hDC, pScreenPriv->cursor.sm_cx, - pScreenPriv->cursor.sm_cy); - SetDIBits(hDC, hXor, 0, pScreenPriv->cursor.sm_cy, lpBits, - (BITMAPINFO *) &bi, DIB_RGB_COLORS); - ReleaseDC(NULL, hDC); - } - free(lpBits); - - if (hAnd && hXor) { - ii.fIcon = FALSE; - ii.xHotspot = pCursor->bits->xhot; - ii.yHotspot = pCursor->bits->yhot; - ii.hbmMask = hAnd; - ii.hbmColor = hXor; - hCursor = (HCURSOR) CreateIconIndirect(&ii); - - if (hCursor == NULL) - winW32Error(2, "winLoadCursor - CreateIconIndirect failed:"); - else { - if (GetIconInfo(hCursor, &ii)) { - if (ii.fIcon) { - WIN_DEBUG_MSG - ("winLoadCursor: CreateIconIndirect returned no cursor. Trying again.\n"); - - DestroyCursor(hCursor); - - ii.fIcon = FALSE; - ii.xHotspot = pCursor->bits->xhot; - ii.yHotspot = pCursor->bits->yhot; - hCursor = (HCURSOR) CreateIconIndirect(&ii); - - if (hCursor == NULL) - winW32Error(2, - "winLoadCursor - CreateIconIndirect failed:"); - } - /* GetIconInfo creates new bitmaps. Destroy them again */ - if (ii.hbmMask) - DeleteObject(ii.hbmMask); - if (ii.hbmColor) - DeleteObject(ii.hbmColor); - } - } - } - - if (hAnd) - DeleteObject(hAnd); - if (hXor) - DeleteObject(hXor); - } - - if (!hCursor) { - /* We couldn't make a color cursor for this screen, use - black and white instead */ - hCursor = CreateCursor(g_hInstance, - pCursor->bits->xhot, pCursor->bits->yhot, - pScreenPriv->cursor.sm_cx, - pScreenPriv->cursor.sm_cy, pAnd, pXor); - if (hCursor == NULL) - winW32Error(2, "winLoadCursor - CreateCursor failed:"); - } - free(pAnd); - free(pXor); - - return hCursor; + WMUTIL_CURSOR cursor; + + cursor.width = pCursor->bits->width; + cursor.height = pCursor->bits->height; + cursor.xhot = pCursor->bits->xhot; + cursor.yhot = pCursor->bits->yhot; + cursor.argb = (uint32_t *)pCursor->bits->argb; + cursor.source = pCursor->bits->source; + cursor.mask = pCursor->bits->mask; + cursor.emptyMask = pCursor->bits->emptyMask; + cursor.foreRed = pCursor->foreRed; + cursor.foreGreen = pCursor->foreGreen; + cursor.foreBlue = pCursor->foreBlue; + cursor.backRed = pCursor->backRed; + cursor.backGreen = pCursor->backGreen; + cursor.backBlue = pCursor->backBlue; + + return winXCursorToHCURSOR(&cursor); } /* diff --git a/hw/xwin/winengine.c b/hw/xwin/winengine.c index b8f8da06b..d816851e2 100644 --- a/hw/xwin/winengine.c +++ b/hw/xwin/winengine.c @@ -203,7 +203,7 @@ winSetEngine(ScreenPtr pScreen) return TRUE; } - return TRUE; + return FALSE; } /* diff --git a/hw/xwin/winerror.c b/hw/xwin/winerror.c index 1318b0f36..09b8dda0c 100644 --- a/hw/xwin/winerror.c +++ b/hw/xwin/winerror.c @@ -69,14 +69,20 @@ OsVendorFatalError(const char *f, va_list args) { char errormsg[1024] = ""; - /* Don't give duplicate warning if UseMsg was called */ + /* If we want to silence it, + * detect if we are going to abort due to duplication error */ + if (g_fSilentDupError) { + if ((strcmp(f, "InitOutput - Duplicate invocation on display number: %s. Exiting.\n") == 0) + || (strcmp(f, "Server is already active for display %s\n%s %s\n%s\n") == 0) + || (strcmp(f, "MakeAllCOTSServerListeners: server already running\n") == 0)) { + g_fSilentFatalError = TRUE; + } + } + + /* Don't give warning if it's been silenced */ if (g_fSilentFatalError) return; - if (!g_fLogInited) { - g_fLogInited = TRUE; - g_pszLogFile = LogInit(g_pszLogFile, NULL); - } LogClose(EXIT_ERR_ABORT); /* Format the error message */ diff --git a/hw/xwin/winglobals.c b/hw/xwin/winglobals.c index 1382c8972..8a699f236 100644 --- a/hw/xwin/winglobals.c +++ b/hw/xwin/winglobals.c @@ -63,13 +63,12 @@ HICON g_hIconX = NULL; HICON g_hSmallIconX = NULL; #ifndef RELOCATE_PROJECTROOT -const char *g_pszLogFile = DEFAULT_LOGDIR "/XWin.%s.log"; +const char *g_pszLogFileFormat = DEFAULT_LOGDIR "/XWin.%s.log"; #else -const char *g_pszLogFile = "XWin.log"; -Bool g_fLogFileChanged = FALSE; +const char *g_pszLogFileFormat = "XWin.%s.log"; #endif +const char *g_pszLogFile = NULL; int g_iLogVerbose = 2; -Bool g_fLogInited = FALSE; char *g_pszCommandLine = NULL; Bool g_fSilentFatalError = FALSE; DWORD g_dwCurrentThreadID = 0; diff --git a/hw/xwin/winglobals.h b/hw/xwin/winglobals.h index d7b813dbb..a20f266c2 100644 --- a/hw/xwin/winglobals.h +++ b/hw/xwin/winglobals.h @@ -40,13 +40,10 @@ extern int g_iNumScreens; extern int g_iLastScreen; extern char *g_pszCommandLine; extern Bool g_fSilentFatalError; +extern const char *g_pszLogFileFormat; extern const char *g_pszLogFile; -#ifdef RELOCATE_PROJECTROOT -extern Bool g_fLogFileChanged; -#endif extern int g_iLogVerbose; -extern Bool g_fLogInited; extern Bool g_fAuthEnabled; extern Bool g_fXdmcpEnabled; diff --git a/hw/xwin/winkeybd.c b/hw/xwin/winkeybd.c index ab53af4ba..ec03f0c84 100644 --- a/hw/xwin/winkeybd.c +++ b/hw/xwin/winkeybd.c @@ -34,17 +34,24 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + #include "win.h" -#include "winkeybd.h" +#include "wmutil/scancodes.h" +#include "wmutil/keyboard.h" #include "winconfig.h" #include "winmsg.h" #include "xkbsrv.h" +#include "dixgrabs.h" /* C does not have a logical XOR operator, so we use a macro instead */ #define LOGICAL_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) -static Bool g_winKeyState[NUM_KEYCODES]; +#define AltMask Mod1Mask +#define NumLockMask Mod2Mask +#define AltLangMask Mod3Mask +#define KanaMask Mod4Mask +#define ScrollLockMask Mod5Mask /* * Local prototypes @@ -56,68 +63,6 @@ static void static void winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl); -/* - * Translate a Windows WM_[SYS]KEY(UP/DOWN) message - * into an ASCII scan code. - * - * We do this ourselves, rather than letting Windows handle it, - * because Windows tends to munge the handling of special keys, - * like AltGr on European keyboards. - */ - -int -winTranslateKey(WPARAM wParam, LPARAM lParam) -{ - int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1]; - int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2]; - int iParam = HIWORD(lParam); - int iParamScanCode = LOBYTE(iParam); - int iScanCode; - - winDebug("winTranslateKey: wParam %08x lParam %08x\n", (int)wParam, (int)lParam); - -/* WM_ key messages faked by Vista speech recognition (WSR) don't have a - * scan code. - * - * Vocola 3 (Rick Mohr's supplement to WSR) uses - * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a - * scan code of 1 - */ - if (iParamScanCode <= 1) { - if (VK_PRIOR <= wParam && wParam <= VK_DOWN) - /* Trigger special case table to translate to extended - * keycode, otherwise if num_lock is on, we can get keypad - * numbers instead of navigation keys. */ - iParam |= KF_EXTENDED; - else - iParamScanCode = MapVirtualKeyEx(wParam, - /*MAPVK_VK_TO_VSC */ 0, - GetKeyboardLayout(0)); - } - - /* Branch on special extended, special non-extended, or normal key */ - if ((iParam & KF_EXTENDED) && iKeyFixupEx) - iScanCode = iKeyFixupEx; - else if (iKeyFixup) - iScanCode = iKeyFixup; - else if (wParam == 0 && iParamScanCode == 0x70) - iScanCode = KEY_HKTG; - else - switch (iParamScanCode) { - case 0x70: - iScanCode = KEY_HKTG; - break; - case 0x73: - iScanCode = KEY_BSlash2; - break; - default: - iScanCode = iParamScanCode; - break; - } - - return iScanCode; -} - /* Ring the keyboard bell (system speaker on PCs) */ static void winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass) @@ -337,209 +282,46 @@ winRestoreModeKeyStates(void) */ } -/* - * Look for the lovely fake Control_L press/release generated by Windows - * when AltGr is pressed/released on a non-U.S. keyboard. - */ - -Bool -winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam) -{ - MSG msgNext; - LONG lTime; - Bool fReturn; - - static Bool lastWasControlL = FALSE; - static LONG lastTime; - - /* - * Fake Ctrl_L presses will be followed by an Alt_R press - * with the same timestamp as the Ctrl_L press. - */ - if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) - && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) { - /* Got a Ctrl_L press */ - - /* Get time of current message */ - lTime = GetMessageTime(); - - /* Look for next press message */ - fReturn = PeekMessage(&msgNext, NULL, - WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE); - - if (fReturn && msgNext.message != WM_KEYDOWN && - msgNext.message != WM_SYSKEYDOWN) - fReturn = 0; - - if (!fReturn) { - lastWasControlL = TRUE; - lastTime = lTime; - } - else { - lastWasControlL = FALSE; - } - - /* Is next press an Alt_R with the same timestamp? */ - if (fReturn && msgNext.wParam == VK_MENU - && msgNext.time == lTime - && (HIWORD(msgNext.lParam) & KF_EXTENDED)) { - /* - * Next key press is Alt_R with same timestamp as current - * Ctrl_L message. Therefore, this Ctrl_L press is a fake - * event, so discard it. - */ - return TRUE; - } - } - /* - * Sometimes, the Alt_R press message is not yet posted when the - * fake Ctrl_L press message arrives (even though it has the - * same timestamp), so check for an Alt_R press message that has - * arrived since the last Ctrl_L message. - */ - else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) - && wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) { - /* Got a Alt_R press */ - - if (lastWasControlL) { - lTime = GetMessageTime(); - - if (lastTime == lTime) { - /* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */ - winSendKeyEvent(KEY_LCtrl, FALSE); - } - lastWasControlL = FALSE; - } - } - /* - * Fake Ctrl_L releases will be followed by an Alt_R release - * with the same timestamp as the Ctrl_L release. - */ - else if ((message == WM_KEYUP || message == WM_SYSKEYUP) - && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) { - /* Got a Ctrl_L release */ - - /* Get time of current message */ - lTime = GetMessageTime(); - - /* Look for next release message */ - fReturn = PeekMessage(&msgNext, NULL, - WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE); - - if (fReturn && msgNext.message != WM_KEYUP && - msgNext.message != WM_SYSKEYUP) - fReturn = 0; - - lastWasControlL = FALSE; - - /* Is next press an Alt_R with the same timestamp? */ - if (fReturn - && (msgNext.message == WM_KEYUP || msgNext.message == WM_SYSKEYUP) - && msgNext.wParam == VK_MENU - && msgNext.time == lTime - && (HIWORD(msgNext.lParam) & KF_EXTENDED)) { - /* - * Next key release is Alt_R with same timestamp as current - * Ctrl_L message. Therefore, this Ctrl_L release is a fake - * event, so discard it. - */ - return TRUE; - } - } - else { - /* On any other press or release message, we don't have a - potentially fake Ctrl_L to worry about anymore... */ - lastWasControlL = FALSE; - } - - /* Not a fake control left press/release */ - return FALSE; -} - -/* - * Lift any modifier keys that are pressed - */ - void -winKeybdReleaseKeys(void) +winSendKeyEventCallback(DWORD dwKey, bool fDown) { - int i; - #ifdef HAS_DEVWINDOWS /* Verify that the mi input system has been initialized */ if (g_fdMessageQueue == WIN_FD_INVALID) return; #endif - /* Loop through all keys */ - for (i = 0; i < NUM_KEYCODES; ++i) { - /* Pop key if pressed */ - if (g_winKeyState[i]) - winSendKeyEvent(i, FALSE); - - /* Reset pressed flag for keys */ - g_winKeyState[i] = FALSE; - } + QueueKeyboardEvents(g_pwinKeyboard, fDown ? KeyPress : KeyRelease, + dwKey); } /* - * Take a raw X key code and send an up or down event for it. - * - * Thanks to VNC for inspiration, though it is a simple function. */ - -void -winSendKeyEvent(DWORD dwKey, Bool fDown) -{ - /* - * When alt-tabing between screens we can get phantom key up messages - * Here we only pass them through it we think we should! - */ - if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) - return; - - /* Update the keyState map */ - g_winKeyState[dwKey] = fDown; - - QueueKeyboardEvents(g_pwinKeyboard, fDown ? KeyPress : KeyRelease, - dwKey + MIN_KEYCODE); - - winDebug("winSendKeyEvent: dwKey: %u, fDown: %u\n", (unsigned int)dwKey, fDown); -} - -BOOL -winCheckKeyPressed(WPARAM wParam, LPARAM lParam) +int +XkbDDXPrivate(DeviceIntPtr dev,KeyCode key,XkbAction *act) { - switch (wParam) { - case VK_CONTROL: - if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl]) - return TRUE; - if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl]) - return TRUE; - break; - case VK_SHIFT: - if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR]) - return TRUE; - if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL]) - return TRUE; - break; - default: - return TRUE; + XkbAnyAction *xf86act = &(act->any); + char msgbuf[XkbAnyActionDataSize+1]; + + if (xf86act->type == XkbSA_XFree86Private) + { + memcpy(msgbuf, xf86act->data, XkbAnyActionDataSize); + msgbuf[XkbAnyActionDataSize]= '\0'; + if (strcasecmp(msgbuf, "prgrbs")==0) { + DeviceIntPtr tmp; + winMsg(X_INFO, "Printing all currently active device grabs:\n"); + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) + if (tmp->deviceGrab.grab) + PrintDeviceGrabInfo(tmp); + winMsg(X_INFO, "End list of active device grabs\n"); + } + else if (strcasecmp(msgbuf, "ungrab")==0) + UngrabAllDevices(FALSE); + else if (strcasecmp(msgbuf, "clsgrb")==0) + UngrabAllDevices(TRUE); + else if (strcasecmp(msgbuf, "prwins")==0) + PrintWindowTree(); } - return FALSE; -} - -/* Only one shift release message is sent even if both are pressed. - * Fix this here - */ -void -winFixShiftKeys(int iScanCode) -{ - if (GetKeyState(VK_SHIFT) & 0x8000) - return; - if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR]) - winSendKeyEvent(KEY_ShiftR, FALSE); - if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL]) - winSendKeyEvent(KEY_ShiftL, FALSE); + return 0; } diff --git a/hw/xwin/winlayouts.h b/hw/xwin/winlayouts.h index a61fd7ac1..c7905e3c2 100644 --- a/hw/xwin/winlayouts.h +++ b/hw/xwin/winlayouts.h @@ -42,7 +42,8 @@ typedef struct { */ WinKBLayoutRec winKBLayouts[] = { - {0x00000404, -1, "pc105", "zh_TW", NULL, NULL, "Chinese (Taiwan)"}, + {0x00000404, -1, "pc105", "cn", NULL, NULL, "Chinese (Traditional)"}, + {0x00000804, -1, "pc105", "cn", NULL, NULL, "Chinese (Simplified)"}, {0x00000405, -1, "pc105", "cz", NULL, NULL, "Czech"}, {0x00010405, -1, "pc105", "cz_qwerty", NULL, NULL, "Czech (QWERTY)"}, {0x00000406, -1, "pc105", "dk", NULL, NULL, "Danish"}, @@ -72,8 +73,8 @@ WinKBLayoutRec winKBLayouts[] = { {0x0000040f, -1, "pc105", "is", NULL, NULL, "Icelandic"}, {0x00000410, -1, "pc105", "it", NULL, NULL, "Italian"}, {0x00010410, -1, "pc105", "it", NULL, NULL, "Italian (142)"}, - {0xa0000410, -1, "macbook79", "it", "mac", NULL, "Italiano (Apple)"}, {0x00000411, 7, "jp106", "jp", NULL, NULL, "Japanese"}, + {0x00000412, -1, "kr106", "kr", NULL, NULL, "Korean"}, {0x00000413, -1, "pc105", "nl", NULL, NULL, "Dutch"}, {0x00000813, -1, "pc105", "be", NULL, NULL, "Dutch (Belgian)"}, {0x00000414, -1, "pc105", "no", NULL, NULL, "Norwegian"}, diff --git a/hw/xwin/winmouse.c b/hw/xwin/winmouse.c index bbe21cba6..59705e655 100644 --- a/hw/xwin/winmouse.c +++ b/hw/xwin/winmouse.c @@ -41,6 +41,8 @@ #include "xserver-properties.h" #include "inpututils.h" +#include "wmutil/mouse.h" + /* Peek the internal button mapping */ static CARD8 const *g_winMouseButtonMap = NULL; @@ -143,86 +145,20 @@ winMouseProc(DeviceIntPtr pDeviceInt, int iState) return Success; } -/* Handle the mouse wheel */ -int -winMouseWheel(int *iTotalDeltaZ, int iDeltaZ, int iButtonUp, int iButtonDown) -{ - int button; - - /* Do we have any previous delta stored? */ - if ((*iTotalDeltaZ > 0 && iDeltaZ > 0) - || (*iTotalDeltaZ < 0 && iDeltaZ < 0)) { - /* Previous delta and of same sign as current delta */ - iDeltaZ += *iTotalDeltaZ; - *iTotalDeltaZ = 0; - } - else { - /* - * Previous delta of different sign, or zero. - * We will set it to zero for either case, - * as blindly setting takes just as much time - * as checking, then setting if necessary :) - */ - *iTotalDeltaZ = 0; - } - - /* - * Only process this message if the wheel has moved further than - * WHEEL_DELTA - */ - if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA) { - *iTotalDeltaZ = 0; - - /* Figure out how many whole deltas of the wheel we have */ - iDeltaZ /= WHEEL_DELTA; - } - else { - /* - * Wheel has not moved past WHEEL_DELTA threshold; - * we will store the wheel delta until the threshold - * has been reached. - */ - *iTotalDeltaZ = iDeltaZ; - return 0; - } - - /* Set the button to indicate up or down wheel delta */ - if (iDeltaZ > 0) { - button = iButtonUp; - } - else { - button = iButtonDown; - } - - /* - * Flip iDeltaZ to positive, if negative, - * because always need to generate a *positive* number of - * button clicks for the Z axis. - */ - if (iDeltaZ < 0) { - iDeltaZ *= -1; - } - - /* Generate X input messages for each wheel delta we have seen */ - while (iDeltaZ--) { - /* Push the wheel button */ - winMouseButtonsSendEvent(ButtonPress, button); - - /* Release the wheel button */ - winMouseButtonsSendEvent(ButtonRelease, button); - } - - return 0; -} - /* * Enqueue a mouse button event */ void -winMouseButtonsSendEvent(int iEventType, int iButton) +winMouseButtonsSendEvent(bool bPress, int iButton) { ValuatorMask mask; + int iEventType; + + if (bPress) + iEventType = ButtonPress; + else + iEventType = ButtonRelease; if (g_winMouseButtonMap) iButton = g_winMouseButtonMap[iButton]; @@ -251,7 +187,7 @@ winMouseButtonsHandle(ScreenPtr pScreen, /* Send button events right away if emulate 3 buttons is off */ if (pScreenInfo->iE3BTimeout == WIN_E3B_OFF) { /* Emulate 3 buttons is off, send the button event */ - winMouseButtonsSendEvent(iEventType, iButton); + winMouseButtonsSendEvent((iEventType == ButtonPress), iButton); return 0; } @@ -288,7 +224,7 @@ winMouseButtonsHandle(ScreenPtr pScreen, pScreenPriv->iE3BCachedPress = 0; /* Send fake middle button */ - winMouseButtonsSendEvent(ButtonPress, Button2); + winMouseButtonsSendEvent(TRUE, Button2); /* Indicate that a fake middle button event was sent */ pScreenPriv->fE3BFakeButton2Sent = TRUE; @@ -303,8 +239,8 @@ winMouseButtonsHandle(ScreenPtr pScreen, pScreenPriv->iE3BCachedPress = 0; /* Send cached press, then send release */ - winMouseButtonsSendEvent(ButtonPress, iButton); - winMouseButtonsSendEvent(ButtonRelease, iButton); + winMouseButtonsSendEvent(TRUE, iButton); + winMouseButtonsSendEvent(FALSE, iButton); } else if (iEventType == ButtonRelease && pScreenPriv->fE3BFakeButton2Sent && !(wParam & MK_LBUTTON) @@ -315,7 +251,7 @@ winMouseButtonsHandle(ScreenPtr pScreen, pScreenPriv->fE3BFakeButton2Sent = FALSE; /* Send middle mouse button release */ - winMouseButtonsSendEvent(ButtonRelease, Button2); + winMouseButtonsSendEvent(FALSE, Button2); } else if (iEventType == ButtonRelease && pScreenPriv->iE3BCachedPress == 0 @@ -324,7 +260,7 @@ winMouseButtonsHandle(ScreenPtr pScreen, * Button was release, no button is cached, * and there is no fake button 2 release is pending. */ - winMouseButtonsSendEvent(ButtonRelease, iButton); + winMouseButtonsSendEvent(FALSE, iButton); } return 0; diff --git a/hw/xwin/winmsg.c b/hw/xwin/winmsg.c index 575bc47b2..1d3a387d8 100644 --- a/hw/xwin/winmsg.c +++ b/hw/xwin/winmsg.c @@ -38,17 +38,7 @@ #endif #include <stdarg.h> -void -winVMsg(int, MessageType, int verb, const char *, va_list) -_X_ATTRIBUTE_PRINTF(4, 0); - -void -winVMsg(int scrnIndex, MessageType type, int verb, const char *format, - va_list ap) -{ - LogVMessageVerb(type, verb, format, ap); -} - +#ifdef XWIN_XF86CONFIG void winDrvMsg(int scrnIndex, MessageType type, const char *format, ...) { @@ -60,16 +50,6 @@ winDrvMsg(int scrnIndex, MessageType type, const char *format, ...) } void -winMsg(MessageType type, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - LogVMessageVerb(type, 1, format, ap); - va_end(ap); -} - -void winDrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, ...) { @@ -79,24 +59,25 @@ winDrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, LogVMessageVerb(type, verb, format, ap); va_end(ap); } +#endif void -winMsgVerb(MessageType type, int verb, const char *format, ...) +winErrorFVerb(int verb, const char *format, ...) { va_list ap; va_start(ap, format); - LogVMessageVerb(type, verb, format, ap); + LogVMessageVerb(X_NONE, verb, format, ap); va_end(ap); } void -winErrorFVerb(int verb, const char *format, ...) +winError(const char *format, ...) { va_list ap; va_start(ap, format); - LogVMessageVerb(X_NONE, verb, format, ap); + LogVMessageVerb(X_NONE, -1, format, ap); va_end(ap); } diff --git a/hw/xwin/winmsg.h b/hw/xwin/winmsg.h index 6c96c4070..25d887510 100644 --- a/hw/xwin/winmsg.h +++ b/hw/xwin/winmsg.h @@ -1,5 +1,3 @@ -#ifndef __WIN_MSG_H__ -#define __WIN_MSG_H__ /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * @@ -30,12 +28,17 @@ * Authors: Alexander Gottwald */ +#ifndef __WIN_MSG_H__ +#define __WIN_MSG_H__ + #include <X11/Xwindows.h> +#include <X11/Xfuncproto.h> /* * Function prototypes */ +#ifdef XWIN_XF86CONFIG void winDrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, ...) @@ -43,12 +46,10 @@ _X_ATTRIBUTE_PRINTF(4, 5); void winDrvMsg(int scrnIndex, MessageType type, const char *format, ...) _X_ATTRIBUTE_PRINTF(3, 4); -void -winMsgVerb(MessageType type, int verb, const char *format, ...) -_X_ATTRIBUTE_PRINTF(3, 4); -void -winMsg(MessageType type, const char *format, ...) -_X_ATTRIBUTE_PRINTF(2, 3); +#endif + +#define winMsg LogMessage + void winDebug(const char *format, ...) _X_ATTRIBUTE_PRINTF(1, 2); @@ -59,6 +60,10 @@ _X_ATTRIBUTE_PRINTF(1, 2); void winErrorFVerb(int verb, const char *format, ...) _X_ATTRIBUTE_PRINTF(2, 3); +void +winError(const char *format, ...) +_X_ATTRIBUTE_PRINTF(1, 2); + void winW32Error(int verb, const char *message); void winW32ErrorEx(int verb, const char *message, DWORD errorcode); void winDebugWin32Message(const char *function, HWND hwnd, UINT message, diff --git a/hw/xwin/winmultiwindowclass.h b/hw/xwin/winmultiwindowclass.h index 3244f78e3..37ee9fb13 100644 --- a/hw/xwin/winmultiwindowclass.h +++ b/hw/xwin/winmultiwindowclass.h @@ -31,11 +31,24 @@ */ /* + * The next block of definitions are for window manager properties that + * clients and applications use for communication. + */ + +/* * Structures */ +/* + * WM_HINTS structure + * + * NOTE: this structure represents the internal format stored in the property + * after it is marshalled by libX11, converting the flags field from an + * arch-dependent long to a 32-bit int. + */ + typedef struct { - long flags; /* marks which fields in this structure are defined */ + int flags; /* marks which fields in this structure are defined */ Bool input; /* does this application rely on the window manager to get keyboard input? */ int initial_state; /* see below */ @@ -59,11 +72,15 @@ typedef struct { #define AllHints (InputHint|StateHint|IconPixmapHint|IconWindowHint|IconPositionHint|IconMaskHint|WindowGroupHint) /* - * new version containing base_width, base_height, and win_gravity fields; + * ICCCM 1.0 version containing base_width, base_height, and win_gravity fields; * used with WM_NORMAL_HINTS. + * + * NOTE: this structure represents the internal format stored in the property + * after it is marshalled by libX11, converting the flags field from an + * arch-dependent long to a 32-bit int. */ typedef struct { - long flags; /* marks which fields in this structure are defined */ + int flags; /* marks which fields in this structure are defined */ int x, y; /* obsolete for new window mgrs, but clients */ int width, height; /* should set so old wm's don't mess up */ int min_width, min_height; @@ -77,11 +94,6 @@ typedef struct { int win_gravity; /* added by ICCCM version 1 */ } WinXSizeHints; -/* - * The next block of definitions are for window manager properties that - * clients and applications use for communication. - */ - /* flags argument in size hints */ #define USPosition (1L << 0) /* user specified x, y */ #define USSize (1L << 1) /* user specified width, height */ diff --git a/hw/xwin/winmultiwindowicons.c b/hw/xwin/winmultiwindowicons.c index cc4538709..02884cbe4 100644 --- a/hw/xwin/winmultiwindowicons.c +++ b/hw/xwin/winmultiwindowicons.c @@ -32,564 +32,68 @@ #include <xwin-config.h> #endif -#ifndef WINVER -#define WINVER 0x0500 -#endif - #include <X11/Xwindows.h> #include <X11/Xlib.h> -#include <X11/Xutil.h> #include "winresource.h" #include "winprefs.h" -#include "winmsg.h" #include "winmultiwindowicons.h" #include "winglobals.h" +#include "wmutil/icon_convert.h" + /* * global variables */ extern HINSTANCE g_hInstance; /* - * Scale an X icon ZPixmap into a Windoze icon bitmap - */ - -static void -winScaleXImageToWindowsIcon(int iconSize, - int effBPP, - int stride, XImage * pixmap, unsigned char *image) -{ - int row, column, effXBPP, effXDepth; - unsigned char *outPtr; - unsigned char *iconData = 0; - int xStride; - float factX, factY; - int posX, posY; - unsigned char *ptr; - unsigned int zero; - unsigned int color; - - effXBPP = pixmap->bits_per_pixel; - if (pixmap->bits_per_pixel == 15) - effXBPP = 16; - - effXDepth = pixmap->depth; - if (pixmap->depth == 15) - effXDepth = 16; - - xStride = pixmap->bytes_per_line; - if (stride == 0 || xStride == 0) { - ErrorF("winScaleXBitmapToWindows - stride or xStride is zero. " - "Bailing.\n"); - return; - } - - /* Get icon data */ - iconData = (unsigned char *) pixmap->data; - - /* Keep aspect ratio */ - factX = ((float) pixmap->width) / ((float) iconSize); - factY = ((float) pixmap->height) / ((float) iconSize); - if (factX > factY) - factY = factX; - else - factX = factY; - - /* Out-of-bounds, fill icon with zero */ - zero = 0; - - for (row = 0; row < iconSize; row++) { - outPtr = image + stride * row; - for (column = 0; column < iconSize; column++) { - posX = factX * column; - posY = factY * row; - - ptr = (unsigned char *) iconData + posY * xStride; - if (effXBPP == 1) { - ptr += posX / 8; - - /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->width || posY >= pixmap->height) - ptr = (unsigned char *) &zero; - - if ((*ptr) & (1 << (posX & 7))) - switch (effBPP) { - case 32: - *(outPtr++) = 0; - case 24: - *(outPtr++) = 0; - case 16: - *(outPtr++) = 0; - case 8: - *(outPtr++) = 0; - break; - case 1: - outPtr[column / 8] &= ~(1 << (7 - (column & 7))); - break; - } - else - switch (effBPP) { - case 32: - *(outPtr++) = 255; - *(outPtr++) = 255; - *(outPtr++) = 255; - *(outPtr++) = 0; - break; - case 24: - *(outPtr++) = 255; - case 16: - *(outPtr++) = 255; - case 8: - *(outPtr++) = 255; - break; - case 1: - outPtr[column / 8] |= (1 << (7 - (column & 7))); - break; - } - } - else if (effXDepth == 24 || effXDepth == 32) { - ptr += posX * (effXBPP / 8); - - /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->width || posY >= pixmap->height) - ptr = (unsigned char *) &zero; - color = (((*ptr) << 16) - + ((*(ptr + 1)) << 8) - + ((*(ptr + 2)) << 0)); - switch (effBPP) { - case 32: - *(outPtr++) = *(ptr++); /* b */ - *(outPtr++) = *(ptr++); /* g */ - *(outPtr++) = *(ptr++); /* r */ - *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */ - break; - case 24: - *(outPtr++) = *(ptr++); - *(outPtr++) = *(ptr++); - *(outPtr++) = *(ptr++); - break; - case 16: - color = ((((*ptr) >> 2) << 10) - + (((*(ptr + 1)) >> 2) << 5) - + (((*(ptr + 2)) >> 2))); - *(outPtr++) = (color >> 8); - *(outPtr++) = (color & 255); - break; - case 8: - color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2)))); - color /= 3; - *(outPtr++) = color; - break; - case 1: - if (color) - outPtr[column / 8] |= (1 << (7 - (column & 7))); - else - outPtr[column / 8] &= ~(1 << (7 - (column & 7))); - } - } - else if (effXDepth == 16) { - ptr += posX * (effXBPP / 8); - - /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->width || posY >= pixmap->height) - ptr = (unsigned char *) &zero; - color = ((*ptr) << 8) + (*(ptr + 1)); - switch (effBPP) { - case 32: - *(outPtr++) = (color & 31) << 2; - *(outPtr++) = ((color >> 5) & 31) << 2; - *(outPtr++) = ((color >> 10) & 31) << 2; - *(outPtr++) = 0; /* resvd */ - break; - case 24: - *(outPtr++) = (color & 31) << 2; - *(outPtr++) = ((color >> 5) & 31) << 2; - *(outPtr++) = ((color >> 10) & 31) << 2; - break; - case 16: - *(outPtr++) = *(ptr++); - *(outPtr++) = *(ptr++); - break; - case 8: - *(outPtr++) = (((color & 31) - + ((color >> 5) & 31) - + ((color >> 10) & 31)) / 3) << 2; - break; - case 1: - if (color) - outPtr[column / 8] |= (1 << (7 - (column & 7))); - else - outPtr[column / 8] &= ~(1 << (7 - (column & 7))); - break; - } /* end switch(effbpp) */ - } /* end if effxbpp==16) */ - } /* end for column */ - } /* end for row */ -} - -static HICON -NetWMToWinIconAlpha(uint32_t * icon) -{ - int width = icon[0]; - int height = icon[1]; - uint32_t *pixels = &icon[2]; - HICON result; - HDC hdc = GetDC(NULL); - uint32_t *DIB_pixels; - ICONINFO ii; - BITMAPV4HEADER bmh = { sizeof(bmh) }; - - /* Define an ARGB pixel format used for Color+Alpha icons */ - bmh.bV4Width = width; - bmh.bV4Height = -height; /* Invert the image */ - bmh.bV4Planes = 1; - bmh.bV4BitCount = 32; - bmh.bV4V4Compression = BI_BITFIELDS; - bmh.bV4AlphaMask = 0xFF000000; - bmh.bV4RedMask = 0x00FF0000; - bmh.bV4GreenMask = 0x0000FF00; - bmh.bV4BlueMask = 0x000000FF; - - ii.fIcon = TRUE; - ii.xHotspot = 0; /* ignored */ - ii.yHotspot = 0; /* ignored */ - ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *) &bmh, - DIB_RGB_COLORS, (void **) &DIB_pixels, NULL, - 0); - ReleaseDC(NULL, hdc); - - if (!ii.hbmColor) - return NULL; - - ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL); - memcpy(DIB_pixels, pixels, height * width * 4); - - /* CreateIconIndirect() traditionally required DDBitmaps */ - /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */ - /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */ - result = CreateIconIndirect(&ii); - - DeleteObject(ii.hbmColor); - DeleteObject(ii.hbmMask); - - winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result); - return result; -} - -static HICON -NetWMToWinIconThreshold(uint32_t * icon) -{ - int width = icon[0]; - int height = icon[1]; - uint32_t *pixels = &icon[2]; - int row, col; - HICON result; - ICONINFO ii; - - HDC hdc = GetDC(NULL); - HDC xorDC = CreateCompatibleDC(hdc); - HDC andDC = CreateCompatibleDC(hdc); - - ii.fIcon = TRUE; - ii.xHotspot = 0; /* ignored */ - ii.yHotspot = 0; /* ignored */ - ii.hbmColor = CreateCompatibleBitmap(hdc, width, height); - ii.hbmMask = CreateCompatibleBitmap(hdc, width, height); - ReleaseDC(NULL, hdc); - SelectObject(xorDC, ii.hbmColor); - SelectObject(andDC, ii.hbmMask); - - for (row = 0; row < height; row++) { - for (col = 0; col < width; col++) { - if ((*pixels & 0xFF000000) > 31 << 24) { /* 31 alpha threshold, i.e. opaque above, transparent below */ - SetPixelV(xorDC, col, row, - RGB(((char *) pixels)[2], ((char *) pixels)[1], - ((char *) pixels)[0])); - SetPixelV(andDC, col, row, RGB(0, 0, 0)); /* black mask */ - } - else { - SetPixelV(xorDC, col, row, RGB(0, 0, 0)); - SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */ - } - pixels++; - } - } - DeleteDC(xorDC); - DeleteDC(andDC); - - result = CreateIconIndirect(&ii); - - DeleteObject(ii.hbmColor); - DeleteObject(ii.hbmMask); - - winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1], - result); - return result; -} - -static HICON -NetWMToWinIcon(int bpp, uint32_t * icon) -{ - static Bool hasIconAlphaChannel = FALSE; - static BOOL versionChecked = FALSE; - - if (!versionChecked) { - OSVERSIONINFOEX osvi = { 0 }; - ULONGLONG dwlConditionMask = 0; - - osvi.dwOSVersionInfoSize = sizeof(osvi); - osvi.dwMajorVersion = 5; - osvi.dwMinorVersion = 1; - - /* Windows versions later than XP have icon alpha channel suport, 2000 does not */ - VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, - VER_GREATER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, - VER_GREATER_EQUAL); - hasIconAlphaChannel = - VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, - dwlConditionMask); - versionChecked = TRUE; - - ErrorF("OS has icon alpha channel support: %s\n", - hasIconAlphaChannel ? "yes" : "no"); - } - - if (hasIconAlphaChannel && (bpp == 32)) - return NetWMToWinIconAlpha(icon); - else - return NetWMToWinIconThreshold(icon); -} - -/* - * Attempt to create a custom icon from the WM_HINTS bitmaps - */ - -static - HICON -winXIconToHICON(Display * pDisplay, Window id, int iconSize) -{ - unsigned char *mask, *image = NULL, *imageMask; - unsigned char *dst, *src; - int planes, bpp, i; - unsigned int biggest_size = 0; - HDC hDC; - ICONINFO ii; - XWMHints *hints; - HICON hIcon = NULL; - uint32_t *biggest_icon = NULL; - static Atom _XA_NET_WM_ICON; - static int generation; - uint32_t *icon, *icon_data = NULL; - unsigned long int size; - Atom type; - int format; - unsigned long int left; - - hDC = GetDC(GetDesktopWindow()); - planes = GetDeviceCaps(hDC, PLANES); - bpp = GetDeviceCaps(hDC, BITSPIXEL); - ReleaseDC(GetDesktopWindow(), hDC); - - /* Always prefer _NET_WM_ICON icons */ - if (generation != serverGeneration) { - generation = serverGeneration; - _XA_NET_WM_ICON = XInternAtom(pDisplay, "_NET_WM_ICON", FALSE); - } - - if ((XGetWindowProperty(pDisplay, id, _XA_NET_WM_ICON, - 0, MAXINT, FALSE, - AnyPropertyType, &type, &format, &size, &left, - (unsigned char **) &icon_data) == Success) && - (icon_data != NULL)) { - for (icon = icon_data; icon < &icon_data[size] && *icon; - icon = &icon[icon[0] * icon[1] + 2]) { - winDebug("winXIconToHICON: %u x %u NetIcon\n", icon[0], icon[1]); - - /* Icon data size will overflow an int and thus is bigger than the - property can possibly be */ - if ((INT_MAX/icon[0]) < icon[1]) { - winDebug("winXIconToHICON: _NET_WM_ICON icon data size overflow\n"); - break; - } - - /* Icon data size is bigger than amount of data remaining */ - if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) { - winDebug("winXIconToHICON: _NET_WM_ICON data is malformed\n"); - break; - } - - /* Found an exact match to the size we require... */ - if (icon[0] == iconSize && icon[1] == iconSize) { - winDebug("winXIconToHICON: selected %d x %d NetIcon\n", - iconSize, iconSize); - hIcon = NetWMToWinIcon(bpp, icon); - break; - } - /* Otherwise, find the biggest icon and let Windows scale the size */ - else if (biggest_size < icon[0]) { - biggest_icon = icon; - biggest_size = icon[0]; - } - } - - if (!hIcon && biggest_icon) { - winDebug - ("winXIconToHICON: selected %u x %u NetIcon for scaling to %d x %d\n", - biggest_icon[0], biggest_icon[1], iconSize, iconSize); - - hIcon = NetWMToWinIcon(bpp, biggest_icon); - } - - XFree(icon_data); - } - - if (!hIcon) { - winDebug("winXIconToHICON: no suitable NetIcon\n"); - - hints = XGetWMHints(pDisplay, id); - if (hints) { - winDebug("winXIconToHICON: id 0x%x icon_pixmap hint 0x%x\n", - (unsigned int)id, - (unsigned int)hints->icon_pixmap); - - if (hints->icon_pixmap) { - Window root; - int x, y; - unsigned int width, height, border_width, depth; - XImage *xImageIcon; - XImage *xImageMask = NULL; - - XGetGeometry(pDisplay, hints->icon_pixmap, &root, &x, &y, - &width, &height, &border_width, &depth); - - xImageIcon = - XGetImage(pDisplay, hints->icon_pixmap, 0, 0, width, height, - 0xFFFFFFFF, ZPixmap); - winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%p\n", - (unsigned int)id, xImageIcon); - - if (hints->icon_mask) - xImageMask = - XGetImage(pDisplay, hints->icon_mask, 0, 0, width, - height, 0xFFFFFFFF, ZPixmap); - - if (xImageIcon) { - int effBPP, stride, maskStride; - - /* 15 BPP is really 16BPP as far as we care */ - if (bpp == 15) - effBPP = 16; - else - effBPP = bpp; - - /* Need 16-bit aligned rows for DDBitmaps */ - stride = ((iconSize * effBPP + 15) & (~15)) / 8; - - /* Mask is 1-bit deep */ - maskStride = ((iconSize * 1 + 15) & (~15)) / 8; - - image = malloc(stride * iconSize); - imageMask = malloc(stride * iconSize); - mask = malloc(maskStride * iconSize); - - /* Default to a completely black mask */ - memset(imageMask, 0, stride * iconSize); - memset(mask, 0, maskStride * iconSize); - - winScaleXImageToWindowsIcon(iconSize, effBPP, stride, - xImageIcon, image); - - if (xImageMask) { - winScaleXImageToWindowsIcon(iconSize, 1, maskStride, - xImageMask, mask); - winScaleXImageToWindowsIcon(iconSize, effBPP, stride, - xImageMask, imageMask); - } - - /* Now we need to set all bits of the icon which are not masked */ - /* on to 0 because Color is really an XOR, not an OR function */ - dst = image; - src = imageMask; - - for (i = 0; i < (stride * iconSize); i++) - if ((*(src++))) - *(dst++) = 0; - else - dst++; - - ii.fIcon = TRUE; - ii.xHotspot = 0; /* ignored */ - ii.yHotspot = 0; /* ignored */ - - /* Create Win32 mask from pixmap shape */ - ii.hbmMask = - CreateBitmap(iconSize, iconSize, planes, 1, mask); - - /* Create Win32 bitmap from pixmap */ - ii.hbmColor = - CreateBitmap(iconSize, iconSize, planes, bpp, image); - - /* Merge Win32 mask and bitmap into icon */ - hIcon = CreateIconIndirect(&ii); - - /* Release Win32 mask and bitmap */ - DeleteObject(ii.hbmMask); - DeleteObject(ii.hbmColor); - - /* Free X mask and bitmap */ - free(mask); - free(image); - free(imageMask); - - if (xImageMask) - XDestroyImage(xImageMask); - - XDestroyImage(xImageIcon); - } - } - XFree(hints); - } - } - return hIcon; -} - -/* * Change the Windows window icon */ #ifdef XWIN_MULTIWINDOW void -winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew) +winUpdateIcon(HWND hWnd, xcb_connection_t *conn, Window id, HICON hIconNew) { HICON hIcon, hIconSmall = NULL, hIconOld; - /* Start with the icon from preferences, if any */ - hIcon = hIconNew; - hIconSmall = hIconNew; - - /* If we still need an icon, try and get the icon from WM_HINTS */ - if (!hIcon) - hIcon = winXIconToHICON(pDisplay, id, GetSystemMetrics(SM_CXICON)); - if (!hIconSmall) - hIconSmall = - winXIconToHICON(pDisplay, id, GetSystemMetrics(SM_CXSMICON)); + if (hIconNew) + { + /* Start with the icon from preferences, if any */ + hIcon = hIconNew; + hIconSmall = hIconNew; + } + else + { + /* If we still need an icon, try and get the icon from WM_HINTS */ + hIcon = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXICON)); + hIconSmall = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXSMICON)); + + /* If we got the small, but not the large one swap them */ + if (!hIcon && hIconSmall) { + hIcon = hIconSmall; + hIconSmall = NULL; + } + } - /* If we got the small, but not the large one swap them */ - if (!hIcon && hIconSmall) { - hIcon = hIconSmall; - hIconSmall = NULL; + /* If we still need an icon, use the default one */ + if (!hIcon) { + hIcon = g_hIconX; + hIconSmall = g_hSmallIconX; } - /* Set the large icon */ - hIconOld = (HICON) SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); - /* Delete the old icon if its not the default */ - winDestroyIcon(hIconOld); + if (hIcon) { + /* Set the large icon */ + hIconOld = (HICON) SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); + /* Delete the old icon if its not the default */ + winDestroyIcon(hIconOld); + } - /* Same for the small icon */ - hIconOld = - (HICON) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); - winDestroyIcon(hIconOld); + if (hIconSmall) { + /* Same for the small icon */ + hIconOld = + (HICON) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); + winDestroyIcon(hIconOld); + } } void diff --git a/hw/xwin/winmultiwindowicons.h b/hw/xwin/winmultiwindowicons.h index bf7f6eda7..87ba8d1cf 100644 --- a/hw/xwin/winmultiwindowicons.h +++ b/hw/xwin/winmultiwindowicons.h @@ -27,8 +27,10 @@ #ifndef WINMULTIWINDOWICONS_H #define WINMULTIWINDOWICONS_H +#include <xcb/xcb.h> + void - winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew); + winUpdateIcon(HWND hWnd, xcb_connection_t *conn, Window id, HICON hIconNew); void winInitGlobalIcons(void); diff --git a/hw/xwin/winmultiwindowwindow.c b/hw/xwin/winmultiwindowwindow.c index f4de91242..28828af8a 100644 --- a/hw/xwin/winmultiwindowwindow.c +++ b/hw/xwin/winmultiwindowwindow.c @@ -35,9 +35,11 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + #include "win.h" #include "dixevents.h" #include "winmultiwindowclass.h" +#include "winmultiwindowicons.h" /* * Prototypes for local functions @@ -55,11 +57,27 @@ static void static void winFindWindow(void *value, XID id, void *cdata); +static Bool +isToplevelWindow(WindowPtr pWin) +{ + assert(pWin->parent); /* root window isn't expected here */ + + /* If the immediate parent is the root window, this is a top-level window */ + if ((pWin->parent) && (pWin->parent->parent == NULL)) { + assert(pWin->parent == pWin->drawable.pScreen->root); + return TRUE; + } + + /* otherwise, a child window */ + return FALSE; +} + static void winInitMultiWindowClass(void) { static wATOM atomXWinClass = 0; + static wATOM atomXWinChildClass = 0; WNDCLASSEX wcx; if (atomXWinClass == 0) { @@ -83,11 +101,40 @@ winInitMultiWindowClass(void) wcx.hIconSm = hIconSmall; #if CYGMULTIWINDOW_DEBUG - ErrorF("winCreateWindowsWindow - Creating class: %s\n", WINDOW_CLASS_X); + ErrorF("winInitMultiWindowClass - Creating class: %s\n", + WINDOW_CLASS_X); #endif atomXWinClass = RegisterClassEx(&wcx); } + + if (atomXWinChildClass == 0) { + HICON hIcon, hIconSmall; + + /* Load the default icons */ + winSelectIcons(&hIcon, &hIconSmall); + + /* Setup our window class */ + wcx.cbSize = sizeof(WNDCLASSEX); + wcx.style = CS_HREDRAW | CS_VREDRAW | (g_fNativeGl ? CS_OWNDC : 0); + wcx.lpfnWndProc = winChildWindowProc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = g_hInstance; + wcx.hIcon = hIcon; + wcx.hCursor = 0; + wcx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = WINDOW_CLASS_X_CHILD; + wcx.hIconSm = hIconSmall; + +#if CYGMULTIWINDOW_DEBUG + ErrorF("winInitMultiWindowClass - Creating class: %s\n", + WINDOW_CLASS_X_CHILD); +#endif + + atomXWinChildClass = RegisterClassEx(&wcx); + } } /* @@ -202,6 +249,29 @@ winPositionWindowMultiWindow(WindowPtr pWin, int x, int y) return fResult; } + if (!isToplevelWindow(pWin)) { + POINT parentOrigin; + + /* Get the X and Y location of the X window */ + iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); + iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); + + /* Get the height and width of the X window */ + iWidth = pWin->drawable.width; + iHeight = pWin->drawable.height; + + /* Convert screen coordinates into client area co-ordinates of the parent */ + parentOrigin.x = 0; + parentOrigin.y = 0; + ClientToScreen(GetParent(hWnd), &parentOrigin); + + MoveWindow(hWnd, + iX - parentOrigin.x, iY - parentOrigin.y, iWidth, iHeight, + TRUE); + + return fResult; + } + /* Get the Windows window style and extended style */ dwExStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE); dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE); @@ -471,12 +541,8 @@ winRestackWindowMultiWindow(WindowPtr pWin, WindowPtr pOldNextSib) #endif } -/* - * winCreateWindowsWindow - Create a Windows window associated with an X window - */ - -void -winCreateWindowsWindow(WindowPtr pWin) +static void +winCreateWindowsTopLevelWindow(WindowPtr pWin) { int iX, iY; int iWidth; @@ -485,7 +551,6 @@ winCreateWindowsWindow(WindowPtr pWin) HWND hFore = NULL; winWindowPriv(pWin); - winPrivScreenPtr pScreenPriv = pWinPriv->pScreenPriv; WinXSizeHints hints; Window daddyId; DWORD dwStyle, dwExStyle; @@ -503,39 +568,63 @@ winCreateWindowsWindow(WindowPtr pWin) iHeight = pWin->drawable.height; /* If it's an InputOutput window, and so is going to end up being made visible, - make sure the window actually ends up somewhere where it will be visible */ - if (pWin->drawable.class != InputOnly) { - if ((iX < GetSystemMetrics(SM_XVIRTUALSCREEN)) || - (iX > GetSystemMetrics(SM_CXVIRTUALSCREEN))) - iX = CW_USEDEFAULT; + make sure the window actually ends up somewhere where it will be visible - if ((iY < GetSystemMetrics(SM_YVIRTUALSCREEN)) || - (iY > GetSystemMetrics(SM_CYVIRTUALSCREEN))) - iY = CW_USEDEFAULT; + To handle arrangements of monitors which form a non-rectangular virtual + desktop, check if the window will end up with it's top-left corner on any + monitor + */ + if (pWin->drawable.class != InputOnly) { + POINT pt = { iX, iY }; + if (MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) == NULL) + { + iX = CW_USEDEFAULT; + iY = CW_USEDEFAULT; + } } - winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX, - iY); + winDebug("winCreateWindowsTopLevelWindow - %dx%d @ %dx%d\n", iWidth, + iHeight, iX, iY); if (winMultiWindowGetTransientFor(pWin, &daddyId)) { if (daddyId) { - hFore = GetForegroundWindow(); - if (hFore && (daddyId != (Window) (INT_PTR) GetProp(hFore, WIN_WID_PROP))) - hFore = NULL; + WindowPtr pParent; + int res = dixLookupWindow(&pParent, daddyId, serverClient, DixReadAccess); + if (res == Success) + { + winPrivWinPtr pParentPriv = winGetWindowPriv(pParent); + hFore = pParentPriv->hWnd; + } } } else { - /* Default positions if none specified */ - if (!winMultiWindowGetWMNormalHints(pWin, &hints)) - hints.flags = 0; - if (!(hints.flags & (USPosition | PPosition)) && - !pWin->overrideRedirect) { - iX = CW_USEDEFAULT; - iY = CW_USEDEFAULT; + if (!pWin->overrideRedirect) { + /* Default positions if none specified */ + if (!winMultiWindowGetWMNormalHints(pWin, &hints)) + hints.flags = 0; + + if ((hints.flags & USPosition) || + ((hints.flags & PPosition) && + ((pWin->drawable.x - pWin->borderWidth != 0) || + (pWin->drawable.y - pWin->borderWidth != 0)))) { + /* + Always respect user specified position, respect program + specified position if it's not the origin + */ + } + else { + /* Use default position */ + iX = CW_USEDEFAULT; + iY = CW_USEDEFAULT; + } } } - /* Make it WS_OVERLAPPED in create call since WS_POPUP doesn't support */ + winDebug("winCreateWindowsTopLevelWindow - %dx%d @ %dx%d\n", iWidth, + iHeight, iX, iY); + + /* Create the window */ + /* Make it OVERLAPPED in create call since WS_POPUP doesn't support */ /* CW_USEDEFAULT, change back to popup after creation */ dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; dwExStyle = WS_EX_TOOLWINDOW; @@ -573,11 +662,14 @@ winCreateWindowsWindow(WindowPtr pWin) GetModuleHandle(NULL), /* Instance handle */ pWin); /* ScreenPrivates */ if (hWnd == NULL) { - ErrorF("winCreateWindowsWindow - CreateWindowExA () failed: %d\n", - (int) GetLastError()); + ErrorF + ("winCreateWindowsTopLevelWindow - CreateWindowExA () failed: %d\n", + (int) GetLastError()); } pWinPriv->hWnd = hWnd; + winDebug("winCreateWindowsTopLevelWindow - hwnd 0x%p\n", hWnd); + /* Change style back to popup, already placed... */ SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); @@ -598,9 +690,107 @@ winCreateWindowsWindow(WindowPtr pWin) /* Flag that this Windows window handles its own activation */ SetProp(hWnd, WIN_NEEDMANAGE_PROP, (HANDLE) 0); +} + +static void +winCreateWindowsChildWindow(WindowPtr pWin) +{ + int iX, iY, iWidth, iHeight; + HWND hWnd; + WindowPtr pParent = pWin->parent; + DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED; + DWORD dwExStyle = WS_EX_TRANSPARENT; + + /* + WS_DISABLED means child window never gains the input focus, so only the + top-level window needs deal with passing input to the X server + + WS_EX_TRANSPARENT ensures that the contents of the top-level + Windows window (which will contain all non-OpenGL drawing for the hierarchy) + can be seen through any intermediate child windows which have nothing + drawn to them + */ + winPrivWinPtr pParentPriv, pWinPriv; + + winDebug("winCreateWindowsChildWindow - pWin:%p XID:0x%x\n", pWin, + pWin->drawable.id); + + winInitMultiWindowClass(); + + assert(pParent); + + pParentPriv = winGetWindowPriv(pParent); + pWinPriv = winGetWindowPriv(pWin); + + iX = pWin->drawable.x - pParent->drawable.x; + iY = pWin->drawable.y - pParent->drawable.y; + iWidth = pWin->drawable.width; + iHeight = pWin->drawable.height; + + winDebug + ("winCreateWindowsChildWindow - parent pWin:%p XID:0x%08x hWnd:0x%p\n", + pParent, pParent->drawable.id, pParentPriv->hWnd); + winDebug("winCreateWindowsChildWindow - %dx%d @ %dx%d\n", iWidth, iHeight, + iX, iY); + + /* Create the window */ + hWnd = CreateWindowExA(dwExStyle, /* Extended styles */ + WINDOW_CLASS_X_CHILD, /* Class name */ + WINDOW_TITLE_X, /* Window name */ + dwStyle, /* Styles */ + iX, /* Horizontal position */ + iY, /* Vertical position */ + iWidth, /* Right edge */ + iHeight, /* Bottom edge */ + pParentPriv->hWnd, /* parent window */ + (HMENU) NULL, /* No menu */ + GetModuleHandle(NULL), /* Instance handle */ + pWin); /* ScreenPrivates */ + if (hWnd == NULL) { + ErrorF("winCreateWindowsChildWindow - CreateWindowExA () failed: %d\n", + (int) GetLastError()); + } + winDebug("winCreateWindowsChildWindow - hwnd 0x%p\n", hWnd); + pWinPriv->hWnd = hWnd; + + SetProp(hWnd, WIN_WID_PROP, (HANDLE) (INT_PTR) winGetWindowID(pWin)); +} + +/* + * winCreateWindowsWindow - Create a Windows window associated with an X window + */ + +void +winCreateWindowsWindow(WindowPtr pWin) +{ + winDebug("winCreateWindowsWindow - pWin:%p XID:0x%x \n", pWin, + pWin->drawable.id); + + if (isToplevelWindow(pWin)) { + winCreateWindowsTopLevelWindow(pWin); + } + else { + winCreateWindowsChildWindow(pWin); + } +} + +static int +winDestroyChildWindowsWindow(WindowPtr pWin, void *data) +{ + winWindowPriv(pWin); + + winDebug("winDestroyChildWindowsWindow - pWin:%p XID:0x%x \n", pWin, + pWin->drawable.id); + + /* Null our handle to the Window so referencing it will cause an error */ + pWinPriv->hWnd = NULL; - /* Call engine-specific create window procedure */ - (*pScreenPriv->pwinFinishCreateWindowsWindow) (pWin); +#ifdef XWIN_GLX_WINDOWS + /* No longer note WGL used on this window */ + pWinPriv->fWglUsed = FALSE; +#endif + + return WT_WALKCHILDREN; /* continue enumeration */ } Bool winInDestroyWindowsWindow = FALSE; @@ -618,6 +808,7 @@ winDestroyWindowsWindow(WindowPtr pWin) BOOL oldstate = winInDestroyWindowsWindow; HICON hIcon; HICON hIconSm; + HWND hWnd; winDebug("winDestroyWindowsWindow - pWin:%p XID:0x%x \n", pWin, (unsigned int)pWin->drawable.id); @@ -632,21 +823,20 @@ winDestroyWindowsWindow(WindowPtr pWin) hIcon = (HICON) SendMessage(pWinPriv->hWnd, WM_GETICON, ICON_BIG, 0); hIconSm = (HICON) SendMessage(pWinPriv->hWnd, WM_GETICON, ICON_SMALL, 0); - /* Destroy the Windows window */ - DestroyWindow(pWinPriv->hWnd); + hWnd = pWinPriv->hWnd; - /* Null our handle to the Window so referencing it will cause an error */ - pWinPriv->hWnd = NULL; + /* DestroyWindow() implicitly destroys all child windows, + so first walk over the child tree of this window, clearing + any hWnds */ + TraverseTree(pWin, winDestroyChildWindowsWindow, 0); + + /* Destroy the Windows window */ + DestroyWindow(hWnd); /* Destroy any icons we created for this window */ winDestroyIcon(hIcon); winDestroyIcon(hIconSm); -#ifdef XWIN_GLX_WINDOWS - /* No longer note WGL used on this window */ - pWinPriv->fWglUsed = FALSE; -#endif - /* Process all messages on our queue */ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (g_hDlgDepthChange == 0 || !IsDialogMessage(g_hDlgDepthChange, &msg)) { @@ -668,29 +858,58 @@ static void winUpdateWindowsWindow(WindowPtr pWin) { winWindowPriv(pWin); - HWND hWnd = pWinPriv->hWnd; #if CYGMULTIWINDOW_DEBUG ErrorF("winUpdateWindowsWindow\n"); #endif - /* Check if the Windows window's parents have been destroyed */ - if (pWin->parent != NULL && pWin->parent->parent == NULL && pWin->mapped) { - /* Create the Windows window if it has been destroyed */ - if (hWnd == NULL) { - winCreateWindowsWindow(pWin); - assert(pWinPriv->hWnd != NULL); + /* Ignore the root window */ + if (pWin->parent == NULL) + return; + + /* If it's mapped */ + if (pWin->mapped) { + /* If it's a top-level window */ + if (isToplevelWindow(pWin)) { + /* Create the Windows window if needed */ + if (pWinPriv->hWnd == NULL) { + winCreateWindowsWindow(pWin); + assert(pWinPriv->hWnd != NULL); + } + + /* Display the window without activating it */ + if (pWin->drawable.class != InputOnly) + ShowWindow(pWinPriv->hWnd, SW_SHOWNOACTIVATE); + + } + /* It's not a top-level window, but we created a window for GLX */ + else if (pWinPriv->hWnd) { + winPrivWinPtr pParentPriv = winGetWindowPriv(pWin->parent); + + /* XXX: This really belongs in winReparentWindow ??? */ + /* XXX: this assumes parent window has been made to exist */ + assert(pParentPriv->hWnd); + + /* Ensure we have the correct parent and position if reparented */ + SetParent(pWinPriv->hWnd, pParentPriv->hWnd); + SetWindowPos(pWinPriv->hWnd, NULL, + pWin->drawable.x - pWin->parent->drawable.x, + pWin->drawable.y - pWin->parent->drawable.y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); } - /* Display the window without activating it */ - if (pWin->drawable.class != InputOnly) - ShowWindow(pWinPriv->hWnd, SW_SHOWNOACTIVATE); + /* If it's top level, or a GLX window which has already been created getting mapped, show it */ + if (pWinPriv->hWnd != NULL) { + /* Display the window without activating it */ + if (pWin->drawable.class != InputOnly) + ShowWindow(pWinPriv->hWnd, SW_SHOWNOACTIVATE); - /* Send first paint message */ - UpdateWindow(pWinPriv->hWnd); + /* Send first paint message */ + UpdateWindow(pWinPriv->hWnd); + } } - else if (hWnd != NULL) { - /* Destroy the Windows window if its parents are destroyed */ + else if (pWinPriv->hWnd != NULL) { + /* If it's been reparented to an unmapped window when previously mapped, destroy the Windows window */ winDestroyWindowsWindow(pWin); assert(pWinPriv->hWnd == NULL); } @@ -794,56 +1013,6 @@ winReorderWindowsMultiWindow(void) } /* - * winMinimizeWindow - Minimize in response to WM_CHANGE_STATE - */ - -void -winMinimizeWindow(Window id) -{ - WindowPtr pWin; - winPrivWinPtr pWinPriv; - -#ifdef XWIN_MULTIWINDOWEXTWM - win32RootlessWindowPtr pRLWinPriv; -#endif - HWND hWnd; - ScreenPtr pScreen = NULL; - winPrivScreenPtr pScreenPriv = NULL; - -#if CYGWINDOWING_DEBUG - ErrorF("winMinimizeWindow\n"); -#endif - - dixLookupResourceByType((void *) &pWin, id, RT_WINDOW, NullClient, - DixUnknownAccess); - if (!pWin) { - ErrorF("%s: NULL pWin. Leaving\n", __FUNCTION__); - return; - } - - pScreen = pWin->drawable.pScreen; - if (pScreen) - pScreenPriv = winGetScreenPriv(pScreen); - -#ifdef XWIN_MULTIWINDOWEXTWM - if (pScreenPriv && pScreenPriv->pScreenInfo->fInternalWM) { - pRLWinPriv = - (win32RootlessWindowPtr) RootlessFrameForWindow(pWin, FALSE); - hWnd = pRLWinPriv->hWnd; - } - else -#else - if (pScreenPriv) -#endif - { - pWinPriv = winGetWindowPriv(pWin); - hWnd = pWinPriv->hWnd; - } - - ShowWindow(hWnd, SW_MINIMIZE); -} - -/* * CopyWindow - See Porting Layer Definition - p. 39 */ void @@ -927,6 +1096,14 @@ winAdjustXWindow(WindowPtr pWin, HWND hwnd) ErrorF("winAdjustXWindow\n"); #endif + if (!isToplevelWindow(pWin)) { +#if 1 + ErrorF + ("winAdjustXWindow - immediately return because not a top-level window\n"); +#endif + return 0; + } + if (IsIconic(hwnd)) { #if CYGWINDOWING_DEBUG ErrorF("\timmediately return because the window is iconized\n"); diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index 1efe96a15..ac5a58309 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -30,10 +30,24 @@ * Colin Harrison */ +#ifndef WINVER +#define WINVER 0x0500 +#endif + /* X headers */ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + +/* + * Including any server header might define the macro _XSERVER64 on 64 bit machines. + * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen. + * So let's undef that macro if necessary. + */ +#ifdef _XSERVER64 +#undef _XSERVER64 +#endif + #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -45,31 +59,26 @@ #define HANDLE void * #include <pthread.h> #undef HANDLE -#include <X11/X.h> -#include <X11/Xatom.h> -#include <X11/Xlib.h> -#include <X11/Xlocale.h> -#include <X11/Xproto.h> -#include <X11/Xutil.h> -#include <X11/cursorfont.h> +#include <xcb/xcb.h> +#include <xcb/xcb_icccm.h> +#include <xcb/xcb_ewmh.h> +#include <xcb/xcb_aux.h> +#include <xcb/composite.h> + #include <X11/Xwindows.h> /* Local headers */ +#include "X11/Xdefs.h" // for Bool type #include "winwindow.h" #include "winprefs.h" #include "window.h" -#include "pixmapstr.h" -#include "windowstr.h" #include "winglobals.h" #include "windisplay.h" +#include "winmultiwindowicons.h" -#ifdef XWIN_MULTIWINDOWEXTWM -#include <X11/extensions/windowswmstr.h> -#else /* We need the native HWND atom for intWM, so for consistency use the - same name as extWM would if we were building with enabled... */ + same name as extWM does */ #define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND" -#endif #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 @@ -78,6 +87,8 @@ extern void winDebug(const char *format, ...); extern void winReshapeMultiWindow(WindowPtr pWin); extern void winUpdateRgnMultiWindow(WindowPtr pWin); +extern xcb_auth_info_t *winGetXcbAuthInfo(void); +extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle); #ifndef CYGDEBUG #define CYGDEBUG NO @@ -92,8 +103,6 @@ extern void winUpdateRgnMultiWindow(WindowPtr pWin); #ifdef HAS_DEVWINDOWS #define WIN_MSG_QUEUE_FNAME "/dev/windows" #endif -#define WIN_JMP_OKAY 0 -#define WIN_JMP_ERROR_IO 2 /* * Local structures @@ -113,13 +122,20 @@ typedef struct _WMMsgQueueRec { } WMMsgQueueRec, *WMMsgQueuePtr; typedef struct _WMInfo { - Display *pDisplay; + xcb_connection_t *conn; WMMsgQueueRec wmMsgQueue; - Atom atmWmProtos; - Atom atmWmDelete; - Atom atmWmTakeFocus; - Atom atmPrivMap; - Bool fAllowOtherWM; + xcb_atom_t atmWmProtos; + xcb_atom_t atmWmDelete; + xcb_atom_t atmWmTakeFocus; + xcb_atom_t atmPrivMap; + xcb_atom_t atmUtf8String; + xcb_atom_t atmNetWmName; + xcb_atom_t atmCurrentDesktop; + xcb_atom_t atmNumberDesktops; + xcb_atom_t atmDesktopNames; + xcb_atom_t atmWmState; + xcb_ewmh_connection_t ewmh; + Bool fCompositeWM; } WMInfoRec, *WMInfoPtr; typedef struct _WMProcArgRec { @@ -129,7 +145,7 @@ typedef struct _WMProcArgRec { } WMProcArgRec, *WMProcArgPtr; typedef struct _XMsgProcArgRec { - Display *pDisplay; + xcb_connection_t *conn; DWORD dwScreen; WMInfoPtr pWMInfo; pthread_mutex_t *ppmServerStarted; @@ -149,65 +165,101 @@ static Bool InitQueue(WMMsgQueuePtr pQueue); static void - GetWindowName(Display * pDpy, Window iWin, char **ppWindowName); + GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName); -static int - SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData); +static void + SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData); static void - UpdateName(WMInfoPtr pWMInfo, Window iWindow); + UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow); static void *winMultiWindowWMProc(void *pArg); -static int - winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr); - -static int - winMultiWindowWMIOErrorHandler(Display * pDisplay); - static void *winMultiWindowXMsgProc(void *pArg); -static int - winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr); - -static int - winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay); - -static int - winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr); +static void +winMultiWindowThreadExit(void *arg); static void winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg); #if 0 static void - PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction); + PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction); #endif static Bool - -CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, - Bool fAllowOtherWM); +CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen); static void - winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle); + winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle, Bool onCreate); -void - winUpdateWindowPosition(HWND hWnd, HWND * zstyle); +static void + winApplyUrgency(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd); /* * Local globals */ -static jmp_buf g_jmpWMEntry; -static XIOErrorHandler g_winMultiWindowWMOldIOErrorHandler; -static pthread_t g_winMultiWindowWMThread; -static jmp_buf g_jmpXMsgProcEntry; -static XIOErrorHandler g_winMultiWindowXMsgProcOldIOErrorHandler; -static pthread_t g_winMultiWindowXMsgProcThread; static Bool g_shutdown = FALSE; -static Bool redirectError = FALSE; -static Bool g_fAnotherWMRunning = FALSE; + +/* + * Translate msg id to text, for debug purposes + */ + +static const char * +MessageName(winWMMessagePtr msg) +{ + switch (msg->msg) + { + case WM_WM_MOVE: + return "WM_WM_MOVE"; + break; + case WM_WM_SIZE: + return "WM_WM_SIZE"; + break; + case WM_WM_RAISE: + return "WM_WM_RAISE"; + break; + case WM_WM_LOWER: + return "WM_WM_LOWER"; + break; + case WM_WM_UNMAP: + return "WM_WM_UNMAP"; + break; + case WM_WM_KILL: + return "WM_WM_KILL"; + break; + case WM_WM_ACTIVATE: + return "WM_WM_ACTIVATE"; + break; + case WM_WM_NAME_EVENT: + return "WM_WM_NAME_EVENT"; + break; + case WM_WM_ICON_EVENT: + return "WM_WM_ICON_EVENT"; + break; + case WM_WM_CHANGE_STATE: + return "WM_WM_CHANGE_STATE"; + break; + case WM_WM_MAP: + return "WM_WM_MAP"; + break; + case WM_WM_MAP_UNMANAGED: + return "WM_WM_MAP_UNMANAGED"; + break; + case WM_WM_MAP_MANAGED: + return "WM_WM_MAP_MANAGED"; + break; + case WM_WM_HINTS_EVENT: + return "WM_WM_HINTS_EVENT"; + break; + default: + return "Unknown Message"; + break; + } +} + /* * PushMessage - Push a message onto the queue @@ -231,44 +283,6 @@ PushMessage(WMMsgQueuePtr pQueue, WMMsgNodePtr pNode) pQueue->pHead = pNode; } -#if 0 - switch (pNode->msg.msg) { - case WM_WM_MOVE: - ErrorF("\tWM_WM_MOVE\n"); - break; - case WM_WM_SIZE: - ErrorF("\tWM_WM_SIZE\n"); - break; - case WM_WM_RAISE: - ErrorF("\tWM_WM_RAISE\n"); - break; - case WM_WM_LOWER: - ErrorF("\tWM_WM_LOWER\n"); - break; - case WM_WM_MAP: - ErrorF("\tWM_WM_MAP\n"); - break; - case WM_WM_MAP2: - ErrorF("\tWM_WM_MAP2\n"); - break; - case WM_WM_MAP3: - ErrorF("\tWM_WM_MAP3\n"); - break; - case WM_WM_UNMAP: - ErrorF("\tWM_WM_UNMAP\n"); - break; - case WM_WM_KILL: - ErrorF("\tWM_WM_KILL\n"); - break; - case WM_WM_ACTIVATE: - ErrorF("\tWM_WM_ACTIVATE\n"); - break; - default: - ErrorF("\tUnknown Message.\n"); - break; - } -#endif - /* Increase the count of elements in the queue by one */ ++(pQueue->nQueueSize); @@ -343,7 +357,7 @@ PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo) */ static Bool -HaveMessage(WMMsgQueuePtr pQueue, UINT msg, Window iWindow) +HaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow) { WMMsgNodePtr pNode; @@ -399,29 +413,20 @@ InitQueue(WMMsgQueuePtr pQueue) static char * -Xutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp) +Xutf8TextPropertyToString(WMInfoPtr pWMInfo, xcb_icccm_get_text_property_reply_t *xtp) { - int nNum; - char **ppList; char *pszReturnData; - if (Xutf8TextPropertyToTextList(pDisplay, xtp, &ppList, &nNum) >= Success && - nNum > 0 && *ppList) { - int i; - int iLen = 0; - - for (i = 0; i < nNum; i++) - iLen += strlen(ppList[i]); - pszReturnData = malloc(iLen + 1); - pszReturnData[0] = '\0'; - for (i = 0; i < nNum; i++) - strcat(pszReturnData, ppList[i]); - if (ppList) - XFreeStringList(ppList); + if ((xtp->encoding == XCB_ATOM_STRING) || // Latin1 ISO 8859-1 + (xtp->encoding == pWMInfo->atmUtf8String)) { // UTF-8 ISO 10646 + pszReturnData = strndup(xtp->name, xtp->name_len); } else { - pszReturnData = malloc(1); - pszReturnData[0] = '\0'; + // Converting from COMPOUND_TEXT to UTF-8 properly is complex to + // implement, and not very much use unless you have an old + // application which isn't UTF-8 aware. + ErrorF("Xutf8TextPropertyToString: text encoding %d is not implemented\n", xtp->encoding); + pszReturnData = strdup(""); } return pszReturnData; @@ -432,51 +437,81 @@ Xutf8TextPropertyToString(Display * pDisplay, XTextProperty * xtp) */ static void -GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) +GetWindowName(WMInfoPtr pWMInfo, xcb_window_t iWin, char **ppWindowName) { - int nResult; - XTextProperty xtpWindowName; - XTextProperty xtpClientMachine; - char *pszWindowName; - char *pszClientMachine; - char hostname[HOST_NAME_MAX + 1]; + xcb_connection_t *conn = pWMInfo->conn; + char *pszWindowName = NULL; #if CYGMULTIWINDOW_DEBUG ErrorF("GetWindowName\n"); #endif - /* Intialize ppWindowName to NULL */ - *ppWindowName = NULL; - - /* Try to get window name */ - nResult = XGetWMName(pDisplay, iWin, &xtpWindowName); - if (!nResult || !xtpWindowName.value || !xtpWindowName.nitems) { -#if CYGMULTIWINDOW_DEBUG - ErrorF("GetWindowName - XGetWMName failed. No name.\n"); -#endif - return; + /* Try to get window name from _NET_WM_NAME */ + { + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + + cookie = xcb_get_property(pWMInfo->conn, FALSE, iWin, + pWMInfo->atmNetWmName, + XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX); + reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL); + if (reply && (reply->type != XCB_NONE)) { + pszWindowName = strndup(xcb_get_property_value(reply), + xcb_get_property_value_length(reply)); + free(reply); + } } - pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName); - XFree(xtpWindowName.value); + /* Otherwise, try to get window name from WM_NAME */ + if (!pszWindowName) + { + xcb_get_property_cookie_t cookie; + xcb_icccm_get_text_property_reply_t reply; + + cookie = xcb_icccm_get_wm_name(conn, iWin); + if (!xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL)) { + ErrorF("GetWindowName - xcb_icccm_get_wm_name_reply failed. No name.\n"); + *ppWindowName = NULL; + return; + } + + pszWindowName = Xutf8TextPropertyToString(pWMInfo, &reply); + xcb_icccm_get_text_property_reply_wipe(&reply); + } + + /* return the window name, unless... */ + *ppWindowName = pszWindowName; if (g_fHostInTitle) { + xcb_get_property_cookie_t cookie; + xcb_icccm_get_text_property_reply_t reply; + /* Try to get client machine name */ - nResult = XGetWMClientMachine(pDisplay, iWin, &xtpClientMachine); - if (nResult && xtpClientMachine.value && xtpClientMachine.nitems) { - pszClientMachine = - Xutf8TextPropertyToString(pDisplay, &xtpClientMachine); - XFree(xtpClientMachine.value); + cookie = xcb_icccm_get_wm_client_machine(conn, iWin); + if (xcb_icccm_get_wm_client_machine_reply(conn, cookie, &reply, NULL)) { + char *pszClientMachine; + char *pszClientHostname; + char *dot; + char hostname[HOST_NAME_MAX + 1]; + + pszClientMachine = Xutf8TextPropertyToString(pWMInfo, &reply); + xcb_icccm_get_text_property_reply_wipe(&reply); + + /* If client machine name looks like a FQDN, find the hostname */ + pszClientHostname = strdup(pszClientMachine); + dot = strchr(pszClientHostname, '.'); + if (dot) + *dot = '\0'; /* - If we have a client machine name - and it's not the local host name + If we have a client machine hostname + and it's not the local hostname and it's not already in the window title... */ - if (strlen(pszClientMachine) && + if (strlen(pszClientHostname) && !gethostname(hostname, HOST_NAME_MAX + 1) && - strcmp(hostname, pszClientMachine) && - (strstr(pszWindowName, pszClientMachine) == 0)) { + strcmp(hostname, pszClientHostname) && + (strstr(pszWindowName, pszClientHostname) == 0)) { /* ... add '@<clientmachine>' to end of window name */ *ppWindowName = malloc(strlen(pszWindowName) + @@ -486,15 +521,12 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) strcat(*ppWindowName, pszClientMachine); free(pszWindowName); - free(pszClientMachine); - - return; } + + free(pszClientMachine); + free(pszClientHostname); } } - - /* otherwise just return the window name */ - *ppWindowName = pszWindowName; } /* @@ -502,17 +534,21 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) */ static Bool -IsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom atmProtocol) +IsWmProtocolAvailable(WMInfoPtr pWMInfo, xcb_window_t iWindow, xcb_atom_t atmProtocol) { - int i, n, found = 0; - Atom *protocols; - - if (XGetWMProtocols(pDisplay, iWindow, &protocols, &n)) { - for (i = 0; i < n; ++i) - if (protocols[i] == atmProtocol) - ++found; - - XFree(protocols); + int i, found = 0; + xcb_get_property_cookie_t cookie; + xcb_icccm_get_wm_protocols_reply_t reply; + xcb_connection_t *conn = pWMInfo->conn; + + cookie = xcb_icccm_get_wm_protocols(conn, iWindow, pWMInfo->ewmh.WM_PROTOCOLS); + if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, NULL)) { + for (i = 0; i < reply.atoms_len; ++i) + if (reply.atoms[i] == atmProtocol) { + ++found; + break; + } + xcb_icccm_get_wm_protocols_reply_wipe(&reply); } return found > 0; @@ -522,49 +558,46 @@ IsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom atmProtocol) * Send a message to the X server from the WM thread */ -static int -SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData) +static void +SendXMessage(xcb_connection_t *conn, xcb_window_t iWin, xcb_atom_t atmType, long nData) { - XEvent e; + xcb_client_message_event_t e; /* Prepare the X event structure */ - e.type = ClientMessage; - e.xclient.window = iWin; - e.xclient.message_type = atmType; - e.xclient.format = 32; - e.xclient.data.l[0] = nData; - e.xclient.data.l[1] = CurrentTime; + memset(&e, 0, sizeof(e)); + e.response_type = XCB_CLIENT_MESSAGE; + e.window = iWin; + e.type = atmType; + e.format = 32; + e.data.data32[0] = nData; + e.data.data32[1] = XCB_CURRENT_TIME; /* Send the event to X */ - return XSendEvent(pDisplay, iWin, False, NoEventMask, &e); + xcb_send_event(conn, FALSE, iWin, XCB_EVENT_MASK_NO_EVENT, (const char *)&e); } /* * See if we can get the stored HWND for this window... */ static HWND -getHwnd(WMInfoPtr pWMInfo, Window iWindow) +getHwnd(WMInfoPtr pWMInfo, xcb_window_t iWindow) { - Atom atmType; - int fmtRet; - unsigned long items, remain; - HWND *retHwnd, hWnd = NULL; - - if (XGetWindowProperty(pWMInfo->pDisplay, - iWindow, - pWMInfo->atmPrivMap, - 0, - sizeof(HWND)/4, - False, - XA_INTEGER, - &atmType, - &fmtRet, - &items, - &remain, (unsigned char **) &retHwnd) == Success) { - if (retHwnd) { - hWnd = *retHwnd; - XFree(retHwnd); + HWND hWnd = NULL; + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + + cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, pWMInfo->atmPrivMap, + XCB_ATOM_INTEGER, 0L, sizeof(HWND)/4L); + reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL); + + if (reply) { + int length = xcb_get_property_value_length(reply); + HWND *value = xcb_get_property_value(reply); + + if (value && (length == sizeof(HWND))) { + hWnd = *value; } + free(reply); } /* Some sanity checks */ @@ -577,26 +610,81 @@ getHwnd(WMInfoPtr pWMInfo, Window iWindow) } /* + * Helper function to check for override-redirect + */ +static Bool +IsOverrideRedirect(xcb_connection_t *conn, xcb_window_t iWin) +{ + Bool result = FALSE; + xcb_get_window_attributes_reply_t *reply; + xcb_get_window_attributes_cookie_t cookie; + + cookie = xcb_get_window_attributes(conn, iWin); + reply = xcb_get_window_attributes_reply(conn, cookie, NULL); + if (reply) { + result = (reply->override_redirect != 0); + free(reply); + } + else { + ErrorF("IsOverrideRedirect: Failed to get window attributes\n"); + } + + return result; +} + +/* + * Helper function to get class and window names +*/ +static void +GetClassNames(WMInfoPtr pWMInfo, xcb_window_t iWindow, char **res_name, + char **res_class, char **window_name) +{ + xcb_get_property_cookie_t cookie1; + xcb_icccm_get_wm_class_reply_t reply1; + xcb_get_property_cookie_t cookie2; + xcb_icccm_get_text_property_reply_t reply2; + + cookie1 = xcb_icccm_get_wm_class(pWMInfo->conn, iWindow); + if (xcb_icccm_get_wm_class_reply(pWMInfo->conn, cookie1, &reply1, + NULL)) { + *res_name = strdup(reply1.instance_name); + *res_class = strdup(reply1.class_name); + xcb_icccm_get_wm_class_reply_wipe(&reply1); + } + else { + *res_name = strdup(""); + *res_class = strdup(""); + } + + cookie2 = xcb_icccm_get_wm_name(pWMInfo->conn, iWindow); + if (xcb_icccm_get_wm_name_reply(pWMInfo->conn, cookie2, &reply2, NULL)) { + *window_name = strndup(reply2.name, reply2.name_len); + xcb_icccm_get_text_property_reply_wipe(&reply2); + } + else { + *window_name = strdup(""); + } +} + +/* * Updates the name of a HWND according to its X WM_NAME property */ static void -UpdateName(WMInfoPtr pWMInfo, Window iWindow) +UpdateName(WMInfoPtr pWMInfo, xcb_window_t iWindow) { HWND hWnd; - XWindowAttributes attr; hWnd = getHwnd(pWMInfo, iWindow); if (!hWnd) return; /* If window isn't override-redirect */ - XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr); - if (!attr.override_redirect) { + if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) { char *pszWindowName; /* Get the X windows window name */ - GetWindowName(pWMInfo->pDisplay, iWindow, &pszWindowName); + GetWindowName(pWMInfo, iWindow, &pszWindowName); if (pszWindowName) { /* Convert from UTF-8 to wide char */ @@ -621,39 +709,30 @@ UpdateName(WMInfoPtr pWMInfo, Window iWindow) */ static void -UpdateIcon(WMInfoPtr pWMInfo, Window iWindow) +UpdateIcon(WMInfoPtr pWMInfo, xcb_window_t iWindow) { HWND hWnd; HICON hIconNew = NULL; - XWindowAttributes attr; hWnd = getHwnd(pWMInfo, iWindow); if (!hWnd) return; /* If window isn't override-redirect */ - XGetWindowAttributes(pWMInfo->pDisplay, iWindow, &attr); - if (!attr.override_redirect) { - XClassHint class_hint = { 0, 0 }; + if (!IsOverrideRedirect(pWMInfo->conn, iWindow)) { char *window_name = 0; + char *res_name = 0; + char *res_class = 0; - if (XGetClassHint(pWMInfo->pDisplay, iWindow, &class_hint)) { - XFetchName(pWMInfo->pDisplay, iWindow, &window_name); + GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name); - hIconNew = - (HICON) winOverrideIcon(class_hint.res_name, - class_hint.res_class, window_name); + hIconNew = winOverrideIcon(res_name, res_class, window_name); - if (class_hint.res_name) - XFree(class_hint.res_name); - if (class_hint.res_class) - XFree(class_hint.res_class); - if (window_name) - XFree(window_name); - } + free(res_name); + free(res_class); + free(window_name); + winUpdateIcon(hWnd, pWMInfo->conn, iWindow, hIconNew); } - - winUpdateIcon(hWnd, pWMInfo->pDisplay, iWindow, hIconNew); } /* @@ -661,7 +740,7 @@ UpdateIcon(WMInfoPtr pWMInfo, Window iWindow) */ static void -UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) +UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow, Bool onCreate) { HWND hWnd; HWND zstyle = HWND_NOTOPMOST; @@ -672,7 +751,7 @@ UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) return; /* Determine the Window style, which determines borders and clipping region... */ - winApplyHints(pWMInfo->pDisplay, iWindow, hWnd, &zstyle); + winApplyHints(pWMInfo, iWindow, hWnd, &zstyle, onCreate); winUpdateWindowPosition(hWnd, &zstyle); /* Apply the updated window style, without changing it's show or activation state */ @@ -693,6 +772,155 @@ UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) winShowWindowOnTaskbar(hWnd, (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) ? TRUE : FALSE); + + /* Check urgency hint */ + winApplyUrgency(pWMInfo, iWindow, hWnd); +} + +/* + * Updates the state of a HWND + */ + +static void +UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow, int state) +{ + HWND hWnd; + int current_state = -1; + + winDebug("UpdateState: iWindow 0x%08x %d\n", (int)iWindow, state); + + hWnd = getHwnd(pWMInfo, iWindow); + if (hWnd) + { + // Keep track of the Window state, do nothing if it's not changing + current_state = (intptr_t)GetProp(hWnd, WIN_STATE_PROP); + + if (current_state == state) + return; + + SetProp(hWnd, WIN_STATE_PROP, (HANDLE)(intptr_t)state); + + switch (state) + { + case XCB_ICCCM_WM_STATE_ICONIC: + ShowWindow(hWnd, SW_SHOWMINNOACTIVE); + break; + +#define XCB_ICCCM_WM_STATE_ZOOM 2 + case XCB_ICCCM_WM_STATE_ZOOM: + // There doesn't seem to be a SW_SHOWMAXNOACTIVE. Hopefully + // always activating a maximized window isn't so bad... + ShowWindow(hWnd, SW_SHOWMAXIMIZED); + break; + + case XCB_ICCCM_WM_STATE_NORMAL: + ShowWindow(hWnd, SW_SHOWNOACTIVATE); + break; + + case XCB_ICCCM_WM_STATE_WITHDRAWN: + ShowWindow(hWnd, SW_HIDE); + break; + } + } + + // Update WM_STATE property + { + // ZoomState is obsolete in ICCCM, so map it to NormalState + int icccm_state = state; + int icccm_current_state = current_state; + + if (icccm_state == XCB_ICCCM_WM_STATE_ZOOM) + icccm_state = XCB_ICCCM_WM_STATE_NORMAL; + + if (icccm_current_state == XCB_ICCCM_WM_STATE_ZOOM) + icccm_current_state = XCB_ICCCM_WM_STATE_NORMAL; + + // Don't change property unnecessarily + // + // (Note that we do not take notice of WM_STATE PropertyNotify, only + // WM_CHANGE_STATE ClientMessage, so this should not cause the state to + // change itself) + if (icccm_current_state != icccm_state) + { + struct + { + CARD32 state; + XID icon; + } wmstate; + + wmstate.state = icccm_state; + wmstate.icon = None; + + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + iWindow, pWMInfo->atmWmState, + pWMInfo->atmWmState, 32, + sizeof(wmstate)/sizeof(int), + (unsigned char *) &wmstate); + } + } + + // Update _NET_WM_STATE property + if (state == XCB_ICCCM_WM_STATE_WITHDRAWN) { + xcb_delete_property(pWMInfo->conn, iWindow, pWMInfo->ewmh._NET_WM_STATE); + } + else { + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + + cookie = xcb_get_property(pWMInfo->conn, FALSE, iWindow, + pWMInfo->ewmh._NET_WM_STATE, + XCB_ATOM_ATOM, + 0, INT_MAX); + reply = xcb_get_property_reply(pWMInfo->conn, cookie, NULL); + if (reply) { + int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); + xcb_atom_t *pAtom = xcb_get_property_value(reply); + unsigned long i, o = 0; + xcb_atom_t netwmstate[nitems + 2]; + Bool changed = FALSE; + + // Make a copy with _NET_WM_HIDDEN, _NET_WM_MAXIMIZED_{VERT,HORZ} + // removed + for (i = 0; i < nitems; i++) { + if ((pAtom[i] != pWMInfo->ewmh._NET_WM_STATE_HIDDEN) && + (pAtom[i] != pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) && + (pAtom[i] != pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ)) + netwmstate[o++] = pAtom[i]; + } + free(reply); + + // if iconized, add _NET_WM_HIDDEN + if (state == XCB_ICCCM_WM_STATE_ICONIC) { + netwmstate[o++] = pWMInfo->ewmh._NET_WM_STATE_HIDDEN; + } + + // if maximized, add _NET_WM_MAXIMIZED_{VERT,HORZ} + if (state == XCB_ICCCM_WM_STATE_ZOOM) { + netwmstate[o++] = pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT; + netwmstate[o++] = pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ; + } + + // Don't change property unnecessarily + if (nitems != o) + changed = TRUE; + else + for (i = 0; i < nitems; i++) + { + if (pAtom[i] != netwmstate[i]) + { + changed = TRUE; + break; + } + } + + if (changed) + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + iWindow, + pWMInfo->ewmh._NET_WM_STATE, + XCB_ATOM_ATOM, 32, + o, (unsigned char *) &netwmstate); + } + } } #if 0 @@ -701,11 +929,11 @@ UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) * starting at the window passed in */ static void -PreserveWin32Stack(WMInfoPtr pWMInfo, Window iWindow, UINT direction) +PreserveWin32Stack(WMInfoPtr pWMInfo, xcb_window_t iWindow, UINT direction) { HWND hWnd; DWORD myWinProcID, winProcID; - Window xWindow; + xcb_window_t xWindow; WINDOWPLACEMENT wndPlace; hWnd = getHwnd(pWMInfo, iWindow); @@ -746,6 +974,8 @@ winMultiWindowWMProc(void *pArg) WMProcArgPtr pProcArg = (WMProcArgPtr) pArg; WMInfoPtr pWMInfo = pProcArg->pWMInfo; + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); + /* Initialize the Window Manager */ winInitMultiWindowWM(pWMInfo, pProcArg); @@ -757,11 +987,6 @@ winMultiWindowWMProc(void *pArg) for (;;) { WMMsgNodePtr pNode; - if (g_fAnotherWMRunning) { /* Another Window manager exists. */ - Sleep(1000); - continue; - } - /* Pop a message off of our queue */ pNode = PopMessage(&pWMInfo->wmMsgQueue, pWMInfo); if (pNode == NULL) { @@ -772,77 +997,72 @@ winMultiWindowWMProc(void *pArg) } #if CYGMULTIWINDOW_DEBUG - ErrorF("winMultiWindowWMProc - MSG: %d ID: %d\n", - (int) pNode->msg.msg, (int) pNode->msg.dwID); + ErrorF("winMultiWindowWMProc - MSG: %s (%d) ID: %d\n", + MessageName(&(pNode->msg)), (int)pNode->msg.msg, (int)pNode->msg.dwID); #endif /* Branch on the message type */ switch (pNode->msg.msg) { #if 0 case WM_WM_MOVE: - ErrorF("\tWM_WM_MOVE\n"); break; case WM_WM_SIZE: - ErrorF("\tWM_WM_SIZE\n"); break; #endif case WM_WM_RAISE: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_RAISE\n"); -#endif /* Raise the window */ - XRaiseWindow(pWMInfo->pDisplay, pNode->msg.iWindow); + { + const static uint32_t values[] = { XCB_STACK_MODE_ABOVE }; + xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow, + XCB_CONFIG_WINDOW_STACK_MODE, values); + } + #if 0 PreserveWin32Stack(pWMInfo, pNode->msg.iWindow, GW_HWNDPREV); #endif break; case WM_WM_LOWER: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_LOWER\n"); -#endif - /* Lower the window */ - XLowerWindow(pWMInfo->pDisplay, pNode->msg.iWindow); + { + const static uint32_t values[] = { XCB_STACK_MODE_BELOW }; + xcb_configure_window(pWMInfo->conn, pNode->msg.iWindow, + XCB_CONFIG_WINDOW_STACK_MODE, values); + } break; case WM_WM_MAP: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_MAP\n"); -#endif /* Put a note as to the HWND associated with this Window */ - XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, - 32, - PropModeReplace, - (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + pNode->msg.iWindow, pWMInfo->atmPrivMap, + XCB_ATOM_INTEGER, 32, + sizeof(HWND)/4, &(pNode->msg.hwndWindow)); + UpdateName(pWMInfo, pNode->msg.iWindow); UpdateIcon(pWMInfo, pNode->msg.iWindow); break; - case WM_WM_MAP2: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_MAP2\n"); -#endif - XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, - 32, - PropModeReplace, - (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); + case WM_WM_MAP_UNMANAGED: + /* Put a note as to the HWND associated with this Window */ + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + pNode->msg.iWindow, pWMInfo->atmPrivMap, + XCB_ATOM_INTEGER, 32, + sizeof(HWND)/4, &(pNode->msg.hwndWindow)); + break; - case WM_WM_MAP3: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_MAP3\n"); -#endif + case WM_WM_MAP_MANAGED: /* Put a note as to the HWND associated with this Window */ - XChangeProperty(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmPrivMap, XA_INTEGER, - 32, - PropModeReplace, - (unsigned char *) &(pNode->msg.hwndWindow), sizeof(HWND)/4); + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, + pNode->msg.iWindow, pWMInfo->atmPrivMap, + XCB_ATOM_INTEGER, 32, + sizeof(HWND)/4, &(pNode->msg.hwndWindow)); + UpdateName(pWMInfo, pNode->msg.iWindow); + UpdateStyle(pWMInfo, pNode->msg.iWindow, TRUE); UpdateIcon(pWMInfo, pNode->msg.iWindow); - UpdateStyle(pWMInfo, pNode->msg.iWindow); /* Reshape */ @@ -858,35 +1078,26 @@ winMultiWindowWMProc(void *pArg) break; case WM_WM_UNMAP: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_UNMAP\n"); -#endif /* Unmap the window */ - XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow); + xcb_unmap_window(pWMInfo->conn, pNode->msg.iWindow); break; case WM_WM_KILL: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_KILL\n"); -#endif { /* --- */ - if (IsWmProtocolAvailable(pWMInfo->pDisplay, + if (IsWmProtocolAvailable(pWMInfo, pNode->msg.iWindow, pWMInfo->atmWmDelete)) - SendXMessage(pWMInfo->pDisplay, + SendXMessage(pWMInfo->conn, pNode->msg.iWindow, pWMInfo->atmWmProtos, pWMInfo->atmWmDelete); else - XKillClient(pWMInfo->pDisplay, pNode->msg.iWindow); + xcb_kill_client(pWMInfo->conn, pNode->msg.iWindow); } break; case WM_WM_ACTIVATE: -#if CYGMULTIWINDOW_DEBUG - ErrorF("\tWM_WM_ACTIVATE\n"); -#endif /* Set the input focus */ /* @@ -899,23 +1110,24 @@ winMultiWindowWMProc(void *pArg) */ { Bool neverFocus = FALSE; - XWMHints *hints = XGetWMHints(pWMInfo->pDisplay, pNode->msg.iWindow); - - if (hints) { - if (hints->flags & InputHint) - neverFocus = !hints->input; - XFree(hints); + xcb_get_property_cookie_t cookie; + xcb_icccm_wm_hints_t hints; + + cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, pNode->msg.iWindow); + if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints, + NULL)) { + if (hints.flags & XCB_ICCCM_WM_HINT_INPUT) + neverFocus = !hints.input; } if (!neverFocus) - XSetInputFocus(pWMInfo->pDisplay, - pNode->msg.iWindow, - RevertToPointerRoot, CurrentTime); + xcb_set_input_focus(pWMInfo->conn, XCB_INPUT_FOCUS_POINTER_ROOT, + pNode->msg.iWindow, XCB_CURRENT_TIME); - if (IsWmProtocolAvailable(pWMInfo->pDisplay, + if (IsWmProtocolAvailable(pWMInfo, pNode->msg.iWindow, pWMInfo->atmWmTakeFocus)) - SendXMessage(pWMInfo->pDisplay, + SendXMessage(pWMInfo->conn, pNode->msg.iWindow, pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus); @@ -932,20 +1144,16 @@ winMultiWindowWMProc(void *pArg) case WM_WM_HINTS_EVENT: { - XWindowAttributes attr; - /* Don't do anything if this is an override-redirect window */ - XGetWindowAttributes (pWMInfo->pDisplay, pNode->msg.iWindow, &attr); - if (attr.override_redirect) + if (IsOverrideRedirect(pWMInfo->conn, pNode->msg.iWindow)) break; - UpdateStyle(pWMInfo, pNode->msg.iWindow); + UpdateStyle(pWMInfo, pNode->msg.iWindow, FALSE); } break; case WM_WM_CHANGE_STATE: - /* Minimize the window in Windows */ - winMinimizeWindow(pNode->msg.iWindow); + UpdateState(pWMInfo, pNode->msg.iWindow, pNode->msg.dwID); break; default: @@ -958,7 +1166,31 @@ winMultiWindowWMProc(void *pArg) free(pNode); /* Flush any pending events on our display */ - XFlush(pWMInfo->pDisplay); + xcb_flush(pWMInfo->conn); + + /* This is just laziness rather than making sure we used _checked everywhere */ + { + xcb_generic_event_t *event = xcb_poll_for_event(pWMInfo->conn); + if (event) { + if ((event->response_type & ~0x80) == 0) { + xcb_generic_error_t *err = (xcb_generic_error_t *)event; + winDebug("winMultiWindowWMProc - Error code: %i, ID: 0x%08x, " + "Major opcode: %i, Minor opcode: %i\n", + err->error_code, err->resource_id, + err->major_code, err->minor_code); + } + } + } + + /* I/O errors etc. */ + { + int e = xcb_connection_has_error(pWMInfo->conn); + if (e) { + ErrorF("winMultiWindowWMProc - Fatal error %d on xcb connection\n", e); + pthread_exit(NULL); + break; + } + } } /* Free the condition variable */ @@ -973,9 +1205,28 @@ winMultiWindowWMProc(void *pArg) #if CYGMULTIWINDOW_DEBUG ErrorF("-winMultiWindowWMProc ()\n"); #endif + + pthread_cleanup_pop(0); + return NULL; } +static xcb_atom_t +intern_atom(xcb_connection_t *conn, const char *atomName) +{ + xcb_intern_atom_reply_t *atom_reply; + xcb_intern_atom_cookie_t atom_cookie; + xcb_atom_t atom = XCB_ATOM_NONE; + + atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName); + atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL); + if (atom_reply) { + atom = atom_reply->atom; + free(atom_reply); + } + return atom; +} + /* * X message procedure */ @@ -987,14 +1238,18 @@ winMultiWindowXMsgProc(void *pArg) XMsgProcArgPtr pProcArg = (XMsgProcArgPtr) pArg; char pszDisplay[512]; int iRetries; - XEvent event; - Atom atmWmName; - Atom atmWmHints; - Atom atmWmChange; - Atom atmNetWmIcon; - Atom atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints; + xcb_atom_t atmWmName; + xcb_atom_t atmNetWmName; + xcb_atom_t atmWmHints; + xcb_atom_t atmWmChange; + xcb_atom_t atmNetWmIcon; + xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints; int iReturn; - XIconSize *xis; + xcb_auth_info_t *auth_info; + xcb_screen_t *root_screen; + xcb_window_t root_window_id; + + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); winDebug("winMultiWindowXMsgProc - Hello\n"); @@ -1004,7 +1259,7 @@ winMultiWindowXMsgProc(void *pArg) pthread_exit(NULL); } - ErrorF("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); + winDebug("winMultiWindowXMsgProc - Calling pthread_mutex_lock ()\n"); /* Grab the server started mutex - pause until we get it */ iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); @@ -1014,44 +1269,12 @@ winMultiWindowXMsgProc(void *pArg) pthread_exit(NULL); } - ErrorF("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); - - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winMultiWindowXMsgProc - XInitThreads () failed. Exiting.\n"); - pthread_exit(NULL); - } - - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winMultiWindowXMsgProc - Warning: locale not supported by X\n"); - } + winDebug("winMultiWindowXMsgProc - pthread_mutex_lock () returned.\n"); /* Release the server started mutex */ pthread_mutex_unlock(pProcArg->ppmServerStarted); - ErrorF("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); - - /* Install our error handler */ - XSetErrorHandler(winMultiWindowXMsgProcErrorHandler); - g_winMultiWindowXMsgProcThread = pthread_self(); - g_winMultiWindowXMsgProcOldIOErrorHandler = - XSetIOErrorHandler(winMultiWindowXMsgProcIOErrorHandler); - - /* Set jump point for IO Error exits */ - iReturn = setjmp(g_jmpXMsgProcEntry); - - /* Check if we should continue operations */ - if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { - /* setjmp returned an unknown value, exit */ - ErrorF("winInitMultiWindowXMsgProc - setjmp returned: %d. Exiting.\n", - iReturn); - pthread_exit(NULL); - } - else if (iReturn == WIN_JMP_ERROR_IO) { - ErrorF("winInitMultiWindowXMsgProc - Caught IO Error. Exiting.\n"); - pthread_exit(NULL); - } + winDebug("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); /* Setup the display connection string x */ winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen); @@ -1060,7 +1283,7 @@ winMultiWindowXMsgProc(void *pArg) ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay); /* Use our generated cookie for authentication */ - winSetAuthorization(); + auth_info = winGetXcbAuthInfo(); /* Initialize retry count */ iRetries = 0; @@ -1068,8 +1291,9 @@ winMultiWindowXMsgProc(void *pArg) /* Open the X display */ do { /* Try to open the display */ - pProcArg->pDisplay = XOpenDisplay(pszDisplay); - if (pProcArg->pDisplay == NULL) { + pProcArg->conn = xcb_connect_to_display_with_auth_info(pszDisplay, + auth_info, NULL); + if (xcb_connection_has_error(pProcArg->conn)) { ErrorF("winMultiWindowXMsgProc - Could not open display, try: %d, " "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); ++iRetries; @@ -1079,102 +1303,139 @@ winMultiWindowXMsgProc(void *pArg) else break; } - while (pProcArg->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); + while (xcb_connection_has_error(pProcArg->conn) && iRetries < WIN_CONNECT_RETRIES); /* Make sure that the display opened */ - if (pProcArg->pDisplay == NULL) { + if (xcb_connection_has_error(pProcArg->conn)) { ErrorF("winMultiWindowXMsgProc - Failed opening the display. " "Exiting.\n"); pthread_exit(NULL); } - ErrorF("winMultiWindowXMsgProc - XOpenDisplay () returned and " + ErrorF("winMultiWindowXMsgProc - xcb_connect() returned and " "successfully opened the display.\n"); /* Check if another window manager is already running */ - g_fAnotherWMRunning = - CheckAnotherWindowManager(pProcArg->pDisplay, pProcArg->dwScreen, - pProcArg->pWMInfo->fAllowOtherWM); - - if (g_fAnotherWMRunning && !pProcArg->pWMInfo->fAllowOtherWM) { + if (CheckAnotherWindowManager(pProcArg->conn, pProcArg->dwScreen)) { ErrorF("winMultiWindowXMsgProc - " "another window manager is running. Exiting.\n"); pthread_exit(NULL); } - /* Set up the supported icon sizes */ - xis = XAllocIconSize(); - if (xis) { - xis->min_width = xis->min_height = 16; - xis->max_width = xis->max_height = 48; - xis->width_inc = xis->height_inc = 16; - XSetIconSizes(pProcArg->pDisplay, - RootWindow(pProcArg->pDisplay, pProcArg->dwScreen), - xis, 1); - XFree(xis); + /* Get root window id */ + root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen); + root_window_id = root_screen->root; + + { + /* Set WM_ICON_SIZE property indicating desired icon sizes */ + typedef struct { + uint32_t min_width, min_height; + uint32_t max_width, max_height; + int32_t width_inc, height_inc; + } xcb_wm_icon_size_hints_hints_t; + + xcb_wm_icon_size_hints_hints_t xis; + xis.min_width = xis.min_height = 16; + xis.max_width = xis.max_height = 48; + xis.width_inc = xis.height_inc = 16; + + xcb_change_property(pProcArg->conn, XCB_PROP_MODE_REPLACE, root_window_id, + XCB_ATOM_WM_ICON_SIZE, XCB_ATOM_WM_ICON_SIZE, 32, + sizeof(xis)/4, &xis); } - atmWmName = XInternAtom(pProcArg->pDisplay, "WM_NAME", False); - atmWmHints = XInternAtom(pProcArg->pDisplay, "WM_HINTS", False); - atmWmChange = XInternAtom(pProcArg->pDisplay, "WM_CHANGE_STATE", False); - atmNetWmIcon = XInternAtom(pProcArg->pDisplay, "_NET_WM_ICON", False); - atmWindowState = XInternAtom(pProcArg->pDisplay, "_NET_WM_STATE", False); - atmMotifWmHints = XInternAtom(pProcArg->pDisplay, "_MOTIF_WM_HINTS", False); - atmWindowType = XInternAtom(pProcArg->pDisplay, "_NET_WM_WINDOW_TYPE", False); - atmNormalHints = XInternAtom(pProcArg->pDisplay, "WM_NORMAL_HINTS", False); + atmWmName = intern_atom(pProcArg->conn, "WM_NAME"); + atmNetWmName = intern_atom(pProcArg->conn, "_NET_WM_NAME"); + atmWmHints = intern_atom(pProcArg->conn, "WM_HINTS"); + atmWmChange = intern_atom(pProcArg->conn, "WM_CHANGE_STATE"); + atmNetWmIcon = intern_atom(pProcArg->conn, "_NET_WM_ICON"); + atmWindowState = intern_atom(pProcArg->conn, "_NET_WM_STATE"); + atmMotifWmHints = intern_atom(pProcArg->conn, "_MOTIF_WM_HINTS"); + atmWindowType = intern_atom(pProcArg->conn, "_NET_WM_WINDOW_TYPE"); + atmNormalHints = intern_atom(pProcArg->conn, "WM_NORMAL_HINTS"); /* - iiimxcf had a bug until 2009-04-27, assuming that the - WM_STATE atom exists, causing clients to fail with - a BadAtom X error if it doesn't. - - Since this is on in the default Solaris 10 install, - workaround this by making sure it does exist... + Enable Composite extension and redirect subwindows of the root window */ - XInternAtom(pProcArg->pDisplay, "WM_STATE", 0); + if (pProcArg->pWMInfo->fCompositeWM) { + const char *extension_name = "Composite"; + xcb_query_extension_cookie_t cookie; + xcb_query_extension_reply_t *reply; + + cookie = xcb_query_extension(pProcArg->conn, strlen(extension_name), extension_name); + reply = xcb_query_extension_reply(pProcArg->conn, cookie, NULL); + + if (reply && (reply->present)) { + xcb_composite_redirect_subwindows(pProcArg->conn, + root_window_id, + XCB_COMPOSITE_REDIRECT_AUTOMATIC); + + /* + We use automatic updating of the root window for two + reasons: + + 1) redirected window contents are mirrored to the root + window so that the root window draws correctly when shown. + + 2) updating the root window causes damage against the + shadow framebuffer, which ultimately causes WM_PAINT to be + sent to the affected window(s) to cause the damage regions + to be redrawn. + */ + + ErrorF("Using Composite redirection\n"); + + free(reply); + } + } /* Loop until we explicitly break out */ while (1) { + xcb_generic_event_t *event; + uint8_t type; + Bool send_event; + if (g_shutdown) break; - if (pProcArg->pWMInfo->fAllowOtherWM && !XPending(pProcArg->pDisplay)) { - if (CheckAnotherWindowManager - (pProcArg->pDisplay, pProcArg->dwScreen, TRUE)) { - if (!g_fAnotherWMRunning) { - g_fAnotherWMRunning = TRUE; - SendMessage(pProcArg->hwndScreen, WM_UNMANAGE, 0, 0); - } - } - else { - if (g_fAnotherWMRunning) { - g_fAnotherWMRunning = FALSE; - SendMessage(pProcArg->hwndScreen, WM_MANAGE, 0, 0); - } - } - Sleep(500); - continue; - } - /* Fetch next event */ - XNextEvent(pProcArg->pDisplay, &event); - - /* Branch on event type */ - if (event.type == CreateNotify) { - XWindowAttributes attr; + event = xcb_wait_for_event(pProcArg->conn); + if (!event) { // returns NULL on I/O error + int e = xcb_connection_has_error(pProcArg->conn); + ErrorF("winMultiWindowXMsgProc - Fatal error %d on xcb connection\n", e); + pthread_exit(NULL); + break; + } - XSelectInput(pProcArg->pDisplay, - event.xcreatewindow.window, PropertyChangeMask); + type = event->response_type & ~0x80; + send_event = event->response_type & 0x80; - /* Get the window attributes */ - XGetWindowAttributes(pProcArg->pDisplay, - event.xcreatewindow.window, &attr); + winDebug("winMultiWindowXMsgProc - event %d\n", type); - if (!attr.override_redirect) - XSetWindowBorderWidth(pProcArg->pDisplay, - event.xcreatewindow.window, 0); + /* Branch on event type */ + if (type == 0) { + xcb_generic_error_t *err = (xcb_generic_error_t *)event; + winDebug("winMultiWindowXMsgProc - Error code: %i, ID: 0x%08x, " + "Major opcode: %i, Minor opcode: %i\n", + err->error_code, err->resource_id, + err->major_code, err->minor_code); + } + else if (type == XCB_CREATE_NOTIFY) { + xcb_create_notify_event_t *notify = (xcb_create_notify_event_t *)event; + + /* Request property change events */ + const static uint32_t mask_value[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; + xcb_change_window_attributes (pProcArg->conn, notify->window, + XCB_CW_EVENT_MASK, mask_value); + + /* If it's not override-redirect, set the border-width to 0 */ + if (!IsOverrideRedirect(pProcArg->conn, notify->window)) { + const static uint32_t width_value[] = { 0 }; + xcb_configure_window(pProcArg->conn, notify->window, + XCB_CONFIG_WINDOW_BORDER_WIDTH, width_value); + } } - else if (event.type == MapNotify) { + else if (type == XCB_MAP_NOTIFY) { /* Fake a reparentNotify event as SWT/Motif expects a Window Manager to reparent a top-level window when it is mapped and waits until they do. @@ -1190,43 +1451,54 @@ winMultiWindowXMsgProc(void *pArg) See sourceware bugzilla #9848 */ - XWindowAttributes attr; - Window root; - Window parent; - Window *children; - unsigned int nchildren; - - if (XGetWindowAttributes(event.xmap.display, - event.xmap.window, - &attr) && - XQueryTree(event.xmap.display, - event.xmap.window, - &root, &parent, &children, &nchildren)) { - if (children) - XFree(children); + xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)event; + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + xcb_query_tree_cookie_t cookie_qt; + xcb_query_tree_reply_t *reply_qt; + + cookie = xcb_get_geometry(pProcArg->conn, notify->window); + cookie_qt = xcb_query_tree(pProcArg->conn, notify->window); + reply = xcb_get_geometry_reply(pProcArg->conn, cookie, NULL); + reply_qt = xcb_query_tree_reply(pProcArg->conn, cookie_qt, NULL); + + if (reply && reply_qt) { /* It's a top-level window if the parent window is a root window Only non-override_redirect windows can get reparented */ - if ((attr.root == parent) && !event.xmap.override_redirect) { - XEvent event_send; - - event_send.type = ReparentNotify; - event_send.xreparent.event = event.xmap.window; - event_send.xreparent.window = event.xmap.window; - event_send.xreparent.parent = parent; - event_send.xreparent.x = attr.x; - event_send.xreparent.y = attr.y; - - XSendEvent(event.xmap.display, - event.xmap.window, - True, StructureNotifyMask, &event_send); + if ((reply->root == reply_qt->parent) && !notify->override_redirect) { + xcb_reparent_notify_event_t event_send; + + event_send.response_type = ReparentNotify; + event_send.event = notify->window; + event_send.window = notify->window; + event_send.parent = reply_qt->parent; + event_send.x = reply->x; + event_send.y = reply->y; + + xcb_send_event (pProcArg->conn, TRUE, notify->window, + XCB_EVENT_MASK_STRUCTURE_NOTIFY, + (const char *)&event_send); + + free(reply_qt); + free(reply); } } } - else if (event.type == ConfigureNotify) { - if (!event.xconfigure.send_event) { + else if (type == XCB_UNMAP_NOTIFY) { + xcb_unmap_notify_event_t *notify = (xcb_unmap_notify_event_t *)event; + + memset(&msg, 0, sizeof(msg)); + msg.msg = WM_WM_CHANGE_STATE; + msg.iWindow = notify->window; + msg.dwID = XCB_ICCCM_WM_STATE_WITHDRAWN; + + winSendMessageToWM(pProcArg->pWMInfo, &msg); + } + else if (type == XCB_CONFIGURE_NOTIFY) { + if (!send_event) { /* Java applications using AWT on JRE 1.6.0 break with non-reparenting WMs AWT doesn't explicitly know about (See sun bug #6434227) @@ -1238,21 +1510,34 @@ winMultiWindowXMsgProc(void *pArg) Rather than tell all sorts of lies to get XWM to recognize us as one of those, simply send a synthetic ConfigureNotify for every non-synthetic one */ - XEvent event_send = event; + xcb_configure_notify_event_t *notify = (xcb_configure_notify_event_t *)event; + xcb_configure_notify_event_t event_send = *notify; + + event_send.event = notify->window; - event_send.xconfigure.send_event = TRUE; - event_send.xconfigure.event = event.xconfigure.window; - XSendEvent(event.xconfigure.display, - event.xconfigure.window, - True, StructureNotifyMask, &event_send); + xcb_send_event(pProcArg->conn, TRUE, notify->window, + XCB_EVENT_MASK_STRUCTURE_NOTIFY, + (const char *)&event_send); } } - else if (event.type == PropertyNotify) { - if (event.xproperty.atom == atmWmName) { + else if (type == XCB_PROPERTY_NOTIFY) { + xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)event; + + xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(pProcArg->conn, notify->atom); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(pProcArg->conn, cookie, NULL); + if (reply) { + winDebug("winMultiWindowXMsgProc: PropertyNotify %.*s\n", + xcb_get_atom_name_name_length(reply), + xcb_get_atom_name_name(reply)); + free(reply); + } + + if ((notify->atom == atmWmName) || + (notify->atom == atmNetWmName)) { memset(&msg, 0, sizeof(msg)); msg.msg = WM_WM_NAME_EVENT; - msg.iWindow = event.xproperty.window; + msg.iWindow = notify->window; /* Other fields ignored */ winSendMessageToWM(pProcArg->pWMInfo, &msg); @@ -1262,47 +1547,95 @@ winMultiWindowXMsgProc(void *pArg) Several properties are considered for WM hints, check if this property change affects any of them... (this list needs to be kept in sync with winApplyHints()) */ - if ((event.xproperty.atom == atmWmHints) || - (event.xproperty.atom == atmWindowState) || - (event.xproperty.atom == atmMotifWmHints) || - (event.xproperty.atom == atmWindowType) || - (event.xproperty.atom == atmNormalHints)) { + if ((notify->atom == atmWmHints) || + (notify->atom == atmWindowState) || + (notify->atom == atmMotifWmHints) || + (notify->atom == atmWindowType) || + (notify->atom == atmNormalHints)) { memset(&msg, 0, sizeof(msg)); msg.msg = WM_WM_HINTS_EVENT; - msg.iWindow = event.xproperty.window; + msg.iWindow = notify->window; /* Other fields ignored */ winSendMessageToWM(pProcArg->pWMInfo, &msg); } /* Not an else as WM_HINTS affects both style and icon */ - if ((event.xproperty.atom == atmWmHints) || - (event.xproperty.atom == atmNetWmIcon)) { + if ((notify->atom == atmWmHints) || + (notify->atom == atmNetWmIcon)) { memset(&msg, 0, sizeof(msg)); msg.msg = WM_WM_ICON_EVENT; - msg.iWindow = event.xproperty.window; + msg.iWindow = notify->window; /* Other fields ignored */ winSendMessageToWM(pProcArg->pWMInfo, &msg); } } } - else if (event.type == ClientMessage - && event.xclient.message_type == atmWmChange - && event.xclient.data.l[0] == IconicState) { - ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n"); + else if (type == XCB_CLIENT_MESSAGE) { + xcb_client_message_event_t *client_msg = (xcb_client_message_event_t *)event; + winDebug("winMultiWindowXMsgProc: ClientMessage: type %d window 0x%08x data[0] %d\n", client_msg->type, client_msg->window, client_msg->data.data32[0]); - memset(&msg, 0, sizeof(msg)); + if (client_msg->type == atmWmChange + && client_msg->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) { + ErrorF("winMultiWindowXMsgProc - WM_CHANGE_STATE - IconicState\n"); - msg.msg = WM_WM_CHANGE_STATE; - msg.iWindow = event.xclient.window; + memset(&msg, 0, sizeof(msg)); + msg.msg = WM_WM_CHANGE_STATE; + msg.iWindow = client_msg->window; + msg.dwID = client_msg->data.data32[0]; - winSendMessageToWM(pProcArg->pWMInfo, &msg); + winSendMessageToWM(pProcArg->pWMInfo, &msg); + } + else if (client_msg->type == pProcArg->pWMInfo->ewmh._NET_WM_STATE) { + int action = client_msg->data.data32[0]; + int state = -1; + + if (action == XCB_EWMH_WM_STATE_ADD) { + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ)) + state = XCB_ICCCM_WM_STATE_ZOOM; + + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT)) + state = XCB_ICCCM_WM_STATE_ZOOM; + + if (client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_HIDDEN) + state = XCB_ICCCM_WM_STATE_ICONIC; + } + else if (action == XCB_EWMH_WM_STATE_REMOVE) { + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ)) + state = XCB_ICCCM_WM_STATE_NORMAL; + + if ((client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ) && + (client_msg->data.data32[2] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT)) + state = XCB_ICCCM_WM_STATE_NORMAL; + + if (client_msg->data.data32[1] == pProcArg->pWMInfo->ewmh._NET_WM_STATE_HIDDEN) + state = XCB_ICCCM_WM_STATE_NORMAL; + } + else { + ErrorF("winMultiWindowXMsgProc: ClientMEssage _NET_WM_STATE unsupported action %d\n", action); + } + + if (state != -1) { + memset(&msg, 0, sizeof(msg)); + msg.msg = WM_WM_CHANGE_STATE; + msg.iWindow = client_msg->window; + msg.dwID = state; + + winSendMessageToWM(pProcArg->pWMInfo, &msg); + } + } } + + /* Free the event */ + free(event); } - XCloseDisplay(pProcArg->pDisplay); - pthread_exit(NULL); + xcb_disconnect(pProcArg->conn); + pthread_cleanup_pop(0); return NULL; } @@ -1317,7 +1650,7 @@ winInitWM(void **ppWMInfo, pthread_t * ptWMProc, pthread_t * ptXMsgProc, pthread_mutex_t * ppmServerStarted, - int dwScreen, HWND hwndScreen, BOOL allowOtherWM) + int dwScreen, HWND hwndScreen, Bool compositeWM) { WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec)); WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec)); @@ -1339,7 +1672,7 @@ winInitWM(void **ppWMInfo, /* Set a return pointer to the Window Manager info structure */ *ppWMInfo = pWMInfo; - pWMInfo->fAllowOtherWM = allowOtherWM; + pWMInfo->fCompositeWM = compositeWM; /* Setup the argument structure for the thread function */ pArg->dwScreen = dwScreen; @@ -1387,6 +1720,9 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) int iRetries = 0; char pszDisplay[512]; int iReturn; + xcb_auth_info_t *auth_info; + xcb_screen_t *root_screen; + xcb_window_t root_window_id; winDebug("winInitMultiWindowWM - Hello\n"); @@ -1396,7 +1732,7 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pthread_exit(NULL); } - ErrorF("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); + winDebug("winInitMultiWindowWM - Calling pthread_mutex_lock ()\n"); /* Grab our garbage mutex to satisfy pthread_cond_wait */ iReturn = pthread_mutex_lock(pProcArg->ppmServerStarted); @@ -1406,44 +1742,12 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pthread_exit(NULL); } - ErrorF("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); - - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winInitMultiWindowWM - XInitThreads () failed. Exiting.\n"); - pthread_exit(NULL); - } - - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winInitMultiWindowWM - Warning: Locale not supported by X.\n"); - } + winDebug("winInitMultiWindowWM - pthread_mutex_lock () returned.\n"); /* Release the server started mutex */ pthread_mutex_unlock(pProcArg->ppmServerStarted); - ErrorF("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); - - /* Install our error handler */ - XSetErrorHandler(winMultiWindowWMErrorHandler); - g_winMultiWindowWMThread = pthread_self(); - g_winMultiWindowWMOldIOErrorHandler = - XSetIOErrorHandler(winMultiWindowWMIOErrorHandler); - - /* Set jump point for IO Error exits */ - iReturn = setjmp(g_jmpWMEntry); - - /* Check if we should continue operations */ - if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { - /* setjmp returned an unknown value, exit */ - ErrorF("winInitMultiWindowWM - setjmp returned: %d. Exiting.\n", - iReturn); - pthread_exit(NULL); - } - else if (iReturn == WIN_JMP_ERROR_IO) { - ErrorF("winInitMultiWindowWM - Caught IO Error. Exiting.\n"); - pthread_exit(NULL); - } + winDebug("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); /* Setup the display connection string x */ winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen); @@ -1452,13 +1756,14 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay); /* Use our generated cookie for authentication */ - winSetAuthorization(); + auth_info = winGetXcbAuthInfo(); /* Open the X display */ do { /* Try to open the display */ - pWMInfo->pDisplay = XOpenDisplay(pszDisplay); - if (pWMInfo->pDisplay == NULL) { + pWMInfo->conn = xcb_connect_to_display_with_auth_info(pszDisplay, + auth_info, NULL); + if (xcb_connection_has_error(pWMInfo->conn)) { ErrorF("winInitMultiWindowWM - Could not open display, try: %d, " "sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); ++iRetries; @@ -1468,151 +1773,149 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) else break; } - while (pWMInfo->pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); + while (xcb_connection_has_error(pWMInfo->conn) && iRetries < WIN_CONNECT_RETRIES); /* Make sure that the display opened */ - if (pWMInfo->pDisplay == NULL) { + if (xcb_connection_has_error(pWMInfo->conn)) { ErrorF("winInitMultiWindowWM - Failed opening the display. " "Exiting.\n"); pthread_exit(NULL); } - ErrorF("winInitMultiWindowWM - XOpenDisplay () returned and " + ErrorF("winInitMultiWindowWM - xcb_connect () returned and " "successfully opened the display.\n"); /* Create some atoms */ - pWMInfo->atmWmProtos = XInternAtom(pWMInfo->pDisplay, - "WM_PROTOCOLS", False); - pWMInfo->atmWmDelete = XInternAtom(pWMInfo->pDisplay, - "WM_DELETE_WINDOW", False); - pWMInfo->atmWmTakeFocus = XInternAtom(pWMInfo->pDisplay, - "WM_TAKE_FOCUS", False); - - pWMInfo->atmPrivMap = XInternAtom(pWMInfo->pDisplay, - WINDOWSWM_NATIVE_HWND, False); - - if (1) { - Cursor cursor = XCreateFontCursor(pWMInfo->pDisplay, XC_left_ptr); - - if (cursor) { - XDefineCursor(pWMInfo->pDisplay, - DefaultRootWindow(pWMInfo->pDisplay), cursor); - XFreeCursor(pWMInfo->pDisplay, cursor); + pWMInfo->atmWmProtos = intern_atom(pWMInfo->conn, "WM_PROTOCOLS"); + pWMInfo->atmWmDelete = intern_atom(pWMInfo->conn, "WM_DELETE_WINDOW"); + pWMInfo->atmWmTakeFocus = intern_atom(pWMInfo->conn, "WM_TAKE_FOCUS"); + pWMInfo->atmPrivMap = intern_atom(pWMInfo->conn, WINDOWSWM_NATIVE_HWND); + pWMInfo->atmUtf8String = intern_atom(pWMInfo->conn, "UTF8_STRING"); + pWMInfo->atmNetWmName = intern_atom(pWMInfo->conn, "_NET_WM_NAME"); + pWMInfo->atmCurrentDesktop = intern_atom(pWMInfo->conn, "_NET_CURRENT_DESKTOP"); + pWMInfo->atmNumberDesktops = intern_atom(pWMInfo->conn, "_NET_NUMBER_OF_DESKTOPS"); + pWMInfo->atmDesktopNames = intern_atom(pWMInfo->conn, "__NET_DESKTOP_NAMES"); + pWMInfo->atmWmState = intern_atom(pWMInfo->conn, "WM_STATE"); + + /* Initialization for the xcb_ewmh and EWMH atoms */ + { + xcb_intern_atom_cookie_t *atoms_cookie; + atoms_cookie = xcb_ewmh_init_atoms(pWMInfo->conn, &pWMInfo->ewmh); + if (xcb_ewmh_init_atoms_replies(&pWMInfo->ewmh, atoms_cookie, NULL)) { + /* Set the _NET_SUPPORTED atom for this context. + + TODO: Audit to ensure we implement everything defined as MUSTs + for window managers in the EWMH standard.*/ + xcb_atom_t supported[] = + { + pWMInfo->ewmh.WM_PROTOCOLS, + pWMInfo->ewmh._NET_SUPPORTED, + pWMInfo->ewmh._NET_SUPPORTING_WM_CHECK, + pWMInfo->ewmh._NET_CLOSE_WINDOW, + pWMInfo->ewmh._NET_WM_WINDOW_TYPE, + pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK, + pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH, + pWMInfo->ewmh._NET_WM_STATE, + pWMInfo->ewmh._NET_WM_STATE_HIDDEN, + pWMInfo->ewmh._NET_WM_STATE_ABOVE, + pWMInfo->ewmh._NET_WM_STATE_BELOW, + pWMInfo->ewmh._NET_WM_STATE_SKIP_TASKBAR, + pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT, + pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ, + }; + + xcb_ewmh_set_supported(&pWMInfo->ewmh, pProcArg->dwScreen, + sizeof(supported)/sizeof(xcb_atom_t), supported); + } + else { + ErrorF("winInitMultiWindowWM - xcb_ewmh_init_atoms() failed\n"); } } -} -/* - * winSendMessageToWM - Send a message from the X thread to the WM thread - */ - -void -winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) -{ - WMMsgNodePtr pNode; + /* Get root window id */ + root_screen = xcb_aux_get_screen(pWMInfo->conn, pProcArg->dwScreen); + root_window_id = root_screen->root; -#if CYGMULTIWINDOW_DEBUG - ErrorF("winSendMessageToWM ()\n"); -#endif - - pNode = malloc(sizeof(WMMsgNodeRec)); - if (pNode != NULL) { - memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec)); - PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode); - } -} - -/* - * Window manager error handler - */ - -static int -winMultiWindowWMErrorHandler(Display * pDisplay, XErrorEvent * pErr) -{ - char pszErrorMsg[100]; - - if (pErr->request_code == X_ChangeWindowAttributes - && pErr->error_code == BadAccess) { - ErrorF("winMultiWindowWMErrorHandler - ChangeWindowAttributes " - "BadAccess.\n"); - return 0; + /* + Set root window properties for describing multiple desktops to describe + the one desktop we have + */ + { + int data; + const char buf[] = "Desktop"; + + data = 0; + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id, + pWMInfo->atmCurrentDesktop, XCB_ATOM_CARDINAL, 32, + 1, &data); + data = 1; + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id, + pWMInfo->atmNumberDesktops, XCB_ATOM_CARDINAL, 32, + 1, &data); + + xcb_change_property(pWMInfo->conn, XCB_PROP_MODE_REPLACE, root_window_id, + pWMInfo->atmDesktopNames, pWMInfo->atmUtf8String, 8, + strlen(buf), (unsigned char *) buf); } - XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); - ErrorF("winMultiWindowWMErrorHandler - ERROR: %s\n", pszErrorMsg); + /* + Set the root window cursor to left_ptr (this controls the cursor an + application gets over it's windows when it doesn't set one) + */ + { +#define XC_left_ptr 68 + xcb_cursor_t cursor = xcb_generate_id(pWMInfo->conn); + xcb_font_t font = xcb_generate_id(pWMInfo->conn); + xcb_font_t *mask_font = &font; /* An alias to clarify */ + int shape = XC_left_ptr; + uint32_t mask = XCB_CW_CURSOR; + uint32_t value_list = cursor; - return 0; -} + static const uint16_t fgred = 0, fggreen = 0, fgblue = 0; + static const uint16_t bgred = 0xFFFF, bggreen = 0xFFFF, bgblue = 0xFFFF; -/* - * Window manager IO error handler - */ + xcb_open_font(pWMInfo->conn, font, sizeof("cursor"), "cursor"); -static int -winMultiWindowWMIOErrorHandler(Display * pDisplay) -{ - ErrorF("winMultiWindowWMIOErrorHandler!\n"); + xcb_create_glyph_cursor(pWMInfo->conn, cursor, font, *mask_font, + shape, shape + 1, + fgred, fggreen, fgblue, bgred, bggreen, bgblue); - if (pthread_equal(pthread_self(), g_winMultiWindowWMThread)) { - if (g_shutdown) - pthread_exit(NULL); + xcb_change_window_attributes(pWMInfo->conn, root_window_id, mask, &value_list); - /* Restart at the main entry point */ - longjmp(g_jmpWMEntry, WIN_JMP_ERROR_IO); + xcb_free_cursor(pWMInfo->conn, cursor); + xcb_close_font(pWMInfo->conn, font); } - - if (g_winMultiWindowWMOldIOErrorHandler) - g_winMultiWindowWMOldIOErrorHandler(pDisplay); - - return 0; } /* - * X message procedure error handler + * winSendMessageToWM - Send a message from the X thread to the WM thread */ -static int -winMultiWindowXMsgProcErrorHandler(Display * pDisplay, XErrorEvent * pErr) +void +winSendMessageToWM(void *pWMInfo, winWMMessagePtr pMsg) { - char pszErrorMsg[100]; + WMMsgNodePtr pNode; - XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); #if CYGMULTIWINDOW_DEBUG - ErrorF("winMultiWindowXMsgProcErrorHandler - ERROR: %s\n", pszErrorMsg); + ErrorF("winSendMessageToWM %s\n", MessageName(pMsg)); #endif - return 0; -} - -/* - * X message procedure IO error handler - */ - -static int -winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay) -{ - ErrorF("winMultiWindowXMsgProcIOErrorHandler!\n"); - - if (pthread_equal(pthread_self(), g_winMultiWindowXMsgProcThread)) { - /* Restart at the main entry point */ - longjmp(g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO); + pNode = malloc(sizeof(WMMsgNodeRec)); + if (pNode != NULL) { + memcpy(&pNode->msg, pMsg, sizeof(winWMMessageRec)); + PushMessage(&((WMInfoPtr) pWMInfo)->wmMsgQueue, pNode); } - - if (g_winMultiWindowXMsgProcOldIOErrorHandler) - g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay); - - return 0; } /* - * Catch RedirectError to detect other window manager running + * winMultiWindowThreadExit - Thread exit handler */ -static int -winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr) +static void +winMultiWindowThreadExit(void *arg) { - redirectError = TRUE; - return 0; + /* multiwindow client thread has exited, stop server as well */ + raise(SIGTERM); } /* @@ -1620,31 +1923,46 @@ winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr) */ static Bool -CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, - Bool fAllowOtherWM) +CheckAnotherWindowManager(xcb_connection_t *conn, DWORD dwScreen) { + Bool redirectError = FALSE; + + /* Get root window id */ + xcb_screen_t *root_screen = xcb_aux_get_screen(conn, dwScreen); + xcb_window_t root_window_id = root_screen->root; + /* Try to select the events which only one client at a time is allowed to select. If this causes an error, another window manager is already running... */ - redirectError = FALSE; - XSetErrorHandler(winRedirectErrorHandler); - XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), - ResizeRedirectMask | SubstructureRedirectMask | - ButtonPressMask); - XSync(pDisplay, 0); - XSetErrorHandler(winMultiWindowXMsgProcErrorHandler); + const static uint32_t test_mask[] = { XCB_EVENT_MASK_RESIZE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_BUTTON_PRESS }; + + xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn, + root_window_id, + XCB_CW_EVENT_MASK, + test_mask); + xcb_generic_error_t *error; + if ((error = xcb_request_check(conn, cookie))) + { + redirectError = TRUE; + free(error); + } /* Side effect: select the events we are actually interested in... - If other WMs are not allowed, also select one of the events which only one client + Other WMs are not allowed, also select one of the events which only one client at a time is allowed to select, so other window managers won't start... */ - XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), - SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask : - 0)); - XSync(pDisplay, 0); + { + const uint32_t mask[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_BUTTON_PRESS }; + + xcb_change_window_attributes(conn, root_window_id, XCB_CW_EVENT_MASK, mask); + } + return redirectError; } @@ -1659,6 +1977,40 @@ winDeinitMultiWindowWM(void) g_shutdown = TRUE; } +static void +winApplyUrgency(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd) +{ + xcb_get_property_cookie_t cookie; + xcb_icccm_wm_hints_t hints; + + cookie = xcb_icccm_get_wm_hints(pWMInfo->conn, iWindow); + if (xcb_icccm_get_wm_hints_reply(pWMInfo->conn, cookie, &hints, NULL)) { + FLASHWINFO fwi; + + fwi.cbSize = sizeof(FLASHWINFO); + fwi.hwnd = hWnd; + + winDebug("winApplyUrgency: window 0x%08x has urgency hint %s\n", iWindow, + (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) ? "on" : "off"); + + if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) { + DWORD count = 3; + + SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &count, 0); + fwi.dwFlags = FLASHW_TRAY; + fwi.uCount = count; + fwi.dwTimeout = 0; + } + else { + fwi.dwFlags = FLASHW_STOP; + fwi.uCount = 0; + fwi.dwTimeout = 0; + } + + FlashWindowEx(&fwi); + } +} + /* Windows window styles */ #define HINT_NOFRAME (1L<<0) #define HINT_BORDER (1L<<1) @@ -1673,18 +2025,19 @@ winDeinitMultiWindowWM(void) #define HINT_MIN (1L<<1) static void -winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) +winApplyHints(WMInfoPtr pWMInfo, xcb_window_t iWindow, HWND hWnd, HWND * zstyle, Bool onCreate) { - static Atom windowState, motif_wm_hints, windowType; - static Atom hiddenState, fullscreenState, belowState, aboveState, + + xcb_connection_t *conn = pWMInfo->conn; + static xcb_atom_t windowState, motif_wm_hints; + static xcb_atom_t hiddenState, fullscreenState, belowState, aboveState, skiptaskbarState; - static Atom dockWindow; + static xcb_atom_t splashType; static int generation; - Atom type, *pAtom = NULL; - int format; - unsigned long hint = 0, maxmin = 0, nitems = 0, left = 0; + + unsigned long hint = HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION; + unsigned long maxmin = 0; unsigned long style, exStyle; - MwmHints *mwm_hint = NULL; if (!hWnd) return; @@ -1693,25 +2046,25 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) if (generation != serverGeneration) { generation = serverGeneration; - windowState = XInternAtom(pDisplay, "_NET_WM_STATE", False); - motif_wm_hints = XInternAtom(pDisplay, "_MOTIF_WM_HINTS", False); - windowType = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE", False); - hiddenState = XInternAtom(pDisplay, "_NET_WM_STATE_HIDDEN", False); - fullscreenState = - XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", False); - belowState = XInternAtom(pDisplay, "_NET_WM_STATE_BELOW", False); - aboveState = XInternAtom(pDisplay, "_NET_WM_STATE_ABOVE", False); - dockWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_DOCK", False); - skiptaskbarState = - XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False); + windowState = intern_atom(conn, "_NET_WM_STATE"); + motif_wm_hints = intern_atom(conn, "_MOTIF_WM_HINTS"); + hiddenState = intern_atom(conn, "_NET_WM_STATE_HIDDEN"); + fullscreenState = intern_atom(conn, "_NET_WM_STATE_FULLSCREEN"); + belowState = intern_atom(conn, "_NET_WM_STATE_BELOW"); + aboveState = intern_atom(conn, "_NET_WM_STATE_ABOVE"); + skiptaskbarState = intern_atom(conn, "_NET_WM_STATE_SKIP_TASKBAR"); + splashType = intern_atom(conn, "_NET_WM_WINDOW_TYPE_SPLASHSCREEN"); } - if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L, - MAXINT, False, XA_ATOM, &type, &format, - &nitems, &left, - (unsigned char **) &pAtom) == Success) { - if (pAtom ) { - unsigned long i; + { + xcb_get_property_cookie_t cookie_wm_state = xcb_get_property(conn, FALSE, iWindow, windowState, XCB_ATOM_ATOM, 0L, INT_MAX); + xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_wm_state, NULL); + if (reply) { + int i; + int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); + xcb_atom_t *pAtom = xcb_get_property_value(reply); + Bool verMax = FALSE; + Bool horMax = FALSE; for (i = 0; i < nitems; i++) { if (pAtom[i] == skiptaskbarState) @@ -1724,28 +2077,38 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) *zstyle = HWND_BOTTOM; else if (pAtom[i] == aboveState) *zstyle = HWND_TOPMOST; + if (pAtom[i] == pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_VERT) + verMax = TRUE; + if (pAtom[i] == pWMInfo->ewmh._NET_WM_STATE_MAXIMIZED_HORZ) + horMax = TRUE; } - XFree(pAtom); - } + if (verMax && horMax) + maxmin |= HINT_MAX; + + free(reply); + } } - nitems = left = 0; - if (XGetWindowProperty(pDisplay, iWindow, motif_wm_hints, 0L, - PropMwmHintsElements, False, motif_wm_hints, &type, - &format, &nitems, &left, - (unsigned char **) &mwm_hint) == Success) { - if (mwm_hint && nitems == PropMwmHintsElements && + { + xcb_get_property_cookie_t cookie_mwm_hint = xcb_get_property(conn, FALSE, iWindow, motif_wm_hints, motif_wm_hints, 0L, sizeof(MwmHints)); + xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie_mwm_hint, NULL); + if (reply) { + int nitems = xcb_get_property_value_length(reply)/4; + MwmHints *mwm_hint = xcb_get_property_value(reply); + if (mwm_hint && (nitems >= PropMwmHintsElements) && (mwm_hint->flags & MwmHintsDecorations)) { - if (!mwm_hint->decorations) - hint |= HINT_NOFRAME; + if (!mwm_hint->decorations) { + hint &= ~(HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION); + hint |= (HINT_NOFRAME | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); + } else if (!(mwm_hint->decorations & MwmDecorAll)) { - if (mwm_hint->decorations & MwmDecorBorder) - hint |= HINT_BORDER; - if (mwm_hint->decorations & MwmDecorHandle) - hint |= HINT_SIZEBOX; - if (mwm_hint->decorations & MwmDecorTitle) - hint |= HINT_CAPTION; + if (!(mwm_hint->decorations & MwmDecorBorder)) + hint &= ~HINT_BORDER; + if (!(mwm_hint->decorations & MwmDecorHandle)) + hint &= ~HINT_SIZEBOX; + if (!(mwm_hint->decorations & MwmDecorTitle)) + hint &= ~HINT_CAPTION; if (!(mwm_hint->decorations & MwmDecorMenu)) hint |= HINT_NOSYSMENU; if (!(mwm_hint->decorations & MwmDecorMinimize)) @@ -1760,49 +2123,64 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) */ } } - if (mwm_hint) - XFree(mwm_hint); + free(reply); + } } - nitems = left = 0; - pAtom = NULL; - if (XGetWindowProperty(pDisplay, iWindow, windowType, 0L, - 1L, False, XA_ATOM, &type, &format, - &nitems, &left, - (unsigned char **) &pAtom) == Success) { - if (pAtom && nitems == 1) { - if (*pAtom == dockWindow) { - hint = (hint & ~HINT_NOFRAME) | HINT_SIZEBOX; /* Xming puts a sizebox on dock windows */ + { + int i; + xcb_ewmh_get_atoms_reply_t type; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type(&pWMInfo->ewmh, iWindow); + if (xcb_ewmh_get_wm_window_type_reply(&pWMInfo->ewmh, cookie, &type, NULL)) { + for (i = 0; i < type.atoms_len; i++) { + if (type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_DOCK) { + hint &= ~(HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION | HINT_NOFRAME); + hint |= (HINT_SKIPTASKBAR | HINT_SIZEBOX); + *zstyle = HWND_TOPMOST; + } + else if ((type.atoms[i] == pWMInfo->ewmh._NET_WM_WINDOW_TYPE_SPLASH) + || (type.atoms[i] == splashType)) { + hint &= ~(HINT_BORDER | HINT_SIZEBOX | HINT_CAPTION); + hint |= (HINT_SKIPTASKBAR | HINT_NOSYSMENU | HINT_NOMINIMIZE | HINT_NOMAXIMIZE); *zstyle = HWND_TOPMOST; } } - if (pAtom) - XFree(pAtom); + } } { - XSizeHints *normal_hint = XAllocSizeHints(); - long supplied; - - if (normal_hint && - (XGetWMNormalHints(pDisplay, iWindow, normal_hint, &supplied) == - Success)) { - if (normal_hint->flags & PMaxSize) { - /* Not maximizable if a maximum size is specified */ - hint |= HINT_NOMAXIMIZE; + xcb_size_hints_t size_hints; + xcb_get_property_cookie_t cookie; + + cookie = xcb_icccm_get_wm_normal_hints(conn, iWindow); + if (xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &size_hints, NULL)) { + /* Notwithstanding MwmDecorHandle, if we have a border, and + WM_NORMAL_HINTS indicates the window should be resizeable, let + the window have a resizing border. This is necessary for windows + with gtk3+ 3.14 csd. */ + if (hint & HINT_BORDER) + hint |= HINT_SIZEBOX; + + if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { + /* Not maximizable if a maximum size is specified, and that size + is smaller (in either dimension) than the screen size */ + if ((size_hints.max_width < GetSystemMetrics(SM_CXVIRTUALSCREEN)) + || (size_hints.max_height < GetSystemMetrics(SM_CYVIRTUALSCREEN))) + hint |= HINT_NOMAXIMIZE; - if (normal_hint->flags & PMinSize) { + if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { /* If both minimum size and maximum size are specified and are the same, don't bother with a resizing frame */ - if ((normal_hint->min_width == normal_hint->max_width) - && (normal_hint->min_height == normal_hint->max_height)) + if ((size_hints.min_width == size_hints.max_width) + && (size_hints.min_height == size_hints.max_height)) { + hint |= HINT_NOMAXIMIZE; hint = (hint & ~HINT_SIZEBOX); + } } } } - XFree(normal_hint); } /* @@ -1810,41 +2188,38 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) application id for grouping. */ { - XClassHint class_hint = { 0, 0 }; - char *window_name = 0; char *application_id = 0; + char *window_name = 0; + char *res_name = 0; + char *res_class = 0; - if (XGetClassHint(pDisplay, iWindow, &class_hint)) { - XFetchName(pDisplay, iWindow, &window_name); + GetClassNames(pWMInfo, iWindow, &res_name, &res_class, &window_name); - style = - winOverrideStyle(class_hint.res_name, class_hint.res_class, - window_name); + style = STYLE_NONE; + style = winOverrideStyle(res_name, res_class, window_name); + /* + It only makes sense to apply minimize/maximize override when the + window is mapped, as otherwise the state can't be changed. + */ + if (!onCreate) + style &= ~(STYLE_MAXIMIZE | STYLE_MINIMIZE); #define APPLICATION_ID_FORMAT "%s.xwin.%s" #define APPLICATION_ID_UNKNOWN "unknown" - if (class_hint.res_class) { - asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, - class_hint.res_class); - } - else { - asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, - APPLICATION_ID_UNKNOWN); - } - winSetAppUserModelID(hWnd, application_id); - - if (class_hint.res_name) - XFree(class_hint.res_name); - if (class_hint.res_class) - XFree(class_hint.res_class); - if (application_id) - free(application_id); - if (window_name) - XFree(window_name); + if (res_class) { + asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, + res_class); } else { - style = STYLE_NONE; + asprintf(&application_id, APPLICATION_ID_FORMAT, XVENDORNAME, + APPLICATION_ID_UNKNOWN); } + winSetAppUserModelID(hWnd, application_id); + + free(application_id); + free(res_name); + free(res_class); + free(window_name); } if (style & STYLE_TOPMOST) @@ -1874,6 +2249,9 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) (hint & ~HINT_BORDER & ~HINT_CAPTION & ~HINT_SIZEBOX) | HINT_NOFRAME; + if (style & STYLE_SKIPTASKBAR) + hint |= HINT_SKIPTASKBAR; + /* Now apply styles to window */ style = GetWindowLongPtr(hWnd, GWL_STYLE); if (!style) @@ -1881,6 +2259,11 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) style &= ~WS_CAPTION & ~WS_SIZEBOX; /* Just in case */ + if (GetParent(hWnd)) + style |= WS_SYSMENU; + else + style |= WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; + if (!(hint & ~HINT_SKIPTASKBAR)) /* No hints, default */ style = style | WS_CAPTION | WS_SIZEBOX; else if (hint & HINT_NOFRAME) /* No frame, no decorations */ @@ -1915,57 +2298,3 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) ("winApplyHints: iWindow 0x%08x hints 0x%08x style 0x%08x exstyle 0x%08x\n", iWindow, hint, style, exStyle); } - -void -winUpdateWindowPosition(HWND hWnd, HWND * zstyle) -{ - int iX, iY, iWidth, iHeight; - int iDx, iDy; - RECT rcNew; - WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP); - DrawablePtr pDraw = NULL; - - if (!pWin) - return; - pDraw = &pWin->drawable; - if (!pDraw) - return; - - /* Get the X and Y location of the X window */ - iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); - iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); - - /* Get the height and width of the X window */ - iWidth = pWin->drawable.width; - iHeight = pWin->drawable.height; - - /* Setup a rectangle with the X window position and size */ - SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight); - - winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n", - rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); - - AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, - GetWindowLongPtr(hWnd, GWL_EXSTYLE)); - - /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */ - if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) { - iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left; - rcNew.left += iDx; - rcNew.right += iDx; - } - - if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) { - iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top; - rcNew.top += iDy; - rcNew.bottom += iDy; - } - - winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n", - rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); - - /* Position the Windows window */ - SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top, - rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0); - -} diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c index 656f6c2da..6f3291175 100644 --- a/hw/xwin/winmultiwindowwndproc.c +++ b/hw/xwin/winmultiwindowwndproc.c @@ -41,6 +41,7 @@ #include "winprefs.h" #include "winmsg.h" #include "inputstr.h" +#include "wmutil/keyboard.h" extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle); @@ -294,6 +295,31 @@ winStartMousePolling(winPrivScreenPtr s_pScreenPriv) MOUSE_POLLING_INTERVAL, NULL); } +static +void +winAdjustXWindowState(winPrivScreenPtr s_pScreenPriv, winWMMessageRec *wmMsg) +{ + wmMsg->msg = WM_WM_CHANGE_STATE; + if (IsIconic(wmMsg->hwndWindow)) { + wmMsg->dwID = 3; // IconicState + winSendMessageToWM(s_pScreenPriv->pWMInfo, wmMsg); + } + else if (IsZoomed(wmMsg->hwndWindow)) { + wmMsg->dwID = 2; // ZoomState + winSendMessageToWM(s_pScreenPriv->pWMInfo, wmMsg); + } + else if (IsWindowVisible(wmMsg->hwndWindow)) { + wmMsg->dwID = 1; // NormalState + winSendMessageToWM(s_pScreenPriv->pWMInfo, wmMsg); + } + else { + /* Only the client, not the user can Withdraw windows, so it doesn't make + much sense to handle that state here, and anything else is an + unanticapted state. */ + ErrorF("winAdjustXWindowState - Unknown state for %p\n", wmMsg->hwndWindow); + } +} + /* * winTopLevelWindowProc - Window procedure for all top-level Windows windows. */ @@ -302,7 +328,6 @@ LRESULT CALLBACK winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { POINT ptMouse; - HDC hdcUpdate; PAINTSTRUCT ps; WindowPtr pWin = NULL; winPrivWinPtr pWinPriv = NULL; @@ -457,18 +482,9 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_PAINT: /* Only paint if our window handle is valid */ - if (hwndScreen == NULL) + if (hwnd == NULL) break; - /* BeginPaint gives us an hdc that clips to the invalidated region */ - hdcUpdate = BeginPaint(hwnd, &ps); - /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */ - if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 && - ps.rcPaint.left == 0 && ps.rcPaint.top == 0) { - EndPaint(hwnd, &ps); - return 0; - } - #ifdef XWIN_GLX_WINDOWS if (pWinPriv->fWglUsed) { /* @@ -478,36 +494,16 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) XXX: For now, just leave it alone, but ideally we want to send an expose event to the window so it really redraws the affected region... */ + BeginPaint(hwnd, &ps); ValidateRect(hwnd, &(ps.rcPaint)); + EndPaint(hwnd, &ps); } else #endif - /* Try to copy from the shadow buffer */ - if (!BitBlt(hdcUpdate, - ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right - ps.rcPaint.left, - ps.rcPaint.bottom - ps.rcPaint.top, - s_pScreenPriv->hdcShadow, - ps.rcPaint.left + pWin->drawable.x, - ps.rcPaint.top + pWin->drawable.y, SRCCOPY)) { - LPVOID lpMsgBuf; - - /* Display a fancy error message */ - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, 0, NULL); - - ErrorF("winTopLevelWindowProc - BitBlt failed: %s\n", - (LPSTR) lpMsgBuf); - LocalFree(lpMsgBuf); - } + /* Call the engine dependent repainter */ + if (*s_pScreenPriv->pwinBltExposedWindowRegion) + (*s_pScreenPriv->pwinBltExposedWindowRegion) (s_pScreen, pWin); - /* EndPaint frees the DC */ - EndPaint(hwnd, &ps); return 0; case WM_MOUSEMOVE: @@ -868,6 +864,7 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) RemoveProp(hwnd, WIN_WINDOW_PROP); RemoveProp(hwnd, WIN_WID_PROP); RemoveProp(hwnd, WIN_NEEDMANAGE_PROP); + RemoveProp(hwnd, WIN_STATE_PROP); break; @@ -878,77 +875,6 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* else: Wait for WM_EXITSIZEMOVE */ return 0; - case WM_SHOWWINDOW: - /* Bail out if the window is being hidden */ - if (!wParam) - return 0; - - /* */ - if (!pWin->overrideRedirect) { - HWND zstyle = HWND_NOTOPMOST; - - /* Flag that this window needs to be made active when clicked */ - SetProp(hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1); - - /* Set the transient style flags */ - if (GetParent(hwnd)) - SetWindowLongPtr(hwnd, GWL_STYLE, - WS_POPUP | WS_OVERLAPPED | WS_SYSMENU | - WS_CLIPCHILDREN | WS_CLIPSIBLINGS); - /* Set the window standard style flags */ - else - SetWindowLongPtr(hwnd, GWL_STYLE, - (WS_POPUP | WS_OVERLAPPEDWINDOW | - WS_CLIPCHILDREN | WS_CLIPSIBLINGS) - & ~WS_CAPTION & ~WS_SIZEBOX); - - winUpdateWindowPosition(hwnd, &zstyle); - - { - WinXWMHints hints; - - if (winMultiWindowGetWMHints(pWin, &hints)) { - /* - Give the window focus, unless it has an InputHint - which is FALSE (this is used by e.g. glean to - avoid every test window grabbing the focus) - */ - if (!((hints.flags & InputHint) && (!hints.input))) { - SetForegroundWindow(hwnd); - } - } - } - wmMsg.msg = WM_WM_MAP3; - } - else { /* It is an overridden window so make it top of Z stack */ - - HWND forHwnd = GetForegroundWindow(); - -#if CYGWINDOWING_DEBUG - ErrorF("overridden window is shown\n"); -#endif - if (forHwnd != NULL) { - if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR) - XMING_SIGNATURE) { - if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - else - SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } - } - wmMsg.msg = WM_WM_MAP2; - } - - /* Tell our Window Manager thread to map the window */ - if (fWMMsgInitialized) - winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg); - - winStartMousePolling(s_pScreenPriv); - - return 0; - case WM_SIZING: /* Need to legalize the size according to WM_NORMAL_HINTS */ /* for applications like xterm */ @@ -1001,12 +927,75 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } } } + + /* Window is being shown */ + if (pWinPos->flags & SWP_SHOWWINDOW) { + if (!pWin->overrideRedirect) { + HWND zstyle = HWND_NOTOPMOST; + + /* Flag that this window needs to be made active when clicked */ + SetProp(hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1); + + winUpdateWindowPosition(hwnd, &zstyle); + + { + WinXWMHints hints; + + if (winMultiWindowGetWMHints(pWin, &hints)) { + /* + Give the window focus, unless it has an InputHint + which is FALSE (this is used by e.g. glean to + avoid every test window grabbing the focus) + */ + if (!((hints.flags & InputHint) && (!hints.input))) { + SetForegroundWindow(hwnd); + } + } + } + wmMsg.msg = WM_WM_MAP_MANAGED; + } + else { /* It is an overridden window so make it top of Z stack */ + HWND forHwnd = GetForegroundWindow(); + + if (forHwnd != NULL) { + if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR) + XMING_SIGNATURE) { + if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + else + SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + wmMsg.msg = WM_WM_MAP_UNMANAGED; + } + + /* Tell our Window Manager thread to map the window */ + if (fWMMsgInitialized) + winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg); + + winStartMousePolling(s_pScreenPriv); + } + + /* + We don't react to SWP_HIDEWINDOW indicating window is being hidden in + a symmetrical way (i.e. by sending WM_WM_UNMAP) + + If the cause of the window being hidden is the X windows being unmapped, + (WM_STATE has changed to WithdrawnState), then the window has already + been unmapped. + + Virtual desktop software (like VirtuaWin or Dexpot) uses SWP_HIDEWINDOW + to hide windows on other desktops. We mustn't unmap the X window in + that situation, as it becomes inaccessible. + */ } - /* - * Pass the message to DefWindowProc to let the function - * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE. - */ - break; + /* + * Pass the message to DefWindowProc to let the function + * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE. + */ + break; case WM_ENTERSIZEMOVE: hasEnteredSizeMove = TRUE; @@ -1016,6 +1005,8 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Adjust the X Window to the moved Windows window */ hasEnteredSizeMove = FALSE; winAdjustXWindow(pWin, hwnd); + if (fWMMsgInitialized) + winAdjustXWindowState(s_pScreenPriv, &wmMsg); return 0; case WM_SIZE: @@ -1044,6 +1035,10 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (!hasEnteredSizeMove) { /* Adjust the X Window to the moved Windows window */ winAdjustXWindow(pWin, hwnd); + if (fWMMsgInitialized) + winAdjustXWindowState(s_pScreenPriv, &wmMsg); + if (wParam == SIZE_MINIMIZED) + winReorderWindowsMultiWindow(); } /* else: wait for WM_EXITSIZEMOVE */ return 0; /* end of WM_SIZE handler */ @@ -1155,3 +1150,93 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) winReorderWindowsMultiWindow(); return ret; } + +/* + * winChildWindowProc - Window procedure for all top-level Windows windows. + */ + +LRESULT CALLBACK +winChildWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ +#if CYGDEBUG + winDebugWin32Message("winChildWindowProc", hwnd, message, wParam, lParam); +#endif + + switch (message) { + case WM_ERASEBKGND: + return TRUE; + + case WM_PAINT: + /* + We don't have the bits to draw into the window, they went straight into the OpenGL + surface + + XXX: For now, just leave it alone, but ideally we want to send an expose event to + the window so it really redraws the affected region... + */ + { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + ValidateRect(hwnd, &(ps.rcPaint)); + EndPaint(hwnd, &ps); + return 0; + } + /* XXX: this is exactly what DefWindowProc does? */ + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +void +winUpdateWindowPosition(HWND hWnd, HWND * zstyle) +{ + int iX, iY, iWidth, iHeight; + int iDx, iDy; + RECT rcNew; + WindowPtr pWin = GetProp(hWnd, WIN_WINDOW_PROP); + DrawablePtr pDraw = NULL; + + if (!pWin) + return; + pDraw = &pWin->drawable; + if (!pDraw) + return; + + /* Get the X and Y location of the X window */ + iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); + iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); + + /* Get the height and width of the X window */ + iWidth = pWin->drawable.width; + iHeight = pWin->drawable.height; + + /* Setup a rectangle with the X window position and size */ + SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight); + + winDebug("winUpdateWindowPosition - drawable extent (%d, %d)-(%d, %d)\n", + rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); + + AdjustWindowRectEx(&rcNew, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, + GetWindowLongPtr(hWnd, GWL_EXSTYLE)); + + /* Don't allow window decoration to disappear off to top-left as a result of this adjustment */ + if (rcNew.left < GetSystemMetrics(SM_XVIRTUALSCREEN)) { + iDx = GetSystemMetrics(SM_XVIRTUALSCREEN) - rcNew.left; + rcNew.left += iDx; + rcNew.right += iDx; + } + + if (rcNew.top < GetSystemMetrics(SM_YVIRTUALSCREEN)) { + iDy = GetSystemMetrics(SM_YVIRTUALSCREEN) - rcNew.top; + rcNew.top += iDy; + rcNew.bottom += iDy; + } + + winDebug("winUpdateWindowPosition - Window extent (%d, %d)-(%d, %d)\n", + rcNew.left, rcNew.top, rcNew.right, rcNew.bottom); + + /* Position the Windows window */ + SetWindowPos(hWnd, *zstyle, rcNew.left, rcNew.top, + rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 0); + +} diff --git a/hw/xwin/winos.c b/hw/xwin/winos.c index 0d825bb83..4e72daa7f 100644 --- a/hw/xwin/winos.c +++ b/hw/xwin/winos.c @@ -37,19 +37,27 @@ static const char* IsWow64(void) { #ifdef __x86_64__ - return " (64-bit)"; + return " (Win64)"; #else - WINBOOL bIsWow64; + /* Check if we are running under WoW64 */ LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); if (NULL != fnIsWow64Process) { - if (fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) - return bIsWow64 ? " (WoW64)" : " (32-bit)"; - } + WINBOOL bIsWow64 = FALSE; - /* OS doesn't support IsWow64Process() */ - return ""; + if (fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { + return bIsWow64 ? " (WoW64)" : " (Win32)"; + } + else { + /* IsWow64Process() failed */ + return " (Unknown)"; + } + } + else { + /* OS doesn't support IsWow64Process() */ + return ""; + } #endif } @@ -61,12 +69,89 @@ void winOS(void) { OSVERSIONINFOEX osvi = {0}; + const char *windowstype = "Unknown"; + const char *prodName = "Unknown"; + const char *isWow = "Unknown"; /* Get operating system version information */ osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx((LPOSVERSIONINFO)&osvi); - ErrorF("OS: Windows NT %d.%d build %d%s\n", - (int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, - (int)osvi.dwBuildNumber, IsWow64()); + /* Branch on platform ID */ + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + windowstype = "Windows NT"; + + if (osvi.dwMajorVersion <= 4) + prodName = "Windows NT"; + else if (osvi.dwMajorVersion == 10) { + if (osvi.dwMinorVersion == 0) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows 10"; + else + prodName = "Windows Server 2016"; + } + } + else if (osvi.dwMajorVersion == 6) { + if (osvi.dwMinorVersion == 4) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows 10"; + else + prodName = "Windows Server 2016"; + } + if (osvi.dwMinorVersion == 3) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows 8.1"; + else + prodName = "Windows Server 2012 R2"; + } + if (osvi.dwMinorVersion == 2) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows 8"; + else + prodName = "Windows Server 2012"; + } + else if (osvi.dwMinorVersion == 1) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows 7"; + else + prodName = "Windows Server 2008 R2"; + } + else if (osvi.dwMinorVersion == 0) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows Vista"; + else + prodName = "Windows Server 2008"; + } + } + else if (osvi.dwMajorVersion == 5) { + if (osvi.dwMinorVersion == 2) { + if (osvi.wProductType == VER_NT_WORKSTATION) + prodName = "Windows XP x64 Edition"; + else if (GetSystemMetrics(SM_SERVERR2)) + prodName = "Windows Server 2003 R2"; + else + prodName = "Windows Server 2003"; + } + else if (osvi.dwMinorVersion == 1) + prodName = "Windows XP"; + else if (osvi.dwMinorVersion == 0) { + prodName = "Windows 2000"; + break; + } + } + + break; + + case VER_PLATFORM_WIN32_WINDOWS: + windowstype = "Windows"; + break; + } + + isWow = IsWow64(); + + ErrorF("OS: %s %s [%s %d.%d build %d]%s\n", + prodName, osvi.szCSDVersion, + windowstype, (int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, + (int)osvi.dwBuildNumber, isWow); } diff --git a/hw/xwin/winprefs.c b/hw/xwin/winprefs.c index 505292714..4d53f8a79 100644 --- a/hw/xwin/winprefs.c +++ b/hw/xwin/winprefs.c @@ -37,6 +37,8 @@ #include <stdlib.h> #ifdef __CYGWIN__ #include <sys/resource.h> +#include <sys/wait.h> +#include <pthread.h> #endif #include "win.h" @@ -46,6 +48,7 @@ #include "winprefs.h" #include "windisplay.h" #include "winmultiwindowclass.h" +#include "winmultiwindowicons.h" /* Where will the custom menu commands start counting from? */ #define STARTMENUID WM_USER @@ -297,6 +300,110 @@ HandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu) } +#ifdef __CYGWIN__ +static void +LogLineFromFd(int fd, const char *fdname, int pid) +{ +#define BUFSIZE 512 /* must be less than internal buffer size used in LogVWrite */ + char buf[BUFSIZE]; + char *bufptr = buf; + + /* read from fd until eof, newline or our buffer is full */ + while ((read(fd, bufptr, 1) > 0) && (bufptr < &(buf[BUFSIZE - 1]))) { + if (*bufptr == '\n') + break; + bufptr++; + } + + /* null terminate and log */ + *bufptr = 0; + if (strlen(buf)) + ErrorF("(pid %d %s) %s\n", pid, fdname, buf); +} + +static void * +ExecAndLogThread(void *cmd) +{ + int pid; + int stdout_filedes[2]; + int stderr_filedes[2]; + int status; + + /* Create a pair of pipes */ + pipe(stdout_filedes); + pipe(stderr_filedes); + + switch (pid = fork()) { + case 0: /* child */ + { + struct rlimit rl; + unsigned int fd; + + /* dup write end of pipes onto stderr and stdout */ + close(STDOUT_FILENO); + close(STDERR_FILENO); + + dup2(stdout_filedes[1], STDOUT_FILENO); + dup2(stderr_filedes[1], STDERR_FILENO); + + /* Close any open descriptors except for STD* */ + getrlimit(RLIMIT_NOFILE, &rl); + for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++) + close(fd); + + /* Disassociate any TTYs */ + setsid(); + + execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); + perror("execl failed"); + exit(127); + } + break; + + default: /* parent */ + { + close(stdout_filedes[1]); + close(stderr_filedes[1]); + + ErrorF("executing '%s', pid %d\n", (char *) cmd, pid); + + /* read from pipes, write to log, until both are closed */ + while (TRUE) { + fd_set readfds, errorfds; + int nfds = max(stdout_filedes[0], stderr_filedes[0]) + 1; + + FD_ZERO(&readfds); + FD_SET(stdout_filedes[0], &readfds); + FD_SET(stderr_filedes[0], &readfds); + errorfds = readfds; + + if (select(nfds, &readfds, NULL, &errorfds, NULL) > 0) { + if (FD_ISSET(stdout_filedes[0], &readfds)) + LogLineFromFd(stdout_filedes[0], "stdout", pid); + if (FD_ISSET(stderr_filedes[0], &readfds)) + LogLineFromFd(stderr_filedes[0], "stderr", pid); + + if (FD_ISSET(stdout_filedes[0], &errorfds) && + FD_ISSET(stderr_filedes[0], &errorfds)) + break; + } + else { + break; + } + } + + waitpid(pid, &status, 0); + } + break; + + case -1: /* error */ + ErrorF("fork() to run command failed\n"); + } + + return (void *) (intptr_t) status; +} +#endif + /* * Searches for the custom WM_COMMAND command ID and performs action. * Return TRUE if command is proccessed, FALSE otherwise. @@ -319,24 +426,17 @@ HandleCustomWM_COMMAND(HWND hwnd, int command) switch (m->menuItem[j].cmd) { #ifdef __CYGWIN__ case CMD_EXEC: - if (fork() == 0) { - struct rlimit rl; - int fd; - - /* Close any open descriptors except for STD* */ - getrlimit(RLIMIT_NOFILE, &rl); - for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++) - close(fd); - - /* Disassociate any TTYs */ - setsid(); + { + pthread_t t; - execl("/bin/sh", - "/bin/sh", "-c", m->menuItem[j].param, NULL); - exit(0); - } + if (!pthread_create + (&t, NULL, ExecAndLogThread, m->menuItem[j].param)) + pthread_detach(t); else - return TRUE; + ErrorF + ("Creating command output logging thread failed\n"); + } + return TRUE; break; #else case CMD_EXEC: @@ -637,11 +737,17 @@ winPrefsLoadPreferences(const char *path) "MENU rmenu {\n" " \"How to customize this menu\" EXEC \"xterm +tb -e man XWinrc\"\n" " \"Launch xterm\" EXEC xterm\n" - " \"Load .XWinrc\" RELOAD\n" + " SEPARATOR\n" + " FAQ EXEC \"cygstart http://x.cygwin.com/docs/faq/cygwin-x-faq.html\"\n" + " \"User's Guide\" EXEC \"cygstart http://x.cygwin.com/docs/ug/cygwin-x-ug.html\"\n" + " SEPARATOR\n" + " \"Reload .XWinrc\" RELOAD\n" " SEPARATOR\n" "}\n" "\n" "ROOTMENU rmenu\n"; path = "built-in default"; prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r"); + + } #endif @@ -672,7 +778,7 @@ LoadPreferences(void) char *home; char fname[PATH_MAX + NAME_MAX + 2]; char szDisplay[512]; - char *szEnvDisplay; + char *szEnvDisplay, *szEnvLogFile; int i, j; char param[PARAM_MAX + 1]; char *srcParam, *dstParam; @@ -720,6 +826,11 @@ LoadPreferences(void) putenv(szEnvDisplay); } + /* Setup XWINLOGFILE environment variable */ + szEnvLogFile = (char *) (malloc(strlen(g_pszLogFile) + strlen("XWINLOGFILE=") + 1)); + snprintf(szEnvLogFile, 512, "XWINLOGFILE=%s", g_pszLogFile); + putenv(szEnvLogFile); + /* Replace any "%display%" in menu commands with display string */ for (i = 0; i < pref.menuItems; i++) { for (j = 0; j < pref.menu[i].menuItems; j++) { diff --git a/hw/xwin/winprefs.h b/hw/xwin/winprefs.h index 8f4eb0807..c41710419 100644 --- a/hw/xwin/winprefs.h +++ b/hw/xwin/winprefs.h @@ -34,9 +34,6 @@ /* Need Bool */ #include <X11/Xdefs.h> -/* Need TRUE */ -#include "misc.h" - /* Need to know how long paths can be... */ #include <limits.h> /* Xwindows redefines PATH_MAX to at least 1024 */ @@ -65,6 +62,7 @@ typedef enum MENUCOMMANDTYPE { #define STYLE_MAXIMIZE (1L<<4) /* Open a window maximized */ #define STYLE_MINIMIZE (1L<<5) /* Open a window minimized */ #define STYLE_BOTTOM (1L<<6) /* Open a window at the bottom of the Z order */ +#define STYLE_SKIPTASKBAR (1L<<7) /* Omit from taskbar */ /* Where to place a system menu */ typedef enum MENUPOSITION { diff --git a/hw/xwin/winprefslex.l b/hw/xwin/winprefslex.l index 9e6f0d6d4..e7547729c 100644 --- a/hw/xwin/winprefslex.l +++ b/hw/xwin/winprefslex.l @@ -77,6 +77,7 @@ BOTTOM { return BOTTOM; } NOTITLE { return NOTITLE; } OUTLINE { return OUTLINE; } NOFRAME { return NOFRAME; } +SKIPTASKBAR { return SKIPTASKBAR; } ROOTMENU { return ROOTMENU; } DEFAULTSYSMENU { return DEFAULTSYSMENU; } SYSMENU { return SYSMENU; } @@ -90,6 +91,12 @@ RELOAD { return RELOAD; } TRAYICON { return TRAYICON; } FORCEEXIT { return FORCEEXIT; } SILENTEXIT { return SILENTEXIT; } +DPI { return DPI; } +XKBLAYOUT { return XKBLAYOUT; } +XKBMODEL { return XKBMODEL; } +XKBOPTIONS { return XKBOPTIONS; } +XKBRULES { return XKBRULES; } +XKBVARIANT { return XKBVARIANT; } "{" { return LB; } "}" { return RB; } "\""[^\"\r\n]+"\"" { yylval.sVal = makestr(yytext+1); \ diff --git a/hw/xwin/winprefsyacc.y b/hw/xwin/winprefsyacc.y index 9bb28ae92..e4e305a0f 100644 --- a/hw/xwin/winprefsyacc.y +++ b/hw/xwin/winprefsyacc.y @@ -39,6 +39,8 @@ #include <stdlib.h> #define _STDLIB_H 1 /* bison checks this to know if stdlib has been included */ #include <string.h> +#include "globals.h" +#include "winconfig.h" #include "winprefs.h" /* The following give better error messages in bison at the cost of a few KB */ @@ -57,6 +59,13 @@ static MENUPARSED menu; /* Functions for parsing the tokens into out structure */ /* Defined at the end section of this file */ +static void SetDPI (char *dpi); +static void SetXKBLayout (char *layout); +static void SetXKBModel (char *model); +static void SetXKBOptions (char *options); +static void SetXKBRules (char *rules); +static void SetXKBVariant (char *variant); + static void SetIconDirectory (char *path); static void SetDefaultIcon (char *fname); static void SetRootMenu (char *menu); @@ -108,6 +117,7 @@ extern int yylex(void); %token NOTITLE %token OUTLINE %token NOFRAME +%token SKIPTASKBAR %token DEFAULTSYSMENU %token SYSMENU %token ROOTMENU @@ -121,10 +131,17 @@ extern int yylex(void); %token TRAYICON %token FORCEEXIT %token SILENTEXIT +%token DPI +%token XKBLAYOUT +%token XKBMODEL +%token XKBOPTIONS +%token XKBRULES +%token XKBVARIANT %token <sVal> STRING %type <uVal> group1 %type <uVal> group2 +%type <uVal> group3 %type <uVal> stylecombo %type <iVal> atspot @@ -155,6 +172,30 @@ command: defaulticon | trayicon | forceexit | silentexit + | dpi + | xkblayout + | xkbmodel + | xkboptions + | xkbrules + | xkbvariant + ; + +dpi: DPI STRING NEWLINE { SetDPI($2); free($2); } + ; + +xkblayout: XKBLAYOUT STRING NEWLINE { SetXKBLayout($2); } + ; + +xkbmodel: XKBMODEL STRING NEWLINE { SetXKBModel($2); } + ; + +xkboptions: XKBOPTIONS STRING NEWLINE { SetXKBOptions($2); } + ; + +xkbrules: XKBRULES STRING NEWLINE { SetXKBRules($2); } + ; + +xkbvariant: XKBVARIANT STRING NEWLINE { SetXKBVariant($2); } ; trayicon: TRAYICON STRING NEWLINE { SetTrayIcon($2); free($2); } @@ -207,10 +248,24 @@ group2: NOTITLE { $$=STYLE_NOTITLE; } | NOFRAME { $$=STYLE_NOFRAME; } ; +group3: SKIPTASKBAR { $$=STYLE_SKIPTASKBAR; } + ; + stylecombo: group1 { $$=$1; } | group2 { $$=$1; } + | group3 { $$=$1; } | group1 group2 { $$=$1|$2; } + | group1 group3 { $$=$1|$2; } | group2 group1 { $$=$1|$2; } + | group2 group3 { $$=$1|$2; } + | group3 group1 { $$=$1|$2; } + | group3 group2 { $$=$1|$2; } + | group1 group2 group3 { $$=$1|$2|$3; } + | group1 group3 group2 { $$=$1|$2|$3; } + | group2 group1 group3 { $$=$1|$2|$3; } + | group2 group3 group1 { $$=$1|$2|$3; } + | group3 group1 group2 { $$=$1|$2|$3; } + | group3 group2 group1 { $$=$1|$2|$3; } ; styleline: STRING stylecombo NEWLINE newline_or_nada { AddStyleLine($1, $2); free($1); } @@ -259,6 +314,58 @@ yyerror (const char *s) return 1; } +static void +SetDPI (char *dpi) +{ + if (!g_cmdline.customDPI) + monitorResolution = atoi (dpi); +} + +static void +SetXKBLayout (char *layout) +{ + if (!g_cmdline.xkbLayout) + g_cmdline.xkbLayout = layout; + else + free (layout); +} + +static void +SetXKBModel (char *model) +{ + if (!g_cmdline.xkbModel) + g_cmdline.xkbModel = model; + else + free (model); +} + +static void +SetXKBOptions (char *options) +{ + if (!g_cmdline.xkbOptions) + g_cmdline.xkbOptions = options; + else + free (options); +} + +static void +SetXKBRules (char *rules) +{ + if (!g_cmdline.xkbRules) + g_cmdline.xkbRules = rules; + else + free (rules); +} + +static void +SetXKBVariant (char *variant) +{ + if (!g_cmdline.xkbVariant) + g_cmdline.xkbVariant = variant; + else + free (variant); +} + /* Miscellaneous functions to store TOKENs into the structure */ static void SetIconDirectory (char *path) diff --git a/hw/xwin/winprocarg.c b/hw/xwin/winprocarg.c index 73aa027d8..4f6275be1 100644 --- a/hw/xwin/winprocarg.c +++ b/hw/xwin/winprocarg.c @@ -130,18 +130,18 @@ winInitializeScreenDefaults(void) defaultScreenInfo.fDecoration = TRUE; #ifdef XWIN_MULTIWINDOWEXTWM defaultScreenInfo.fMWExtWM = FALSE; - defaultScreenInfo.fInternalWM = FALSE; #endif defaultScreenInfo.fRootless = FALSE; #ifdef XWIN_MULTIWINDOW defaultScreenInfo.fMultiWindow = FALSE; + defaultScreenInfo.fCompositeWM = FALSE; #endif #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) defaultScreenInfo.fMultiMonitorOverride = FALSE; #endif defaultScreenInfo.fMultipleMonitors = FALSE; defaultScreenInfo.fLessPointer = FALSE; - defaultScreenInfo.iResizeMode = resizeWithRandr; + defaultScreenInfo.iResizeMode = resizeDefault; defaultScreenInfo.fNoTrayIcon = FALSE; defaultScreenInfo.iE3BTimeout = WIN_E3B_DEFAULT; defaultScreenInfo.fUseWinKillKey = WIN_DEFAULT_WIN_KILL; @@ -247,7 +247,7 @@ ddxProcessArgument(int argc, char *argv[], int i) * OsVendorInit () gets called, otherwise we will overwrite * settings changed by parameters such as -fullscreen, etc. */ - winErrorFVerb(2, "ddxProcessArgument - Initializing default " + winErrorFVerb(3, "ddxProcessArgument - Initializing default " "screens\n"); winInitializeScreenDefaults(); } @@ -292,6 +292,9 @@ ddxProcessArgument(int argc, char *argv[], int i) /* Display the usage message if the argument is malformed */ if (i + 1 >= argc) { + ErrorF("ddxProcessArgument - screen - Missing screen number\n"); + UseMsg(); + FatalError("-screen missing screen number\n"); return 0; } @@ -577,11 +580,8 @@ ddxProcessArgument(int argc, char *argv[], int i) * Look for the '-internalwm' argument */ if (IS_OPTION("-internalwm")) { - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = TRUE; - screenInfoPtr->fMWExtWM = TRUE; - screenInfoPtr->fInternalWM = TRUE; - + ErrorF("Ignoring obsolete -internalwm option\n"); + /* Ignored, but we still accept the arg for backwards compatibility */ /* Indicate that we have processed this argument */ return 1; } @@ -615,6 +615,16 @@ ddxProcessArgument(int argc, char *argv[], int i) /* Indicate that we have processed this argument */ return 1; } + + /* + * Look for the '-compositewm' argument + */ + if (IS_OPTION("-compositewm")) { + screenInfoPtr->fCompositeWM = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } #endif /* @@ -666,7 +676,7 @@ ddxProcessArgument(int argc, char *argv[], int i) if (IS_OPTION("-resize")) mode = resizeWithRandr; else if (IS_OPTION("-noresize")) - mode = notAllowed; + mode = resizeNotAllowed; else if (strncmp(argv[i], "-resize=", strlen("-resize=")) == 0) { char *option = argv[i] + strlen("-resize="); @@ -675,7 +685,7 @@ ddxProcessArgument(int argc, char *argv[], int i) else if (strcmp(option, "scrollbars") == 0) mode = resizeWithScrollbars; else if (strcmp(option, "none") == 0) - mode = notAllowed; + mode = resizeNotAllowed; else { ErrorF("ddxProcessArgument - resize - Invalid resize mode %s\n", option); @@ -957,6 +967,14 @@ ddxProcessArgument(int argc, char *argv[], int i) } /* + * Look for the '-dpi' argument + */ + if (IS_OPTION("-dpi")) { + g_cmdline.customDPI = TRUE; + return 0; /* Let DIX parse this again */ + } + + /* * Look for the '-config' argument */ if (IS_OPTION("-config") @@ -1011,9 +1029,6 @@ ddxProcessArgument(int argc, char *argv[], int i) if (IS_OPTION("-logfile")) { CHECK_ARGS(1); g_pszLogFile = argv[++i]; -#ifdef RELOCATE_PROJECTROOT - g_fLogFileChanged = TRUE; -#endif return 2; } @@ -1203,6 +1218,5 @@ winLogVersionInfo(void) winOS(); if (strlen(BUILDERSTRING)) ErrorF("%s\n", BUILDERSTRING); - ErrorF("Contact: %s\n", BUILDERADDR); ErrorF("\n"); } diff --git a/hw/xwin/winrandr.c b/hw/xwin/winrandr.c index f4ba054bc..1b28e5223 100644 --- a/hw/xwin/winrandr.c +++ b/hw/xwin/winrandr.c @@ -34,11 +34,6 @@ #include <xwin-config.h> #endif #include "win.h" -#include "mivalidate.h" // for union _Validate used by windowstr.h - -#ifndef RANDR_12_INTERFACE -#error X server must have RandR 1.2 interface -#endif /* * Answer queries about the RandR features supported. @@ -47,17 +42,47 @@ static Bool winRandRGetInfo(ScreenPtr pScreen, Rotation * pRotations) { + rrScrPrivPtr pRRScrPriv; + RROutputPtr output; + + pRRScrPriv = rrGetScrPriv(pScreen); + output = pRRScrPriv->outputs[0]; + winDebug("winRandRGetInfo ()\n"); /* Don't support rotations */ *pRotations = RR_Rotate_0; - /* - The screen doesn't have to be limited to the actual - monitor size (we can have scrollbars :-), so what is - the upper limit? - */ - RRScreenSetSizeRange(pScreen, 0, 0, 4096, 4096); + /* Delete previous mode */ + if (output->modes[0]) + { + RRModeDestroy(output->modes[0]); + RRModeDestroy(output->crtc->mode); + } + + /* Register current mode */ + { + xRRModeInfo modeInfo; + RRModePtr mode; + char name[100]; + + memset(&modeInfo, '\0', sizeof(modeInfo)); + snprintf(name, sizeof(name), "%dx%d", pScreen->width, pScreen->height); + + modeInfo.width = pScreen->width; + modeInfo.height = pScreen->height; + modeInfo.hTotal = pScreen->width; + modeInfo.vTotal = pScreen->height; + modeInfo.dotClock = 0; + modeInfo.nameLength = strlen(name); + mode = RRModeGet(&modeInfo, name); + + output->modes[0] = mode; + output->numModes = 1; + + mode = RRModeGet(&modeInfo, name); + output->crtc->mode = mode; + } return TRUE; } @@ -74,6 +99,11 @@ winDoRandRScreenSetSize(ScreenPtr pScreen, winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; WindowPtr pRoot = pScreen->root; + /* Ignore changes which do nothing */ + if ((pScreen->width == width) && (pScreen->height == height) && + (pScreen->mmWidth == mmWidth) && (pScreen->mmHeight == mmHeight)) + return; + // Prevent screen updates while we change things around SetRootClip(pScreen, FALSE); @@ -214,5 +244,45 @@ winRandRInit(ScreenPtr pScreen) pRRScrPriv->rrCrtcSet = NULL; pRRScrPriv->rrCrtcSetGamma = NULL; + /* Create a CRTC and an output for the screen, and hook them together */ + { + RRCrtcPtr crtc; + RROutputPtr output; + + crtc = RRCrtcCreate(pScreen, NULL); + if (!crtc) + return FALSE; + + crtc->rotations = RR_Rotate_0; + + output = RROutputCreate(pScreen, "default", 7, NULL); + if (!output) + return FALSE; + + RROutputSetCrtcs(output, &crtc, 1); + RROutputSetConnection(output, RR_Connected); + RROutputSetSubpixelOrder(output, PictureGetSubpixelOrder(pScreen)); + + output->crtc = crtc; + + /* Set crtc outputs (should use RRCrtcNotify?) */ + crtc->outputs = malloc(sizeof(RROutputPtr)); + crtc->outputs[0] = output; + crtc->numOutputs = 1; + + pRRScrPriv->primaryOutput = output; + + /* Ensure we have space for exactly one mode */ + output->modes = malloc(sizeof(RRModePtr)); + output->modes[0] = NULL; + } + + /* + The screen doesn't have to be limited to the actual + monitor size (we can have scrollbars :-), so what is + the upper limit? + */ + RRScreenSetSizeRange(pScreen, 0, 0, 4096, 4096); + return TRUE; } diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c index 735ce9325..b839eaf1c 100644 --- a/hw/xwin/winscrinit.c +++ b/hw/xwin/winscrinit.c @@ -534,10 +534,12 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) #ifdef XWIN_MULTIWINDOW || pScreenInfo->fMultiWindow #endif -#ifdef XWIN_MULTIWINDOWEXTWM - || pScreenInfo->fInternalWM -#endif ) { + if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) { + ErrorF("-compositewm disabled due to 8bpp depth\n"); + pScreenInfo->fCompositeWM = FALSE; + } + #if CYGDEBUG || YES winDebug("winFinishScreenInitFB - Calling winInitWM.\n"); #endif @@ -547,11 +549,9 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) &pScreenPriv->ptWMProc, &pScreenPriv->ptXMsgProc, &pScreenPriv->pmServerStarted, - pScreenInfo->dwScreen, (HWND) &pScreenPriv->hwndScreen, -#ifdef XWIN_MULTIWINDOWEXTWM - pScreenInfo->fInternalWM || -#endif - FALSE)) { + pScreenInfo->dwScreen, + (HWND) &pScreenPriv->hwndScreen, + pScreenInfo->fCompositeWM)) { ErrorF("winFinishScreenInitFB - winInitWM () failed.\n"); return FALSE; } diff --git a/hw/xwin/winshadddnl.c b/hw/xwin/winshadddnl.c index d4f940ec1..9481ecb42 100644 --- a/hw/xwin/winshadddnl.c +++ b/hw/xwin/winshadddnl.c @@ -1203,6 +1203,7 @@ winSetEngineFunctionsShadowDDNL(ScreenPtr pScreen) pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDDNL; + pScreenPriv->pwinBltExposedWindowRegion = NULL; pScreenPriv->pwinActivateApp = winActivateAppShadowDDNL; pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDDNL; pScreenPriv->pwinRealizeInstalledPalette @@ -1211,14 +1212,8 @@ winSetEngineFunctionsShadowDDNL(ScreenPtr pScreen) pScreenPriv->pwinStoreColors = winStoreColorsShadowDDNL; pScreenPriv->pwinCreateColormap = winCreateColormapShadowDDNL; pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowDDNL; - pScreenPriv->pwinHotKeyAltTab = - (winHotKeyAltTabProcPtr) (void (*)(void)) NoopDDA; pScreenPriv->pwinCreatePrimarySurface = winCreatePrimarySurfaceShadowDDNL; pScreenPriv->pwinReleasePrimarySurface = winReleasePrimarySurfaceShadowDDNL; -#ifdef XWIN_MULTIWINDOW - pScreenPriv->pwinFinishCreateWindowsWindow - = (winFinishCreateWindowsWindowProcPtr) (void (*)(void)) NoopDDA; -#endif return TRUE; } diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index bf655174d..797152f13 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -62,6 +62,9 @@ static Bool winBltExposedRegionsShadowGDI(ScreenPtr pScreen); static Bool + winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin); + +static Bool winActivateAppShadowGDI(ScreenPtr pScreen); static Bool @@ -760,6 +763,12 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen) /* BeginPaint gives us an hdc that clips to the invalidated region */ hdcUpdate = BeginPaint(pScreenPriv->hwndScreen, &ps); + /* Avoid the BitBlt if the PAINTSTRUCT region is bogus */ + if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 && + ps.rcPaint.left == 0 && ps.rcPaint.top == 0) { + EndPaint(pScreenPriv->hwndScreen, &ps); + return 0; + } /* Realize the palette, if we have one */ if (pScreenPriv->pcmapInstalled != NULL) { @@ -769,11 +778,30 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen) RealizePalette(hdcUpdate); } - /* Our BitBlt will be clipped to the invalidated region */ - BitBlt(hdcUpdate, - 0, 0, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - pScreenPriv->hdcShadow, 0, 0, SRCCOPY); + /* Try to copy from the shadow buffer to the invalidated region */ + if (!BitBlt(hdcUpdate, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + pScreenPriv->hdcShadow, + ps.rcPaint.left, + ps.rcPaint.top, + SRCCOPY)) { + LPVOID lpMsgBuf; + + /* Display an error message */ + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL); + + ErrorF("winBltExposedRegionsShadowGDI - BitBlt failed: %s\n", + (LPSTR) lpMsgBuf); + LocalFree(lpMsgBuf); + } /* EndPaint frees the DC */ EndPaint(pScreenPriv->hwndScreen, &ps); @@ -789,6 +817,149 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen) } /* + * Blt exposed region to the given HWND + */ + +static Bool +winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) +{ + winScreenPriv(pScreen); + winPrivWinPtr pWinPriv = winGetWindowPriv(pWin); + + HWND hWnd = pWinPriv->hWnd; + HDC hdcUpdate; + PAINTSTRUCT ps; + + hdcUpdate = BeginPaint(hWnd, &ps); + /* Avoid the BitBlt if the PAINTSTRUCT region is bogus */ + if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 && + ps.rcPaint.left == 0 && ps.rcPaint.top == 0) { + EndPaint(hWnd, &ps); + return 0; + } + +#ifdef COMPOSITE + if (pWin->redirectDraw != RedirectDrawNone) { + HBITMAP hBitmap; + HDC hdcPixmap; + PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); + + /* + This is kind of clunky, and possibly not very efficient. + + Would it be more efficient to only create the DIB bitmap when the + composite bitmap is realloced and store it in a window private? + + But we still end up copying and converting all the bits from the + window pixmap into a DDB for every update. + + Perhaps better still would be to wrap the screen CreatePixmap routine + so it uses CreateDIBSection()? + */ + + BITMAPV4HEADER bmih; + memset(&bmih, sizeof(bmih), 0); + bmih.bV4Size = sizeof(BITMAPV4HEADER); + bmih.bV4Width = pPixmap->drawable.width; + bmih.bV4Height = -pPixmap->drawable.height; /* top-down bitmap */ + bmih.bV4Planes = 1; + bmih.bV4BitCount = pPixmap->drawable.bitsPerPixel; + bmih.bV4SizeImage = 0; + /* window pixmap format is the same as the screen pixmap */ + assert(pPixmap->drawable.bitsPerPixel > 8); + bmih.bV4V4Compression = BI_BITFIELDS; + bmih.bV4RedMask = pScreenPriv->dwRedMask; + bmih.bV4GreenMask = pScreenPriv->dwGreenMask; + bmih.bV4BlueMask = pScreenPriv->dwBlueMask; + bmih.bV4AlphaMask = 0; + + /* Create the window bitmap from the pixmap */ + hBitmap = CreateDIBitmap(pScreenPriv->hdcScreen, + (BITMAPINFOHEADER *)&bmih, CBM_INIT, + pPixmap->devPrivate.ptr, (BITMAPINFO *)&bmih, + DIB_RGB_COLORS); + + /* Select the window bitmap into a screen-compatible DC */ + hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen); + SelectObject(hdcPixmap, hBitmap); + + /* Blt from the window bitmap to the invalidated region */ + if (!BitBlt(hdcUpdate, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + hdcPixmap, + ps.rcPaint.left + pWin->borderWidth, + ps.rcPaint.top + pWin->borderWidth, + SRCCOPY)) + ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n", + GetLastError()); + + /* Release */ + DeleteDC(hdcPixmap); + DeleteObject(hBitmap); + } + else +#endif + { + /* Try to copy from the shadow buffer to the invalidated region */ + /* XXX: looks like those coordinates should get transformed ??? */ + if (!BitBlt(hdcUpdate, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + pScreenPriv->hdcShadow, + ps.rcPaint.left + pWin->drawable.x, + ps.rcPaint.top + pWin->drawable.y, + SRCCOPY)) { + LPVOID lpMsgBuf; + + /* Display an error message */ + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL); + + ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: %s\n", + (LPSTR) lpMsgBuf); + LocalFree(lpMsgBuf); + } + } + + /* If part of the invalidated region is outside the window (which can happen + if the native window is being re-sized), fill that area with black */ + if (ps.rcPaint.right > ps.rcPaint.left + pWin->drawable.width) { + BitBlt(hdcUpdate, + ps.rcPaint.left + pWin->drawable.width, + ps.rcPaint.top, + ps.rcPaint.right - (ps.rcPaint.left + pWin->drawable.width), + ps.rcPaint.bottom - ps.rcPaint.top, + NULL, + 0, 0, + BLACKNESS); + } + + if (ps.rcPaint.bottom > ps.rcPaint.top + pWin->drawable.height) { + BitBlt(hdcUpdate, + ps.rcPaint.left, + ps.rcPaint.top + pWin->drawable.height, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - (ps.rcPaint.top + pWin->drawable.height), + NULL, + 0, 0, + BLACKNESS); + } + + /* EndPaint frees the DC */ + EndPaint(hWnd, &ps); + + return TRUE; +} + +/* * Do any engine-specific appliation-activation processing */ @@ -1135,6 +1306,7 @@ winSetEngineFunctionsShadowGDI(ScreenPtr pScreen) pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowGDI; + pScreenPriv->pwinBltExposedWindowRegion = winBltExposedWindowRegionShadowGDI; pScreenPriv->pwinActivateApp = winActivateAppShadowGDI; pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowGDI; pScreenPriv->pwinRealizeInstalledPalette = @@ -1143,16 +1315,8 @@ winSetEngineFunctionsShadowGDI(ScreenPtr pScreen) pScreenPriv->pwinStoreColors = winStoreColorsShadowGDI; pScreenPriv->pwinCreateColormap = winCreateColormapShadowGDI; pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowGDI; - pScreenPriv->pwinHotKeyAltTab = - (winHotKeyAltTabProcPtr) (void (*)(void)) NoopDDA; - pScreenPriv->pwinCreatePrimarySurface = - (winCreatePrimarySurfaceProcPtr) (void (*)(void)) NoopDDA; - pScreenPriv->pwinReleasePrimarySurface = - (winReleasePrimarySurfaceProcPtr) (void (*)(void)) NoopDDA; -#ifdef XWIN_MULTIWINDOW - pScreenPriv->pwinFinishCreateWindowsWindow = - (winFinishCreateWindowsWindowProcPtr) (void (*)(void)) NoopDDA; -#endif + pScreenPriv->pwinCreatePrimarySurface = NULL; + pScreenPriv->pwinReleasePrimarySurface = NULL; return TRUE; } diff --git a/hw/xwin/wintaskbar.c b/hw/xwin/wintaskbar.c index 7dd4ec30b..401ec175a 100644 --- a/hw/xwin/wintaskbar.c +++ b/hw/xwin/wintaskbar.c @@ -66,7 +66,7 @@ DECLARE_INTERFACE_(ITaskbarList, IUnknown) seem to be the case */ -void winShowWindowOnTaskbar(HWND hWnd, BOOL show) +void winShowWindowOnTaskbar(HWND hWnd, Bool show) { ITaskbarList* pTaskbarList = NULL; diff --git a/hw/xwin/winvalargs.c b/hw/xwin/winvalargs.c index edfd71f72..f93872419 100644 --- a/hw/xwin/winvalargs.c +++ b/hw/xwin/winvalargs.c @@ -127,7 +127,7 @@ winValidateArgs(void) return FALSE; } - /* Check for -multiwindow, -mwextwm, or -rootless and fullscreen */ + /* Check for -multiwindow, -mwextwm, or -rootless and -fullscreen */ if (g_ScreenInfo[i].fFullScreen && (FALSE #ifdef XWIN_MULTIWINDOW || g_ScreenInfo[i].fMultiWindow @@ -142,6 +142,21 @@ winValidateArgs(void) return FALSE; } + /* Check for -multiwindow, -mwextwm, or -rootless and -nodecoration */ + if (!g_ScreenInfo[i].fDecoration && (FALSE +#ifdef XWIN_MULTIWINDOW + || g_ScreenInfo[i].fMultiWindow +#endif +#ifdef XWIN_MULTIWINDOWEXTWM + || g_ScreenInfo[i].fMWExtWM +#endif + || g_ScreenInfo[i].fRootless) + ) { + ErrorF("winValidateArgs - -nodecoration is invalid with " + "-multiwindow, -mwextwm, or -rootless.\n"); + return FALSE; + } + /* Check for !fullscreen and any fullscreen-only parameters */ if (!g_ScreenInfo[i].fFullScreen && (g_ScreenInfo[i].dwRefreshRate != WIN_DEFAULT_REFRESH @@ -153,7 +168,7 @@ winValidateArgs(void) /* Check for fullscreen and any non-fullscreen parameters */ if (g_ScreenInfo[i].fFullScreen - && ((g_ScreenInfo[i].iResizeMode != notAllowed) + && ((g_ScreenInfo[i].iResizeMode != resizeNotAllowed) || !g_ScreenInfo[i].fDecoration || g_ScreenInfo[i].fLessPointer)) { ErrorF("winValidateArgs - -fullscreen is invalid with " diff --git a/hw/xwin/winwin32rootless.c b/hw/xwin/winwin32rootless.c index 660a78f2d..52806887f 100644 --- a/hw/xwin/winwin32rootless.c +++ b/hw/xwin/winwin32rootless.c @@ -40,6 +40,7 @@ #define _WINDOWSWM_SERVER_ #include <X11/extensions/windowswmstr.h> #include "winmultiwindowclass.h" +#include "winmultiwindowicons.h" #include <X11/Xatom.h> /* @@ -516,12 +517,6 @@ winMWExtWMRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) win32RootlessWindowPtr pRLNextWinPriv = (win32RootlessWindowPtr) nextWid; winScreenPriv(pRLWinPriv->pFrame->win->drawable.pScreen); - winScreenInfo *pScreenInfo = NULL; - DWORD dwCurrentProcessID = GetCurrentProcessId(); - DWORD dwWindowProcessID = 0; - HWND hWnd; - Bool fFirst = TRUE; - Bool fNeedRestack = TRUE; #if CYGMULTIWINDOW_DEBUG winDebug("winMWExtWMRestackFrame (%p)\n", pRLWinPriv); @@ -530,9 +525,6 @@ winMWExtWMRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) if (pScreenPriv && pScreenPriv->fRestacking) return; - if (pScreenPriv) - pScreenInfo = pScreenPriv->pScreenInfo; - pRLWinPriv->fRestackingNow = TRUE; /* Show window */ @@ -541,68 +533,12 @@ winMWExtWMRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) if (pRLNextWinPriv == NULL) { #if CYGMULTIWINDOW_DEBUG - winDebug("Win %08x is top\n", pRLWinPriv); + winDebug("Win %p is top\n", pRLWinPriv); #endif pScreenPriv->widTop = wid; SetWindowPos(pRLWinPriv->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } - else if (winIsInternalWMRunning(pScreenInfo)) { - /* using mulwinidow wm */ -#if CYGMULTIWINDOW_DEBUG - winDebug("Win %08x is not top\n", pRLWinPriv); -#endif - for (hWnd = GetNextWindow(pRLWinPriv->hWnd, GW_HWNDPREV); - fNeedRestack && hWnd != NULL; - hWnd = GetNextWindow(hWnd, GW_HWNDPREV)) { - GetWindowThreadProcessId(hWnd, &dwWindowProcessID); - - if ((dwWindowProcessID == dwCurrentProcessID) - && GetProp(hWnd, WIN_WINDOW_PROP)) { - if (hWnd == pRLNextWinPriv->hWnd) { - /* Enable interleave X window and Windows window */ - if (!fFirst) { -#if CYGMULTIWINDOW_DEBUG - winDebug("raise: Insert after Win %08x\n", - pRLNextWinPriv); -#endif - SetWindowPos(pRLWinPriv->hWnd, pRLNextWinPriv->hWnd, - 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } - else { -#if CYGMULTIWINDOW_DEBUG - winDebug("No change\n"); -#endif - } - fNeedRestack = FALSE; - break; - } - if (fFirst) - fFirst = FALSE; - } - } - - for (hWnd = GetNextWindow(pRLWinPriv->hWnd, GW_HWNDNEXT); - fNeedRestack && hWnd != NULL; - hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) { - GetWindowThreadProcessId(hWnd, &dwWindowProcessID); - - if ((dwWindowProcessID == dwCurrentProcessID) - && GetProp(hWnd, WIN_WINDOW_PROP)) { - if (hWnd == pRLNextWinPriv->hWnd) { -#if CYGMULTIWINDOW_DEBUG - winDebug("lower: Insert after Win %08x\n", pRLNextWinPriv); -#endif - SetWindowPos(pRLWinPriv->hWnd, pRLNextWinPriv->hWnd, - 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - fNeedRestack = FALSE; - break; - } - } - } - } else { /* using general wm like twm, wmaker etc. Interleave X window and Windows window will cause problem. */ diff --git a/hw/xwin/winwin32rootlesswindow.c b/hw/xwin/winwin32rootlesswindow.c index 1faa531df..817cd093e 100644 --- a/hw/xwin/winwin32rootlesswindow.c +++ b/hw/xwin/winwin32rootlesswindow.c @@ -194,10 +194,6 @@ winMWExtWMUpdateWindowDecoration(win32RootlessWindowPtr pRLWinPriv, /* Get current window placement */ GetWindowPlacement(pRLWinPriv->hWnd, &wndPlace); - if (winIsInternalWMRunning(pScreenInfo)) { - if (!pRLWinPriv->pFrame->win->overrideRedirect) - fDecorate = TRUE; - } #if 0 if (wndPlace.showCmd == SW_HIDE) return; //showCmd = SWP_HIDEWINDOW; @@ -345,15 +341,6 @@ winMWExtWMUpdateWindowDecoration(win32RootlessWindowPtr pRLWinPriv, } /* - * winIsInternalWMRunning (winScreenInfoPtr pScreenInfo) - */ -Bool -winIsInternalWMRunning(winScreenInfoPtr pScreenInfo) -{ - return pScreenInfo->fInternalWM && !pScreenInfo->fAnotherWMRunning; -} - -/* * winMWExtWMRestackWindows */ @@ -402,7 +389,7 @@ winMWExtWMRestackWindows(ScreenPtr pScreen) #if CYGMULTIWINDOW_DEBUG winDebug - ("winMWExtWMRestackWindows - DeferWindowPos (%08x, %08x)\n", + ("winMWExtWMRestackWindows - DeferWindowPos (%p, %p)\n", pRLWin->hWnd, pRLWinPrev ? pRLWinPrev->hWnd : HWND_TOP); #endif hWinPosInfo = DeferWindowPos(hWinPosInfo, pRLWin->hWnd, diff --git a/hw/xwin/winwin32rootlesswndproc.c b/hw/xwin/winwin32rootlesswndproc.c index 79d959161..85c9cbf22 100644 --- a/hw/xwin/winwin32rootlesswndproc.c +++ b/hw/xwin/winwin32rootlesswndproc.c @@ -42,6 +42,7 @@ #include "winmultiwindowclass.h" #include "winmsg.h" #include "inputstr.h" +#include "wmutil/keyboard.h" /* * Constant defines @@ -60,9 +61,9 @@ static UINT_PTR g_uipMousePollingTimerID = 0; * Local function */ -DEFINE_ATOM_HELPER(AtmWindowsWmRaiseOnClick, WINDOWSWM_RAISE_ON_CLICK) - DEFINE_ATOM_HELPER(AtmWindowsWMMouseActivate, WINDOWSWM_MOUSE_ACTIVATE) +DEFINE_ATOM_HELPER(AtmWindowsWMMouseActivate, WINDOWSWM_MOUSE_ACTIVATE) /* DEFINE_ATOM_HELPER(AtmWindowsWMClientWindow, WINDOWSWM_CLIENT_WINDOW) */ + /* * ConstrainSize - Taken from TWM sources - Respects hints for sizing */ @@ -272,55 +273,6 @@ ValidateSizing(HWND hwnd, WindowPtr pWin, WPARAM wParam, LPARAM lParam) } /* - * IsRaiseOnClick - */ - -static Bool -IsRaiseOnClick(WindowPtr pWin) -{ - - struct _Window *pwin; - struct _Property *prop; - - /* XXX We're getting inputInfo.poniter here, but this might be really wrong. - * Which pointer's current window do we want? */ - WindowPtr pRoot = GetCurrentRootWindow(inputInfo.pointer); - - if (!pWin) { - ErrorF("IsRaiseOnClick - no prop use default value:%d\n", - RAISE_ON_CLICK_DEFAULT); - return RAISE_ON_CLICK_DEFAULT; - } - - pwin = (struct _Window *) pWin; - - if (pwin->optional) - prop = (struct _Property *) pwin->optional->userProps; - else - prop = NULL; - - while (prop) { - if (prop->propertyName == AtmWindowsWmRaiseOnClick() - && prop->type == XA_INTEGER && prop->format == 32) { - return *(int *) prop->data; - } - else - prop = prop->next; - } - - if (pWin != pRoot) { - return IsRaiseOnClick(pRoot); - } - else { -#if CYGMULTIWINDOW_DEBUG - winDebug("IsRaiseOnClick - no prop use default value:%d\n", - RAISE_ON_CLICK_DEFAULT); -#endif - return RAISE_ON_CLICK_DEFAULT; - } -} - -/* * IsMouseActive */ @@ -388,8 +340,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) PAINTSTRUCT ps; LPWINDOWPOS pWinPos = NULL; RECT rcClient; - winWMMessageRec wmMsg; - Bool fWMMsgInitialized = FALSE; /* Check if the Windows window property for our X window pointer is valid */ if ((pRLWinPriv = @@ -403,26 +353,16 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (pScreenPriv) hwndScreen = pScreenPriv->hwndScreen; - wmMsg.msg = 0; - wmMsg.hwndWindow = hwnd; - wmMsg.iWindow = (Window) pWin->drawable.id; - - wmMsg.iX = pRLWinPriv->pFrame->x; - wmMsg.iY = pRLWinPriv->pFrame->y; - wmMsg.iWidth = pRLWinPriv->pFrame->width; - wmMsg.iHeight = pRLWinPriv->pFrame->height; - - fWMMsgInitialized = TRUE; #if CYGDEBUG winDebugWin32Message("winMWExtWMWindowProc", hwnd, message, wParam, lParam); - winDebug("\thWnd %08X\n", hwnd); - winDebug("\tpScreenPriv %08X\n", pScreenPriv); - winDebug("\tpScreenInfo %08X\n", pScreenInfo); - winDebug("\thwndScreen %08X\n", hwndScreen); - winDebug("winMWExtWMWindowProc (%08x) %08x %08x %08x\n", - pRLWinPriv, message, wParam, lParam); + winDebug("\thWnd %p\n", hwnd); + winDebug("\tpScreenPriv %p\n", pScreenPriv); + winDebug("\tpScreenInfo %p\n", pScreenInfo); + winDebug("\thwndScreen %p\n", hwndScreen); + winDebug("winMWExtWMWindowProc (%p) %08x %08x %08x\n", + pRLWinPriv, message, (int)wParam, (int)lParam); #endif } /* Branch on message type */ @@ -446,12 +386,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) DestroyWindow(hwnd); } else { - if (winIsInternalWMRunning(pScreenInfo)) { - /* Tell our Window Manager thread to kill the window */ - wmMsg.msg = WM_WM_KILL; - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } winWindowsWMSendEvent(WindowsWMControllerNotify, WindowsWMControllerNotifyMask, 1, @@ -680,19 +614,7 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #if CYGMULTIWINDOW_DEBUG winDebug("winMWExtWMWindowProc - WM_MOUSEACTIVATE\n"); #endif -#if 1 - /* Check if this window needs to be made active when clicked */ - if (winIsInternalWMRunning(pScreenInfo) && pWin->overrideRedirect) { -#if CYGMULTIWINDOW_DEBUG - winDebug("winMWExtWMWindowProc - WM_MOUSEACTIVATE - " - "MA_NOACTIVATE\n"); -#endif - - /* */ - return MA_NOACTIVATE; - } -#endif - if (!winIsInternalWMRunning(pScreenInfo) && !IsMouseActive(pWin)) + if (!IsMouseActive(pWin)) return MA_NOACTIVATE; break; @@ -805,19 +727,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) winDebug("winMWExtWMWindowProc - WM_ACTIVATE\n"); #endif if (LOWORD(wParam) != WA_INACTIVE) { - if (winIsInternalWMRunning(pScreenInfo)) { -#if 0 - /* Raise the window to the top in Z order */ - wmMsg.msg = WM_WM_RAISE; - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); -#endif - /* Tell our Window Manager thread to activate the window */ - wmMsg.msg = WM_WM_ACTIVATE; - if (fWMMsgInitialized) - if (!pWin || !pWin->overrideRedirect) /* for OOo menus */ - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } winWindowsWMSendEvent(WindowsWMControllerNotify, WindowsWMControllerNotifyMask, 1, @@ -838,14 +747,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; } - if (winIsInternalWMRunning(pScreenInfo) || IsRaiseOnClick(pWin)) { -#if CYGMULTIWINDOW_DEBUG - winDebug("Win %p has WINDOWSWM_RAISE_ON_CLICK.\n", - pRLWinPriv); -#endif - break; - } - #if CYGMULTIWINDOW_DEBUG winDebug("Win %p forbid to change z order (%p).\n", pRLWinPriv, @@ -889,9 +790,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (short) HIWORD(lParam)); #endif if (!pRLWinPriv->fMovingOrSizing) { - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); - winMWExtWMMoveXWindow(pWin, (LOWORD(lParam) - wBorderWidth(pWin) - GetSystemMetrics(SM_XVIRTUALSCREEN)), (HIWORD(lParam) - wBorderWidth(pWin) @@ -907,31 +805,8 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (!wParam) return 0; - if (!pScreenInfo->fInternalWM) //XXXX - return 0; - winMWExtWMUpdateWindowDecoration(pRLWinPriv, pScreenInfo); - if (winIsInternalWMRunning(pScreenInfo)) { -#if CYGMULTIWINDOW_DEBUG || TRUE - winDebug("\tMapWindow\n"); -#endif - /* Tell X to map the window */ - MapWindow(pWin, wClient(pWin)); - - if (!pRLWinPriv->pFrame->win->overrideRedirect) - /* Bring the Windows window to the foreground */ - SetForegroundWindow(hwnd); - - /* Setup the Window Manager message */ - wmMsg.msg = WM_WM_MAP; - wmMsg.iWidth = pRLWinPriv->pFrame->width; - wmMsg.iHeight = pRLWinPriv->pFrame->height; - - /* Tell our Window Manager thread to map the window */ - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } break; case WM_SIZING: @@ -967,72 +842,12 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (pWinPos->flags & SWP_HIDEWINDOW) break; - /* Reorder if window z order was changed */ - if ((pScreenPriv != NULL) - && !(pWinPos->flags & SWP_NOZORDER) - && !(pWinPos->flags & SWP_SHOWWINDOW) - && winIsInternalWMRunning(pScreenInfo)) { -#if CYGMULTIWINDOW_DEBUG - winDebug("\twindow z order was changed\n"); -#endif - if (pWinPos->hwndInsertAfter == HWND_TOP - || pWinPos->hwndInsertAfter == HWND_TOPMOST - || pWinPos->hwndInsertAfter == HWND_NOTOPMOST) { -#if CYGMULTIWINDOW_DEBUG - winDebug("\traise to top\n"); -#endif - /* Raise the window to the top in Z order */ - wmMsg.msg = WM_WM_RAISE; - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } -#if 1 - else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) { - } - else { - /* Check if this window is top of X windows. */ - HWND hWndAbove = NULL; - DWORD dwCurrentProcessID = GetCurrentProcessId(); - DWORD dwWindowProcessID = 0; - - for (hWndAbove = pWinPos->hwndInsertAfter; - hWndAbove != NULL; - hWndAbove = GetNextWindow(hWndAbove, GW_HWNDPREV)) { - /* Ignore other XWin process's window */ - GetWindowThreadProcessId(hWndAbove, &dwWindowProcessID); - - if ((dwWindowProcessID == dwCurrentProcessID) - && GetProp(hWndAbove, WIN_WINDOW_PROP) - && !IsWindowVisible(hWndAbove) - && !IsIconic(hWndAbove)) /* ignore minimized windows */ - break; - } - /* If this is top of X windows in Windows stack, - raise it in X stack. */ - if (hWndAbove == NULL) { -#if CYGMULTIWINDOW_DEBUG - winDebug("\traise to top\n"); -#endif - /* Raise the window to the top in Z order */ - wmMsg.msg = WM_WM_RAISE; - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } - } -#endif - } - if (!(pWinPos->flags & SWP_NOSIZE)) { if (IsIconic(hwnd)) { #if CYGMULTIWINDOW_DEBUG winDebug("\tIconic -> MINIMIZED\n"); #endif - if (winIsInternalWMRunning(pScreenInfo)) { - /* Raise the window to the top in Z order */ - wmMsg.msg = WM_WM_LOWER; - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } + winWindowsWMSendEvent(WindowsWMControllerNotify, WindowsWMControllerNotifyMask, 1, @@ -1072,8 +887,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #if CYGMULTIWINDOW_DEBUG winDebug("\tmove & resize\n"); #endif - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); winMWExtWMMoveResizeXWindow(pWin, rcClient.left - @@ -1095,8 +908,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #if CYGMULTIWINDOW_DEBUG winDebug("\tmove\n"); #endif - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); winMWExtWMMoveResizeXWindow(pWin, rcClient.left - @@ -1118,8 +929,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #if CYGMULTIWINDOW_DEBUG winDebug("\tmove\n"); #endif - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); winMWExtWMMoveXWindow(pWin, rcClient.left - wBorderWidth(pWin) @@ -1132,8 +941,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #if CYGMULTIWINDOW_DEBUG winDebug("\tresize\n"); #endif - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); winMWExtWMResizeXWindow(pWin, rcClient.right - rcClient.left @@ -1168,12 +975,7 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #if CYGMULTIWINDOW_DEBUG winDebug("\tSIZE_MINIMIZED\n"); #endif - if (winIsInternalWMRunning(pScreenInfo)) { - /* Raise the window to the top in Z order */ - wmMsg.msg = WM_WM_LOWER; - if (fWMMsgInitialized) - winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg); - } + winWindowsWMSendEvent(WindowsWMControllerNotify, WindowsWMControllerNotifyMask, 1, @@ -1209,9 +1011,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Perform the resize and notify the X client */ if (!pRLWinPriv->fMovingOrSizing) { - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); - winMWExtWMResizeXWindow(pWin, (short) LOWORD(lParam) - wBorderWidth(pWin) * 2, (short) HIWORD(lParam) @@ -1224,10 +1023,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) winDebug("winMWExtWMWindowProc - WM_ACTIVATEAPP\n"); #endif if (wParam) { - if (winIsInternalWMRunning(pScreenInfo)) { - } - else { - } winWindowsWMSendEvent(WindowsWMActivationNotify, WindowsWMActivationNotifyMask, 1, @@ -1268,9 +1063,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT) &rcClient, 2); - if (winIsInternalWMRunning(pScreenInfo)) - winAdjustXWindow(pWin, hwnd); - winMWExtWMMoveResizeXWindow(pWin, rcClient.left - wBorderWidth(pWin) - GetSystemMetrics(SM_XVIRTUALSCREEN), rcClient.top - wBorderWidth(pWin) @@ -1281,14 +1073,6 @@ winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) - wBorderWidth(pWin) * 2); break; - case WM_MANAGE: - ErrorF("winMWExtWMWindowProc - WM_MANAGE\n"); - break; - - case WM_UNMANAGE: - ErrorF("winMWExtWMWindowProc - WM_UNMANAGE\n"); - break; - default: break; } diff --git a/hw/xwin/winwindow.h b/hw/xwin/winwindow.h index 7e6bd565c..83c772c09 100644 --- a/hw/xwin/winwindow.h +++ b/hw/xwin/winwindow.h @@ -1,5 +1,3 @@ -#if !defined(_WINWINDOW_H_) -#define _WINWINDOW_H_ /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. *Copyright (C) Colin Harrison 2005-2009 @@ -31,6 +29,8 @@ * Authors: Kensuke Matsuzaki * Colin Harrison */ +#if !defined(_WINWINDOW_H_) +#define _WINWINDOW_H_ #ifndef NO #define NO 0 @@ -50,6 +50,7 @@ #define WIN_SCR_PROP "cyg_screen_prop rl" #define WINDOW_CLASS_X "cygwin/x X rl" #define WINDOW_CLASS_X_MSG "cygwin/x X msg" +#define WINDOW_CLASS_X_CHILD "cygwin/x X child" #define WINDOW_TITLE_X PROJECT_NAME " X" #define WIN_WINDOW_PROP "cyg_window_prop_rl" #ifdef HAS_DEVWINDOWS @@ -57,6 +58,7 @@ #endif #define WIN_WID_PROP "cyg_wid_prop_rl" #define WIN_NEEDMANAGE_PROP "cyg_override_redirect_prop_rl" +#define WIN_STATE_PROP "cyg_state_prop_rl" #ifndef CYGMULTIWINDOW_DEBUG #define CYGMULTIWINDOW_DEBUG NO #endif @@ -109,11 +111,9 @@ typedef struct _winWMMessageRec { #define WM_WM_NAME_EVENT (WM_USER + 9) #define WM_WM_ICON_EVENT (WM_USER + 10) #define WM_WM_CHANGE_STATE (WM_USER + 11) -#define WM_WM_MAP2 (WM_USER + 12) -#define WM_WM_MAP3 (WM_USER + 13) +#define WM_WM_MAP_UNMANAGED (WM_USER + 12) +#define WM_WM_MAP_MANAGED (WM_USER + 13) #define WM_WM_HINTS_EVENT (WM_USER + 14) -#define WM_MANAGE (WM_USER + 100) -#define WM_UNMANAGE (WM_USER + 102) #define MwmHintsDecorations (1L << 1) @@ -125,10 +125,16 @@ typedef struct _winWMMessageRec { #define MwmDecorMinimize (1L << 5) #define MwmDecorMaximize (1L << 6) -/* This structure only contains 3 elements... the Motif 2.0 structure -contains 5... we only need the first 3... so that is all we will define */ +/* + This structure only contains 3 elements. The Motif 2.0 structure contains 5, + but we only need the first 3, so that is all we will define + + This structure represents xcb_get_property()'s view of the property as a + sequence of ints, rather than XGetWindowProperty()'s view of the property as a + sequence of arch-dependent longs. +*/ typedef struct MwmHints { - unsigned long flags, functions, decorations; + unsigned int flags, functions, decorations; } MwmHints; #define PropMwmHintsElements 3 @@ -142,15 +148,12 @@ winInitWM(void **ppWMInfo, pthread_t * ptWMProc, pthread_t * ptXMsgProc, pthread_mutex_t * ppmServerStarted, - int dwScreen, HWND hwndScreen, BOOL allowOtherWM); + int dwScreen, HWND hwndScreen, Bool compositeWM); void winDeinitMultiWindowWM(void); void - winMinimizeWindow(Window id); - -void winPropertyStoreInit(void); void @@ -160,7 +163,7 @@ void winSetAppUserModelID(HWND hWnd, const char *AppID); void - winShowWindowOnTaskbar(HWND hWnd, BOOL show); + winShowWindowOnTaskbar(HWND hWnd, Bool show); #endif /* XWIN_MULTIWINDOW */ #endif diff --git a/hw/xwin/winwindowswm.c b/hw/xwin/winwindowswm.c index db41d6b60..b9399fae3 100644 --- a/hw/xwin/winwindowswm.c +++ b/hw/xwin/winwindowswm.c @@ -312,7 +312,7 @@ ProcWindowsWMFrameGetRect(ClientPtr client) REQUEST(xWindowsWMFrameGetRectReq); #if CYGMULTIWINDOW_DEBUG - ErrorF("ProcWindowsWMFrameGetRect %d %d\n", + ErrorF("ProcWindowsWMFrameGetRect %zu %d\n", (sizeof(xWindowsWMFrameGetRectReq) >> 2), (int) client->req_len); #endif diff --git a/hw/xwin/winwndproc.c b/hw/xwin/winwndproc.c index 123b84f31..61c185785 100644 --- a/hw/xwin/winwndproc.c +++ b/hw/xwin/winwndproc.c @@ -45,6 +45,8 @@ #ifdef XWIN_CLIPBOARD #include "winclipboard/winclipboard.h" #endif +#include "wmutil/mouse.h" +#include "wmutil/keyboard.h" /* * Global variables @@ -290,22 +292,16 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) * the display dimensions change. */ - /* - * NOTE: The non-DirectDraw engines set the ReleasePrimarySurface - * and CreatePrimarySurface function pointers to point - * to the no operation function, NoopDDA. This allows us - * to blindly call these functions, even if they are not - * relevant to the current engine (e.g., Shadow GDI). - */ - winDebug ("winWindowProc - WM_DISPLAYCHANGE - Releasing and recreating primary surface\n"); /* Release the old primary surface */ - (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen); + if (*s_pScreenPriv->pwinReleasePrimarySurface) + (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen); /* Create the new primary surface */ - (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen); + if (*s_pScreenPriv->pwinCreatePrimarySurface) + (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen); } } @@ -322,7 +318,7 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #endif /* Break if we do not allow resizing */ - if ((s_pScreenInfo->iResizeMode == notAllowed) + if ((s_pScreenInfo->iResizeMode == resizeNotAllowed) || !s_pScreenInfo->fDecoration #ifdef XWIN_MULTIWINDOWEXTWM || s_pScreenInfo->fMWExtWM @@ -909,7 +905,7 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (wParam) { case WIN_E3B_TIMER_ID: /* Send delayed button press */ - winMouseButtonsSendEvent(ButtonPress, + winMouseButtonsSendEvent(TRUE, s_pScreenPriv->iE3BCachedPress); /* Kill this timer */ @@ -1107,14 +1103,6 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) winFixShiftKeys(iScanCode); return 0; - case WM_HOTKEY: - if (s_pScreenPriv == NULL) - break; - - /* Call the engine-specific hot key handler */ - (*s_pScreenPriv->pwinHotKeyAltTab) (s_pScreen); - return 0; - case WM_ACTIVATE: if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) break; @@ -1192,7 +1180,7 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #ifdef XWIN_MULTIWINDOWEXTWM if (s_pScreenPriv->fActive) { /* Restack all window unless using built-in wm. */ - if (s_pScreenInfo->fInternalWM && s_pScreenInfo->fAnotherWMRunning) + if (s_pScreenInfo->fMWExtWM) winMWExtWMRestackWindows(s_pScreen); } #endif @@ -1256,28 +1244,6 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; -#ifdef XWIN_MULTIWINDOWEXTWM - case WM_MANAGE: - ErrorF("winWindowProc - WM_MANAGE\n"); - s_pScreenInfo->fAnotherWMRunning = FALSE; - - if (s_pScreenInfo->fInternalWM) { - EnumThreadWindows(g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0); - //RootlessRepositionWindows (s_pScreen); - } - break; - - case WM_UNMANAGE: - ErrorF("winWindowProc - WM_UNMANAGE\n"); - s_pScreenInfo->fAnotherWMRunning = TRUE; - - if (s_pScreenInfo->fInternalWM) { - EnumThreadWindows(g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0); - winMWExtWMRestackWindows(s_pScreen); - } - break; -#endif - default: if (message == s_uTaskbarRestart) { winInitNotifyIcon(s_pScreenPriv); diff --git a/hw/xwin/wmutil/Makefile.am b/hw/xwin/wmutil/Makefile.am new file mode 100644 index 000000000..d4e213b7f --- /dev/null +++ b/hw/xwin/wmutil/Makefile.am @@ -0,0 +1,24 @@ +lib_LTLIBRARIES = libXWinWMUtil.la + +library_includedir=$(includedir)/XWinWMUtil + +library_include_HEADERS = \ + icon_convert.h \ + cursor_convert.h \ + mouse.h \ + keyboard.h + +libXWinWMUtil_la_SOURCES = \ + icon_convert.c \ + cursor_convert.c \ + mouse.c \ + keyboard.c \ + winvkmap.h \ + scancodes.h + +AM_CFLAGS = -DHAVE_XWIN_CONFIG_H \ + $(DIX_CFLAGS) \ + $(XWINMODULES_CFLAGS) \ + -I$(top_srcdir) -I$(top_srcdir)/miext/rootless -I$(srcdir)/.. + +libXWinWMUtil_la_LDFLAGS = -static -no-undefined diff --git a/hw/xwin/wmutil/cursor_convert.c b/hw/xwin/wmutil/cursor_convert.c new file mode 100644 index 000000000..b91200478 --- /dev/null +++ b/hw/xwin/wmutil/cursor_convert.c @@ -0,0 +1,351 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + +#include <X11/Xwindows.h> + +#include "win.h" +#include "winmsg.h" +#include <cursorstr.h> + +#include "cursor_convert.h" + +#define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114) + +#if 1 +#define WIN_DEBUG_MSG winDebug +#else +#define WIN_DEBUG_MSG(...) +#endif + +static unsigned char +reverse(unsigned char c) +{ + int i; + unsigned char ret = 0; + + for (i = 0; i < 8; ++i) { + ret |= ((c >> i) & 1) << (7 - i); + } + return ret; +} + +/* + * Convert X cursor to Windows cursor + * FIXME: Perhaps there are more smart code + */ +HCURSOR +winXCursorToHCURSOR(WMUTIL_CURSOR *pCursor) +{ + HCURSOR hCursor = NULL; + unsigned char *pAnd; + unsigned char *pXor; + int nCX, nCY; + int nBytes; + double dForeY, dBackY; + BOOL fReverse; + HBITMAP hAnd, hXor; + ICONINFO ii; + unsigned char *pCur; + unsigned char bit; + HDC hDC; + BITMAPV4HEADER bi; + BITMAPINFO *pbmi; + uint32_t *lpBits; + + int sm_cx = GetSystemMetrics(SM_CXCURSOR); + int sm_cy = GetSystemMetrics(SM_CYCURSOR); + + WIN_DEBUG_MSG("winXCursorToHCURSOR: Win32 size: %dx%d X11 size: %dx%d hotspot: %d,%d\n", + sm_cx, sm_cy, + pCursor->width, pCursor->height, + pCursor->xhot, pCursor->yhot); + + /* We can use only White and Black, so calc brightness of color + * Also check if the cursor is inverted */ + dForeY = BRIGHTNESS(pCursor->fore); + dBackY = BRIGHTNESS(pCursor->back); + fReverse = dForeY < dBackY; + + /* Check whether the X11 cursor is bigger than the win32 cursor */ + if (sm_cx < pCursor->width || + sm_cy < pCursor->height) { + winError("winXCursorToHCURSOR - Windows requires %dx%d cursor but X requires %dx%d\n", + sm_cx, sm_cy, + pCursor->width, pCursor->height); + } + + /* Get the number of bytes required to store the whole cursor image + * This is roughly (sm_cx * sm_cy) / 8 + * round up to 8 pixel boundary so we can convert whole bytes */ + nBytes = + bits_to_bytes(sm_cx) * sm_cy; + + /* Get the effective width and height */ + nCX = min(sm_cx, pCursor->width); + nCY = min(sm_cy, pCursor->height); + + /* Allocate memory for the bitmaps */ + pAnd = malloc(nBytes); + memset(pAnd, 0xFF, nBytes); + pXor = calloc(1, nBytes); + memset(pXor, 0x00, nBytes); + + /* prepare the pointers */ + hCursor = NULL; + lpBits = NULL; + + /* We have a truecolor alpha-blended cursor and can use it! */ + if (pCursor->argb) { + WIN_DEBUG_MSG("winXCursorToHCURSOR: Trying truecolor alphablended cursor\n"); + memset(&bi, 0, sizeof(BITMAPV4HEADER)); + bi.bV4Size = sizeof(BITMAPV4HEADER); + bi.bV4Width = sm_cx; + bi.bV4Height = -(sm_cy); /* right-side up */ + bi.bV4Planes = 1; + bi.bV4BitCount = 32; + bi.bV4V4Compression = BI_BITFIELDS; + bi.bV4RedMask = 0x00FF0000; + bi.bV4GreenMask = 0x0000FF00; + bi.bV4BlueMask = 0x000000FF; + bi.bV4AlphaMask = 0xFF000000; + + lpBits = calloc(sm_cx * sm_cy, sizeof(uint32_t)); + + if (lpBits) { + int y; + for (y = 0; y < nCY; y++) { + void *src, *dst; + src = &(pCursor->argb[y * pCursor->width]); + dst = &(lpBits[y * sm_cx]); + memcpy(dst, src, 4 * nCX); + } + } + } /* End if-truecolor-icon */ + else + { + /* Convert the X11 bitmap to a win32 bitmap + * The first is for an empty mask */ + if (pCursor->emptyMask) { + int x, y, xmax = bits_to_bytes(nCX); + + for (y = 0; y < nCY; ++y) + for (x = 0; x < xmax; ++x) { + int nWinPix = bits_to_bytes(sm_cx) * y + x; + int nXPix = BitmapBytePad(pCursor->width) * y + x; + + pAnd[nWinPix] = 0; + if (fReverse) + pXor[nWinPix] = reverse(~pCursor->source[nXPix]); + else + pXor[nWinPix] = reverse(pCursor->source[nXPix]); + } + } + else { + int x, y, xmax = bits_to_bytes(nCX); + + for (y = 0; y < nCY; ++y) + for (x = 0; x < xmax; ++x) { + int nWinPix = bits_to_bytes(sm_cx) * y + x; + int nXPix = BitmapBytePad(pCursor->width) * y + x; + + unsigned char mask = pCursor->mask[nXPix]; + + pAnd[nWinPix] = reverse(~mask); + if (fReverse) + pXor[nWinPix] = + reverse(~pCursor->source[nXPix] & mask); + else + pXor[nWinPix] = + reverse(pCursor->source[nXPix] & mask); + } + } + } + + if (!lpBits) { + RGBQUAD *pbmiColors; + /* Bicolor, use a palettized DIB */ + WIN_DEBUG_MSG("winXCursorToHCURSOR: Trying two color cursor\n"); + pbmi = (BITMAPINFO *) &bi; + pbmiColors = &(pbmi->bmiColors[0]); + + memset(pbmi, 0, sizeof(BITMAPINFOHEADER)); + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = sm_cx; + pbmi->bmiHeader.biHeight = -abs(sm_cy); /* right-side up */ + pbmi->bmiHeader.biPlanes = 1; + pbmi->bmiHeader.biBitCount = 8; + pbmi->bmiHeader.biCompression = BI_RGB; + pbmi->bmiHeader.biSizeImage = 0; + pbmi->bmiHeader.biClrUsed = 3; + pbmi->bmiHeader.biClrImportant = 3; + + pbmiColors[0].rgbRed = 0; /* Empty */ + pbmiColors[0].rgbGreen = 0; + pbmiColors[0].rgbBlue = 0; + pbmiColors[0].rgbReserved = 0; + pbmiColors[1].rgbRed = pCursor->backRed >> 8; /* Background */ + pbmiColors[1].rgbGreen = pCursor->backGreen >> 8; + pbmiColors[1].rgbBlue = pCursor->backBlue >> 8; + pbmiColors[1].rgbReserved = 0; + pbmiColors[2].rgbRed = pCursor->foreRed >> 8; /* Foreground */ + pbmiColors[2].rgbGreen = pCursor->foreGreen >> 8; + pbmiColors[2].rgbBlue = pCursor->foreBlue >> 8; + pbmiColors[2].rgbReserved = 0; + + lpBits = calloc(sm_cx * sm_cy, 1); + + pCur = (unsigned char *) lpBits; + if (lpBits) { + int x, y; + for (y = 0; y < sm_cy; y++) { + for (x = 0; x < sm_cx; x++) { + if (x >= nCX || y >= nCY) /* Outside of X11 icon bounds */ + (*pCur++) = 0; + else { /* Within X11 icon bounds */ + + int nWinPix = + bits_to_bytes(sm_cx) * y + + (x / 8); + + bit = pAnd[nWinPix]; + bit = bit & (1 << (7 - (x & 7))); + if (!bit) { /* Within the cursor mask? */ + int nXPix = + BitmapBytePad(pCursor->width) * y + + (x / 8); + bit = + ~reverse(~pCursor-> + source[nXPix] & pCursor-> + mask[nXPix]); + bit = bit & (1 << (7 - (x & 7))); + if (bit) /* Draw foreground */ + (*pCur++) = 2; + else /* Draw background */ + (*pCur++) = 1; + } + else /* Outside the cursor mask */ + (*pCur++) = 0; + } + } /* end for (x) */ + } /* end for (y) */ + } /* end if (lpbits) */ + } + + /* If one of the previous two methods gave us the bitmap we need, make a cursor */ + if (lpBits) { + WIN_DEBUG_MSG("winXCursorToHCURSOR: Creating bitmap cursor\n"); + + hAnd = NULL; + hXor = NULL; + + hAnd = + CreateBitmap(sm_cx, sm_cy, + 1, 1, pAnd); + + hDC = GetDC(NULL); + if (hDC) { + hXor = + CreateCompatibleBitmap(hDC, sm_cx, + sm_cy); + SetDIBits(hDC, hXor, 0, sm_cy, lpBits, + (BITMAPINFO *) &bi, DIB_RGB_COLORS); + ReleaseDC(NULL, hDC); + } + free(lpBits); + + if (hAnd && hXor) { + ii.fIcon = FALSE; + ii.xHotspot = pCursor->xhot; + ii.yHotspot = pCursor->yhot; + ii.hbmMask = hAnd; + ii.hbmColor = hXor; + hCursor = (HCURSOR) CreateIconIndirect(&ii); + + if (hCursor == NULL) + winError("winXCursorToHCURSOR - CreateIconIndirect failed: %x", GetLastError()); + else { + /* + Apparently, CreateIconIndirect() sometimes creates an Icon instead of a Cursor. + This breaks the hotspot and makes the cursor unusable. Discard the broken cursor + and revert to simple b&w cursor. (Seen on W2K in 2004...) + */ + if (GetIconInfo(hCursor, &ii)) { + if (ii.fIcon) { + winError + ("winXCursorToHCURSOR: CreateIconIndirect made an icon, not a cursor. Trying again.\n"); + + DestroyCursor(hCursor); + + ii.fIcon = FALSE; + ii.xHotspot = pCursor->xhot; + ii.yHotspot = pCursor->yhot; + hCursor = (HCURSOR) CreateIconIndirect(&ii); + + if (hCursor == NULL) + winError("winXCursorToHCURSOR - CreateIconIndirect failed: %x", GetLastError()); + } + /* GetIconInfo creates new bitmaps. Destroy them again */ + if (ii.hbmMask) + DeleteObject(ii.hbmMask); + if (ii.hbmColor) + DeleteObject(ii.hbmColor); + } + } + } + + if (hAnd) + DeleteObject(hAnd); + if (hXor) + DeleteObject(hXor); + } + + if (!hCursor) { + WIN_DEBUG_MSG("winXCursorToHCURSOR: Creating b&w cursor\n"); + /* We couldn't make a color cursor for this screen, use + black and white instead */ + hCursor = CreateCursor(GetModuleHandle(NULL), + pCursor->xhot, pCursor->yhot, + sm_cx, + sm_cy, pAnd, pXor); + if (hCursor == NULL) + winError("winXCursorToHCURSOR - CreateCursor failed: %x", GetLastError()); + } + free(pAnd); + free(pXor); + + return hCursor; +} diff --git a/hw/xwin/wmutil/cursor_convert.h b/hw/xwin/wmutil/cursor_convert.h new file mode 100644 index 000000000..a5ddba3c2 --- /dev/null +++ b/hw/xwin/wmutil/cursor_convert.h @@ -0,0 +1,54 @@ +/* + * File: cursor_convert.h + * Purpose: interface for X->Windows cursor conversion + * + * Copyright (c) Jon TURNEY 2012 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef WMUTILS_CURSOR_H +#define WMUTILS_CURSOR_H + +#include <stdbool.h> +#include <stdint.h> + +typedef struct _WMUTIL_CURSOR +{ + // this is the data for cursor created with RENDER CreateCusor or read + // with XFIXES GetCursorImage + int width; + int height; + int xhot; + int yhot; + uint32_t *argb; + + // for a core CreateCursor, we might need the following... + unsigned char *source; + unsigned char *mask; + bool emptyMask; + unsigned short foreRed, foreGreen, foreBlue; + unsigned short backRed, backGreen, backBlue; + +} WMUTIL_CURSOR; + +HCURSOR +winXCursorToHCURSOR(WMUTIL_CURSOR *cursordata); + +#endif /* WMUTILS_CURSOR_H */ diff --git a/hw/xwin/wmutil/icon_convert.c b/hw/xwin/wmutil/icon_convert.c new file mode 100644 index 000000000..be9f4e027 --- /dev/null +++ b/hw/xwin/wmutil/icon_convert.c @@ -0,0 +1,572 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + +#ifndef WINVER +#define WINVER 0x0500 +#endif + +#include <xcb/xcb.h> +#include <xcb/xcb_icccm.h> +#include <xcb/xcb_image.h> + +#include <windows.h> + +#include <limits.h> +#include <stdbool.h> + +#include "winmsg.h" + +#include "icon_convert.h" + +extern unsigned long serverGeneration; + +/* + * Scale an X icon ZPixmap into a Windoze icon bitmap + */ + +static void +winScaleXImageToWindowsIcon(int iconSize, + int effBPP, + int stride, xcb_image_t* pixmap, unsigned char *image) +{ + int row, column, effXBPP, effXDepth; + unsigned char *outPtr; + unsigned char *iconData = 0; + int xStride; + float factX, factY; + int posX, posY; + unsigned char *ptr; + unsigned int zero; + unsigned int color; + + effXBPP = pixmap->bpp; + if (pixmap->bpp == 15) + effXBPP = 16; + + effXDepth = pixmap->depth; + if (pixmap->depth == 15) + effXDepth = 16; + + xStride = pixmap->stride; + if (stride == 0 || xStride == 0) { + winError("winScaleXBitmapToWindows - stride or xStride is zero. " + "Bailing.\n"); + return; + } + + /* Get icon data */ + iconData = (unsigned char *) pixmap->data; + + /* Keep aspect ratio */ + factX = ((float) pixmap->width) / ((float) iconSize); + factY = ((float) pixmap->height) / ((float) iconSize); + if (factX > factY) + factY = factX; + else + factX = factY; + + /* Out-of-bounds, fill icon with zero */ + zero = 0; + + for (row = 0; row < iconSize; row++) { + outPtr = image + stride * row; + for (column = 0; column < iconSize; column++) { + posX = factX * column; + posY = factY * row; + + ptr = (unsigned char *) iconData + posY * xStride; + if (effXBPP == 1) { + ptr += posX / 8; + + /* Out of X icon bounds, leave space blank */ + if (posX >= pixmap->width || posY >= pixmap->height) + ptr = (unsigned char *) &zero; + + if ((*ptr) & (1 << (posX & 7))) + switch (effBPP) { + case 32: + *(outPtr++) = 0; + case 24: + *(outPtr++) = 0; + case 16: + *(outPtr++) = 0; + case 8: + *(outPtr++) = 0; + break; + case 1: + outPtr[column / 8] &= ~(1 << (7 - (column & 7))); + break; + } + else + switch (effBPP) { + case 32: + *(outPtr++) = 255; + *(outPtr++) = 255; + *(outPtr++) = 255; + *(outPtr++) = 0; + break; + case 24: + *(outPtr++) = 255; + case 16: + *(outPtr++) = 255; + case 8: + *(outPtr++) = 255; + break; + case 1: + outPtr[column / 8] |= (1 << (7 - (column & 7))); + break; + } + } + else if (effXDepth == 24 || effXDepth == 32) { + ptr += posX * (effXBPP / 8); + + /* Out of X icon bounds, leave space blank */ + if (posX >= pixmap->width || posY >= pixmap->height) + ptr = (unsigned char *) &zero; + color = (((*ptr) << 16) + + ((*(ptr + 1)) << 8) + + ((*(ptr + 2)) << 0)); + switch (effBPP) { + case 32: + *(outPtr++) = *(ptr++); /* b */ + *(outPtr++) = *(ptr++); /* g */ + *(outPtr++) = *(ptr++); /* r */ + *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */ + break; + case 24: + *(outPtr++) = *(ptr++); + *(outPtr++) = *(ptr++); + *(outPtr++) = *(ptr++); + break; + case 16: + color = ((((*ptr) >> 2) << 10) + + (((*(ptr + 1)) >> 2) << 5) + + (((*(ptr + 2)) >> 2))); + *(outPtr++) = (color >> 8); + *(outPtr++) = (color & 255); + break; + case 8: + color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2)))); + color /= 3; + *(outPtr++) = color; + break; + case 1: + if (color) + outPtr[column / 8] |= (1 << (7 - (column & 7))); + else + outPtr[column / 8] &= ~(1 << (7 - (column & 7))); + } + } + else if (effXDepth == 16) { + ptr += posX * (effXBPP / 8); + + /* Out of X icon bounds, leave space blank */ + if (posX >= pixmap->width || posY >= pixmap->height) + ptr = (unsigned char *) &zero; + color = ((*ptr) << 8) + (*(ptr + 1)); + switch (effBPP) { + case 32: + *(outPtr++) = (color & 31) << 2; + *(outPtr++) = ((color >> 5) & 31) << 2; + *(outPtr++) = ((color >> 10) & 31) << 2; + *(outPtr++) = 0; /* resvd */ + break; + case 24: + *(outPtr++) = (color & 31) << 2; + *(outPtr++) = ((color >> 5) & 31) << 2; + *(outPtr++) = ((color >> 10) & 31) << 2; + break; + case 16: + *(outPtr++) = *(ptr++); + *(outPtr++) = *(ptr++); + break; + case 8: + *(outPtr++) = (((color & 31) + + ((color >> 5) & 31) + + ((color >> 10) & 31)) / 3) << 2; + break; + case 1: + if (color) + outPtr[column / 8] |= (1 << (7 - (column & 7))); + else + outPtr[column / 8] &= ~(1 << (7 - (column & 7))); + break; + } /* end switch(effbpp) */ + } /* end if effxbpp==16) */ + } /* end for column */ + } /* end for row */ +} + +static HICON +NetWMToWinIconAlpha(uint32_t * icon) +{ + int width = icon[0]; + int height = icon[1]; + uint32_t *pixels = &icon[2]; + HICON result; + HDC hdc = GetDC(NULL); + uint32_t *DIB_pixels; + ICONINFO ii; + BITMAPV4HEADER bmh = { sizeof(bmh) }; + + /* Define an ARGB pixel format used for Color+Alpha icons */ + bmh.bV4Width = width; + bmh.bV4Height = -height; /* Invert the image */ + bmh.bV4Planes = 1; + bmh.bV4BitCount = 32; + bmh.bV4V4Compression = BI_BITFIELDS; + bmh.bV4AlphaMask = 0xFF000000; + bmh.bV4RedMask = 0x00FF0000; + bmh.bV4GreenMask = 0x0000FF00; + bmh.bV4BlueMask = 0x000000FF; + + ii.fIcon = TRUE; + ii.xHotspot = 0; /* ignored */ + ii.yHotspot = 0; /* ignored */ + ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *) &bmh, + DIB_RGB_COLORS, (void **) &DIB_pixels, NULL, + 0); + ReleaseDC(NULL, hdc); + + if (!ii.hbmColor) + return NULL; + + ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL); + memcpy(DIB_pixels, pixels, height * width * 4); + + /* CreateIconIndirect() traditionally required DDBitmaps */ + /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */ + /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */ + result = CreateIconIndirect(&ii); + + DeleteObject(ii.hbmColor); + DeleteObject(ii.hbmMask); + + winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result); + return result; +} + +static HICON +NetWMToWinIconThreshold(uint32_t * icon) +{ + int width = icon[0]; + int height = icon[1]; + uint32_t *pixels = &icon[2]; + int row, col; + HICON result; + ICONINFO ii; + + HDC hdc = GetDC(NULL); + HDC xorDC = CreateCompatibleDC(hdc); + HDC andDC = CreateCompatibleDC(hdc); + + ii.fIcon = TRUE; + ii.xHotspot = 0; /* ignored */ + ii.yHotspot = 0; /* ignored */ + ii.hbmColor = CreateCompatibleBitmap(hdc, width, height); + ii.hbmMask = CreateCompatibleBitmap(hdc, width, height); + ReleaseDC(NULL, hdc); + SelectObject(xorDC, ii.hbmColor); + SelectObject(andDC, ii.hbmMask); + + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + if ((*pixels & 0xFF000000) > 31 << 24) { /* 31 alpha threshold, i.e. opaque above, transparent below */ + SetPixelV(xorDC, col, row, + RGB(((char *) pixels)[2], ((char *) pixels)[1], + ((char *) pixels)[0])); + SetPixelV(andDC, col, row, RGB(0, 0, 0)); /* black mask */ + } + else { + SetPixelV(xorDC, col, row, RGB(0, 0, 0)); + SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */ + } + pixels++; + } + } + DeleteDC(xorDC); + DeleteDC(andDC); + + result = CreateIconIndirect(&ii); + + DeleteObject(ii.hbmColor); + DeleteObject(ii.hbmMask); + + winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1], + result); + return result; +} + +static HICON +NetWMToWinIcon(int bpp, uint32_t * icon) +{ + static bool hasIconAlphaChannel = FALSE; + static bool versionChecked = FALSE; + + if (!versionChecked) { + OSVERSIONINFOEX osvi = { 0 }; + ULONGLONG dwlConditionMask = 0; + + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = 5; + osvi.dwMinorVersion = 1; + + /* Windows versions later than XP have icon alpha channel suport, 2000 does not */ + VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, + VER_GREATER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, + VER_GREATER_EQUAL); + hasIconAlphaChannel = + VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, + dwlConditionMask); + versionChecked = TRUE; + + winError("OS has icon alpha channel support: %s\n", + hasIconAlphaChannel ? "yes" : "no"); + } + + if (hasIconAlphaChannel && (bpp == 32)) + return NetWMToWinIconAlpha(icon); + else + return NetWMToWinIconThreshold(icon); +} + +/* + * Attempt to create a custom icon from the WM_HINTS bitmaps + */ + +HICON +winXIconToHICON(xcb_connection_t *conn, xcb_window_t id, int iconSize) +{ + unsigned char *mask, *image = NULL, *imageMask; + unsigned char *dst, *src; + int planes, bpp, i; + unsigned int biggest_size = 0; + HDC hDC; + ICONINFO ii; + xcb_icccm_wm_hints_t hints; + HICON hIcon = NULL; + uint32_t *biggest_icon = NULL; + static xcb_atom_t _XA_NET_WM_ICON; + static int generation; + uint32_t *icon, *icon_data = NULL; + unsigned long int size; + + hDC = GetDC(GetDesktopWindow()); + planes = GetDeviceCaps(hDC, PLANES); + bpp = GetDeviceCaps(hDC, BITSPIXEL); + ReleaseDC(GetDesktopWindow(), hDC); + + /* Always prefer _NET_WM_ICON icons */ + if (generation != serverGeneration) { + xcb_intern_atom_reply_t *atom_reply; + xcb_intern_atom_cookie_t atom_cookie; + const char *atomName = "_NET_WM_ICON"; + + generation = serverGeneration; + + _XA_NET_WM_ICON = XCB_NONE; + + atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName); + atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL); + if (atom_reply) { + _XA_NET_WM_ICON = atom_reply->atom; + free(atom_reply); + } + } + + { + xcb_get_property_cookie_t cookie = xcb_get_property(conn, FALSE, id, _XA_NET_WM_ICON, XCB_ATOM_CARDINAL, 0L, INT_MAX); + xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL); + + if (reply && + ((icon_data = xcb_get_property_value(reply)) != NULL)) { + size = xcb_get_property_value_length(reply)/sizeof(uint32_t); + for (icon = icon_data; icon < &icon_data[size] && *icon; + icon = &icon[icon[0] * icon[1] + 2]) { + winDebug("winXIconToHICON: %u x %u NetIcon\n", icon[0], icon[1]); + + /* Icon data size will overflow an int and thus is bigger than the + property can possibly be */ + if ((INT_MAX/icon[0]) < icon[1]) { + winDebug("winXIconToHICON: _NET_WM_ICON icon data size overflow\n"); + break; + } + + /* Icon data size is bigger than amount of data remaining */ + if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) { + winDebug("winXIconToHICON: _NET_WM_ICON data is malformed\n"); + break; + } + + /* Found an exact match to the size we require... */ + if (icon[0] == iconSize && icon[1] == iconSize) { + winDebug("winXIconToHICON: selected %d x %d NetIcon\n", + iconSize, iconSize); + hIcon = NetWMToWinIcon(bpp, icon); + break; + } + /* Otherwise, find the biggest icon and let Windows scale the size */ + else if (biggest_size < icon[0]) { + biggest_icon = icon; + biggest_size = icon[0]; + } + } + + if (!hIcon && biggest_icon) { + winDebug + ("winXIconToHICON: selected %u x %u NetIcon for scaling to %d x %d\n", + biggest_icon[0], biggest_icon[1], iconSize, iconSize); + + hIcon = NetWMToWinIcon(bpp, biggest_icon); + } + + free(reply); + } + } + + if (!hIcon) { + xcb_get_property_cookie_t wm_hints_cookie; + + winDebug("winXIconToHICON: no suitable NetIcon\n"); + + wm_hints_cookie = xcb_icccm_get_wm_hints(conn, id); + if (xcb_icccm_get_wm_hints_reply(conn, wm_hints_cookie, &hints, NULL)) { + winDebug("winXIconToHICON: id 0x%x icon_pixmap hint 0x%x\n", + (unsigned int)id, + (unsigned int)hints.icon_pixmap); + + if (hints.icon_pixmap) { + unsigned int width, height; + xcb_image_t *xImageIcon; + xcb_image_t *xImageMask = NULL; + + xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, hints.icon_pixmap); + xcb_get_geometry_reply_t *geom_reply = xcb_get_geometry_reply(conn, geom_cookie, NULL); + + if (geom_reply) { + width = geom_reply->width; + height = geom_reply->height; + + xImageIcon = xcb_image_get(conn, hints.icon_pixmap, + 0, 0, width, height, + 0xFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); + + winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%p\n", + (unsigned int)id, xImageIcon); + + if (hints.icon_mask) + xImageMask = xcb_image_get(conn, hints.icon_mask, + 0, 0, width, height, + 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); + + if (xImageIcon) { + int effBPP, stride, maskStride; + + /* 15 BPP is really 16BPP as far as we care */ + if (bpp == 15) + effBPP = 16; + else + effBPP = bpp; + + /* Need 16-bit aligned rows for DDBitmaps */ + stride = ((iconSize * effBPP + 15) & (~15)) / 8; + + /* Mask is 1-bit deep */ + maskStride = ((iconSize * 1 + 15) & (~15)) / 8; + + image = malloc(stride * iconSize); + imageMask = malloc(stride * iconSize); + mask = malloc(maskStride * iconSize); + + /* Default to a completely black mask */ + memset(imageMask, 0, stride * iconSize); + memset(mask, 0, maskStride * iconSize); + + winScaleXImageToWindowsIcon(iconSize, effBPP, stride, + xImageIcon, image); + + if (xImageMask) { + winScaleXImageToWindowsIcon(iconSize, 1, maskStride, + xImageMask, mask); + winScaleXImageToWindowsIcon(iconSize, effBPP, stride, + xImageMask, imageMask); + } + + /* Now we need to set all bits of the icon which are not masked */ + /* on to 0 because Color is really an XOR, not an OR function */ + dst = image; + src = imageMask; + + for (i = 0; i < (stride * iconSize); i++) + if ((*(src++))) + *(dst++) = 0; + else + dst++; + + ii.fIcon = TRUE; + ii.xHotspot = 0; /* ignored */ + ii.yHotspot = 0; /* ignored */ + + /* Create Win32 mask from pixmap shape */ + ii.hbmMask = + CreateBitmap(iconSize, iconSize, planes, 1, mask); + + /* Create Win32 bitmap from pixmap */ + ii.hbmColor = + CreateBitmap(iconSize, iconSize, planes, bpp, image); + + /* Merge Win32 mask and bitmap into icon */ + hIcon = CreateIconIndirect(&ii); + + /* Release Win32 mask and bitmap */ + DeleteObject(ii.hbmMask); + DeleteObject(ii.hbmColor); + + /* Free X mask and bitmap */ + free(mask); + free(image); + free(imageMask); + + if (xImageMask) + xcb_image_destroy(xImageMask); + + xcb_image_destroy(xImageIcon); + } + } + } + } + } + return hIcon; +} diff --git a/hw/xwin/wmutil/icon_convert.h b/hw/xwin/wmutil/icon_convert.h new file mode 100644 index 000000000..0065326be --- /dev/null +++ b/hw/xwin/wmutil/icon_convert.h @@ -0,0 +1,34 @@ +/* + * File: icons.h + * Purpose: interface for X->Windows icon conversion + * + * Copyright (c) Jon TURNEY 2012 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef WMUTILS_ICONS_H +#define WMUTILS_ICONS_H + +#include <xcb/xcb.h> + +HICON +winXIconToHICON(xcb_connection_t *conn, xcb_window_t id, int iconSize); + +#endif /* WMUTILS_ICONS_H */ diff --git a/hw/xwin/wmutil/keyboard.c b/hw/xwin/wmutil/keyboard.c new file mode 100644 index 000000000..78a92a6dc --- /dev/null +++ b/hw/xwin/wmutil/keyboard.c @@ -0,0 +1,308 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + +#include <X11/Xwindows.h> +#include <X11/Xmd.h> // to provide a BYTE type, since the Windows one is eclipsed + +#include "winvkmap.h" +#include "keyboard.h" + +#include "winmsg.h" + +static bool g_winKeyState[NUM_KEYCODES]; + +/* + * Translate a Windows WM_[SYS]KEY(UP/DOWN) message + * into an ASCII scan code. + * + * We do this ourselves, rather than letting Windows handle it, + * because Windows tends to munge the handling of special keys, + * like AltGr on European keyboards. + */ + +int +winTranslateKey(WPARAM wParam, LPARAM lParam) +{ + int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1]; + int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2]; + int iParam = HIWORD(lParam); + int iParamScanCode = LOBYTE(iParam); + int iScanCode; + + winDebug("winTranslateKey: wParam %08x lParam %08x\n", (int)wParam, (int)lParam); + +/* WM_ key messages faked by Vista speech recognition (WSR) don't have a + * scan code. + * + * Vocola 3 (Rick Mohr's supplement to WSR) uses + * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a + * scan code of 1 + */ + if (iParamScanCode <= 1) { + if (VK_PRIOR <= wParam && wParam <= VK_DOWN) + /* Trigger special case table to translate to extended + * keycode, otherwise if num_lock is on, we can get keypad + * numbers instead of navigation keys. */ + iParam |= KF_EXTENDED; + else + iParamScanCode = MapVirtualKeyEx(wParam, + /*MAPVK_VK_TO_VSC */ 0, + GetKeyboardLayout(0)); + } + + /* Branch on special extended, special non-extended, or normal key */ + if ((iParam & KF_EXTENDED) && iKeyFixupEx) + iScanCode = iKeyFixupEx; + else if (iKeyFixup) + iScanCode = iKeyFixup; + else if (wParam == 0 && iParamScanCode == 0x70) + iScanCode = KEY_HKTG; + else + switch (iParamScanCode) { + case 0x70: + iScanCode = KEY_HKTG; + break; + case 0x73: + iScanCode = KEY_BSlash2; + break; + default: + iScanCode = iParamScanCode; + break; + } + + return iScanCode; +} + +/* + * Look for the lovely fake Control_L press/release generated by Windows + * when AltGr is pressed/released on a non-U.S. keyboard. + */ + +bool +winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam) +{ + MSG msgNext; + LONG lTime; + bool fReturn; + + static bool lastWasControlL = FALSE; + static LONG lastTime; + + /* + * Fake Ctrl_L presses will be followed by an Alt_R press + * with the same timestamp as the Ctrl_L press. + */ + if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) + && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) { + /* Got a Ctrl_L press */ + + /* Get time of current message */ + lTime = GetMessageTime(); + + /* Look for next press message */ + fReturn = PeekMessage(&msgNext, NULL, + WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE); + + if (fReturn && msgNext.message != WM_KEYDOWN && + msgNext.message != WM_SYSKEYDOWN) + fReturn = 0; + + if (!fReturn) { + lastWasControlL = TRUE; + lastTime = lTime; + } + else { + lastWasControlL = FALSE; + } + + /* Is next press an Alt_R with the same timestamp? */ + if (fReturn && msgNext.wParam == VK_MENU + && msgNext.time == lTime + && (HIWORD(msgNext.lParam) & KF_EXTENDED)) { + /* + * Next key press is Alt_R with same timestamp as current + * Ctrl_L message. Therefore, this Ctrl_L press is a fake + * event, so discard it. + */ + return TRUE; + } + } + /* + * Sometimes, the Alt_R press message is not yet posted when the + * fake Ctrl_L press message arrives (even though it has the + * same timestamp), so check for an Alt_R press message that has + * arrived since the last Ctrl_L message. + */ + else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) + && wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) { + /* Got a Alt_R press */ + + if (lastWasControlL) { + lTime = GetMessageTime(); + + if (lastTime == lTime) { + /* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */ + winSendKeyEvent(KEY_LCtrl, FALSE); + } + lastWasControlL = FALSE; + } + } + /* + * Fake Ctrl_L releases will be followed by an Alt_R release + * with the same timestamp as the Ctrl_L release. + */ + else if ((message == WM_KEYUP || message == WM_SYSKEYUP) + && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) { + /* Got a Ctrl_L release */ + + /* Get time of current message */ + lTime = GetMessageTime(); + + /* Look for next release message */ + fReturn = PeekMessage(&msgNext, NULL, + WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE); + + if (fReturn && msgNext.message != WM_KEYUP && + msgNext.message != WM_SYSKEYUP) + fReturn = 0; + + lastWasControlL = FALSE; + + /* Is next press an Alt_R with the same timestamp? */ + if (fReturn + && (msgNext.message == WM_KEYUP || msgNext.message == WM_SYSKEYUP) + && msgNext.wParam == VK_MENU + && msgNext.time == lTime + && (HIWORD(msgNext.lParam) & KF_EXTENDED)) { + /* + * Next key release is Alt_R with same timestamp as current + * Ctrl_L message. Therefore, this Ctrl_L release is a fake + * event, so discard it. + */ + return TRUE; + } + } + else { + /* On any other press or release message, we don't have a + potentially fake Ctrl_L to worry about anymore... */ + lastWasControlL = FALSE; + } + + /* Not a fake control left press/release */ + return FALSE; +} + +/* + * Lift any modifier keys that are pressed + */ + +void +winKeybdReleaseKeys(void) +{ + int i; + + /* Loop through all keys */ + for (i = 0; i < NUM_KEYCODES; ++i) { + /* Pop key if pressed */ + if (g_winKeyState[i]) + winSendKeyEvent(i, FALSE); + + /* Reset pressed flag for keys */ + g_winKeyState[i] = FALSE; + } +} + +/* + * Take a raw X key code and send an up or down event for it. + * + * Thanks to VNC for inspiration, though it is a simple function. + */ + +void +winSendKeyEvent(DWORD dwKey, bool fDown) +{ + /* + * When alt-tabing between screens we can get phantom key up messages + * Here we only pass them through it we think we should! + */ + if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) + return; + + /* Update the keyState map */ + g_winKeyState[dwKey] = fDown; + + winSendKeyEventCallback(dwKey + MIN_KEYCODE, fDown); + + winDebug("winSendKeyEvent: dwKey: %u, fDown: %u\n", (unsigned int)dwKey, fDown); +} + +bool +winCheckKeyPressed(WPARAM wParam, LPARAM lParam) +{ + switch (wParam) { + case VK_CONTROL: + if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl]) + return TRUE; + if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl]) + return TRUE; + break; + case VK_SHIFT: + if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR]) + return TRUE; + if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL]) + return TRUE; + break; + default: + return TRUE; + } + return FALSE; +} + +/* Only one shift release message is sent even if both are pressed. + * Fix this here + */ +void +winFixShiftKeys(int iScanCode) +{ + if (GetKeyState(VK_SHIFT) & 0x8000) + return; + + if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR]) + winSendKeyEvent(KEY_ShiftR, FALSE); + if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL]) + winSendKeyEvent(KEY_ShiftL, FALSE); +} diff --git a/hw/xwin/wmutil/keyboard.h b/hw/xwin/wmutil/keyboard.h new file mode 100644 index 000000000..5b229c25c --- /dev/null +++ b/hw/xwin/wmutil/keyboard.h @@ -0,0 +1,39 @@ +/* + * File: keyboard.h + * Purpose: interface for X->Windows keyboard event conversion + * + * Copyright (c) Jon TURNEY 2012 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef WMUTILS_KEYBOARD_H +#define WMUTILS_KEYBOARD_H + +#include <stdbool.h> + +void winSendKeyEvent(DWORD dwKey, bool fDown); +void winSendKeyEventCallback(DWORD dwKey, bool fDown); +void winKeybdReleaseKeys(void); +bool winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam); +bool winCheckKeyPressed(WPARAM wParam, LPARAM lParam); +int winTranslateKey(WPARAM wParam, LPARAM lParam); +void winFixShiftKeys(int iScanCode); + +#endif /* WMUTILS_KEYBOARD_H */ diff --git a/hw/xwin/wmutil/mouse.c b/hw/xwin/wmutil/mouse.c new file mode 100644 index 000000000..ba58f067a --- /dev/null +++ b/hw/xwin/wmutil/mouse.c @@ -0,0 +1,111 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + +#include <X11/Xwindows.h> +#include <X11/X.h> + +#include "mouse.h" + +/* Handle the mouse wheel */ +void +winMouseWheel(int *iTotalDeltaZ, int iDeltaZ, int iButtonUp, int iButtonDown) +{ + int button; + + /* Do we have any previous delta stored? */ + if ((*iTotalDeltaZ > 0 && iDeltaZ > 0) + || (*iTotalDeltaZ < 0 && iDeltaZ < 0)) { + /* Previous delta and of same sign as current delta */ + iDeltaZ += *iTotalDeltaZ; + *iTotalDeltaZ = 0; + } + else { + /* + * Previous delta of different sign, or zero. + * We will set it to zero for either case, + * as blindly setting takes just as much time + * as checking, then setting if necessary :) + */ + *iTotalDeltaZ = 0; + } + + /* + * Only process this message if the wheel has moved further than + * WHEEL_DELTA + */ + if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA) { + *iTotalDeltaZ = 0; + + /* Figure out how many whole deltas of the wheel we have */ + iDeltaZ /= WHEEL_DELTA; + } + else { + /* + * Wheel has not moved past WHEEL_DELTA threshold; + * we will store the wheel delta until the threshold + * has been reached. + */ + *iTotalDeltaZ = iDeltaZ; + return; + } + + /* Set the button to indicate up or down wheel delta */ + if (iDeltaZ > 0) { + button = iButtonUp; + } + else { + button = iButtonDown; + } + + /* + * Flip iDeltaZ to positive, if negative, + * because always need to generate a *positive* number of + * button clicks for the Z axis. + */ + if (iDeltaZ < 0) { + iDeltaZ *= -1; + } + + /* Generate X input messages for each wheel delta we have seen */ + while (iDeltaZ--) { + /* Push the wheel button */ + winMouseButtonsSendEvent(TRUE, button); + + /* Release the wheel button */ + winMouseButtonsSendEvent(FALSE, button); + } +} diff --git a/hw/xwin/wmutil/mouse.h b/hw/xwin/wmutil/mouse.h new file mode 100644 index 000000000..8bd6fe9eb --- /dev/null +++ b/hw/xwin/wmutil/mouse.h @@ -0,0 +1,36 @@ +/* + * File: mouse.h + * Purpose: interface for X->Windows mouse event conversion + * + * Copyright (c) Jon TURNEY 2012 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef WMUTILS_MOUSE_H +#define WMUTILS_MOUSE_H + +#include <stdbool.h> + +void winMouseWheel(int *iTotalDeltaz, int iDeltaZ, int iButtonUp, int iButtonDown); + +/* Callback for sending mouse button events */ +void winMouseButtonsSendEvent(bool bPress, int iButton); + +#endif /* WMUTILS_MOUSE_H */ diff --git a/hw/xwin/winkeynames.h b/hw/xwin/wmutil/scancodes.h index bfed9d427..3215a4bcb 100644 --- a/hw/xwin/winkeynames.h +++ b/hw/xwin/wmutil/scancodes.h @@ -1,5 +1,3 @@ -#ifndef _WINKEYNAMES_H -#define _WINKEYNAMES_H /* * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. * @@ -23,18 +21,8 @@ * */ -#define GLYPHS_PER_KEY 4 -#define NUM_KEYCODES 248 -#define MIN_KEYCODE 8 -#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) - -#define AltMask Mod1Mask -#define NumLockMask Mod2Mask -#define AltLangMask Mod3Mask -#define KanaMask Mod4Mask -#define ScrollLockMask Mod5Mask - -#define ModifierDown(k) ((keyc->state & (k)) == (k)) +#ifndef SCANCODES_H +#define SCANCODES_H /* * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three) @@ -203,4 +191,4 @@ #define KEY_NOTUSED 0 #define KEY_UNKNOWN 255 -#endif /* _WINKEYNAMES_H */ +#endif /* SCANCODES_H */ diff --git a/hw/xwin/winkeybd.h b/hw/xwin/wmutil/winvkmap.h index 6701f0959..eff61c7f9 100644 --- a/hw/xwin/winkeybd.h +++ b/hw/xwin/wmutil/winvkmap.h @@ -1,5 +1,3 @@ -#if !defined(WINKEYBD_H) -#define WINKEYBD_H /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * @@ -30,10 +28,17 @@ * Authors: Harold L Hunt II */ +#ifndef WINVKMAP_H +#define WINVKMAP_H + /* * We need symbols for the scan codes of keys. */ -#include "winkeynames.h" +#include "scancodes.h" + +#define NUM_KEYCODES 248 +#define MIN_KEYCODE 8 +#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) #define VK_FN 0xFF @@ -268,8 +273,7 @@ const int /* 220 */ 0, 0, 0, /* 221 */ 0, 0, 0, /* 222 */ 0, 0, 0, - /* 223 */ VK_OEM_8, 0, KEY_RCtrl, - /* at least on Canadian Multilingual Standard layout */ + /* 223 */ VK_OEM_8, 0, KEY_RCtrl, /* at least on Canadian Multilingual Standard layout */ /* 224 */ 0, 0, 0, /* 225 */ 0, 0, 0, /* 226 */ 0, 0, 0, @@ -301,8 +305,7 @@ const int /* 252 */ 0, 0, 0, /* 253 */ 0, 0, 0, /* 254 */ 0, 0, 0, - /* 255 */ VK_FN, 0, KEY_Fn - /* Most keyboards don't generate a scancode for Fn, but a few do... */ + /* 255 */ VK_FN, 0, KEY_Fn /* Most keyboards don't generate a scancode for Fn, but a few do... */ }; -#endif /* WINKEYBD_H */ +#endif /* WINVKMAP_H */ |