diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2014-01-06 18:17:41 +0000 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2014-01-06 18:17:41 +0000 |
commit | 24cc1f4d9f4475d1b0c256586fb8760dc1d92847 (patch) | |
tree | b9f638ca790a70a511016462fdae12dd4455ad8a | |
parent | 2ea973e12f5d954211e1d10085a4c74581b43aca (diff) | |
parent | b1e9e319cb302d138eef484b9878ec670735a340 (diff) |
Merge branch 'cygwin-patches-for-1.15' into cygwin-release-1.15xserver-cygwin-1.15.0-1
109 files changed, 4493 insertions, 2530 deletions
diff --git a/composite/compwindow.c b/composite/compwindow.c index 0be7a1b34..f61600e9e 100644 --- a/composite/compwindow.c +++ b/composite/compwindow.c @@ -104,7 +104,7 @@ compRepaintBorder(ClientPtr pClient, pointer closure) RegionNull(&exposed); RegionSubtract(&exposed, &pWindow->borderClip, &pWindow->winSize); - miPaintWindow(pWindow, &exposed, PW_BORDER); + (*pWindow->drawable.pScreen->PaintWindow)(pWindow, &exposed, PW_BORDER); RegionUninit(&exposed); } return TRUE; diff --git a/configure.ac b/configure.ac index 8f823863d..ed650defa 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,16 @@ AC_PROG_YACC AC_SYS_LARGEFILE XORG_PROG_RAWCPP +dnl we really need yacc and lex to build tarballs made by cygport directly from a git tag not 'make dist' +AC_PATH_PROG(YACC_INST, $YACC) +if test -z "$YACC_INST"; then + AC_MSG_ERROR([yacc not found]) +fi +AC_PATH_PROG(LEX_INST, $LEX) +if test -z "$LEX_INST"; then + AC_MSG_ERROR([lex not found]) +fi + # Quoted so that make will expand $(CWARNFLAGS) in makefiles to allow # easier overrides at build time. XSERVER_CFLAGS='$(CWARNFLAGS)' @@ -2084,7 +2094,7 @@ if test "x$XWIN" = xyes; then AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) AC_CHECK_TOOL(WINDRES, windres) - PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau]) + PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfixes x11-xcb xcb-image xcb-icccm]) if test "x$WINDOWSWM" = xauto; then PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no]) @@ -2506,6 +2516,8 @@ hw/xnest/man/Makefile hw/xwin/Makefile hw/xwin/glx/Makefile hw/xwin/man/Makefile +hw/xwin/wmutil/Makefile +hw/xwin/winclipboard/Makefile hw/xquartz/Makefile hw/xquartz/GL/Makefile hw/xquartz/bundle/Makefile diff --git a/dix/dispatch.c b/dix/dispatch.c index 8dcd9cbcf..f2a136896 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -224,7 +224,7 @@ UpdateCurrentTimeIf(void) #define SMART_SCHEDULE_DEFAULT_INTERVAL 5 #define SMART_SCHEDULE_MAX_SLICE 15 -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) || defined(__CYGWIN__) Bool SmartScheduleDisable = TRUE; #else Bool SmartScheduleDisable = FALSE; diff --git a/dix/globals.c b/dix/globals.c index ad9145b01..1cc622bba 100644 --- a/dix/globals.c +++ b/dix/globals.c @@ -128,6 +128,7 @@ int monitorResolution = 0; char *display; int displayfd; +Bool explicit_display = FALSE; char *ConnectionInfo; CARD32 TimeOutValue = DEFAULT_TIMEOUT * MILLI_PER_SECOND; diff --git a/dix/main.c b/dix/main.c index 05dcbeddd..bbed32241 100644 --- a/dix/main.c +++ b/dix/main.c @@ -110,6 +110,7 @@ Equipment Corporation. #else #include "dixevents.h" /* InitEvents() */ #endif +#include "dixmain.h" #ifdef DPMSExtension #include <X11/extensions/dpmsconst.h> @@ -159,8 +160,6 @@ dix_main(int argc, char *argv[], char *envp[]) DPMSPowerLevel = 0; #endif InitBlockAndWakeupHandlers(); - /* Perform any operating system dependent initializations you'd like */ - OsInit(); if (serverGeneration == 1) { CreateWellKnownSockets(); for (i = 1; i < MAXCLIENTS; i++) @@ -172,6 +171,8 @@ dix_main(int argc, char *argv[], char *envp[]) } else ResetWellKnownSockets(); + /* Perform any operating system dependent initializations you'd like */ + OsInit(); clients[0] = serverClient; currentMaxClients = 1; diff --git a/dix/stubmain.c b/dix/stubmain.c index 7efb4b8e7..b521677d2 100644 --- a/dix/stubmain.c +++ b/dix/stubmain.c @@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE. ******************************************************************/ -int dix_main(int argc, char *argv[], char *envp[]); +#include "dixmain.h" /* A default implementation of main, which can be overridden by the DDX diff --git a/dix/window.c b/dix/window.c index 0e9109e89..7a7b6d3fe 100644 --- a/dix/window.c +++ b/dix/window.c @@ -122,7 +122,6 @@ Equipment Corporation. #endif #include "dixevents.h" #include "globals.h" -#include "mi.h" /* miPaintWindow */ #ifdef COMPOSITE #include "compint.h" #endif @@ -1471,7 +1470,7 @@ ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) RegionNull(&exposed); RegionSubtract(&exposed, &pWin->borderClip, &pWin->winSize); - miPaintWindow(pWin, &exposed, PW_BORDER); + (*pWin->drawable.pScreen->PaintWindow)(pWin, &exposed, PW_BORDER); RegionUninit(&exposed); } return error; diff --git a/glx/glxcmds.c b/glx/glxcmds.c index b8da04882..291774812 100644 --- a/glx/glxcmds.c +++ b/glx/glxcmds.c @@ -213,6 +213,13 @@ __glXdirectContextCreate(__GLXscreen * screen, return context; } +void +FlushContext(__GLXcontext * cx) +{ + glFlush(); + cx->hasUnflushedCommands = GL_FALSE; +} + /** * Create a GL context with the given properties. This routine is used * to implement \c glXCreateContext, \c glXCreateNewContext, and @@ -402,7 +409,9 @@ __glXDisp_DestroyContext(__GLXclientState * cl, GLbyte * pc) &glxc, &err)) return err; - FreeResourceByType(req->context, __glXContextRes, FALSE); + glxc->idExists = GL_FALSE; + if (!glxc->currentClient) + FreeResourceByType(req->context, __glXContextRes, FALSE); return Success; } diff --git a/glx/glxcontext.h b/glx/glxcontext.h index 677898a67..c7cca0b56 100644 --- a/glx/glxcontext.h +++ b/glx/glxcontext.h @@ -138,4 +138,6 @@ extern __GLXcontext *__glXdirectContextCreate(__GLXscreen * screen, __GLXconfig * modes, __GLXcontext * shareContext); +extern void FlushContext(__GLXcontext * cx); + #endif /* !__GLX_context_h__ */ diff --git a/glx/glxdricommon.c b/glx/glxdricommon.c index fc902729d..191130056 100644 --- a/glx/glxdricommon.c +++ b/glx/glxdricommon.c @@ -144,10 +144,14 @@ createModeFromConfig(const __DRIcoreExtension * core, renderType |= GLX_RGBA_BIT; if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) renderType |= GLX_COLOR_INDEX_BIT; +#ifdef __DRI_ATTRIB_FLOAT_BIT if (value & __DRI_ATTRIB_FLOAT_BIT) renderType |= GLX_RGBA_FLOAT_BIT_ARB; +#endif +#ifdef __DRI_ATTRIB_UNSIGNED_FLOAT_BIT if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) renderType |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT; +#endif break; case __DRI_ATTRIB_CONFIG_CAVEAT: if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) @@ -193,8 +197,12 @@ render_type_is_pbuffer_only(unsigned renderType) * GLXFBConfig must have the GLX_PBUFFER_BIT bit set and the * GLX_RENDER_TYPE attribute must have the GLX_RGBA_FLOAT_BIT set." */ +#if defined(__DRI_ATTRIB_UNSIGNED_FLOAT_BIT) && defined(__DRI_ATTRIB_FLOAT_BIT) return !!(renderType & (__DRI_ATTRIB_UNSIGNED_FLOAT_BIT | __DRI_ATTRIB_FLOAT_BIT)); +#else + return 0; +#endif } __GLXconfig * diff --git a/glx/glxdriswrast.c b/glx/glxdriswrast.c index cbc109a6d..67c6547bc 100644 --- a/glx/glxdriswrast.c +++ b/glx/glxdriswrast.c @@ -71,6 +71,8 @@ struct __GLXDRIscreen { const __DRIcopySubBufferExtension *copySubBuffer; const __DRItexBufferExtension *texBuffer; const __DRIconfig **driConfigs; + + unsigned char glx_enable_bits[__GLX_EXT_BYTES]; }; struct __GLXDRIcontext { @@ -406,12 +408,27 @@ initializeExtensions(__GLXDRIscreen * screen) extensions = screen->core->getExtensions(screen->driScreen); + /* GLX_MESA_copy_sub_buffer is always enabled. */ + __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); + for (i = 0; extensions[i]; i++) { +#ifdef __DRI_READ_DRAWABLE + if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { + __glXEnableExtension(screen->glx_enable_bits, + "GLX_SGI_make_current_read"); + + LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); + } +#endif + #ifdef __DRI_COPY_SUB_BUFFER if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { screen->copySubBuffer = (const __DRIcopySubBufferExtension *) extensions[i]; - /* GLX_MESA_copy_sub_buffer is always enabled. */ + __glXEnableExtension(screen->glx_enable_bits, + "GLX_MESA_copy_sub_buffer"); + + LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); } #endif @@ -419,6 +436,7 @@ initializeExtensions(__GLXDRIscreen * screen) if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { screen->texBuffer = (const __DRItexBufferExtension *) extensions[i]; /* GLX_EXT_texture_from_pixmap is always enabled. */ + LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_texture_from_pixmap\n"); } #endif /* Ignore unknown extensions */ @@ -433,6 +451,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) { const char *driverName = "swrast"; __GLXDRIscreen *screen; + size_t buffer_size; screen = calloc(1, sizeof *screen); if (screen == NULL) @@ -444,6 +463,8 @@ __glXDRIscreenProbe(ScreenPtr pScreen) screen->base.swapInterval = NULL; screen->base.pScreen = pScreen; + __glXInitExtensionEnableBits(screen->glx_enable_bits); + screen->driver = glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1, @@ -472,6 +493,19 @@ __glXDRIscreenProbe(ScreenPtr pScreen) __glXScreenInit(&screen->base, pScreen); + /* The first call simply determines the length of the extension string. + * This allows us to allocate some memory to hold the extension string, + * but it requires that we call __glXGetExtensionString a second time. + */ + buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); + if (buffer_size > 0) { + free(screen->base.GLXextensions); + + screen->base.GLXextensions = xnfalloc(buffer_size); + (void) __glXGetExtensionString(screen->glx_enable_bits, + screen->base.GLXextensions); + } + screen->base.GLXmajor = 1; screen->base.GLXminor = 4; diff --git a/glx/glxext.c b/glx/glxext.c index 316b4f6e8..f93642b0c 100644 --- a/glx/glxext.c +++ b/glx/glxext.c @@ -140,6 +140,7 @@ DrawableGone(__GLXdrawable * glxPriv, XID xid) if (c->currentClient && (c->drawPriv == glxPriv || c->readPriv == glxPriv)) { /* just force a re-bind the next time through */ + FlushContext(c); (*c->loseCurrent) (c); if (c == __glXLastContext) __glXFlushContextCache(); diff --git a/glx/glxscreens.c b/glx/glxscreens.c index 78769f401..ac2e43e95 100644 --- a/glx/glxscreens.c +++ b/glx/glxscreens.c @@ -160,20 +160,6 @@ static const char GLServerExtensions[] = */ unsigned glxMajorVersion = SERVER_GLX_MAJOR_VERSION; unsigned glxMinorVersion = SERVER_GLX_MINOR_VERSION; -static char GLXServerExtensions[] = - "GLX_ARB_multisample " - "GLX_EXT_visual_info " - "GLX_EXT_visual_rating " - "GLX_EXT_import_context " - "GLX_EXT_texture_from_pixmap " - "GLX_OML_swap_method " - "GLX_SGI_make_current_read " -#ifndef __APPLE__ - "GLX_SGIS_multisample " -#endif - "GLX_SGIX_fbconfig " - "GLX_SGIX_pbuffer " - "GLX_MESA_copy_sub_buffer "; static Bool glxCloseScreen(ScreenPtr pScreen) @@ -329,7 +315,7 @@ __glXScreenInit(__GLXscreen * pGlxScreen, ScreenPtr pScreen) pGlxScreen->pScreen = pScreen; pGlxScreen->GLextensions = strdup(GLServerExtensions); - pGlxScreen->GLXextensions = strdup(GLXServerExtensions); + pGlxScreen->GLXextensions = strdup(""); /* All GLX providers must support all of the functionality required for at * least GLX 1.2. If the provider supports a higher version, the GLXminor diff --git a/glx/rensize.c b/glx/rensize.c index bcc3a53ad..a78e60c8f 100644 --- a/glx/rensize.c +++ b/glx/rensize.c @@ -226,12 +226,14 @@ __glXImageSize(GLenum format, GLenum type, GLenum target, case GL_INTENSITY: elementsPerGroup = 1; break; + case GL_RG: case GL_422_EXT: case GL_422_REV_EXT: case GL_422_AVERAGE_EXT: case GL_422_REV_AVERAGE_EXT: case GL_DEPTH_STENCIL_NV: case GL_DEPTH_STENCIL_MESA: + case GL_YCBCR_422_APPLE: case GL_YCBCR_MESA: case GL_LUMINANCE_ALPHA: elementsPerGroup = 2; diff --git a/hw/dmx/doc/dmx.xml b/hw/dmx/doc/dmx.xml index 6d7df4133..c6c8544ff 100644 --- a/hw/dmx/doc/dmx.xml +++ b/hw/dmx/doc/dmx.xml @@ -1268,7 +1268,7 @@ default routine is chosen during GC validation. <para>Note that some pointers to functions that draw to the screen are stored in the Screen structure. They include GetImage(), GetSpans(), -CopyWindow() and RestoreAreas(). +PaintWindow(), CopyWindow() and RestoreAreas(). </para> </sect3> diff --git a/hw/xfree86/sdksyms.sh b/hw/xfree86/sdksyms.sh index d7f259d28..f15c2d8e7 100755 --- a/hw/xfree86/sdksyms.sh +++ b/hw/xfree86/sdksyms.sh @@ -315,8 +315,8 @@ topdir=$1 shift LC_ALL=C export LC_ALL -${CPP:-cpp} "$@" sdksyms.c > /dev/null || exit $? -${CPP:-cpp} "$@" sdksyms.c | ${AWK:-awk} -v topdir=$topdir ' +${CPP:-cpp} "$@" -DSDKSYMS sdksyms.c > /dev/null || exit $? +${CPP:-cpp} "$@" -DSDKSYMS sdksyms.c | ${AWK:-awk} -v topdir=$topdir ' BEGIN { sdk = 0; print("/*"); diff --git a/hw/xquartz/quartz.c b/hw/xquartz/quartz.c index 5b977c7f9..1a493e178 100644 --- a/hw/xquartz/quartz.c +++ b/hw/xquartz/quartz.c @@ -300,7 +300,7 @@ QuartzUpdateScreens(void) quartzProcs->UpdateScreen(pScreen); /* miPaintWindow needs to be called after RootlessUpdateScreenPixmap (from xprUpdateScreen) */ - miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); + pScreen->PaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); /* Tell RandR about the new size, so new connections get the correct info */ RRScreenSizeNotify(pScreen); diff --git a/hw/xwin/InitInput.c b/hw/xwin/InitInput.c index 36346b7e1..c42418c23 100644 --- a/hw/xwin/InitInput.c +++ b/hw/xwin/InitInput.c @@ -39,7 +39,6 @@ #ifdef XWIN_CLIPBOARD int winProcEstablishConnection(ClientPtr /* client */ ); -int winProcSetSelectionOwner(ClientPtr /* client */ ); #endif /* diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index b05ca2736..f187c88c2 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 @@ -58,32 +56,24 @@ typedef WINAPI HRESULT(*SHGETFOLDERPATHPROC) (HWND hwndOwner, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath); #endif +#include "winmonitors.h" +#include "pseudoramiX/pseudoramiX.h" #include "glx_extinit.h" +#include "dixmain.h" +#ifdef XWIN_GLX_WINDOWS +#include "glx/glwindows.h" +#endif + /* * References to external symbols */ -#ifdef XWIN_CLIPBOARD -extern Bool g_fUnicodeClipboard; -extern Bool g_fClipboardLaunched; -extern Bool g_fClipboardStarted; -extern pthread_t g_ptClipboardProc; -extern HWND g_hwndClipboard; -extern Bool g_fClipboard; -#endif +extern Bool noRRXineramaExtension; /* * Function prototypes */ -#ifdef XWIN_CLIPBOARD -static void - winClipboardShutdown(void); -#endif - -static Bool - winCheckDisplayNumber(void); - void winLogCommandLine(int argc, char *argv[]); @@ -97,6 +87,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 @@ -122,31 +117,6 @@ static PixmapFormatRec g_PixmapFormats[] = { const int NUMFORMATS = sizeof(g_PixmapFormats) / sizeof(g_PixmapFormats[0]); -#ifdef XWIN_CLIPBOARD -static void -winClipboardShutdown(void) -{ - /* Close down clipboard resources */ - if (g_fClipboard && g_fClipboardLaunched && g_fClipboardStarted) { - /* Synchronously destroy the clipboard window */ - if (g_hwndClipboard != NULL) { - SendMessage(g_hwndClipboard, WM_DESTROY, 0, 0); - /* NOTE: g_hwndClipboard is set to NULL in winclipboardthread.c */ - } - else - return; - - /* Wait for the clipboard thread to exit */ - pthread_join(g_ptClipboardProc, NULL); - - g_fClipboardLaunched = FALSE; - g_fClipboardStarted = FALSE; - - winDebug("winClipboardShutdown - Clipboard thread has exited.\n"); - } -} -#endif - static const ExtensionModule xwinExtensions[] = { #ifdef GLXEXT { GlxExtensionInit, "GLX", &noGlxExtension }, @@ -206,6 +176,8 @@ main(int argc, char *argv[], char *envp[]) ErrorF("ddxMain - pthread_mutex_lock () failed: %d\n", iReturn); } + winCheckMount(); + return dix_main(argc, argv, envp); } @@ -292,6 +264,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) @@ -316,6 +290,9 @@ winCheckMntOpt(const struct mntent *mnt, const char *opt) return NULL; } +/* + Check mounts and issue warnings/activate workarounds as needed + */ static void winCheckMount(void) { @@ -325,6 +302,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) { @@ -363,6 +341,11 @@ winCheckMount(void) binary = FALSE; else binary = TRUE; + + if (strcmp(ent->mnt_type, "vfat") == 0) + fat = TRUE; + else + fat = FALSE; } if (endmntent(mnt) != 1) { @@ -372,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 @@ -783,6 +772,9 @@ winUseMsg(void) ErrorF("-fullscreen\n" "\tRun the server in fullscreen mode.\n"); + ErrorF("-hostintitle\n" + "\tIn multiwindow mode, add remote host names to window titles.\n"); + ErrorF("-ignoreinput\n" "\tIgnore keyboard and mouse input.\n"); #ifdef XWIN_MULTIWINDOWEXTWM @@ -951,14 +943,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()) @@ -1010,6 +994,61 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) } } + /* + Unless full xinerama has been explicitly enabled, register all native screens with pseudoramiX + */ + if (!noPanoramiXExtension) + noPseudoramiXExtension = TRUE; + + if ((g_ScreenInfo[0].fMultipleMonitors) && !noPseudoramiXExtension) + { + int pass; + + noRRXineramaExtension = TRUE; + + PseudoramiXExtensionInit(); + + /* Add primary monitor on pass 0, other monitors on pass 1, to ensure + the primary monitor is first in XINERAMA list */ + for (pass = 0; pass < 2; pass++) + { + int iMonitor; + + for (iMonitor = 1; ; iMonitor++) + { + struct GetMonitorInfoData data; + QueryMonitor(iMonitor, &data); + if (data.bMonitorSpecifiedExists) + { + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + + if (GetMonitorInfo(data.monitorHandle, &mi)) + { + /* pass == 1 XOR primary monitor flags is set */ + if ((!(pass == 1)) != (!(mi.dwFlags & MONITORINFOF_PRIMARY))) + { + /* + Note the screen origin in a normalized coordinate space where (0,0) is at the top left + of the native virtual desktop area + */ + data.monitorOffsetX = data.monitorOffsetX - GetSystemMetrics(SM_XVIRTUALSCREEN); + data.monitorOffsetY = data.monitorOffsetY - GetSystemMetrics(SM_YVIRTUALSCREEN); + + winDebug ("InitOutput - screen %d added at virtual desktop coordinate (%d,%d) (pseudoramiX) \n", + iMonitor-1, data.monitorOffsetX, data.monitorOffsetY); + + PseudoramiXAddScreen(data.monitorOffsetX, data.monitorOffsetY, + data.monitorWidth, data.monitorHeight); + } + } + } + else + break; + } + } + } + #if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) /* Generate a cookie used by internal clients for authorization */ @@ -1018,11 +1057,24 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) /* Perform some one time initialization */ if (1 == serverGeneration) { + /* 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, ""); + if (!setlocale(LC_ALL, "")) { + ErrorF("setlocale failed.\n"); + } + + /* See if X supports the current locale */ + if (XSupportsLocale() == FALSE) { + ErrorF("Warning: Locale not supported by X, falling back to 'C' locale.\n"); + setlocale(LC_ALL, "C"); + } } #endif @@ -1030,70 +1082,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]; - 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 7f0eaf097..b4fa663d3 100644 --- a/hw/xwin/Makefile.am +++ b/hw/xwin/Makefile.am @@ -3,19 +3,16 @@ bin_PROGRAMS = XWin if XWIN_CLIPBOARD SRCS_CLIPBOARD = \ winclipboardinit.c \ - winclipboardtextconv.c \ - winclipboardthread.c \ - winclipboardwndproc.c \ - winclipboardwrappers.c \ - winclipboardxevents.c + winclipboardwrappers.c DEFS_CLIPBOARD = -DXWIN_CLIPBOARD +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 -XWIN_GLX_LINK_FLAGS = -lopengl32 +XWIN_GLX_SYS_LIBS = -lopengl32 endif if XWIN_MULTIWINDOW @@ -27,7 +24,8 @@ SRCS_MULTIWINDOW = \ propertystore.h \ winSetAppUserModelID.c DEFS_MULTIWINDOW = -DXWIN_MULTIWINDOW -MULTIWINDOW_LIBS = -lshlwapi -lole32 +MULTIWINDOW_SYS_LIBS = -lshlwapi -lole32 +MULTIWINDOW_LIBS = $(top_builddir)/hw/xwin/wmutil/libXWinWMUtil.la endif if XWIN_MULTIWINDOWEXTWM @@ -110,12 +108,9 @@ SRCS = InitInput.c \ winwindow.c \ winwndproc.c \ ddraw.h \ - winclipboard.h \ winconfig.h \ win.h \ winglobals.h \ - winkeybd.h \ - winkeynames.h \ winlayouts.h \ winmessages.h \ winmonitors.h \ @@ -126,6 +121,8 @@ SRCS = InitInput.c \ winprefs.h \ winresource.h \ winwindow.h \ + windisplay.c \ + windisplay.h \ XWin.rc \ $(top_srcdir)/Xext/dpmsstubs.c \ $(top_srcdir)/Xi/stubs.c \ @@ -155,12 +152,13 @@ AM_CPPFLAGS = -I$(top_srcdir)/miext/rootless XWIN_SYS_LIBS += -ldxguid XWIN_LIBS += $(top_builddir)/pseudoramiX/libPseudoramiX.la -XWin_DEPENDENCIES = $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_LIBS) $(XSERVER_LIBS) -XWin_LDADD = $(MULTIWINDOW_LIBS) $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_GLX_LINK_FLAGS) $(XWIN_LIBS) $(MAIN_LIB) $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XWIN_SYS_LIBS) +XWin_DEPENDENCIES = $(MULTIWINDOW_LIBS) $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_LIBS) $(XSERVER_LIBS) +XWin_LDADD = $(MULTIWINDOW_LIBS) $(MULTIWINDOWEXTWM_LIBS) $(XWIN_GLX_LIBS) $(XWIN_LIBS) $(XSERVER_LIBS) \ + $(CLIPBOARD_LIBS) $(XWIN_GLX_SYS_LIBS) $(XSERVER_SYS_LIBS) $(XWIN_SYS_LIBS) $(MULTIWINDOW_SYS_LIBS) XWin_LDFLAGS = -mwindows -static -Wl,--disable-stdcall-fixup .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 @@ -192,5 +190,5 @@ EXTRA_DIST = \ relink: $(AM_V_at)rm -f XWin$(EXEEXT) && $(MAKE) XWin$(EXEEXT) -SUBDIRS = man $(GLX_DIR) . +SUBDIRS = man $(GLX_DIR) wmutil winclipboard . DIST_SUBDIRS = man glx . diff --git a/hw/xwin/XWin.exe.manifest b/hw/xwin/XWin.exe.manifest index 477334fb3..ea0e138f5 100755 --- a/hw/xwin/XWin.exe.manifest +++ b/hw/xwin/XWin.exe.manifest @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> - <description>The XWin X Windows server for Cygwin.</description> + <description>The XWin X Windows server</description> <dependency> <dependentAssembly> <assemblyIdentity @@ -18,4 +18,16 @@ <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <!-- Windows Vista --> + <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> + <!-- Windows 7 --> + <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> + <!-- Windows 8 --> + <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> + <!-- Windows 8.1 --> + <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> + </application> + </compatibility> </assembly> diff --git a/hw/xwin/XWin.rc b/hw/xwin/XWin.rc index a142f3070..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", @@ -93,6 +93,7 @@ BEGIN POPUP "TRAYICON_MENU" BEGIN MENUITEM "&Hide Root Window", ID_APP_HIDE_ROOT + MENUITEM "Clipboard may use &PRIMARY selection", ID_APP_MONITOR_PRIMARY MENUITEM "&About...", ID_APP_ABOUT MENUITEM SEPARATOR MENUITEM "E&xit...", ID_APP_EXIT diff --git a/hw/xwin/glx/gen_gl_wrappers.py b/hw/xwin/glx/gen_gl_wrappers.py index 683b9d903..cdbba638a 100755 --- a/hw/xwin/glx/gen_gl_wrappers.py +++ b/hw/xwin/glx/gen_gl_wrappers.py @@ -43,35 +43,18 @@ thunkdefs=False staticwrappers=False nodebug=False -#exclude base WGL API -WinGDI={key: 1 for key in [ - "wglCopyContext" - ,"wglCreateContext" - ,"wglCreateLayerContext" - ,"wglDeleteContext" - ,"wglGetCurrentContext" - ,"wglGetCurrentDC" - ,"wglGetProcAddress" - ,"wglMakeCurrent" - ,"wglShareLists" - ,"wglUseFontBitmapsA" - ,"wglUseFontBitmapsW" - ,"wglUseFontBitmaps" - ,"SwapBuffers" - ,"wglUseFontOutlinesA" - ,"wglUseFontOutlinesW" - ,"wglUseFontOutlines" - ,"wglDescribeLayerPlane" - ,"wglSetLayerPaletteEntries" - ,"wglGetLayerPaletteEntries" - ,"wglRealizeLayerPalette" - ,"wglSwapLayerBuffers" - ,"wglSwapMultipleBuffers" - ,"ChoosePixelFormat" - ,"DescribePixelFormat" - ,"GetEnhMetaFilePixelFormat" - ,"GetPixelFormat" - ,"SetPixelFormat" +# list of WGL extension functions we use +used_wgl_ext_fns = {key: 1 for key in [ + "wglSwapIntervalEXT", + "wglGetExtensionsStringARB", + "wglDestroyPbufferARB", + "wglGetPbufferDCARB", + "wglReleasePbufferDCARB", + "wglCreatePbufferARB", + "wglMakeContextCurrentARB", + "wglChoosePixelFormatARB", + "wglGetPixelFormatAttribivARB", + "wglGetPixelFormatAttribivARB" ]} if __name__ == '__main__': @@ -162,7 +145,7 @@ class PreResolveOutputGenerator(OutputGenerator): def genCmd(self, cmd, name): OutputGenerator.genCmd(self, cmd, name) - if name in WinGDI: + if prefix == 'wgl' and not name in used_wgl_ext_fns: return self.outFile.write('RESOLVE_DECL(PFN' + name.upper() + 'PROC);\n') @@ -190,7 +173,7 @@ class WrapperOutputGenerator(OutputGenerator): def genCmd(self, cmd, name): OutputGenerator.genCmd(self, cmd, name) - if name in WinGDI: + if prefix == 'wgl' and not name in used_wgl_ext_fns: return proto=noneStr(cmd.elem.find('proto')) diff --git a/hw/xwin/glx/glthunk.c b/hw/xwin/glx/glthunk.c index d49fe487c..24dc70d5a 100644 --- a/hw/xwin/glx/glthunk.c +++ b/hw/xwin/glx/glthunk.c @@ -34,10 +34,10 @@ #include <X11/Xwindows.h> #define GL_GLEXT_LEGACY -#include <GL/gl.h> +#include <w32api/GL/gl.h> #undef GL_ARB_imaging #undef GL_VERSION_1_3 -#include <GL/glext.h> +#include <w32api/GL/glext.h> static PROC glWinResolveHelper(PROC * cache, const char *symbol) diff --git a/hw/xwin/glx/winpriv.c b/hw/xwin/glx/winpriv.c index 4f6e4ffd5..11612f905 100644 --- a/hw/xwin/glx/winpriv.c +++ b/hw/xwin/glx/winpriv.c @@ -14,6 +14,36 @@ void winCreateWindowsWindow(WindowPtr pWin); +static void +winCreateWindowsWindowHierarchy(WindowPtr pWin) +{ + winWindowPriv(pWin); + + winDebug("winCreateWindowsWindowHierarchy - pWin:%08x XID:0x%x \n", pWin, + pWin->drawable.id); + + /* recursively ensure parent window exists if it's not the root window */ + if (pWin->parent) { + if (pWin->parent != pWin->drawable.pScreen->root) + 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,8 +80,8 @@ winGetWindowInfo(WindowPtr pWin) } if (pWinPriv->hWnd == NULL) { - winCreateWindowsWindow(pWin); - ErrorF("winGetWindowInfo: forcing window to exist...\n"); + ErrorF("winGetWindowInfo: forcing window to exist\n"); + winCreateWindowsWindowHierarchy(pWin); } if (pWinPriv->hWnd != NULL) { diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man index 18ee667d4..9a046d930 100644 --- a/hw/xwin/man/XWin.man +++ b/hw/xwin/man/XWin.man @@ -76,6 +76,9 @@ preceeding \fB\-screen\fP parameter. .B \-[no]multimonitors or \-[no]multiplemonitors Create a screen 0 that covers all monitors [the primary monitor] on a system with multiple monitors. +Fake XINERAMA data is created describing the individual monitors, +(This is similar to the 'merged framebuffer' or 'pseudo-xinerama' mode provided by +some drivers for the xorg X server). This option is currently enabled by default in \fB\-multiwindow\fP mode. .TP 8 .B "\-screen \fIscreen_number\fP [\fIW\fP \fIH\fP [\fIX\fP \fIY\fP] | [[\fIW\fPx\fIH\fP[+\fIX\fP+\fIY\fP]][@\fIM\fP]] ] " @@ -165,10 +168,16 @@ The maximum dimensions of the screen are the dimensions of the \fIWindows\fP vir on its own is equivalent to \fB\-resize=randr\fP .RE +.SH OPTIONS FOR MULTIWINDOW MODE +.TP 8 +.B \-hostintitle +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. + .SH OPTIONS CONTROLLING WINDOWS INTEGRATION .TP 8 .B \-[no]clipboard -Enables [disables] the integration between the Cygwin/X clipboard and +Enables [disables] the integration between the X11 clipboard and \fIWindows\fP clipboard. The default is enabled. .TP 8 .B "\-emulate3buttons [\fItimeout\fP]" @@ -194,6 +203,10 @@ prevents the \fIWindows\fP mouse cursor from being drawn on top of the X cursor. This parameter has no effect unless \fB-swcursor\fP is also specified. .TP 8 +.B \-[no]primary +Clipboard integration may [will not] use the PRIMARY selection. +The default is enabled. +.TP 8 .B \-swcursor Disable the usage of the \fIWindows\fP cursor and use the X11 software cursor instead. .TP 8 diff --git a/hw/xwin/man/XWinrc.man b/hw/xwin/man/XWinrc.man index 71d8dad23..0f641e92f 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. diff --git a/hw/xwin/system.XWinrc b/hw/xwin/system.XWinrc index f0771c610..5ff3abad6 100644 --- a/hw/xwin/system.XWinrc +++ b/hw/xwin/system.XWinrc @@ -89,9 +89,17 @@ menu apps { } menu root { + "Applications" menu apps // Comments fit here, too... + + SEPARATOR + 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 -e less +F $XWINLOGFILE" + SEPARATOR + "Reload .XWinrc" RELOAD - "Applications" menu apps SEParATOR } diff --git a/hw/xwin/win.h b/hw/xwin/win.h index ce89348fe..5be4659de 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -793,7 +793,7 @@ Bool winInitClipboard(void); void - winFixClipboardChain(void); + winClipboardShutdown(void); #endif /* @@ -917,9 +917,6 @@ void */ int - winTranslateKey(WPARAM wParam, LPARAM lParam); - -int winKeybdProc(DeviceIntPtr pDeviceInt, int iState); void @@ -928,20 +925,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 */ @@ -981,14 +964,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 @@ -1232,6 +1208,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 /* diff --git a/hw/xwin/winauth.c b/hw/xwin/winauth.c index a6a7366a4..59e023479 100644 --- a/hw/xwin/winauth.c +++ b/hw/xwin/winauth.c @@ -38,6 +38,15 @@ #include "securitysrv.h" #include "os/osdep.h" +/* Need to get this from Xlib.h */ +extern void XSetAuthorization( + char * /* name */, + int /* namelen */, + char * /* data */, + int /* datalen */ +); + + /* * Constants */ diff --git a/hw/xwin/winclipboard/Makefile.am b/hw/xwin/winclipboard/Makefile.am new file mode 100644 index 000000000..b1c95f4ef --- /dev/null +++ b/hw/xwin/winclipboard/Makefile.am @@ -0,0 +1,25 @@ +noinst_LTLIBRARIES = libXWinclipboard.la + +libXWinclipboard_la_SOURCES = \ + winclipboard.h \ + textconv.c \ + thread.c \ + wndproc.c \ + xevents.c + +libXWinclipboard_la_CFLAGS = -DHAVE_XWIN_CONFIG_H \ + $(DIX_CFLAGS) \ + $(XWINMODULES_CFLAGS) + +libXWinclipboard_la_LDFLAGS = -static -no-undefined + +bin_PROGRAMS = xwinclip + +xwinclip_SOURCES = xwinclip.c debug.c + +xwinclip_CFLAGS = $(XWINMODULES_CFLAGS) + +xwinclip_LDADD = libXWinclipboard.la $(XWINMODULES_LIBS) -lgdi32 + +include $(top_srcdir)/manpages.am +appman_PRE = xwinclip.man diff --git a/hw/xwin/winclipboard/debug.c b/hw/xwin/winclipboard/debug.c new file mode 100644 index 000000000..78ab6d902 --- /dev/null +++ b/hw/xwin/winclipboard/debug.c @@ -0,0 +1,52 @@ +// +// Copyright © Jon TURNEY 2013 +// +// This file is part of xwinclip. +// +// 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 <stdarg.h> +#include <stdio.h> + +#if 1 +int +winDebug(const char *format, ...) +{ + int count; + va_list ap; + va_start(ap, format); + count = fprintf(stderr, "xwinclip: "); + count += vfprintf(stderr, format, ap); + va_end(ap); + return count; +} +#endif + +int +ErrorF(const char *format, ...) +{ + int count; + va_list ap; + va_start(ap, format); + count = vfprintf(stderr, format, ap); + va_end(ap); + return count; +} diff --git a/hw/xwin/winclipboard.h b/hw/xwin/winclipboard/internal.h index cb7769510..bcf45ca4d 100644 --- a/hw/xwin/winclipboard.h +++ b/hw/xwin/winclipboard/internal.h @@ -1,5 +1,4 @@ -#ifndef _WINCLIPBOARD_H_ -#define _WINCLIPBOARD_H_ + /* *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. * @@ -30,46 +29,19 @@ * Authors: Harold L Hunt II */ -/* Standard library headers */ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#ifdef __CYGWIN__ -#include <sys/select.h> -#else -#include <X11/Xwinsock.h> -#endif -#include <fcntl.h> -#include <setjmp.h> -#include <pthread.h> +#ifndef WINCLIPBOARD_INTERNAL_H +#define WINCLIPBOARD_INTERNAL_H /* X headers */ -#include <X11/X.h> -#include <X11/Xatom.h> -#include <X11/Xproto.h> -#include <X11/Xutil.h> -#include <X11/Xlocale.h> +#include <X11/Xlib.h> /* Windows headers */ #include <X11/Xwindows.h> -/* Clipboard module constants */ -#define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip" -#define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip" -#ifdef HAS_DEVWINDOWS -#define WIN_MSG_QUEUE_FNAME "/dev/windows" -#endif -#define WIN_CONNECT_RETRIES 40 -#define WIN_CONNECT_DELAY 4 -#define WIN_JMP_OKAY 0 -#define WIN_JMP_ERROR_IO 2 -#define WIN_LOCAL_PROPERTY "CYGX_CUT_BUFFER" #define WIN_XEVENTS_SUCCESS 0 -#define WIN_XEVENTS_CONVERT 2 -#define WIN_XEVENTS_NOTIFY 3 -#define WIN_CLIPBOARD_RETRIES 40 -#define WIN_CLIPBOARD_DELAY 1 +#define WIN_XEVENTS_FAILED 1 +#define WIN_XEVENTS_NOTIFY_DATA 3 +#define WIN_XEVENTS_NOTIFY_TARGETS 4 #define WM_WM_REINIT (WM_USER + 1) @@ -77,18 +49,8 @@ * References to external symbols */ -extern char *display; extern void winDebug(const char *format, ...); -extern void winErrorFVerb(int verb, const char *format, ...); - -/* - * winclipboardinit.c - */ - -Bool - winInitClipboard(void); - -HWND winClipboardCreateMessagingWindow(void); +extern void ErrorF(const char *format, ...); /* * winclipboardtextconv.c @@ -104,23 +66,51 @@ void * winclipboardthread.c */ -void *winClipboardProc(void *); + +typedef struct +{ + Atom atomClipboard; + Atom atomLocalProperty; + Atom atomUTF8String; + Atom atomCompoundText; + Atom atomTargets; +} ClipboardAtoms; /* * winclipboardwndproc.c */ -BOOL winClipboardFlushWindowsMessageQueue(HWND hwnd); +Bool winClipboardFlushWindowsMessageQueue(HWND hwnd); LRESULT CALLBACK winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +typedef struct +{ + Display *pClipboardDisplay; + Window iClipboardWindow; + ClipboardAtoms *atoms; +} ClipboardWindowCreationParams; + /* * winclipboardxevents.c */ -int +typedef struct +{ + Bool fUseUnicode; + Atom *targetList; +} ClipboardConversionData; +int winClipboardFlushXEvents(HWND hwnd, - int iWindow, Display * pDisplay, Bool fUnicodeSupport); + Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atom); + + +Atom +winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms); + +void +winClipboardInitMonitoredSelections(void); + #endif diff --git a/hw/xwin/winclipboardtextconv.c b/hw/xwin/winclipboard/textconv.c index fd405a02e..2870a9b8a 100644 --- a/hw/xwin/winclipboardtextconv.c +++ b/hw/xwin/winclipboard/textconv.c @@ -31,14 +31,18 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif -#include "win.h" -#include <stdio.h> -#include <stdlib.h> -void - winClipboardDOStoUNIX(char *pszSrc, int iLength); -void - winClipboardUNIXtoDOS(char **ppszData, int iLength); +/* + * 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 <stdlib.h> +#include "internal.h" /* * Convert \r\n to \n @@ -48,11 +52,14 @@ void */ void -winClipboardDOStoUNIX(char *pszSrc, int iLength) +winClipboardDOStoUNIX(char *pszData, int iLength) { + char *pszSrc = pszData; char *pszDest = pszSrc; char *pszEnd = pszSrc + iLength; + winDebug("DOXtoUNIX() - Original data:'%s'\n", pszData); + /* Loop until the last character */ while (pszSrc < pszEnd) { /* Copy the current source character to current destination character */ @@ -68,6 +75,8 @@ winClipboardDOStoUNIX(char *pszSrc, int iLength) /* Move the terminating null */ *pszDest = '\0'; + + winDebug("DOStoUNIX() - Final string:'%s'\n", pszData); } /* @@ -101,8 +110,10 @@ winClipboardUNIXtoDOS(char **ppszData, int iLength) } /* Return if no naked \n's */ - if (iNewlineCount == 0) + if (iNewlineCount == 0) { + winDebug("UNIXtoDOS () - no conversion necessary\n"); return; + } /* Allocate a new string */ pszDestBegin = pszDest = malloc(iLength + iNewlineCount + 1); diff --git a/hw/xwin/winclipboardthread.c b/hw/xwin/winclipboard/thread.c index 33595be7f..1653747ea 100644 --- a/hw/xwin/winclipboardthread.c +++ b/hw/xwin/winclipboard/thread.c @@ -35,41 +35,62 @@ #else #define HAS_WINSOCK 1 #endif -#include <sys/types.h> -#include <signal.h> -#include "winclipboard.h" -#ifdef __CYGWIN__ -#include <errno.h> -#endif -#include "misc.h" /* - * References to external symbols + * 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 -extern Bool g_fUnicodeClipboard; -extern Bool g_fClipboardStarted; -extern Bool g_fClipboardLaunched; -extern Bool g_fClipboard; -extern HWND g_hwndClipboard; -extern void *g_pClipboardDisplay; -extern Window g_iClipboardWindow; +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#include <setjmp.h> +#include <pthread.h> +#include <sys/param.h> // for MAX() macro + +#ifdef HAS_WINSOCK +#include <X11/Xwinsock.h> +#else +#include <errno.h> +#endif + +#include <X11/Xatom.h> +#include <X11/extensions/Xfixes.h> +#include "winclipboard.h" +#include "internal.h" + +#define WIN_CONNECT_RETRIES 40 +#define WIN_CONNECT_DELAY 4 + +#define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip" +#define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip" +#ifdef HAS_DEVWINDOWS +#define WIN_MSG_QUEUE_FNAME "/dev/windows" +#endif /* * Global variables */ +static HWND g_hwndClipboard = NULL; static jmp_buf g_jmpEntry; -static int clipboardRestarts = 0; static XIOErrorHandler g_winClipboardOldIOErrorHandler; static pthread_t g_winClipboardProcThread; -Bool g_fUseUnicode = FALSE; +int xfixes_event_base; +int xfixes_error_base; /* * Local function prototypes */ +static HWND +winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms); + static int winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr); @@ -77,13 +98,15 @@ static int winClipboardIOErrorHandler(Display * pDisplay); /* - * Main thread function + * Create X11 and Win32 messaging windows, and run message processing loop + * + * returns TRUE if shutdown was signalled to loop, FALSE if some error occurred */ -void * -winClipboardProc(void *pvNotUsed) +Bool +winClipboardProc(Bool fUseUnicode, char *szDisplay) { - Atom atomClipboard; + ClipboardAtoms atoms; int iReturn; HWND hwnd = NULL; int iConnectionNumber = 0; @@ -97,100 +120,41 @@ winClipboardProc(void *pvNotUsed) int iMaxDescriptor; Display *pDisplay = NULL; Window iWindow = None; - int iRetries; - Bool fUseUnicode; - char szDisplay[512]; int iSelectError; + Bool fShutdown = FALSE; winDebug("winClipboardProc - Hello\n"); - ++clipboardRestarts; - - /* Do we use Unicode clipboard? */ - fUseUnicode = g_fUnicodeClipboard; - /* Save the Unicode support flag in a global */ - g_fUseUnicode = fUseUnicode; + /* Set error handler */ + static Bool fErrorHandlerSet = FALSE; - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winClipboardProc - XInitThreads failed.\n"); - goto winClipboardProc_Exit; - } + g_winClipboardProcThread = pthread_self(); - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winClipboardProc - Warning: Locale not supported by X.\n"); + if (! fErrorHandlerSet) { + XSetErrorHandler(winClipboardErrorHandler); + g_winClipboardOldIOErrorHandler = + XSetIOErrorHandler(winClipboardIOErrorHandler); + fErrorHandlerSet = TRUE; } - /* Set error handler */ - XSetErrorHandler(winClipboardErrorHandler); - g_winClipboardProcThread = pthread_self(); - g_winClipboardOldIOErrorHandler = - XSetIOErrorHandler(winClipboardIOErrorHandler); - /* Set jump point for Error exits */ - iReturn = setjmp(g_jmpEntry); - - /* Check if we should continue operations */ - if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { - /* setjmp returned an unknown value, exit */ - ErrorF("winClipboardProc - setjmp returned: %d exiting\n", iReturn); - goto winClipboardProc_Exit; - } - else if (iReturn == WIN_JMP_ERROR_IO) { - /* TODO: Cleanup the Win32 window and free any allocated memory */ + if (setjmp(g_jmpEntry)) { ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n"); - pthread_exit(NULL); - } - - /* Use our generated cookie for authentication */ - winSetAuthorization(); - - /* Initialize retry count */ - iRetries = 0; - - /* Setup the display connection string x */ - /* - * NOTE: Always connect to screen 0 since we require that screen - * numbers start at 0 and increase without gaps. We only need - * to connect to one screen on the display to get events - * for all screens on the display. That is why there is only - * one clipboard client thread. - */ - snprintf(szDisplay, 512, "127.0.0.1:%s.0", display); - - /* Print the display connection string */ - ErrorF("winClipboardProc - DISPLAY=%s\n", szDisplay); - - /* Open the X display */ - do { - pDisplay = XOpenDisplay(szDisplay); - if (pDisplay == NULL) { - ErrorF("winClipboardProc - Could not open display, " - "try: %d, sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); - ++iRetries; - sleep(WIN_CONNECT_DELAY); - continue; - } - else - break; + goto winClipboardProc_Done; } - while (pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); /* Make sure that the display opened */ + pDisplay = XOpenDisplay(szDisplay); if (pDisplay == NULL) { ErrorF("winClipboardProc - Failed opening the display, giving up\n"); goto winClipboardProc_Done; } - /* Save the display in the screen privates */ - g_pClipboardDisplay = pDisplay; - ErrorF("winClipboardProc - XOpenDisplay () returned and " "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 */ @@ -201,22 +165,29 @@ winClipboardProc(void *pvNotUsed) } /* Find max of our file descriptors */ - iMaxDescriptor = max(fdMessageQueue, iConnectionNumber) + 1; + iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1; #else iMaxDescriptor = iConnectionNumber + 1; #endif - /* Create atom */ - atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); + if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base)) + ErrorF ("winClipboardProc - XFixes extension not present\n"); + + /* Create atoms */ + atoms.atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); + atoms.atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False); + atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False); + atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False); + atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False); /* 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; @@ -229,13 +200,27 @@ winClipboardProc(void *pvNotUsed) ErrorF("winClipboardProc - XSelectInput generated BadWindow " "on messaging window\n"); - /* Save the window in the screen privates */ - g_iClipboardWindow = iWindow; + XFixesSelectSelectionInput (pDisplay, + iWindow, + XA_PRIMARY, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + + XFixesSelectSelectionInput (pDisplay, + iWindow, + atoms.atomClipboard, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + + /* Initialize monitored selection state */ + winClipboardInitMonitoredSelections(); /* Create Windows messaging window */ - hwnd = winClipboardCreateMessagingWindow(); + hwnd = winClipboardCreateMessagingWindow(pDisplay, iWindow, &atoms); - /* Save copy of HWND in screen privates */ + /* Save copy of HWND */ g_hwndClipboard = hwnd; /* Assert ownership of selections if Win32 clipboard is owned */ @@ -250,32 +235,35 @@ winClipboardProc(void *pvNotUsed) } /* CLIPBOARD */ - iReturn = XSetSelectionOwner(pDisplay, atomClipboard, + iReturn = XSetSelectionOwner(pDisplay, atoms.atomClipboard, iWindow, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow || - XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) { + XGetSelectionOwner(pDisplay, atoms.atomClipboard) != iWindow) { ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n"); goto winClipboardProc_Done; } } - /* Pre-flush X events */ - /* - * NOTE: Apparently you'll freeze if you don't do this, - * because there may be events in local data structures - * already. - */ - winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); + ClipboardConversionData data; + data.fUseUnicode = fUseUnicode; - /* Pre-flush Windows messages */ - if (!winClipboardFlushWindowsMessageQueue(hwnd)) - return 0; + /* Loop for events */ + while (1) { - /* Signal that the clipboard client has started */ - g_fClipboardStarted = TRUE; + /* Process X events */ + winClipboardFlushXEvents(hwnd, + iWindow, pDisplay, &data, &atoms); + + /* Process Windows messages */ + if (!winClipboardFlushWindowsMessageQueue(hwnd)) { + ErrorF("winClipboardProc - winClipboardFlushWindowsMessageQueue trapped " + "WM_QUIT message, exiting main loop.\n"); + break; + } + + /* We need to ensure that all pending requests are sent */ + XFlush(pDisplay); - /* Loop for X events */ - while (1) { /* Setup the file descriptor set */ /* * NOTE: You have to do this before every call to select @@ -291,6 +279,8 @@ winClipboardProc(void *pvNotUsed) tvTimeout.tv_usec = 100; #endif + winDebug("winClipboardProc - Waiting in select\n"); + /* Wait for a Windows event or an X event */ iReturn = select(iMaxDescriptor, /* Highest fds number */ &fdsRead, /* Read mask */ @@ -322,10 +312,11 @@ winClipboardProc(void *pvNotUsed) break; } - /* Branch on which descriptor became active */ + winDebug("winClipboardProc - select returned %d\n", iReturn); + if (FD_ISSET(iConnectionNumber, &fdsRead)) { - /* Process X events */ - winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); + winDebug + ("winClipboardProc - X connection ready, pumping X event queue\n"); } #ifdef HAS_DEVWINDOWS @@ -335,27 +326,25 @@ winClipboardProc(void *pvNotUsed) if (1) #endif { - /* Process Windows messages */ - if (!winClipboardFlushWindowsMessageQueue(hwnd)) { - ErrorF("winClipboardProc - " - "winClipboardFlushWindowsMessageQueue trapped " - "WM_QUIT message, exiting main loop.\n"); - break; - } + winDebug + ("winClipboardProc - /dev/windows ready, pumping Windows message queue\n"); + } + +#ifdef HAS_DEVWINDOWS + if (!(FD_ISSET(iConnectionNumber, &fdsRead)) && + !(FD_ISSET(fdMessageQueue, &fdsRead))) { + winDebug("winClipboardProc - Spurious wake, select() returned %d\n", iReturn); } +#endif } - winClipboardProc_Exit: - /* disable the clipboard, which means the thread will die */ - g_fClipboard = FALSE; + /* broke out of while loop on a shutdown message */ + fShutdown = TRUE; winClipboardProc_Done: /* Close our Windows window */ if (g_hwndClipboard) { - /* Destroy the Window window (hwnd) */ - winDebug("winClipboardProc - Destroy Windows window\n"); - PostMessage(g_hwndClipboard, WM_DESTROY, 0, 0); - winClipboardFlushWindowsMessageQueue(g_hwndClipboard); + winClipboardWindowDestroy(); } /* Close our X window */ @@ -375,15 +364,18 @@ winClipboardProc(void *pvNotUsed) #if 0 /* - * FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The - * XSync and XSelectInput calls did not help. + * FIXME: XCloseDisplay hangs if we call it + * + * XCloseDisplay() calls XSync(), so any outstanding errors are reported. + * If we are built into the server, this can deadlock if the server is + * in the process of exiting and waiting for this thread to exit. */ /* Discard any remaining events */ XSync(pDisplay, TRUE); /* Select event types to watch */ - XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None); + XSelectInput(pDisplay, XDefaultRootWindow(pDisplay), None); /* Close our X display */ if (pDisplay) { @@ -392,42 +384,64 @@ winClipboardProc(void *pvNotUsed) #endif /* global clipboard variable reset */ - g_fClipboardLaunched = FALSE; - g_fClipboardStarted = FALSE; - g_iClipboardWindow = None; - g_pClipboardDisplay = NULL; g_hwndClipboard = NULL; - /* checking if we need to restart */ - if (clipboardRestarts >= WIN_CLIPBOARD_RETRIES) { - /* terminates clipboard thread but the main server still lives */ - ErrorF - ("winClipboardProc - the clipboard thread has restarted %d times and seems to be unstable, disabling clipboard integration\n", - clipboardRestarts); - g_fClipboard = FALSE; - return NULL; - } - - if (g_fClipboard) { - sleep(WIN_CLIPBOARD_DELAY); - ErrorF("winClipboardProc - trying to restart clipboard thread \n"); - /* Create the clipboard client thread */ - if (!winInitClipboard()) { - ErrorF("winClipboardProc - winClipboardInit failed.\n"); - return NULL; - } + return fShutdown; +} - winDebug("winClipboardProc - winInitClipboard returned.\n"); - /* Flag that clipboard client has been launched */ - g_fClipboardLaunched = TRUE; - } - else { - ErrorF("winClipboardProc - Clipboard disabled - Exit from server \n"); - /* clipboard thread has exited, stop server as well */ - raise(SIGTERM); - } +/* + * Create the Windows window that we use to recieve Windows messages + */ - return NULL; +static HWND +winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms) +{ + WNDCLASSEX wc; + HWND hwnd; + + /* Setup our window class */ + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = winClipboardWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(NULL); + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS; + wc.hIconSm = 0; + RegisterClassEx(&wc); + + /* Information to be passed to WM_CREATE */ + ClipboardWindowCreationParams cwcp; + cwcp.pClipboardDisplay = pDisplay; + cwcp.iClipboardWindow = iWindow; + cwcp.atoms = atoms; + + /* Create the window */ + hwnd = CreateWindowExA(0, /* Extended styles */ + WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */ + WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */ + WS_OVERLAPPED, /* Not visible anyway */ + CW_USEDEFAULT, /* Horizontal position */ + CW_USEDEFAULT, /* Vertical position */ + CW_USEDEFAULT, /* Right edge */ + CW_USEDEFAULT, /* Bottom edge */ + (HWND) NULL, /* No parent or owner window */ + (HMENU) NULL, /* No menu */ + GetModuleHandle(NULL), /* Instance handle */ + &cwcp); /* Creation data */ + assert(hwnd != NULL); + + /* I'm not sure, but we may need to call this to start message processing */ + ShowWindow(hwnd, SW_HIDE); + + /* Similarly, we may need a call to this even though we don't paint */ + UpdateWindow(hwnd); + + return hwnd; } /* @@ -457,7 +471,7 @@ winClipboardIOErrorHandler(Display * pDisplay) if (pthread_equal(pthread_self(), g_winClipboardProcThread)) { /* Restart at the main entry point */ - longjmp(g_jmpEntry, WIN_JMP_ERROR_IO); + longjmp(g_jmpEntry, 2); } if (g_winClipboardOldIOErrorHandler) @@ -465,3 +479,19 @@ winClipboardIOErrorHandler(Display * pDisplay) return 0; } + +void +winClipboardWindowDestroy(void) +{ + if (g_hwndClipboard) { + SendMessage(g_hwndClipboard, WM_DESTROY, 0, 0); + } +} + +void +winFixClipboardChain(void) +{ + if (g_hwndClipboard) { + PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0); + } +} diff --git a/hw/xwin/winclipboard/winclipboard.h b/hw/xwin/winclipboard/winclipboard.h new file mode 100644 index 000000000..e7ccc3637 --- /dev/null +++ b/hw/xwin/winclipboard/winclipboard.h @@ -0,0 +1,38 @@ +// +// Copyright © Jon TURNEY 2013 +// +// 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. +// +// File: winclipboard.h +// Purpose: public interface to winclipboard library +// + +#ifndef WINCLIPBOARD_H +#define WINCLIPBOARD_H + +Bool winClipboardProc(Bool fUseUnicode, char *szDisplay); + +void winFixClipboardChain(void); + +void winClipboardWindowDestroy(void); + +extern int fPrimarySelection; + +#endif diff --git a/hw/xwin/winclipboardwndproc.c b/hw/xwin/winclipboard/wndproc.c index 90dc9e0bb..b5566fa5a 100644 --- a/hw/xwin/winclipboardwndproc.c +++ b/hw/xwin/winclipboard/wndproc.c @@ -33,10 +33,24 @@ #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 <sys/types.h> #include <sys/time.h> +#include <limits.h> + +#include <X11/Xatom.h> + +#include "internal.h" #include "winclipboard.h" -#include "misc.h" /* * Constants @@ -44,21 +58,14 @@ #define WIN_POLL_TIMEOUT 1 -/* - * References to external symbols - */ - -extern void *g_pClipboardDisplay; -extern Window g_iClipboardWindow; -extern Atom g_atomLastOwnedSelection; /* * Process X events up to specified timeout */ static int -winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay, - Bool fUseUnicode, int iTimeoutSec) +winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay, + ClipboardConversionData *data, ClipboardAtoms *atoms, int iTimeoutSec) { int iConnNumber; struct timeval tv; @@ -69,15 +76,25 @@ winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay, iTimeoutSec); /* Get our connection number */ - iConnNumber = ConnectionNumber(pDisplay); + iConnNumber = XConnectionNumber(pDisplay); /* Loop for X events */ while (1) { fd_set fdsRead; long remainingTime; - /* We need to ensure that all pending events are processed */ - XSync(pDisplay, FALSE); + /* Process X events */ + iReturn = winClipboardFlushXEvents(hwnd, iWindow, pDisplay, data, atoms); + + winDebug("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", iReturn); + + if ((WIN_XEVENTS_NOTIFY_DATA == iReturn) || (WIN_XEVENTS_NOTIFY_TARGETS == iReturn) || (WIN_XEVENTS_FAILED == iReturn)) { + /* Bail out */ + return iReturn; + } + + /* We need to ensure that all pending requests are sent */ + XFlush(pDisplay); /* Setup the file descriptor set */ FD_ZERO(&fdsRead); @@ -106,24 +123,8 @@ winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay, break; } - /* Branch on which descriptor became active */ - if (FD_ISSET(iConnNumber, &fdsRead)) { - /* Process X events */ - /* Exit when we see that server is shutting down */ - iReturn = winClipboardFlushXEvents(hwnd, - iWindow, pDisplay, fUseUnicode); - - winDebug - ("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", - iReturn); - - if (WIN_XEVENTS_NOTIFY == iReturn) { - /* Bail out if notify processed */ - return iReturn; - } - } - else { - winDebug("winProcessXEventsTimeout - Spurious wake\n"); + if (!FD_ISSET(iConnNumber, &fdsRead)) { + winDebug("winProcessXEventsTimeout - Spurious wake, select() returned %d\n", iReturn); } } @@ -139,6 +140,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND s_hwndNextViewer; static Bool s_fCBCInitialized; + static Display *pDisplay; + static Window iWindow; + static ClipboardAtoms *atoms; /* Branch on message type */ switch (message) { @@ -162,6 +166,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) winDebug("winClipboardWindowProc - WM_CREATE\n"); + ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams; + pDisplay = cwcp->pClipboardDisplay; + iWindow = cwcp->iClipboardWindow; + atoms = cwcp->atoms; + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ if (first == hwnd) return 0; /* Make sure it's not us! */ @@ -185,8 +194,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) s_hwndNextViewer = (HWND) lParam; if (s_hwndNextViewer == hwnd) { s_hwndNextViewer = NULL; - winErrorFVerb(1, "winClipboardWindowProc - WM_CHANGECBCHAIN: " - "attempted to set next window to ourselves."); + ErrorF("winClipboardWindowProc - WM_CHANGECBCHAIN: " + "attempted to set next window to ourselves."); } } else if (s_hwndNextViewer) @@ -241,20 +250,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DRAWCLIPBOARD: { - static Atom atomClipboard; - static int generation; static Bool s_fProcessingDrawClipboard = FALSE; - Display *pDisplay = g_pClipboardDisplay; - Window iWindow = g_iClipboardWindow; int iReturn; winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n"); - if (generation != serverGeneration) { - generation = serverGeneration; - atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); - } - /* * We've occasionally seen a loop in the clipboard chain. * Try and fix it on the first hint of recursion. @@ -267,8 +267,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) s_fCBCInitialized = FALSE; ChangeClipboardChain(hwnd, s_hwndNextViewer); winFixClipboardChain(); - winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "Nested calls detected. Re-initing.\n"); + ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Nested calls detected. Re-initing.\n"); winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); s_fProcessingDrawClipboard = FALSE; return 0; @@ -314,6 +314,36 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) "Clipboard does not contain CF_TEXT nor " "CF_UNICODETEXT.\n"); + winDebug("winClipboardWindowProc: %d formats\n", + CountClipboardFormats()); + + if (OpenClipboard(hwnd)) { + unsigned int format = 0; + + do { + format = EnumClipboardFormats(format); + if (GetLastError() != ERROR_SUCCESS) { + winDebug + ("winClipboardWindowProc: EnumClipboardFormats failed %x\n", + GetLastError()); + } + if (format > 0xc000) { + char buff[256]; + + GetClipboardFormatName(format, buff, 256); + winDebug("winClipboardWindowProc: %d %s\n", format, + buff); + } + else if (format > 0) + winDebug("winClipboardWindowProc: %d\n", format); + } while (format != 0); + CloseClipboard(); + } + else { + winDebug + ("WindowProc: could not open clipboard to enumerate formats\n"); + } + /* * We need to make sure that the X Server has processed * previous XSetSelectionOwner messages. @@ -324,27 +354,27 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Release PRIMARY selection if owned */ iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY); - if (iReturn == g_iClipboardWindow) { + if (iReturn == iWindow) { winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "PRIMARY selection is owned by us.\n"); + "PRIMARY selection is owned by us, releasing\n"); XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime); } else if (BadWindow == iReturn || BadAtom == iReturn) - winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "XGetSelection failed for PRIMARY: %d\n", - iReturn); + ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "XGetSelectionOwner failed for PRIMARY: %d\n", + iReturn); /* Release CLIPBOARD selection if owned */ - iReturn = XGetSelectionOwner(pDisplay, atomClipboard); - if (iReturn == g_iClipboardWindow) { + iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard); + if (iReturn == iWindow) { winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "CLIPBOARD selection is owned by us.\n"); - XSetSelectionOwner(pDisplay, atomClipboard, None, CurrentTime); + "CLIPBOARD selection is owned by us, releasing\n"); + XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime); } else if (BadWindow == iReturn || BadAtom == iReturn) - winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "XGetSelection failed for CLIPBOARD: %d\n", - iReturn); + ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "XGetSelectionOwner failed for CLIPBOARD: %d\n", + iReturn); winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); s_fProcessingDrawClipboard = FALSE; @@ -358,8 +388,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) XA_PRIMARY, iWindow, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow || XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) { - winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "Could not reassert ownership of PRIMARY\n"); + ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Could not reassert ownership of PRIMARY\n"); } else { winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " @@ -368,12 +398,12 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Reassert ownership of the CLIPBOARD */ iReturn = XSetSelectionOwner(pDisplay, - atomClipboard, iWindow, CurrentTime); + atoms->atomClipboard, iWindow, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow || - XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) { - winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " - "Could not reassert ownership of CLIPBOARD\n"); + XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) { + ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Could not reassert ownership of CLIPBOARD\n"); } else { winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " @@ -409,11 +439,14 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_RENDERALLFORMATS: { int iReturn; - Display *pDisplay = g_pClipboardDisplay; - Window iWindow = g_iClipboardWindow; Bool fConvertToUnicode; + Bool pasted = FALSE; - winDebug("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n"); + if (message == WM_RENDERALLFORMATS) + winDebug("winClipboardWindowProc - WM_RENDERALLFORMATS - Hello.\n"); + else + winDebug("winClipboardWindowProc - WM_RENDERFORMAT %d - Hello.\n", + wParam); /* Flag whether to convert to Unicode or not */ if (message == WM_RENDERALLFORMATS) @@ -421,20 +454,89 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) else fConvertToUnicode = (CF_UNICODETEXT == wParam); - /* Request the selection contents */ - iReturn = XConvertSelection(pDisplay, - g_atomLastOwnedSelection, - XInternAtom(pDisplay, - "COMPOUND_TEXT", False), - XInternAtom(pDisplay, - "CYGX_CUT_BUFFER", False), - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) { - winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMAT - " - "XConvertSelection () failed\n"); - break; + Atom selection = winClipboardGetLastOwnedSelectionAtom(atoms); + + if (selection == None) { + ErrorF("winClipboardWindowProc - no monitored selection is owned\n"); + goto fake_paste; } + winDebug("winClipboardWindowProc - requesting targets for selection from owner\n"); + + /* Request the selection's supported conversion targets */ + XConvertSelection(pDisplay, + selection, + atoms->atomTargets, + atoms->atomLocalProperty, + iWindow, CurrentTime); + + /* Process X events */ + ClipboardConversionData data; + data.fUseUnicode = fConvertToUnicode; + iReturn = winProcessXEventsTimeout(hwnd, + iWindow, + pDisplay, + &data, + atoms, + WIN_POLL_TIMEOUT); + + if (WIN_XEVENTS_NOTIFY_TARGETS != iReturn) { + ErrorF + ("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_TARGETS\n"); + goto fake_paste; + } + + /* Choose the most preferred target */ + struct target_priority + { + Atom target; + unsigned int priority; + }; + + struct target_priority target_priority_table[] = + { + { atoms->atomCompoundText, 0 }, +#ifdef X_HAVE_UTF8_STRING + { atoms->atomUTF8String, 1 }, +#endif + { XA_STRING, 2 }, + }; + + int best_priority = INT_MAX; + int best_target = 0; + + int i,j; + for (i = 0 ; data.targetList[i] != 0; i++) + { + for (j = 0; j < sizeof(target_priority_table)/sizeof(struct target_priority); j ++) + { + if ((data.targetList[i] == target_priority_table[j].target) && + (target_priority_table[j].priority < best_priority)) + { + best_target = target_priority_table[j].target; + best_priority = target_priority_table[j].priority; + } + } + } + + free(data.targetList); + data.targetList = 0; + + winDebug("winClipboardWindowProc - best target is %d\n", best_target); + + /* No useful targets found */ + if (best_target == 0) + goto fake_paste; + + winDebug("winClipboardWindowProc - requesting selection from owner\n"); + + /* Request the selection contents */ + XConvertSelection(pDisplay, + selection, + best_target, + atoms->atomLocalProperty, + iWindow, CurrentTime); + /* Special handling for WM_RENDERALLFORMATS */ if (message == WM_RENDERALLFORMATS) { /* We must open and empty the clipboard */ @@ -445,52 +547,59 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } if (!OpenClipboard(hwnd)) { - winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMATS - " - "OpenClipboard () failed: %08x\n", - GetLastError()); - break; + ErrorF("winClipboardWindowProc - WM_RENDER*FORMATS - " + "OpenClipboard () failed: %08x\n", + GetLastError()); } if (!EmptyClipboard()) { - winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMATS - " - "EmptyClipboard () failed: %08x\n", - GetLastError()); - break; + ErrorF("winClipboardWindowProc - WM_RENDER*FORMATS - " + "EmptyClipboard () failed: %08x\n", + GetLastError()); } } - /* Process the SelectionNotify event */ + /* Process X events */ iReturn = winProcessXEventsTimeout(hwnd, iWindow, pDisplay, - fConvertToUnicode, WIN_POLL_TIMEOUT); + &data, + atoms, + WIN_POLL_TIMEOUT); /* - * The last call to winProcessXEventsTimeout - * from above had better have seen a notify event, or else we - * are dealing with a buggy or old X11 app. In these cases we - * have to paste some fake data to the Win32 clipboard to - * satisfy the requirement that we write something to it. + * winProcessXEventsTimeout had better have seen a notify event, + * or else we are dealing with a buggy or old X11 app. */ - if (WIN_XEVENTS_NOTIFY != iReturn) { + if (WIN_XEVENTS_NOTIFY_DATA != iReturn) { + ErrorF + ("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_DATA\n"); + } + else { + pasted = TRUE; + } + + /* + * If we couldn't get the data from the X clipboard, we + * have to paste some fake data to the Win32 clipboard to + * satisfy the requirement that we write something to it. + */ + fake_paste: + if (!pasted) + { /* Paste no data, to satisfy required call to SetClipboardData */ SetClipboardData(CF_UNICODETEXT, NULL); SetClipboardData(CF_TEXT, NULL); - - ErrorF - ("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY\n"); - } + } /* Special handling for WM_RENDERALLFORMATS */ if (message == WM_RENDERALLFORMATS) { /* We must close the clipboard */ if (!CloseClipboard()) { - winErrorFVerb(1, - "winClipboardWindowProc - WM_RENDERALLFORMATS - " - "CloseClipboard () failed: %08x\n", - GetLastError()); - break; + ErrorF("winClipboardWindowProc - WM_RENDERALLFORMATS - " + "CloseClipboard () failed: %08x\n", + GetLastError()); } } @@ -507,7 +616,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) * Process any pending Windows messages */ -BOOL +Bool winClipboardFlushWindowsMessageQueue(HWND hwnd) { MSG msg; diff --git a/hw/xwin/winclipboardxevents.c b/hw/xwin/winclipboard/xevents.c index 226c3f055..1861b40cc 100644 --- a/hw/xwin/winclipboardxevents.c +++ b/hw/xwin/winclipboard/xevents.c @@ -33,8 +33,156 @@ #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 <limits.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xfixes.h> + #include "winclipboard.h" -#include "misc.h" +#include "internal.h" + +/* + * Constants + */ + +#define CLIP_NUM_SELECTIONS 2 +#define CLIP_OWN_NONE -1 +#define CLIP_OWN_PRIMARY 0 +#define CLIP_OWN_CLIPBOARD 1 + +/* + * Global variables + */ + +extern int xfixes_event_base; +int fPrimarySelection = 1; + +/* + * Local variables + */ + +static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None }; +static const char *szSelectionNames[CLIP_NUM_SELECTIONS] = + { "PRIMARY", "CLIPBOARD" }; + +static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE; + +static void +MonitorSelection(XFixesSelectionNotifyEvent * e, unsigned int i) +{ + /* Look for owned -> not owned transition */ + if (None == e->owner && None != s_iOwners[i]) { + unsigned int other_index; + + winDebug("MonitorSelection - %s - Going from owned to not owned.\n", + szSelectionNames[i]); + + /* If this selection is not owned, the other monitored selection must be the most + recently owned, if it is owned at all */ + if (i == CLIP_OWN_PRIMARY) + other_index = CLIP_OWN_CLIPBOARD; + if (i == CLIP_OWN_CLIPBOARD) + other_index = CLIP_OWN_PRIMARY; + if (None != s_iOwners[other_index]) + lastOwnedSelectionIndex = other_index; + else + lastOwnedSelectionIndex = CLIP_OWN_NONE; + } + + /* Save last owned selection */ + if (None != e->owner) { + lastOwnedSelectionIndex = i; + } + + /* Save new selection owner or None */ + s_iOwners[i] = e->owner; + winDebug("MonitorSelection - %s - Now owned by XID %x\n", + szSelectionNames[i], e->owner); +} + +Atom +winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms) +{ + if (lastOwnedSelectionIndex == CLIP_OWN_NONE) + return None; + + winDebug("GetLastOwnedSelectionAtom: selection %s owned by XID %x\n", szSelectionNames[lastOwnedSelectionIndex], s_iOwners[lastOwnedSelectionIndex]); + + if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY) + return XA_PRIMARY; + + if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD) + return atoms->atomClipboard; + + return None; +} + + +void +winClipboardInitMonitoredSelections(void) +{ + /* Initialize static variables */ + for (int i = 0; i < CLIP_NUM_SELECTIONS; ++i) + s_iOwners[i] = None; + + lastOwnedSelectionIndex = CLIP_OWN_NONE; +} + +static int +winClipboardSelectionNotifyTargets(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms) +{ + Atom type; + int format; + unsigned long nitems; + unsigned long after; + Atom *prop; + + /* Retrieve the selection data and delete the property */ + int iReturn = XGetWindowProperty(pDisplay, + iWindow, + atoms->atomLocalProperty, + 0, + INT_MAX, + True, + AnyPropertyType, + &type, + &format, + &nitems, + &after, + (unsigned char **)&prop); + if (iReturn != Success) { + ErrorF("winClipboardFlushXEvents - SelectionNotify - " + "XGetWindowProperty () failed, aborting: %d\n", iReturn); + } else { + int i; + data->targetList = malloc((nitems+1)*sizeof(Atom)); + + for (i = 0; i < nitems; i++) + { + Atom atom = prop[i]; + data->targetList[i] = atom; + char *pszAtomName = XGetAtomName(pDisplay, atom); + winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName); + XFree(pszAtomName); + } + + data->targetList[nitems] = 0; + + XFree(prop); + } + + return WIN_XEVENTS_NOTIFY_TARGETS; +} /* * Process any pending X events @@ -42,21 +190,13 @@ int winClipboardFlushXEvents(HWND hwnd, - int iWindow, Display * pDisplay, Bool fUseUnicode) + Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms) { - static Atom atomLocalProperty; - static Atom atomCompoundText; - static Atom atomUTF8String; - static Atom atomTargets; - static int generation; - - if (generation != serverGeneration) { - generation = serverGeneration; - atomLocalProperty = XInternAtom(pDisplay, WIN_LOCAL_PROPERTY, False); - atomUTF8String = XInternAtom(pDisplay, "UTF8_STRING", False); - atomCompoundText = XInternAtom(pDisplay, "COMPOUND_TEXT", False); - atomTargets = XInternAtom(pDisplay, "TARGETS", False); - } + Atom atomClipboard = atoms->atomClipboard; + Atom atomLocalProperty = atoms->atomLocalProperty; + Atom atomUTF8String = atoms->atomUTF8String; + Atom atomCompoundText = atoms->atomCompoundText; + Atom atomTargets = atoms->atomTargets; /* Process all pending events */ while (XPending(pDisplay)) { @@ -77,7 +217,6 @@ winClipboardFlushXEvents(HWND hwnd, wchar_t *pwszUnicodeStr = NULL; int iUnicodeLen = 0; int iReturnDataLen = 0; - int i; Bool fAbort = FALSE; Bool fCloseClipboard = FALSE; Bool fSetClipboardData = TRUE; @@ -95,12 +234,14 @@ winClipboardFlushXEvents(HWND hwnd, { char *pszAtomName = NULL; - winDebug("SelectionRequest - target %d\n", - event.xselectionrequest.target); + pszAtomName = XGetAtomName(pDisplay, + event.xselectionrequest.selection); + winDebug("winClipboardFlushXEvents - SelectionRequest - Selection: %s\n", pszAtomName); + XFree(pszAtomName); pszAtomName = XGetAtomName(pDisplay, event.xselectionrequest.target); - winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); + winDebug("winClipboardFlushXEvents - SelectionRequest - Target %d = %s\n", event.xselectionrequest.target, pszAtomName); XFree(pszAtomName); pszAtomName = NULL; } @@ -122,6 +263,7 @@ winClipboardFlushXEvents(HWND hwnd, atomUTF8String, XA_STRING }; + winDebug("winClipboardFlushXEvents - SelectionRequest - populating targets\n"); /* Try to change the property */ iReturn = XChangeProperty(pDisplay, @@ -184,7 +326,7 @@ winClipboardFlushXEvents(HWND hwnd, fCloseClipboard = TRUE; /* Check that clipboard format is available */ - if (fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { + if (data->fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { static int count; /* Hack to stop acroread spamming the log */ static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ @@ -201,7 +343,7 @@ winClipboardFlushXEvents(HWND hwnd, fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } - else if (!fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { + else if (!data->fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { ErrorF("winClipboardFlushXEvents - CF_TEXT is not " "available from Win32 clipboard. Aborting.\n"); @@ -223,7 +365,7 @@ winClipboardFlushXEvents(HWND hwnd, xiccesStyle = XStringStyle; /* Get a pointer to the clipboard text, in desired format */ - if (fUseUnicode) { + if (data->fUseUnicode) { /* Retrieve clipboard data */ hGlobal = GetClipboardData(CF_UNICODETEXT); } @@ -242,7 +384,7 @@ winClipboardFlushXEvents(HWND hwnd, pszGlobalData = (char *) GlobalLock(hGlobal); /* Convert the Unicode string to UTF8 (MBCS) */ - if (fUseUnicode) { + if (data->fUseUnicode) { iConvertDataLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) pszGlobalData, @@ -273,7 +415,7 @@ winClipboardFlushXEvents(HWND hwnd, xtpText.nitems = 0; /* Create the text property from the text list */ - if (fUseUnicode) { + if (data->fUseUnicode) { #ifdef X_HAVE_UTF8_STRING iReturn = Xutf8TextListToTextProperty(pDisplay, pszTextList, @@ -367,6 +509,7 @@ winClipboardFlushXEvents(HWND hwnd, * client when we abort. */ if (fAbort) { + winDebug("winClipboardFlushXEvents - SelectionRequest - aborting\n"); /* Setup selection notify event */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; @@ -418,75 +561,31 @@ winClipboardFlushXEvents(HWND hwnd, } /* - * Request conversion of UTF8 and CompoundText targets. - */ - if (event.xselection.property == None) { - if (event.xselection.target == XA_STRING) { - winDebug("winClipboardFlushXEvents - SelectionNotify - " - "XA_STRING\n"); + SelectionNotify with property of None indicates either: - return WIN_XEVENTS_CONVERT; - } - else if (event.xselection.target == atomUTF8String) { - winDebug("winClipboardFlushXEvents - SelectionNotify - " - "Requesting conversion of UTF8 target.\n"); - - XConvertSelection(pDisplay, - event.xselection.selection, - XA_STRING, - atomLocalProperty, iWindow, CurrentTime); - - /* Process the ConvertSelection event */ - XFlush(pDisplay); - return WIN_XEVENTS_CONVERT; - } -#ifdef X_HAVE_UTF8_STRING - else if (event.xselection.target == atomCompoundText) { - winDebug("winClipboardFlushXEvents - SelectionNotify - " - "Requesting conversion of CompoundText target.\n"); - - XConvertSelection(pDisplay, - event.xselection.selection, - atomUTF8String, - atomLocalProperty, iWindow, CurrentTime); - - /* Process the ConvertSelection event */ - XFlush(pDisplay); - return WIN_XEVENTS_CONVERT; - } -#endif - else { + (i) Generated by the X server if no owner for the specified selection exists + (perhaps it's disappeared on us mid-transaction), or + (ii) Sent by the selection owner when the requested selection conversion could + not be performed or server errors prevented the conversion data being returned + */ + if (event.xselection.property == None) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " - "Unknown format. Cannot request conversion, " - "aborting.\n"); - break; + "Conversion to format %d refused.\n", + event.xselection.target); + return WIN_XEVENTS_FAILED; } - } - /* Retrieve the size of the stored data */ - iReturn = XGetWindowProperty(pDisplay, iWindow, atomLocalProperty, 0, 0, /* Don't get data, just size */ - False, - AnyPropertyType, - &xtpText.encoding, - &xtpText.format, - &xtpText.nitems, - &ulReturnBytesLeft, &xtpText.value); - if (iReturn != Success) { - ErrorF("winClipboardFlushXEvents - SelectionNotify - " - "XGetWindowProperty () failed, aborting: %d\n", iReturn); - break; + if (event.xselection.target == atomTargets) { + return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms); } - winDebug("SelectionNotify - returned data %d left %d\n", - xtpText.nitems, ulReturnBytesLeft); - - /* Request the selection data */ + /* Retrieve the selection data and delete the property */ iReturn = XGetWindowProperty(pDisplay, iWindow, atomLocalProperty, 0, - ulReturnBytesLeft, - False, + INT_MAX, + True, AnyPropertyType, &xtpText.encoding, &xtpText.format, @@ -495,7 +594,7 @@ winClipboardFlushXEvents(HWND hwnd, if (iReturn != Success) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "XGetWindowProperty () failed, aborting: %d\n", iReturn); - break; + goto winClipboardFlushXEvents_SelectionNotify_Done; } { @@ -504,12 +603,13 @@ winClipboardFlushXEvents(HWND hwnd, winDebug("SelectionNotify - returned data %d left %d\n", xtpText.nitems, ulReturnBytesLeft); pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); - winDebug("Notify atom name %s\n", pszAtomName); + winDebug("SelectionNotify - encoding atom name %s\n", + pszAtomName); XFree(pszAtomName); pszAtomName = NULL; } - if (fUseUnicode) { + if (data->fUseUnicode) { #ifdef X_HAVE_UTF8_STRING /* Convert the text property to a text list */ iReturn = Xutf8TextPropertyToTextList(pDisplay, @@ -525,6 +625,8 @@ winClipboardFlushXEvents(HWND hwnd, if (iReturn == Success || iReturn > 0) { /* Conversion succeeded or some unconvertible characters */ if (ppszTextList != NULL) { + int i; + iReturnDataLen = 0; for (i = 0; i < iCount; i++) { iReturnDataLen += strlen(ppszTextList[i]); @@ -574,7 +676,7 @@ winClipboardFlushXEvents(HWND hwnd, /* Convert the X clipboard string to DOS format */ winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData)); - if (fUseUnicode) { + if (data->fUseUnicode) { /* Find out how much space needed to convert MBCS to Unicode */ iUnicodeLen = MultiByteToWideChar(CP_UTF8, 0, @@ -634,7 +736,7 @@ winClipboardFlushXEvents(HWND hwnd, } /* Copy the returned string into the global memory */ - if (fUseUnicode) { + if (data->fUseUnicode) { memcpy(pszGlobalData, pwszUnicodeStr, sizeof(wchar_t) * (iUnicodeLen + 1)); free(pwszUnicodeStr); @@ -651,7 +753,7 @@ winClipboardFlushXEvents(HWND hwnd, pszGlobalData = NULL; /* Push the selection data to the Windows clipboard */ - if (fUseUnicode) + if (data->fUseUnicode) SetClipboardData(CF_UNICODETEXT, hGlobal); else SetClipboardData(CF_TEXT, hGlobal); @@ -681,21 +783,100 @@ winClipboardFlushXEvents(HWND hwnd, SetClipboardData(CF_UNICODETEXT, NULL); SetClipboardData(CF_TEXT, NULL); } - return WIN_XEVENTS_NOTIFY; + return WIN_XEVENTS_NOTIFY_DATA; case SelectionClear: - winDebug("SelectionClear - doing nothing\n"); + winDebug("winClipboardFlushXEvents - SelectionClear - doing nothing\n"); break; case PropertyNotify: + { + char *pszAtomName; + + pszAtomName = XGetAtomName(pDisplay, event.xproperty.atom); + winDebug("winClipboardFlushXEvents - PropertyNotify - ATOM: %s %s\n", + pszAtomName, + event.xproperty.state == PropertyNewValue ? "PropertyNewValue" : "PropertyDelete"); + XFree(pszAtomName); + } break; case MappingNotify: break; default: - ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", - event.type); + if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) { + XFixesSelectionNotifyEvent *e = + (XFixesSelectionNotifyEvent *) & event; + + winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); + + /* Save selection owners for monitored selections, ignore other selections */ + if ((e->selection == XA_PRIMARY) && fPrimarySelection) { + MonitorSelection(e, CLIP_OWN_PRIMARY); + } + else if (e->selection == atomClipboard) { + MonitorSelection(e, CLIP_OWN_CLIPBOARD); + } + else + break; + + /* Selection is being disowned */ + if (e->owner == None) { + winDebug + ("winClipboardFlushXEvents - No window, returning.\n"); + break; + } + + /* + XXX: there are all kinds of wacky edge cases we might need here: + - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it? + - root window is taking ownership? + */ + + /* If we are the owner of the most recently owned selection, don't go all recursive :) */ + if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) && + (s_iOwners[lastOwnedSelectionIndex] == iWindow)) { + winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n"); + break; + } + + /* Close clipboard if we have it open already (possible? correct??) */ + if (GetOpenClipboardWindow() == hwnd) { + CloseClipboard(); + } + + /* Access the Windows clipboard */ + if (!OpenClipboard(hwnd)) { + ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n", + (int) GetLastError()); + break; + } + + /* Take ownership of the Windows clipboard */ + if (!EmptyClipboard()) { + ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n", + (int) GetLastError()); + break; + } + + /* Advertise regular text and unicode */ + SetClipboardData(CF_UNICODETEXT, NULL); + SetClipboardData(CF_TEXT, NULL); + + /* Release the clipboard */ + if (!CloseClipboard()) { + ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n", + (int) GetLastError()); + break; + } + } + /* XFixesSelectionWindowDestroyNotifyMask */ + /* XFixesSelectionClientCloseNotifyMask */ + else { + ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", + event.type); + } break; } } diff --git a/hw/xwin/winclipboard/xwinclip.c b/hw/xwin/winclipboard/xwinclip.c new file mode 100644 index 000000000..8dfd24bd9 --- /dev/null +++ b/hw/xwin/winclipboard/xwinclip.c @@ -0,0 +1,134 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. + *Copyright (C) Colin Harrison 2005-2008 + * + *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 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. + * + *Except as contained in this notice, the name of the copyright holder(s) + *and author(s) 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 copyright holder(s) and author(s). + * + * Authors: Harold L Hunt II + * Colin Harrison + */ + +#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 <string.h> + +/* X headers */ +#include <X11/Xlib.h> +#ifdef X_LOCALE +#include <X11/Xlocale.h> +#else /* X_LOCALE */ +#include <locale.h> +#endif /* X_LOCALE */ + +#include "winclipboard.h" + +/* + * Main function + */ + +int +main (int argc, char *argv[]) +{ + int i; + char *pszDisplay = NULL; + int fUnicodeClipboard = 1; + + /* Parse command-line parameters */ + for (i = 1; i < argc; ++i) + { + /* Look for -display "display_name" or --display "display_name" */ + if (i < argc - 1 + && (!strcmp (argv[i], "-display") + || !strcmp (argv[i], "--display"))) + { + /* Grab a pointer to the display parameter */ + pszDisplay = argv[i + 1]; + + /* Skip the display argument */ + i++; + continue; + } + + /* Look for -nounicodeclipboard */ + if (!strcmp (argv[i], "-nounicodeclipboard")) + { + fUnicodeClipboard = 0; + continue; + } + + /* Look for -noprimary */ + if (!strcmp (argv[i], "-noprimary")) + { + fPrimarySelection = 0; + continue; + } + + /* Yack when we find a parameter that we don't know about */ + printf ("Unknown parameter: %s\nExiting.\n", argv[i]); + exit (1); + } + + /* Do we have Unicode support? */ + if (fUnicodeClipboard) + { + printf ("Unicode clipboard I/O\n"); + } + else + { + printf ("Non Unicode clipboard I/O\n"); + } + + /* Apply locale specified in the LANG environment variable */ + if (!setlocale (LC_ALL, "")) + { + printf ("setlocale() error\n"); + exit (1); + } + + /* See if X supports the current locale */ + if (XSupportsLocale () == False) + { + printf ("Locale not supported by X, falling back to 'C' locale.\n"); + setlocale(LC_ALL, "C"); + } + + winClipboardProc(fUnicodeClipboard, pszDisplay); + + return 0; +} diff --git a/hw/xwin/winclipboard/xwinclip.man b/hw/xwin/winclipboard/xwinclip.man new file mode 100644 index 000000000..a53dc3029 --- /dev/null +++ b/hw/xwin/winclipboard/xwinclip.man @@ -0,0 +1,64 @@ +.TH xwinclip 1 __xorgversion__ +.SH NAME +xwinclip - An X11 and Windows clipboard integration tool + +.SH SYNOPSIS +.B xwinclip [OPTION]... + +.SH DESCRIPTION +\fIxwinclip\fP is a tool for copying and pasting text between the Windows and X11 clipboard systems. + +\fIxwinclip\fP watches for updates to either clipboard and copies data between them when either one is updated. + +\fIxwinclip\fP monitors the X PRIMARY and CLIBPOARD selections for changes in ownership, and makes +the contents of the most recent one to change available to paste from the Windows clipboard. + +It also monitors the contents of the Windows clipboard for changes, taking ownership of the PRIMARY and +CLIPBOARD selections, and making the contents of the Windows clipboard available in them. + +.B Note well: +The \fIXWin(1)\fP X server has internal clipboard integration that is enabled by default. +Do \fINOT\fP run \fIxwinclip\fP unless \fIXWin(1)\fP has been started with the -noclipboard option. + +.SH OPTIONS +\fIxwinclip\fP accepts the following optional command line switches: + +.TP 8 +.B \-display [display] +Specifies the X server display to connect to. +.TP 8 +.B \-nounicodeclipboard +Do not use unicode text on the clipboard. +.TP 8 +.B \-noprimary +Do not monitor the PRIMARY selection. + +.SH "SEE ALSO" +XWin(1) + +.SH BUGS +Only text clipboard contents are supported. + +The INCR (Incrememntal transfer) clipboard protocol for clipboard contents larger than the maximum size of an +X request is not supported. + +Some X clients, notably ones written in Tcl/Tk, do not re-assert ownership of the PRIMARY selection or update +it's timestamp when it's contents change, which currently prevents \fIxwinclip\fP from correctly noticing that +the PRIMARY selection's contents have changed. + +Windows clipboard rendering is synchronous in the WM_RENDER*FORMAT message (that is, we must have placed the +contents onto the clipboard by the time we return from processing this message), but we must wait for the X +client which owns the selection to convert the selection to our requested format. This is currently achieved +using a fixed timeout of one second. + +The XWin(1) server should indicate somehow (by placing an atom on the root window?) that it is running with it's +internal clipboard integration enabled, and xwinclip should notice this and exit with an appropriate error. + +Probably many other bugs. + +.SH "CONFORMING TO" +ICCCM (Inter-Client Communication Conventions Manual) 2.0 + +.SH AUTHORS +Contributors to xwinclip include Benjamin Riefenstahl, Roland Cassard, Brian Genisio, Colin Harrison, +Harold L Hunt II, Matsuzaki Kensuke, Jon Turney, Chris Twiner and Jeremy Wilkins. diff --git a/hw/xwin/winclipboardinit.c b/hw/xwin/winclipboardinit.c index 304e6df9f..79b0f14a4 100644 --- a/hw/xwin/winclipboardinit.c +++ b/hw/xwin/winclipboardinit.c @@ -31,25 +31,79 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif -#include "dixstruct.h" -#include "winclipboard.h" + +#include <unistd.h> +#include <pthread.h> + +#include "win.h" +#include "winclipboard/winclipboard.h" +#include "windisplay.h" + +#define WIN_CLIPBOARD_RETRIES 40 +#define WIN_CLIPBOARD_DELAY 1 /* - * Local typedefs + * Local variables */ -typedef int (*winDispatchProcPtr) (ClientPtr); - -int winProcSetSelectionOwner(ClientPtr /* client */ ); +static pthread_t g_ptClipboardProc; /* - * References to external symbols + * */ +static void * +winClipboardThreadProc(void *arg) +{ + char szDisplay[512]; + int clipboardRestarts = 0; + + while (1) + { + Bool fShutdown; + + ++clipboardRestarts; + + /* Use our generated cookie for authentication */ + winSetAuthorization(); + + /* Setup the display connection string */ + /* + * NOTE: Always connect to screen 0 since we require that screen + * numbers start at 0 and increase without gaps. We only need + * to connect to one screen on the display to get events + * for all screens on the display. That is why there is only + * one clipboard client thread. + */ + winGetDisplayName(szDisplay, 0); + + /* Print the display connection string */ + ErrorF("winClipboardThreadProc - DISPLAY=%s\n", szDisplay); + + /* Flag that clipboard client has been launched */ + g_fClipboardStarted = TRUE; + + fShutdown = winClipboardProc(g_fUnicodeClipboard, szDisplay); + + /* Flag that clipboard client has stopped */ + g_fClipboardStarted = FALSE; + + if (fShutdown) + break; + + /* checking if we need to restart */ + if (clipboardRestarts >= WIN_CLIPBOARD_RETRIES) { + /* terminates clipboard thread but the main server still lives */ + ErrorF("winClipboardProc - the clipboard thread has restarted %d times and seems to be unstable, disabling clipboard integration\n", clipboardRestarts); + g_fClipboard = FALSE; + break; + } -extern pthread_t g_ptClipboardProc; -extern winDispatchProcPtr winProcSetSelectionOwnerOrig; -extern Bool g_fClipboard; -extern HWND g_hwndClipboard; + sleep(WIN_CLIPBOARD_DELAY); + ErrorF("winClipboardProc - trying to restart clipboard thread \n"); + } + + return NULL; +} /* * Intialize the Clipboard module @@ -60,14 +114,8 @@ winInitClipboard(void) { winDebug("winInitClipboard ()\n"); - /* Wrap some internal server functions */ - if (ProcVector[X_SetSelectionOwner] != winProcSetSelectionOwner) { - winProcSetSelectionOwnerOrig = ProcVector[X_SetSelectionOwner]; - ProcVector[X_SetSelectionOwner] = winProcSetSelectionOwner; - } - /* Spawn a thread for the Clipboard module */ - if (pthread_create(&g_ptClipboardProc, NULL, winClipboardProc, NULL)) { + if (pthread_create(&g_ptClipboardProc, NULL, winClipboardThreadProc, NULL)) { /* Bail if thread creation failed */ ErrorF("winInitClipboard - pthread_create failed.\n"); return FALSE; @@ -76,59 +124,20 @@ winInitClipboard(void) return TRUE; } -/* - * Create the Windows window that we use to recieve Windows messages - */ - -HWND -winClipboardCreateMessagingWindow(void) -{ - WNDCLASSEX wc; - HWND hwnd; - - /* Setup our window class */ - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = winClipboardWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandle(NULL); - wc.hIcon = 0; - wc.hCursor = 0; - wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - wc.lpszMenuName = NULL; - wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS; - wc.hIconSm = 0; - RegisterClassEx(&wc); - - /* Create the window */ - hwnd = CreateWindowExA(0, /* Extended styles */ - WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */ - WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */ - WS_OVERLAPPED, /* Not visible anyway */ - CW_USEDEFAULT, /* Horizontal position */ - CW_USEDEFAULT, /* Vertical position */ - CW_USEDEFAULT, /* Right edge */ - CW_USEDEFAULT, /* Bottom edge */ - (HWND) NULL, /* No parent or owner window */ - (HMENU) NULL, /* No menu */ - GetModuleHandle(NULL), /* Instance handle */ - NULL); /* Creation data */ - assert(hwnd != NULL); - - /* I'm not sure, but we may need to call this to start message processing */ - ShowWindow(hwnd, SW_HIDE); - - /* Similarly, we may need a call to this even though we don't paint */ - UpdateWindow(hwnd); - - return hwnd; -} - void -winFixClipboardChain(void) +winClipboardShutdown(void) { - if (g_fClipboard && g_hwndClipboard) { - PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0); - } + /* Close down clipboard resources */ + if (g_fClipboard && g_fClipboardStarted) { + /* Synchronously destroy the clipboard window */ + winClipboardWindowDestroy(); + + /* Wait for the clipboard thread to exit */ + pthread_join(g_ptClipboardProc, NULL); + + g_fClipboardStarted = FALSE; + + winDebug("winClipboardShutdown - Clipboard thread has exited.\n"); + } } + diff --git a/hw/xwin/winclipboardwrappers.c b/hw/xwin/winclipboardwrappers.c index bfd6bff8b..2679f4f98 100644 --- a/hw/xwin/winclipboardwrappers.c +++ b/hw/xwin/winclipboardwrappers.c @@ -33,36 +33,21 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + #include "win.h" #include "dixstruct.h" -#include <X11/Xatom.h> - -/* - * Constants - */ - -#define CLIP_NUM_SELECTIONS 2 -#define CLIP_OWN_PRIMARY 0 -#define CLIP_OWN_CLIPBOARD 1 /* * Local function prototypes */ DISPATCH_PROC(winProcEstablishConnection); -DISPATCH_PROC(winProcSetSelectionOwner); /* * References to external symbols */ -extern Bool g_fClipboardLaunched; -extern Bool g_fClipboardStarted; extern Bool g_fClipboard; -extern Window g_iClipboardWindow; -extern Atom g_atomLastOwnedSelection; -extern HWND g_hwndClipboard; - /* * Wrapper for internal EstablishConnection function. @@ -127,13 +112,6 @@ winProcEstablishConnection(ClientPtr client) /* Clear original function pointer */ winProcEstablishConnectionOrig = NULL; - /* If the clipboard client has already been started, abort */ - if (g_fClipboardLaunched) { - ErrorF("winProcEstablishConnection - Clipboard client already " - "launched, returning.\n"); - return iReturn; - } - /* Startup the clipboard client if clipboard mode is being used */ if (g_fClipboard) { /* @@ -163,207 +141,5 @@ winProcEstablishConnection(ClientPtr client) ErrorF("winProcEstablishConnection - winInitClipboard returned.\n"); } - /* Flag that clipboard client has been launched */ - g_fClipboardLaunched = TRUE; - return iReturn; } - -/* - * Wrapper for internal SetSelectionOwner function. - * Grabs ownership of Windows clipboard when X11 clipboard owner changes. - */ - -int -winProcSetSelectionOwner(ClientPtr client) -{ - int i; - DrawablePtr pDrawable; - WindowPtr pWindow = None; - Bool fOwnedToNotOwned = FALSE; - static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None }; - static unsigned long s_ulServerGeneration = 0; - - REQUEST(xSetSelectionOwnerReq); - - REQUEST_SIZE_MATCH(xSetSelectionOwnerReq); - - winDebug("winProcSetSelectionOwner - Hello.\n"); - - /* Watch for server reset */ - if (s_ulServerGeneration != serverGeneration) { - /* Save new generation number */ - s_ulServerGeneration = serverGeneration; - - /* Initialize static variables */ - for (i = 0; i < CLIP_NUM_SELECTIONS; ++i) - s_iOwners[i] = None; - } - - /* Abort if clipboard not completely initialized yet */ - if (!g_fClipboardStarted) { - /* ErrorF ("winProcSetSelectionOwner - Clipboard not yet started, " - "aborting.\n"); */ - goto winProcSetSelectionOwner_Done; - } - - /* Grab window if we have one */ - if (None != stuff->window) { - /* Grab the Window from the request */ - int rc = - dixLookupWindow(&pWindow, stuff->window, client, DixReadAccess); - if (rc != Success) { - ErrorF("winProcSetSelectionOwner - Found BadWindow, aborting.\n"); - goto winProcSetSelectionOwner_Done; - } - } - - /* Now we either have a valid window or None */ - - /* Save selection owners for monitored selections, ignore other selections */ - if (XA_PRIMARY == stuff->selection) { - /* Look for owned -> not owned transition */ - if (None == stuff->window && None != s_iOwners[CLIP_OWN_PRIMARY]) { - fOwnedToNotOwned = TRUE; - - winDebug("winProcSetSelectionOwner - PRIMARY - Going from " - "owned to not owned.\n"); - - /* Adjust last owned selection */ - if (None != s_iOwners[CLIP_OWN_CLIPBOARD]) - g_atomLastOwnedSelection = MakeAtom("CLIPBOARD", 9, TRUE); - else - g_atomLastOwnedSelection = None; - } - - /* Save new selection owner or None */ - s_iOwners[CLIP_OWN_PRIMARY] = stuff->window; - - winDebug("winProcSetSelectionOwner - PRIMARY - Now owned by: %d\n", - stuff->window); - } - else if (MakeAtom("CLIPBOARD", 9, TRUE) == stuff->selection) { - /* Look for owned -> not owned transition */ - if (None == stuff->window && None != s_iOwners[CLIP_OWN_CLIPBOARD]) { - fOwnedToNotOwned = TRUE; - - winDebug("winProcSetSelectionOwner - CLIPBOARD - Going from " - "owned to not owned.\n"); - - /* Adjust last owned selection */ - if (None != s_iOwners[CLIP_OWN_PRIMARY]) - g_atomLastOwnedSelection = XA_PRIMARY; - else - g_atomLastOwnedSelection = None; - } - - /* Save new selection owner or None */ - s_iOwners[CLIP_OWN_CLIPBOARD] = stuff->window; - - winDebug("winProcSetSelectionOwner - CLIPBOARD - Now owned by: %d\n", - stuff->window); - - } - else - goto winProcSetSelectionOwner_Done; - - /* - * At this point, if one of the selections is still owned by the - * clipboard manager then it should be marked as unowned since - * we will be taking ownership of the Win32 clipboard. - */ - if (g_iClipboardWindow == s_iOwners[CLIP_OWN_PRIMARY]) - s_iOwners[CLIP_OWN_PRIMARY] = None; - if (g_iClipboardWindow == s_iOwners[CLIP_OWN_CLIPBOARD]) - s_iOwners[CLIP_OWN_CLIPBOARD] = None; - - /* - * Handle case when selection is being disowned, - * WM_DRAWCLIPBOARD did not do the disowning, - * both monitored selections are no longer owned, - * an owned to not owned transition was detected, - * and we currently own the Win32 clipboard. - */ - if (stuff->window == None - && s_iOwners[CLIP_OWN_PRIMARY] == None - && s_iOwners[CLIP_OWN_CLIPBOARD] == None - && fOwnedToNotOwned - && g_hwndClipboard != NULL && g_hwndClipboard == GetClipboardOwner()) { - winDebug("winProcSetSelectionOwner - We currently own the " - "clipboard and neither the PRIMARY nor the CLIPBOARD " - "selections are owned, releasing ownership of Win32 " - "clipboard.\n"); - - /* Release ownership of the Windows clipboard */ - OpenClipboard(NULL); - EmptyClipboard(); - CloseClipboard(); - - goto winProcSetSelectionOwner_Done; - } - - /* Abort if no window at this point */ - if (None == stuff->window) { - winDebug("winProcSetSelectionOwner - No window, returning.\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Abort if invalid selection */ - if (!ValidAtom(stuff->selection)) { - ErrorF("winProcSetSelectionOwner - Found BadAtom, aborting.\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Cast Window to Drawable */ - pDrawable = (DrawablePtr) pWindow; - - /* Abort if clipboard manager is owning the selection */ - if (pDrawable->id == g_iClipboardWindow) { - winDebug("winProcSetSelectionOwner - We changed ownership, " - "aborting.\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Abort if root window is taking ownership */ - if (pDrawable->id == 0) { - ErrorF("winProcSetSelectionOwner - Root window taking ownership, " - "aborting\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Close clipboard if we have it open already */ - if (GetOpenClipboardWindow() == g_hwndClipboard) { - CloseClipboard(); - } - - /* Access the Windows clipboard */ - if (!OpenClipboard(g_hwndClipboard)) { - ErrorF("winProcSetSelectionOwner - OpenClipboard () failed: %08x\n", - (int) GetLastError()); - goto winProcSetSelectionOwner_Done; - } - - /* Take ownership of the Windows clipboard */ - if (!EmptyClipboard()) { - ErrorF("winProcSetSelectionOwner - EmptyClipboard () failed: %08x\n", - (int) GetLastError()); - goto winProcSetSelectionOwner_Done; - } - - /* Advertise regular text and unicode */ - SetClipboardData(CF_UNICODETEXT, NULL); - SetClipboardData(CF_TEXT, NULL); - - /* Save handle to last owned selection */ - g_atomLastOwnedSelection = stuff->selection; - - /* Release the clipboard */ - if (!CloseClipboard()) { - ErrorF("winProcSetSelectionOwner - CloseClipboard () failed: " - "%08x\n", (int) GetLastError()); - goto winProcSetSelectionOwner_Done; - } - - winProcSetSelectionOwner_Done: - return (*winProcSetSelectionOwnerOrig) (client); -} diff --git a/hw/xwin/winconfig.c b/hw/xwin/winconfig.c index 9e38113a5..0a8da9c70 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 */ @@ -263,8 +264,8 @@ winConfigKeyboard(DeviceIntPtr pDevice) break; } g_winInfo.keyboard.rate = (kbd_speed > 0) ? kbd_speed : 1; - winMsgVerb(X_PROBED, 1, "Setting autorepeat to delay=%d, rate=%d\n", - g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); + winMsg(X_PROBED, "Setting autorepeat to delay=%d, rate=%d\n", + g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); } } diff --git a/hw/xwin/winconfig.h b/hw/xwin/winconfig.h index 94571ff71..4cf7ab1d6 100644 --- a/hw/xwin/winconfig.h +++ b/hw/xwin/winconfig.h @@ -160,6 +160,7 @@ typedef struct { #ifdef XWIN_XF86CONFIG char *keyboard; #endif + Bool customDPI; char *xkbRules; char *xkbModel; char *xkbLayout; @@ -200,7 +201,7 @@ typedef union { unsigned long num; char *str; double realnum; - Bool bool; + Bool bool_; OptFrequency freq; } ValueUnion; diff --git a/hw/xwin/wincursor.c b/hw/xwin/wincursor.c index a35336a34..8e870414e 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,300 +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 = - (uint32_t *) 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 = - (uint32_t *) calloc(pScreenPriv->cursor.sm_cx * - pScreenPriv->cursor.sm_cy, sizeof(char)); - - 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/windialogs.c b/hw/xwin/windialogs.c index 054ee95b5..61f7fe0bd 100644 --- a/hw/xwin/windialogs.c +++ b/hw/xwin/windialogs.c @@ -37,13 +37,6 @@ #include "winprefs.h" /* - * References to external globals - */ - -#ifdef XWIN_CLIPBOARD -extern Bool g_fClipboardStarted; -#endif -/* * Local function prototypes */ @@ -574,10 +567,7 @@ winAboutDlgProc(HWND hwndDialog, UINT message, WPARAM wParam, LPARAM lParam) winInitDialog(hwndDialog); /* Override the URL buttons */ - winOverrideURLButton(hwndDialog, ID_ABOUT_CHANGELOG); winOverrideURLButton(hwndDialog, ID_ABOUT_WEBSITE); - winOverrideURLButton(hwndDialog, ID_ABOUT_UG); - winOverrideURLButton(hwndDialog, ID_ABOUT_FAQ); return TRUE; @@ -608,28 +598,8 @@ winAboutDlgProc(HWND hwndDialog, UINT message, WPARAM wParam, LPARAM lParam) PostMessage(s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); /* Restore window procedures for URL buttons */ - winUnoverrideURLButton(hwndDialog, ID_ABOUT_CHANGELOG); winUnoverrideURLButton(hwndDialog, ID_ABOUT_WEBSITE); - winUnoverrideURLButton(hwndDialog, ID_ABOUT_UG); - winUnoverrideURLButton(hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - - case ID_ABOUT_CHANGELOG: - { - INT_PTR iReturn; - - const char *pszWinPath = "http://x.cygwin.com/" - "devel/server/changelog.html"; - iReturn = (INT_PTR) ShellExecute(NULL, - "open", - pszWinPath, NULL, NULL, SW_MAXIMIZE); - if (iReturn < 32) { - ErrorF("winAboutDlgProc - WM_COMMAND - ID_ABOUT_CHANGELOG - " - "ShellExecute failed: %d\n", (int)iReturn); - } - } return TRUE; case ID_ABOUT_WEBSITE: @@ -647,36 +617,6 @@ winAboutDlgProc(HWND hwndDialog, UINT message, WPARAM wParam, LPARAM lParam) } } return TRUE; - - case ID_ABOUT_UG: - { - const char *pszPath = "http://x.cygwin.com/docs/ug/"; - INT_PTR iReturn; - - iReturn = (INT_PTR) ShellExecute(NULL, - "open", - pszPath, NULL, NULL, SW_MAXIMIZE); - if (iReturn < 32) { - ErrorF("winAboutDlgProc - WM_COMMAND - ID_ABOUT_UG - " - "ShellExecute failed: %d\n", (int)iReturn); - } - } - return TRUE; - - case ID_ABOUT_FAQ: - { - const char *pszPath = "http://x.cygwin.com/docs/faq/"; - INT_PTR iReturn; - - iReturn = (INT_PTR) ShellExecute(NULL, - "open", - pszPath, NULL, NULL, SW_MAXIMIZE); - if (iReturn < 32) { - ErrorF("winAboutDlgProc - WM_COMMAND - ID_ABOUT_FAQ - " - "ShellExecute failed: %d\n", (int)iReturn); - } - } - return TRUE; } break; @@ -690,10 +630,7 @@ winAboutDlgProc(HWND hwndDialog, UINT message, WPARAM wParam, LPARAM lParam) PostMessage(s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); /* Restore window procedures for URL buttons */ - winUnoverrideURLButton(hwndDialog, ID_ABOUT_CHANGELOG); winUnoverrideURLButton(hwndDialog, ID_ABOUT_WEBSITE); - winUnoverrideURLButton(hwndDialog, ID_ABOUT_UG); - winUnoverrideURLButton(hwndDialog, ID_ABOUT_FAQ); return TRUE; } diff --git a/hw/xwin/windisplay.c b/hw/xwin/windisplay.c new file mode 100644 index 000000000..6f07f97ea --- /dev/null +++ b/hw/xwin/windisplay.c @@ -0,0 +1,60 @@ +/* + * File: windisplay.c + * Purpose: Retrieve server display name + * + * Copyright (C) Jon TURNEY 2009 + * + * 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 <opaque.h> // for display +#include "windisplay.h" +#include "winmsg.h" + +/* + Generate a display name string referring to the display of this server, + using a transport we know is enabled +*/ + +void +winGetDisplayName(char *szDisplay, unsigned int screen) +{ + if (TransIsListening("local")) { + snprintf(szDisplay, 512, ":%s.%d", display, screen); + } + else if (TransIsListening("inet")) { + snprintf(szDisplay, 512, "127.0.0.1:%s.%d", display, screen); + } + else if (TransIsListening("inet6")) { + snprintf(szDisplay, 512, "::1:%s.%d", display, screen); + } + else { + // this can't happen! + ErrorF("winGetDisplay: Don't know what to use for DISPLAY\n"); + snprintf(szDisplay, 512, "localhost:%s.%d", display, screen); + } + + winDebug("winGetDisplay: DISPLAY=%s\n", szDisplay); +} diff --git a/hw/xwin/windisplay.h b/hw/xwin/windisplay.h new file mode 100644 index 000000000..d1d4549bf --- /dev/null +++ b/hw/xwin/windisplay.h @@ -0,0 +1,34 @@ +/* + * File: windisplay.h + * Purpose: Interface to retrieve server display name + * + * Copyright (C) Jon TURNEY 2009 + * + * 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 WINDISPLAY_H +#define WINDISPLAY_H + +void +winGetDisplayName(char *szDisplay, unsigned int screen); + +#endif /* !WINDISPLAY_H */ diff --git a/hw/xwin/winerror.c b/hw/xwin/winerror.c index 1318b0f36..ff2919c27 100644 --- a/hw/xwin/winerror.c +++ b/hw/xwin/winerror.c @@ -48,6 +48,16 @@ OsVendorVErrorF(const char *pszFormat, va_list va_args) pthread_mutex_lock(&s_pmPrinting); #endif + /* If we want to silence it, + * detect if we are going to abort due to duplication error */ + if (g_fSilentDupError) { + if ((strcmp(pszFormat, "InitOutput - Duplicate invocation on display number: %s. Exiting.\n") == 0) + || (strcmp(pszFormat, "Server is already active for display %s\n%s %s\n%s\n") == 0) + || (strcmp(pszFormat, "MakeAllCOTSServerListeners: server already running\n") == 0)) { + g_fSilentFatalError = TRUE; + } + } + /* Print the error message to a log file, could be stderr */ LogVWrite(0, pszFormat, va_args); diff --git a/hw/xwin/winglobals.c b/hw/xwin/winglobals.c index d28132247..ad82b83f6 100644 --- a/hw/xwin/winglobals.c +++ b/hw/xwin/winglobals.c @@ -78,6 +78,7 @@ Bool g_fNoHelpMessageBox = FALSE; Bool g_fSoftwareCursor = FALSE; Bool g_fSilentDupError = FALSE; Bool g_fNativeGl = TRUE; +Bool g_fHostInTitle = FALSE; pthread_mutex_t g_pmTerminating = PTHREAD_MUTEX_INITIALIZER; #ifdef XWIN_CLIPBOARD @@ -85,7 +86,6 @@ pthread_mutex_t g_pmTerminating = PTHREAD_MUTEX_INITIALIZER; * Wrapped DIX functions */ winDispatchProcPtr winProcEstablishConnectionOrig = NULL; -winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL; /* * Clipboard variables @@ -93,13 +93,7 @@ winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL; Bool g_fUnicodeClipboard = TRUE; Bool g_fClipboard = TRUE; -Bool g_fClipboardLaunched = FALSE; Bool g_fClipboardStarted = FALSE; -pthread_t g_ptClipboardProc; -HWND g_hwndClipboard = NULL; -void *g_pClipboardDisplay = NULL; -Window g_iClipboardWindow = None; -Atom g_atomLastOwnedSelection = None; #endif /* @@ -111,10 +105,4 @@ void winInitializeGlobals(void) { g_dwCurrentThreadID = GetCurrentThreadId(); -#ifdef XWIN_CLIPBOARD - g_iClipboardWindow = None; - g_pClipboardDisplay = NULL; - g_atomLastOwnedSelection = None; - g_hwndClipboard = NULL; -#endif } diff --git a/hw/xwin/winglobals.h b/hw/xwin/winglobals.h index 58a919c65..d7b813dbb 100644 --- a/hw/xwin/winglobals.h +++ b/hw/xwin/winglobals.h @@ -54,6 +54,7 @@ extern Bool g_fXdmcpEnabled; extern Bool g_fNoHelpMessageBox; extern Bool g_fSilentDupError; extern Bool g_fNativeGl; +extern Bool g_fHostInTitle; extern HWND g_hDlgDepthChange; extern HWND g_hDlgExit; @@ -71,8 +72,10 @@ typedef int (*winDispatchProcPtr) (ClientPtr); * Wrapped DIX functions */ extern winDispatchProcPtr winProcEstablishConnectionOrig; -extern winDispatchProcPtr winProcSetSelectionOwnerOrig; #endif +extern Bool g_fUnicodeClipboard; +extern Bool g_fClipboard; +extern Bool g_fClipboardStarted; /* The global X default icons */ #if defined(XWIN_MULTIWINDOW) diff --git a/hw/xwin/winkeybd.c b/hw/xwin/winkeybd.c index 9c5d4e9cd..1f4518770 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", wParam, 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, pointer 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, NULL); } /* - * 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, NULL); - - winDebug("winSendKeyEvent: dwKey: %d, fDown: %d\n", 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/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 56e7a097c..8aa8d9ed2 100644 --- a/hw/xwin/winmsg.c +++ b/hw/xwin/winmsg.c @@ -39,17 +39,6 @@ #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); -} - -void winDrvMsg(int scrnIndex, MessageType type, const char *format, ...) { va_list ap; @@ -60,16 +49,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, ...) { @@ -81,22 +60,22 @@ winDrvMsgVerb(int scrnIndex, MessageType type, int verb, const char *format, } 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 b638f2cb3..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,10 +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, ...) @@ -41,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); @@ -57,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/winmsgwindow.c b/hw/xwin/winmsgwindow.c index 8067c693c..59f1da503 100644 --- a/hw/xwin/winmsgwindow.c +++ b/hw/xwin/winmsgwindow.c @@ -22,6 +22,10 @@ * */ +#ifdef HAVE_XWIN_CONFIG_H +#include <xwin-config.h> +#endif + #include "win.h" /* diff --git a/hw/xwin/winmultiwindowicons.c b/hw/xwin/winmultiwindowicons.c index 0531ad6c7..4ac8bffdf 100644 --- a/hw/xwin/winmultiwindowicons.c +++ b/hw/xwin/winmultiwindowicons.c @@ -32,514 +32,22 @@ #include <xwin-config.h> #endif -#ifndef WINVER -#define WINVER 0x0500 -#endif - #include <X11/Xwindows.h> #include <X11/Xlib.h> -#include <X11/Xutil.h> +#include <X11/Xlib-xcb.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; - 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; - unsigned long int 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]) { - /* Find an exact match to the size we require... */ - if (icon[0] == iconSize && icon[1] == iconSize) { - winDebug("winXIconToHICON: found %lu x %lu NetIcon\n", icon[0], - icon[1]); - 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 %lu x %lu NetIcon for scaling to %u x %u\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 %x\n", id, - 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%x\n", 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 */ @@ -549,16 +57,20 @@ winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew) { HICON hIcon, hIconSmall = NULL, hIconOld; - /* Start with the icon from preferences, if any */ - hIcon = hIconNew; - hIconSmall = hIconNew; + 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 */ + xcb_connection_t *conn = XGetXCBConnection(pDisplay); - /* 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)); + 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) { diff --git a/hw/xwin/winmultiwindowicons.h b/hw/xwin/winmultiwindowicons.h index bf7f6eda7..5e0873ab9 100644 --- a/hw/xwin/winmultiwindowicons.h +++ b/hw/xwin/winmultiwindowicons.h @@ -27,8 +27,8 @@ #ifndef WINMULTIWINDOWICONS_H #define WINMULTIWINDOWICONS_H -void - winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew); +//void +// winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew); void winInitGlobalIcons(void); diff --git a/hw/xwin/winmultiwindowwindow.c b/hw/xwin/winmultiwindowwindow.c index 44ad19302..a74577ed9 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(pointer value, XID id, pointer 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); @@ -470,12 +540,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; @@ -513,8 +579,8 @@ winCreateWindowsWindow(WindowPtr pWin) 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) { @@ -534,7 +600,11 @@ winCreateWindowsWindow(WindowPtr pWin) } } - /* 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; @@ -572,11 +642,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%08x\n", hWnd); + /* Change style back to popup, already placed... */ SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); @@ -602,6 +675,107 @@ winCreateWindowsWindow(WindowPtr pWin) (*pScreenPriv->pwinFinishCreateWindowsWindow) (pWin); } +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:%08x 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:%08x XID:0x%08x hWnd:0x%08x\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%08x\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:%08x XID:0x%x \n", pWin, + pWin->drawable.id); + + if (isToplevelWindow(pWin)) { + winCreateWindowsTopLevelWindow(pWin); + } + else { + winCreateWindowsChildWindow(pWin); + } +} + +static int +winDestroyChildWindowsWindow(WindowPtr pWin, pointer data) +{ + winWindowPriv(pWin); + + winDebug("winDestroyChildWindowsWindow - pWin:%08x XID:0x%x \n", pWin, + pWin->drawable.id); + + /* Null our handle to the Window so referencing it will cause an error */ + pWinPriv->hWnd = NULL; + +#ifdef XWIN_GLX_WINDOWS + /* No longer note WGL used on this window */ + pWinPriv->fWglUsed = FALSE; +#endif + + return WT_WALKCHILDREN; /* continue enumeration */ +} + Bool winInDestroyWindowsWindow = FALSE; /* @@ -617,6 +791,7 @@ winDestroyWindowsWindow(WindowPtr pWin) BOOL oldstate = winInDestroyWindowsWindow; HICON hIcon; HICON hIconSm; + HWND hWnd; winDebug("winDestroyWindowsWindow - pWin:%08x XID:0x%x \n", pWin, pWin->drawable.id); @@ -631,21 +806,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)) { @@ -667,29 +841,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); } @@ -926,6 +1129,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 1dd8ba5b3..4a626161d 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> @@ -48,7 +62,6 @@ #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> @@ -58,8 +71,9 @@ #include "winwindow.h" #include "winprefs.h" #include "window.h" -#include "pixmapstr.h" -#include "windowstr.h" +#include "winmultiwindowicons.h" +#include "windisplay.h" +#include "winglobals.h" #ifdef XWIN_MULTIWINDOWEXTWM #include <X11/extensions/windowswmstr.h> @@ -69,9 +83,16 @@ #define WINDOWSWM_NATIVE_HWND "_WINDOWSWM_NATIVE_HWND" #endif +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 255 +#endif + extern void winDebug(const char *format, ...); extern void winReshapeMultiWindow(WindowPtr pWin); extern void winUpdateRgnMultiWindow(WindowPtr pWin); +extern void winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew); +extern void winSetAuthorization(void); +extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle); #ifndef CYGDEBUG #define CYGDEBUG NO @@ -111,6 +132,7 @@ typedef struct _WMInfo { WMMsgQueueRec wmMsgQueue; Atom atmWmProtos; Atom atmWmDelete; + Atom atmWmTakeFocus; Atom atmPrivMap; Bool fAllowOtherWM; } WMInfoRec, *WMInfoPtr; @@ -166,6 +188,9 @@ static int static int winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay); +static void +winMultiWindowThreadExit(void *arg); + static int winRedirectErrorHandler(Display * pDisplay, XErrorEvent * pErr); @@ -183,10 +208,10 @@ CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, Bool fAllowOtherWM); static void - winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle); + winApplyUrgency(Display * pDisplay, Window iWindow, HWND hWnd); -void - winUpdateWindowPosition(HWND hWnd, HWND * zstyle); +static void + winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle); /* * Local globals @@ -429,7 +454,10 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) { int nResult; XTextProperty xtpWindowName; + XTextProperty xtpClientMachine; char *pszWindowName; + char *pszClientMachine; + char hostname[HOST_NAME_MAX + 1]; #if CYGMULTIWINDOW_DEBUG ErrorF("GetWindowName\n"); @@ -449,10 +477,65 @@ GetWindowName(Display * pDisplay, Window iWin, char **ppWindowName) pszWindowName = Xutf8TextPropertyToString(pDisplay, &xtpWindowName); XFree(xtpWindowName.value); + + if (g_fHostInTitle) { + /* Try to get client machine name */ + nResult = XGetWMClientMachine(pDisplay, iWin, &xtpClientMachine); + if (nResult && xtpClientMachine.value && xtpClientMachine.nitems) { + pszClientMachine = + Xutf8TextPropertyToString(pDisplay, &xtpClientMachine); + XFree(xtpClientMachine.value); + + /* + If we have a client machine name + and it's not the local host name... + */ + if (strlen(pszClientMachine) && + !gethostname(hostname, HOST_NAME_MAX + 1) && + strcmp(hostname, pszClientMachine)) { + /* ... add ' (on <clientmachine>)' to end of window name */ + *ppWindowName = + malloc(strlen(pszWindowName) + + strlen(pszClientMachine) + 7); + strcpy(*ppWindowName, pszWindowName); + strcat(*ppWindowName, " (on "); + strcat(*ppWindowName, pszClientMachine); + strcat(*ppWindowName, ")"); + + free(pszWindowName); + free(pszClientMachine); + + return; + } + } + } + + /* otherwise just return the window name */ *ppWindowName = pszWindowName; } /* + * Does the client support the specified WM_PROTOCOLS protocol? + */ + +static Bool +IsWmProtocolAvailable(Display * pDisplay, Window iWindow, Atom 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); + } + + return found > 0; +} + +/* * Send a message to the X server from the WM thread */ @@ -462,6 +545,7 @@ SendXMessage(Display * pDisplay, Window iWin, Atom atmType, long nData) XEvent e; /* Prepare the X event structure */ + memset(&e, 0, sizeof(e)); e.type = ClientMessage; e.xclient.window = iWin; e.xclient.message_type = atmType; @@ -627,6 +711,9 @@ UpdateStyle(WMInfoPtr pWMInfo, Window iWindow) winShowWindowOnTaskbar(hWnd, (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) ? TRUE : FALSE); + + /* Check urgency hint */ + winApplyUrgency(pWMInfo->pDisplay, iWindow, hWnd); } #if 0 @@ -680,6 +767,8 @@ winMultiWindowWMProc(void *pArg) WMProcArgPtr pProcArg = (WMProcArgPtr) pArg; WMInfoPtr pWMInfo = pProcArg->pWMInfo; + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); + /* Initialize the Window Manager */ winInitMultiWindowWM(pWMInfo, pProcArg); @@ -805,21 +894,10 @@ winMultiWindowWMProc(void *pArg) ErrorF("\tWM_WM_KILL\n"); #endif { - int i, n, found = 0; - Atom *protocols; - - /* --- */ - if (XGetWMProtocols(pWMInfo->pDisplay, - pNode->msg.iWindow, &protocols, &n)) { - for (i = 0; i < n; ++i) - if (protocols[i] == pWMInfo->atmWmDelete) - ++found; - - XFree(protocols); - } - /* --- */ - if (found) + if (IsWmProtocolAvailable(pWMInfo->pDisplay, + pNode->msg.iWindow, + pWMInfo->atmWmDelete)) SendXMessage(pWMInfo->pDisplay, pNode->msg.iWindow, pWMInfo->atmWmProtos, pWMInfo->atmWmDelete); @@ -832,11 +910,39 @@ winMultiWindowWMProc(void *pArg) #if CYGMULTIWINDOW_DEBUG ErrorF("\tWM_WM_ACTIVATE\n"); #endif - /* Set the input focus */ - XSetInputFocus(pWMInfo->pDisplay, - pNode->msg.iWindow, - RevertToPointerRoot, CurrentTime); + + /* + ICCCM 4.1.7 is pretty opaque, but it appears that the rules are + actually quite simple: + -- the WM_HINTS input field determines whether the WM should call + XSetInputFocus() + -- independently, the WM_TAKE_FOCUS protocol determines whether + the WM should send a WM_TAKE_FOCUS ClientMessage. + */ + { + Bool neverFocus = FALSE; + XWMHints *hints = XGetWMHints(pWMInfo->pDisplay, pNode->msg.iWindow); + + if (hints) { + if (hints->flags & InputHint) + neverFocus = !hints->input; + XFree(hints); + } + + if (!neverFocus) + XSetInputFocus(pWMInfo->pDisplay, + pNode->msg.iWindow, + RevertToPointerRoot, CurrentTime); + + if (IsWmProtocolAvailable(pWMInfo->pDisplay, + pNode->msg.iWindow, + pWMInfo->atmWmTakeFocus)) + SendXMessage(pWMInfo->pDisplay, + pNode->msg.iWindow, + pWMInfo->atmWmProtos, pWMInfo->atmWmTakeFocus); + + } break; case WM_WM_NAME_EVENT: @@ -890,6 +996,9 @@ winMultiWindowWMProc(void *pArg) #if CYGMULTIWINDOW_DEBUG ErrorF("-winMultiWindowWMProc ()\n"); #endif + + pthread_cleanup_pop(0); + return NULL; } @@ -913,6 +1022,8 @@ winMultiWindowXMsgProc(void *pArg) int iReturn; XIconSize *xis; + pthread_cleanup_push(&winMultiWindowThreadExit, NULL); + winDebug("winMultiWindowXMsgProc - Hello\n"); /* Check that argument pointer is not invalid */ @@ -933,17 +1044,6 @@ winMultiWindowXMsgProc(void *pArg) 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"); - } - /* Release the server started mutex */ pthread_mutex_unlock(pProcArg->ppmServerStarted); @@ -971,8 +1071,7 @@ winMultiWindowXMsgProc(void *pArg) } /* Setup the display connection string x */ - snprintf(pszDisplay, - 512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen); + winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen); /* Print the display connection string */ ErrorF("winMultiWindowXMsgProc - DISPLAY=%s\n", pszDisplay); @@ -1027,7 +1126,7 @@ winMultiWindowXMsgProc(void *pArg) xis->max_width = xis->max_height = 48; xis->width_inc = xis->height_inc = 16; XSetIconSizes(pProcArg->pDisplay, - RootWindow(pProcArg->pDisplay, pProcArg->dwScreen), + XRootWindow(pProcArg->pDisplay, pProcArg->dwScreen), xis, 1); XFree(xis); } @@ -1166,6 +1265,10 @@ winMultiWindowXMsgProc(void *pArg) } } else if (event.type == PropertyNotify) { + char *atomName = + XGetAtomName(pProcArg->pDisplay, event.xproperty.atom); + winDebug("winMultiWindowXMsgProc: PropertyNotify %s\n", atomName); + XFree(atomName); if (event.xproperty.atom == atmWmName) { memset(&msg, 0, sizeof(msg)); @@ -1220,7 +1323,7 @@ winMultiWindowXMsgProc(void *pArg) } XCloseDisplay(pProcArg->pDisplay); - pthread_exit(NULL); + pthread_cleanup_pop(0); return NULL; } @@ -1326,17 +1429,6 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) 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"); - } - /* Release the server started mutex */ pthread_mutex_unlock(pProcArg->ppmServerStarted); @@ -1364,8 +1456,7 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) } /* Setup the display connection string x */ - snprintf(pszDisplay, - 512, "127.0.0.1:%s.%d", display, (int) pProcArg->dwScreen); + winGetDisplayName(pszDisplay, (int) pProcArg->dwScreen); /* Print the display connection string */ ErrorF("winInitMultiWindowWM - DISPLAY=%s\n", pszDisplay); @@ -1404,6 +1495,8 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) "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); @@ -1413,7 +1506,7 @@ winInitMultiWindowWM(WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) if (cursor) { XDefineCursor(pWMInfo->pDisplay, - DefaultRootWindow(pWMInfo->pDisplay), cursor); + XDefaultRootWindow(pWMInfo->pDisplay), cursor); XFreeCursor(pWMInfo->pDisplay, cursor); } } @@ -1522,6 +1615,17 @@ winMultiWindowXMsgProcIOErrorHandler(Display * pDisplay) } /* + * winMultiWindowThreadExit - Thread exit handler + */ + +static void +winMultiWindowThreadExit(void *arg) +{ + /* multiwindow client thread has exited, stop server as well */ + kill(getpid(), SIGTERM); +} + +/* * Catch RedirectError to detect other window manager running */ @@ -1546,7 +1650,7 @@ CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, */ redirectError = FALSE; XSetErrorHandler(winRedirectErrorHandler); - XSelectInput(pDisplay, RootWindow(pDisplay, dwScreen), + XSelectInput(pDisplay, XRootWindow(pDisplay, dwScreen), ResizeRedirectMask | SubstructureRedirectMask | ButtonPressMask); XSync(pDisplay, 0); @@ -1558,7 +1662,7 @@ CheckAnotherWindowManager(Display * pDisplay, DWORD dwScreen, If 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), + XSelectInput(pDisplay, XRootWindow(pDisplay, dwScreen), SubstructureNotifyMask | (!fAllowOtherWM ? ButtonPressMask : 0)); XSync(pDisplay, 0); @@ -1576,6 +1680,40 @@ winDeinitMultiWindowWM(void) g_shutdown = TRUE; } +static void +winApplyUrgency(Display * pDisplay, Window iWindow, HWND hWnd) +{ + XWMHints *hints = XGetWMHints(pDisplay, iWindow); + + if (hints) { + FLASHWINFO fwi; + + fwi.cbSize = sizeof(FLASHWINFO); + fwi.hwnd = hWnd; + + winDebug("winApplyUrgency: window 0x%08x has urgency hint %s\n", + iWindow, (hints->flags & XUrgencyHint) ? "on" : "off"); + + if (hints->flags & XUrgencyHint) { + 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); + + XFree(hints); + } +} + /* Windows window styles */ #define HINT_NOFRAME (1l<<0) #define HINT_BORDER (1L<<1) @@ -1594,7 +1732,7 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) { static Atom windowState, motif_wm_hints, windowType; static Atom hiddenState, fullscreenState, belowState, aboveState, - skiptaskbarState; + skiptaskbarState, vertMaxState, horzMaxState; static Atom dockWindow; static int generation; Atom type, *pAtom = NULL; @@ -1621,12 +1759,17 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) dockWindow = XInternAtom(pDisplay, "_NET_WM_WINDOW_TYPE_DOCK", False); skiptaskbarState = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", False); + vertMaxState = XInternAtom(pDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", False); + horzMaxState = XInternAtom(pDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", False); } if (XGetWindowProperty(pDisplay, iWindow, windowState, 0L, MAXINT, False, XA_ATOM, &type, &format, &nitems, &left, (unsigned char **) &pAtom) == Success) { + Bool verMax = FALSE; + Bool horMax = FALSE; + if (pAtom ) { unsigned long i; @@ -1641,8 +1784,15 @@ winApplyHints(Display * pDisplay, Window iWindow, HWND hWnd, HWND * zstyle) *zstyle = HWND_BOTTOM; else if (pAtom[i] == aboveState) *zstyle = HWND_TOPMOST; + if (pAtom[i] == vertMaxState) + verMax = TRUE; + if (pAtom[i] == horzMaxState) + horMax = TRUE; } + if (verMax && horMax) + maxmin |= HINT_MAX; + XFree(pAtom); } } @@ -1832,57 +1982,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 abb87ee4b..184efa5ab 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); @@ -316,6 +317,7 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) static Bool s_fTracking = FALSE; Bool needRestack = FALSE; LRESULT ret; + static Bool hasEnteredSizeMove = FALSE; #if CYGDEBUG winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam, @@ -872,7 +874,9 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_MOVE: /* Adjust the X Window to the moved Windows window */ - winAdjustXWindow(pWin, hwnd); + if (!hasEnteredSizeMove) + winAdjustXWindow(pWin, hwnd); + /* else: Wait for WM_EXITSIZEMOVE */ return 0; case WM_SHOWWINDOW: @@ -1005,6 +1009,16 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) */ break; + case WM_ENTERSIZEMOVE: + hasEnteredSizeMove = TRUE; + return 0; + + case WM_EXITSIZEMOVE: + /* Adjust the X Window to the moved Windows window */ + hasEnteredSizeMove = FALSE; + winAdjustXWindow(pWin, hwnd); + return 0; + case WM_SIZE: /* see dix/window.c */ #if CYGWINDOWING_DEBUG @@ -1029,8 +1043,13 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (int) (GetTickCount())); } #endif - /* Adjust the X Window to the moved Windows window */ - winAdjustXWindow(pWin, hwnd); + if (!hasEnteredSizeMove) { + /* Adjust the X Window to the moved Windows window */ + winAdjustXWindow(pWin, hwnd); + if (wParam == SIZE_MINIMIZED) + winReorderWindowsMultiWindow(); + } + /* else: wait for WM_EXITSIZEMOVE */ return 0; /* end of WM_SIZE handler */ case WM_STYLECHANGING: @@ -1140,3 +1159,95 @@ 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; + HDC hdcUpdate; + + hdcUpdate = 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/winprefs.c b/hw/xwin/winprefs.c index f386facdd..3f25362d0 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" @@ -44,7 +46,9 @@ #include <shellapi.h> #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 @@ -296,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. @@ -318,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: @@ -636,11 +737,17 @@ winPrefsLoadPreferences(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 @@ -671,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; @@ -712,15 +819,19 @@ LoadPreferences(void) /* Setup a DISPLAY environment variable, need to allocate on heap */ /* because putenv doesn't copy the argument... */ - snprintf(szDisplay, 512, "DISPLAY=127.0.0.1:%s.0", display); - szEnvDisplay = (char *) (malloc(strlen(szDisplay) + 1)); + winGetDisplayName(szDisplay, 0); + szEnvDisplay = (char *) (malloc(strlen(szDisplay) + strlen("DISPLAY=") + 1)); if (szEnvDisplay) { - strcpy(szEnvDisplay, szDisplay); + snprintf(szEnvDisplay, 512, "DISPLAY=%s", szDisplay); 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 */ - snprintf(szDisplay, 512, "127.0.0.1:%s.0", display); for (i = 0; i < pref.menuItems; i++) { for (j = 0; j < pref.menu[i].menuItems; j++) { if (pref.menu[i].menuItem[j].cmd == CMD_EXEC) { diff --git a/hw/xwin/winprefs.h b/hw/xwin/winprefs.h index 8f4eb0807..702e5897d 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 */ diff --git a/hw/xwin/winprefslex.l b/hw/xwin/winprefslex.l index 15f707766..c51b61035 100644 --- a/hw/xwin/winprefslex.l +++ b/hw/xwin/winprefslex.l @@ -91,6 +91,12 @@ DEBUG { return DEBUGOUTPUT; } RELOAD { return RELOAD; } TRAYICON { return TRAYICON; } 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 3b376b3e7..72677b54f 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); @@ -120,6 +129,12 @@ 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 @@ -154,6 +169,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); } @@ -260,6 +299,58 @@ yyerror (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 858be4a56..bb6efc3da 100644 --- a/hw/xwin/winprocarg.c +++ b/hw/xwin/winprocarg.c @@ -31,6 +31,10 @@ from The Open Group. #include <xwin-config.h> #endif +#ifdef HAVE_SYS_UTSNAME_H +#include <sys/utsname.h> +#endif + #include <../xfree86/common/xorgVersion.h> #include "win.h" #include "winconfig.h" @@ -44,6 +48,7 @@ from The Open Group. #ifdef XWIN_CLIPBOARD extern Bool g_fUnicodeClipboard; extern Bool g_fClipboard; +#include "winclipboard/winclipboard.h" #endif /* @@ -716,6 +721,26 @@ ddxProcessArgument(int argc, char *argv[], int i) /* Indicate that we have processed this argument */ return 1; } + + /* + * Look for the '-primary' argument + */ + if (IS_OPTION("-primary")) { + fPrimarySelection = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-noprimary' argument + */ + if (IS_OPTION("-noprimary")) { + fPrimarySelection = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } #endif /* @@ -938,6 +963,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") @@ -1074,6 +1107,11 @@ ddxProcessArgument(int argc, char *argv[], int i) return 1; } + if (IS_OPTION("-hostintitle")) { + g_fHostInTitle = TRUE; + return 1; + } + return 0; } @@ -1145,6 +1183,115 @@ winLogCommandLine(int argc, char *argv[]) } /* + * Detect the OS + */ + +typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +static void +winOS(void) +{ + OSVERSIONINFOEX osvi = { 0 }; + char *windowstype = "Unknown"; + char *prodName = "Unknown"; + char *isWow = "Unknown"; + + /* Get operating system version information */ + osvi.dwOSVersionInfoSize = sizeof(osvi); + GetVersionEx((LPOSVERSIONINFO) & osvi); + + /* 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 == 6) { + 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; + } + +#ifdef __x86_64__ + isWow = "(Win64)"; +#else + { + /* Check if we are running under WoW64 */ + LPFN_ISWOW64PROCESS fnIsWow64Process; + + fnIsWow64Process = + (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle("kernel32"), + "IsWow64Process"); + if (NULL != fnIsWow64Process) { + wBOOL bIsWow64 = FALSE; + + if (fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { + isWow = bIsWow64 ? " (WoW64)" : " (Win32)"; + } + else { + /* IsWow64Process() failed */ + isWow = " (WoWUnknown)"; + } + } + else { + /* OS doesn't support IsWow64Process() */ + isWow = ""; + } + } +#endif + + 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); +} + +/* * winLogVersionInfo - Log version information */ @@ -1161,8 +1308,18 @@ winLogVersionInfo(void) ErrorF("Vendor: %s\n", XVENDORNAME); ErrorF("Release: %d.%d.%d.%d\n", XORG_VERSION_MAJOR, XORG_VERSION_MINOR, XORG_VERSION_PATCH, XORG_VERSION_SNAP); +#ifdef HAVE_SYS_UTSNAME_H + { + struct utsname name; + + if (uname(&name) >= 0) { + ErrorF("OS: %s %s %s %s %s\n", name.sysname, name.nodename, + name.release, name.version, name.machine); + } + } +#endif + 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 1b340850c..5624e7563 100644 --- a/hw/xwin/winrandr.c +++ b/hw/xwin/winrandr.c @@ -104,7 +104,7 @@ winDoRandRScreenSetSize(ScreenPtr pScreen, SetRootClip(pScreen, TRUE); // and arrange for it to be repainted - miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); + pScreen->PaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); /* Indicate that a screen size change took place */ RRScreenSizeNotify(pScreen); diff --git a/hw/xwin/winresource.h b/hw/xwin/winresource.h index a14d402e1..37e92ce61 100644 --- a/hw/xwin/winresource.h +++ b/hw/xwin/winresource.h @@ -43,10 +43,8 @@ #define ID_APP_HIDE_ROOT 201 #define ID_APP_ALWAYS_ON_TOP 202 #define ID_APP_ABOUT 203 +#define ID_APP_MONITOR_PRIMARY 204 -#define ID_ABOUT_UG 300 -#define ID_ABOUT_FAQ 301 -#define ID_ABOUT_CHANGELOG 302 #define ID_ABOUT_WEBSITE 303 #endif diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c index 23152cbd2..2c6fdff68 100644 --- a/hw/xwin/winscrinit.c +++ b/hw/xwin/winscrinit.c @@ -216,15 +216,19 @@ winScreenInit(ScreenPtr pScreen, int argc, char **argv) else winErrorFVerb(2, "winScreenInit - Using software cursor\n"); - /* - Note the screen origin in a normalized coordinate space where (0,0) is at the top left - of the native virtual desktop area - */ - pScreen->x = pScreenInfo->dwInitialX - GetSystemMetrics(SM_XVIRTUALSCREEN); - pScreen->y = pScreenInfo->dwInitialY - GetSystemMetrics(SM_YVIRTUALSCREEN); + if (!noPanoramiXExtension) { + /* + Note the screen origin in a normalized coordinate space where (0,0) is at the top left + of the native virtual desktop area + */ + pScreen->x = + pScreenInfo->dwInitialX - GetSystemMetrics(SM_XVIRTUALSCREEN); + pScreen->y = + pScreenInfo->dwInitialY - GetSystemMetrics(SM_YVIRTUALSCREEN); - ErrorF("Screen %d added at virtual desktop coordinate (%d,%d).\n", - pScreen->myNum, pScreen->x, pScreen->y); + ErrorF("Screen %d added at virtual desktop coordinate (%d,%d).\n", + pScreen->myNum, pScreen->x, pScreen->y); + } #if CYGDEBUG || YES winDebug("winScreenInit - returning\n"); diff --git a/hw/xwin/winshadddnl.c b/hw/xwin/winshadddnl.c index 01097f295..9fc3a15ea 100644 --- a/hw/xwin/winshadddnl.c +++ b/hw/xwin/winshadddnl.c @@ -986,6 +986,10 @@ winRedrawScreenShadowDDNL(ScreenPtr pScreen) RECT rcSrc, rcDest; POINT ptOrigin; + /* Return immediately if we didn't get needed surfaces */ + if (!pScreenPriv->pddsPrimary4 || !pScreenPriv->pddsShadow4) + return; + /* Get the origin of the window in the screen coords */ ptOrigin.x = pScreenInfo->dwXOffset; ptOrigin.y = pScreenInfo->dwYOffset; diff --git a/hw/xwin/wintrayicon.c b/hw/xwin/wintrayicon.c index e0aa7e5ab..6acc0d712 100644 --- a/hw/xwin/wintrayicon.c +++ b/hw/xwin/wintrayicon.c @@ -32,9 +32,13 @@ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif + #include "win.h" #include <shellapi.h> #include "winprefs.h" +#ifdef XWIN_CLIPBOARD +#include "winclipboard/winclipboard.h" +#endif /* * Initialize the tray icon @@ -170,6 +174,21 @@ winHandleIconMessage(HWND hwnd, UINT message, RemoveMenu(hmenuTray, ID_APP_HIDE_ROOT, MF_BYCOMMAND); } +#ifdef XWIN_CLIPBOARD + if (g_fClipboard) { + /* Set menu state to indicate if 'Monitor Primary' is enabled or not */ + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_STATE; + mii.fState = fPrimarySelection ? MFS_CHECKED : MFS_UNCHECKED; + SetMenuItemInfo(hmenuTray, ID_APP_MONITOR_PRIMARY, FALSE, &mii); + } + else { + /* Remove 'Monitor Primary' menu item */ + RemoveMenu(hmenuTray, ID_APP_MONITOR_PRIMARY, MF_BYCOMMAND); + } +#endif + SetupRootMenu(hmenuTray); /* diff --git a/hw/xwin/winwin32rootless.c b/hw/xwin/winwin32rootless.c index 724976a84..2785323db 100644 --- a/hw/xwin/winwin32rootless.c +++ b/hw/xwin/winwin32rootless.c @@ -41,6 +41,7 @@ #include <X11/extensions/windowswmstr.h> #include "dixevents.h" #include "winmultiwindowclass.h" +#include "winmultiwindowicons.h" #include <X11/Xatom.h> /* diff --git a/hw/xwin/winwin32rootlesswndproc.c b/hw/xwin/winwin32rootlesswndproc.c index 001d0d2fc..8261e61c1 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 diff --git a/hw/xwin/winwindow.h b/hw/xwin/winwindow.h index 7e6bd565c..a5b9a386c 100644 --- a/hw/xwin/winwindow.h +++ b/hw/xwin/winwindow.h @@ -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 diff --git a/hw/xwin/winwndproc.c b/hw/xwin/winwndproc.c index c73a75c6f..4a4740048 100644 --- a/hw/xwin/winwndproc.c +++ b/hw/xwin/winwndproc.c @@ -42,6 +42,11 @@ #include "winmsg.h" #include "winmonitors.h" #include "inputstr.h" +#include "wmutil/mouse.h" +#include "wmutil/keyboard.h" +#ifdef XWIN_CLIPBOARD +#include "winclipboard/winclipboard.h" +#endif /* * Global variables @@ -916,7 +921,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 */ @@ -1223,6 +1228,12 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) return 0; #endif +#ifdef XWIN_CLIPBOARD + case ID_APP_MONITOR_PRIMARY: + fPrimarySelection = !fPrimarySelection; + return 0; +#endif + case ID_APP_ABOUT: /* Display the About box */ winDisplayAboutDialog(s_pScreenPriv); diff --git a/hw/xwin/wmutil/Makefile.am b/hw/xwin/wmutil/Makefile.am new file mode 100644 index 000000000..5ccee32a6 --- /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 diff --git a/hw/xwin/wmutil/cursor_convert.c b/hw/xwin/wmutil/cursor_convert.c new file mode 100644 index 000000000..be8c96a2d --- /dev/null +++ b/hw/xwin/wmutil/cursor_convert.c @@ -0,0 +1,355 @@ +/* + *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 = + (uint32_t *) 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 = + (uint32_t *) calloc(sm_cx * sm_cy, sizeof(char)); + + 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..b127eb1e9 --- /dev/null +++ b/hw/xwin/wmutil/icon_convert.c @@ -0,0 +1,567 @@ +/* + *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) { + generation = serverGeneration; + + xcb_intern_atom_reply_t *atom_reply; + xcb_intern_atom_cookie_t atom_cookie; + const char *atomName = "_NET_WM_ICON"; + + _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 may overflow an int and thus is bigger than the + property can possibly be */ + if ((icon[0] > 0xFFFF) || (icon[1] > 0xFFFF)) { + winDebug("winXIconToHICON: malformed _NET_WM_ICON data\n"); + break; + } + + /* Icon data size is bigger than amount of data remaining */ + if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) { + winDebug("winXIconToHICON: malformed _NET_WM_ICON data\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); + 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) { + winDebug("winXIconToHICON: no suitable NetIcon\n"); + + xcb_get_property_cookie_t 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 %x\n", id, + 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%x\n", 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..780668d42 --- /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", wParam, 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: %d, fDown: %d\n", 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 */ diff --git a/include/dixmain.h b/include/dixmain.h new file mode 100644 index 000000000..56fa0cd4b --- /dev/null +++ b/include/dixmain.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 + * + * 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, FIT- + * NESS 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. + */ + +#ifndef DIXMAIN_H +#define DIXMAIN_H + +/* this is separate to avoid being pulled in by sdksyms */ +int dix_main(int argc, char *argv[], char *envp[]); + +#endif diff --git a/include/extinit.h b/include/extinit.h index fa5f29378..10f7b4620 100644 --- a/include/extinit.h +++ b/include/extinit.h @@ -163,7 +163,7 @@ extern void SELinuxExtensionInit(void); extern void XTestExtensionInit(void); #endif -#ifdef INXQUARTZ +#ifndef SDKSYMS extern _X_EXPORT Bool noPseudoramiXExtension; extern void PseudoramiXExtensionInit(void); #endif diff --git a/include/opaque.h b/include/opaque.h index b76ab6e6b..5b73a24c7 100644 --- a/include/opaque.h +++ b/include/opaque.h @@ -51,6 +51,7 @@ extern _X_EXPORT int defaultScreenSaverBlanking; extern _X_EXPORT int defaultScreenSaverAllowExposures; extern _X_EXPORT char *display; extern _X_EXPORT int displayfd; +extern _X_EXPORT Bool explicit_display; extern _X_EXPORT int defaultBackingStore; extern _X_EXPORT Bool disableBackingStore; diff --git a/include/os.h b/include/os.h index 9b6729421..8fdbcc38a 100644 --- a/include/os.h +++ b/include/os.h @@ -121,6 +121,8 @@ extern _X_EXPORT int WriteToClient(ClientPtr /*who */ , int /*count */ , extern _X_EXPORT void ResetOsBuffers(void); +extern _X_EXPORT int TransIsListening(char *protocol); + extern _X_EXPORT void InitConnectionLimits(void); extern _X_EXPORT void NotifyParentProcess(void); @@ -367,6 +369,10 @@ extern _X_EXPORT pointer Fopen(const char *, const char *); extern _X_EXPORT int Fclose(pointer); +#if defined(__CYGWIN__) +extern const char * +Win32TempDir(void); +#endif #else extern const char * diff --git a/include/scrnintstr.h b/include/scrnintstr.h index df7407391..3885a7771 100644 --- a/include/scrnintstr.h +++ b/include/scrnintstr.h @@ -158,6 +158,10 @@ typedef void (*WindowExposuresProcPtr) (WindowPtr /*pWindow */ , RegionPtr /*prgn */ , RegionPtr /*other_exposed */ ); +typedef void (* PaintWindowProcPtr) (WindowPtr /*pWindow*/ , + RegionPtr /*pRegion*/ , + int /*what*/ ); + typedef void (*CopyWindowProcPtr) (WindowPtr /*pWindow */ , DDXPointRec /*ptOldOrg */ , RegionPtr /*prgnSrc */ ); @@ -403,6 +407,7 @@ typedef struct _Screen { ValidateTreeProcPtr ValidateTree; PostValidateTreeProcPtr PostValidateTree; WindowExposuresProcPtr WindowExposures; + PaintWindowProcPtr PaintWindow; CopyWindowProcPtr CopyWindow; ClearToBackgroundProcPtr ClearToBackground; ClipNotifyProcPtr ClipNotify; diff --git a/man/Xserver.man b/man/Xserver.man index b103551fa..a4020139b 100644 --- a/man/Xserver.man +++ b/man/Xserver.man @@ -563,9 +563,6 @@ Outline font directories .I /tmp/.X11-unix/X\fBn\fP Unix domain socket for display number \fBn\fP .TP 30 -.I /usr/adm/X\fBn\fPmsgs -Error log file for display number \fBn\fP if run from \fIinit\fP(__adminmansuffix__) -.TP 30 .I __projectroot__/lib/X11/xdm/xdm-errors Default error log file if the server is run from \fIxdm\fP(1) .SH "SEE ALSO" diff --git a/mi/miexpose.c b/mi/miexpose.c index 8b7c93fb8..881c9698f 100644 --- a/mi/miexpose.c +++ b/mi/miexpose.c @@ -277,7 +277,7 @@ miHandleExposures(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, /* miPaintWindow doesn't clip, so we have to */ RegionIntersect(&rgnExposed, &rgnExposed, &pWin->clipList); } - miPaintWindow((WindowPtr) pDstDrawable, &rgnExposed, PW_BACKGROUND); + (*pWin->drawable.pScreen->PaintWindow)(pWin, &rgnExposed, PW_BACKGROUND); if (extents) { RegionReset(&rgnExposed, &expBox); @@ -467,7 +467,7 @@ miWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) RegionIntersect(prgn, prgn, &pWin->clipList); } if (prgn && !RegionNil(prgn)) - miPaintWindow(pWin, prgn, PW_BACKGROUND); + (*pWin->drawable.pScreen->PaintWindow)(pWin, prgn, PW_BACKGROUND); if (clientInterested && exposures && !RegionNil(exposures)) miSendExposures(pWin, exposures, pWin->drawable.x, pWin->drawable.y); @@ -483,14 +483,6 @@ miWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) RegionDestroy(exposures); } -#ifdef ROOTLESS -/* Ugly, ugly, but we lost our hooks into miPaintWindow... =/ */ -void RootlessSetPixmapOfAncestors(WindowPtr pWin); -void RootlessStartDrawing(WindowPtr pWin); -void RootlessDamageRegion(WindowPtr pWin, RegionPtr prgn); -Bool IsFramedWindow(WindowPtr pWin); -#endif - void miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) { @@ -518,22 +510,6 @@ miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) Bool solid = TRUE; DrawablePtr drawable = &pWin->drawable; -#ifdef ROOTLESS - if (!drawable || drawable->type == UNDRAWABLE_WINDOW) - return; - - if (IsFramedWindow(pWin)) { - RootlessStartDrawing(pWin); - RootlessDamageRegion(pWin, prgn); - - if (pWin->backgroundState == ParentRelative) { - if ((what == PW_BACKGROUND) || - (what == PW_BORDER && !pWin->borderIsPixel)) - RootlessSetPixmapOfAncestors(pWin); - } - } -#endif - if (what == PW_BACKGROUND) { while (pWin->backgroundState == ParentRelative) pWin = pWin->parent; diff --git a/mi/mioverlay.c b/mi/mioverlay.c index 2bfd5e401..018f78a15 100644 --- a/mi/mioverlay.c +++ b/mi/mioverlay.c @@ -844,8 +844,8 @@ miOverlayHandleExposures(WindowPtr pWin) if ((mival = pTree->valdata)) { if (!((*pPriv->InOverlay) (pTree->pWin))) { if (RegionNotEmpty(&mival->borderExposed)) { - miPaintWindow(pTree->pWin, &mival->borderExposed, - PW_BORDER); + (*pTree->pWin->drawable.pScreen->PaintWindow)(pTree->pWin, &mival->borderExposed, + PW_BORDER); } RegionUninit(&mival->borderExposed); @@ -884,7 +884,7 @@ miOverlayHandleExposures(WindowPtr pWin) } else { if (RegionNotEmpty(&val->after.borderExposed)) { - miPaintWindow(pChild, &val->after.borderExposed, PW_BORDER); + (*pChild->drawable.pScreen->PaintWindow)(pChild, &val->after.borderExposed, PW_BORDER); } (*WindowExposures) (pChild, &val->after.exposed, NullRegion); } @@ -984,6 +984,7 @@ miOverlayWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) { RegionPtr exposures = prgn; + ScreenPtr pScreen = pWin->drawable.pScreen; if ((prgn && !RegionNil(prgn)) || (exposures && !RegionNil(exposures)) || other_exposed) { @@ -1002,7 +1003,6 @@ miOverlayWindowExposures(WindowPtr pWin, } if (clientInterested && exposures && (RegionNumRects(exposures) > RECTLIMIT)) { - ScreenPtr pScreen = pWin->drawable.pScreen; miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); BoxRec box; @@ -1028,7 +1028,7 @@ miOverlayWindowExposures(WindowPtr pWin, RegionIntersect(prgn, prgn, &pWin->clipList); } if (prgn && !RegionNil(prgn)) - miPaintWindow(pWin, prgn, PW_BACKGROUND); + (*pScreen->PaintWindow)(pWin, prgn, PW_BACKGROUND); if (clientInterested && exposures && !RegionNil(exposures)) miSendExposures(pWin, exposures, pWin->drawable.x, pWin->drawable.y); @@ -1638,7 +1638,7 @@ miOverlayClearToBackground(WindowPtr pWin, if (generateExposures) (*pScreen->WindowExposures) (pWin, ®, pBSReg); else if (pWin->backgroundState != None) - miPaintWindow(pWin, ®, PW_BACKGROUND); + (*pScreen->PaintWindow)(pWin, ®, PW_BACKGROUND); RegionUninit(®); if (pBSReg) RegionDestroy(pBSReg); diff --git a/mi/miscrinit.c b/mi/miscrinit.c index 4698b532f..f8e6706ee 100644 --- a/mi/miscrinit.c +++ b/mi/miscrinit.c @@ -249,6 +249,7 @@ miScreenInit(ScreenPtr pScreen, pointer pbits, /* pointer to screen bits */ pScreen->ValidateTree = miValidateTree; pScreen->PostValidateTree = (PostValidateTreeProcPtr) 0; pScreen->WindowExposures = miWindowExposures; + pScreen->PaintWindow = miPaintWindow; /* CopyWindow */ pScreen->ClearToBackground = miClearToBackground; pScreen->ClipNotify = (ClipNotifyProcPtr) 0; diff --git a/mi/miwindow.c b/mi/miwindow.c index 8dd99dbf0..4b33ca6a4 100644 --- a/mi/miwindow.c +++ b/mi/miwindow.c @@ -112,7 +112,7 @@ miClearToBackground(WindowPtr pWin, if (generateExposures) (*pWin->drawable.pScreen->WindowExposures) (pWin, ®, NULL); else if (pWin->backgroundState != None) - miPaintWindow(pWin, ®, PW_BACKGROUND); + (*pWin->drawable.pScreen->PaintWindow)(pWin, ®, PW_BACKGROUND); RegionUninit(®); } @@ -218,7 +218,7 @@ miHandleValidateExposures(WindowPtr pWin) while (1) { if ((val = pChild->valdata)) { if (RegionNotEmpty(&val->after.borderExposed)) - miPaintWindow(pChild, &val->after.borderExposed, PW_BORDER); + (*pChild->drawable.pScreen->PaintWindow)(pChild, &val->after.borderExposed, PW_BORDER); RegionUninit(&val->after.borderExposed); (*WindowExposures) (pChild, &val->after.exposed, NullRegion); RegionUninit(&val->after.exposed); diff --git a/miext/rootless/rootlessCommon.h b/miext/rootless/rootlessCommon.h index fd9c941f4..dadeab3cb 100644 --- a/miext/rootless/rootlessCommon.h +++ b/miext/rootless/rootlessCommon.h @@ -96,6 +96,7 @@ typedef struct _RootlessScreenRec { ChangeWindowAttributesProcPtr ChangeWindowAttributes; CreateGCProcPtr CreateGC; + PaintWindowProcPtr PaintWindow; CopyWindowProcPtr CopyWindow; GetImageProcPtr GetImage; SourceValidateProcPtr SourceValidate; diff --git a/miext/rootless/rootlessScreen.c b/miext/rootless/rootlessScreen.c index a1af3e7ac..4e7ecf4d3 100644 --- a/miext/rootless/rootlessScreen.c +++ b/miext/rootless/rootlessScreen.c @@ -473,7 +473,7 @@ expose_1(WindowPtr pWin) if (!pWin->realized) return; - miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND); + (*pWin->drawable.pScreen->PaintWindow)(pWin, &pWin->borderClip, PW_BACKGROUND); /* FIXME: comments in windowstr.h indicate that borderClip doesn't include subwindow visibility. But I'm not so sure.. so we may @@ -668,6 +668,7 @@ RootlessWrap(ScreenPtr pScreen) WRAP(CreateScreenResources); WRAP(CloseScreen); WRAP(CreateGC); + WRAP(PaintWindow); WRAP(CopyWindow); WRAP(GetImage); WRAP(SourceValidate); diff --git a/miext/rootless/rootlessWindow.c b/miext/rootless/rootlessWindow.c index 7e3c28130..e4ada0700 100644 --- a/miext/rootless/rootlessWindow.c +++ b/miext/rootless/rootlessWindow.c @@ -1636,3 +1636,38 @@ RootlessSetPixmapOfAncestors(WindowPtr pWin) pScreen->SetWindowPixmap(pWin, topWinRec->pixmap); } } + +/* + * RootlessPaintWindow + * + * Wrapper for miPaintWindow + * + * Returns directly if there is nothing more for miPaintWindow() to do + * + */ +void +RootlessPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) +{ + DrawablePtr drawable = &pWin->drawable; + + if (!drawable || drawable->type == UNDRAWABLE_WINDOW) + return; + + if (IsFramedWindow(pWin)) { + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, pRegion); + + // For ParentRelative windows, if painting background, or with + // tiled borders, we have to make sure the window pixmap is + // set correctly all the way up the ancestor chain. + if (pWin->backgroundState == ParentRelative) { + if ((what == PW_BACKGROUND) || + (what == PW_BORDER && !pWin->borderIsPixel)) + RootlessSetPixmapOfAncestors(pWin); + } + } + + SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindow); + pWin->drawable.pScreen->PaintWindow(pWin, pRegion, what); + SCREEN_WRAP(pWin->drawable.pScreen, PaintWindow); +} diff --git a/miext/rootless/rootlessWindow.h b/miext/rootless/rootlessWindow.h index d3955fc89..3b7ea42d3 100644 --- a/miext/rootless/rootlessWindow.h +++ b/miext/rootless/rootlessWindow.h @@ -53,6 +53,7 @@ void RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, void RootlessResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib); void RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent); +void RootlessPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what); void RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width); #ifdef __APPLE__ diff --git a/os/Makefile.am b/os/Makefile.am index a1bbb4d1e..0b0eb79d1 100644 --- a/os/Makefile.am +++ b/os/Makefile.am @@ -1,6 +1,6 @@ noinst_LTLIBRARIES = libos.la -AM_CFLAGS = $(DIX_CFLAGS) $(SHA1_CFLAGS) +AM_CFLAGS = $(DIX_CFLAGS) $(SHA1_CFLAGS) -DBINDIR=\"$(bindir)\" SECURERPC_SRCS = rpcauth.c XDMCP_SRCS = xdmcp.c diff --git a/os/backtrace.c b/os/backtrace.c index 3d1195b86..3100d1a13 100644 --- a/os/backtrace.c +++ b/os/backtrace.c @@ -222,10 +222,25 @@ xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) } #endif /* HAVE_WALKCONTEXT */ -#ifdef HAVE_PSTACK +#include <sys/types.h> +#if !defined(__WIN32__) || defined(__CYGWIN__) +#include <sys/wait.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* + fork/exec a program to create a backtrace + Returns 0 if successful. +*/ static int -xorg_backtrace_pstack(void) +xorg_backtrace_exec_wrapper(const char *path) { +#if defined(WIN32) && !defined(__CYGWIN__) + ErrorFSigSafe("Backtrace not implemented on Windows"); + return -1; +#else pid_t kidpid; int pipefd[2]; @@ -233,7 +248,7 @@ xorg_backtrace_pstack(void) return -1; } - kidpid = fork1(); + kidpid = fork(); if (kidpid == -1) { /* ERROR */ @@ -246,11 +261,13 @@ xorg_backtrace_pstack(void) seteuid(0); close(STDIN_FILENO); close(STDOUT_FILENO); + close(STDERR_FILENO); dup2(pipefd[1], STDOUT_FILENO); - closefrom(STDERR_FILENO); + dup2(pipefd[1], STDERR_FILENO); + close(pipefd[1]); snprintf(parent, sizeof(parent), "%d", getppid()); - execle("/usr/bin/pstack", "pstack", parent, NULL); + execle(path, path, parent, NULL, NULL); exit(1); } else { @@ -269,17 +286,35 @@ xorg_backtrace_pstack(void) btline[bytesread] = 0; ErrorFSigSafe("%s", btline); } - else if ((bytesread < 0) || ((errno != EINTR) && (errno != EAGAIN))) + else if ((bytesread == 0) || + ((errno != EINTR) && (errno != EAGAIN))) done = 1; } close(pipefd[0]); waitpid(kidpid, &kidstat, 0); - if (kidstat != 0) + if (!(WIFEXITED(kidstat) && WEXITSTATUS(kidstat) == 0)) { + ErrorFSigSafe("%s failed with returncode %d\n", path, + WEXITSTATUS(kidstat)); return -1; + } } return 0; +#endif +} + +#ifdef HAVE_PSTACK +static int +xorg_backtrace_pstack(void) +{ + return xorg_backtrace_exec_wrapper("/usr/bin/pstack"); +} +#endif + +static int +xorg_backtrace_script(void) +{ + return xorg_backtrace_exec_wrapper(BINDIR "/xorg-backtrace"); } -#endif /* HAVE_PSTACK */ #if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) @@ -316,7 +351,8 @@ xorg_backtrace(void) void xorg_backtrace(void) { - return; + if (xorg_backtrace_script() == 0) + return; } #endif diff --git a/os/connection.c b/os/connection.c index 162e1d93e..20a9f008d 100644 --- a/os/connection.c +++ b/os/connection.c @@ -269,6 +269,21 @@ lookup_trans_conn(int fd) return NULL; } +int +TransIsListening(char *protocol) +{ + /* look for this transport in the list of listeners */ + int i; + + for (i = 0; i < ListenTransCount; i++) { + if (!strcmp(protocol, ListenTransConns[i]->transptr->TransName)) { + return 1; + } + } + + return 0; +} + /* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */ void @@ -351,8 +366,8 @@ void NotifyParentProcess(void) { #if !defined(WIN32) - if (dynamic_display[0]) { - write(displayfd, dynamic_display, strlen(dynamic_display)); + if (displayfd) { + write(displayfd, display, strlen(display)); write(displayfd, "\n", 1); close(displayfd); } @@ -404,9 +419,8 @@ CreateWellKnownSockets(void) FD_ZERO(&WellKnownConnections); /* display is initialized to "0" by main(). It is then set to the display - * number if specified on the command line, or to NULL when the -displayfd - * option is used. */ - if (display) { + * number if specified on the command line. */ + if ((displayfd == 0) || explicit_display) { if (TryCreateSocket(atoi(display), &partial) && ListenTransCount >= 1) if (!PartialNetwork && partial) @@ -415,6 +429,7 @@ CreateWellKnownSockets(void) else { /* -displayfd */ Bool found = 0; for (i = 0; i < 65535 - X_TCP_PORT; i++) { + ErrorF("Trying to create socket for display number %d\n", i); if (TryCreateSocket(i, &partial) && !partial) { found = 1; break; @@ -881,9 +881,9 @@ FatalError(const char *f, ...) static Bool beenhere = FALSE; if (beenhere) - ErrorFSigSafe("\nFatalError re-entered, aborting\n"); + ErrorFSigSafe("FatalError re-entered, aborting\n"); else - ErrorFSigSafe("\nFatal server error:\n"); + ErrorFSigSafe("Fatal server error: "); va_start(args, f); @@ -902,7 +902,8 @@ FatalError(const char *f, ...) #endif VErrorFSigSafe(f, args); va_end(args); - ErrorFSigSafe("\n"); + if (f[strlen(f) - 1] != '\n') + ErrorFSigSafe("\n"); if (!beenhere) OsVendorFatalError(f, args2); va_end(args2); diff --git a/os/osinit.c b/os/osinit.c index 4d48ea94e..2791b53f2 100644 --- a/os/osinit.c +++ b/os/osinit.c @@ -69,10 +69,7 @@ SOFTWARE. #if !defined(SYSV) && !defined(WIN32) #include <sys/resource.h> #endif - -#ifndef ADMPATH -#define ADMPATH "/usr/adm/X%smsgs" -#endif +#include <pthread.h> extern char *display; @@ -85,6 +82,7 @@ int limitStackSpace = -1; #ifdef RLIMIT_NOFILE int limitNoFile = -1; #endif +extern Bool install_os_signal_handler; static OsSigWrapperPtr OsSigWrapper = NULL; @@ -125,8 +123,7 @@ OsSigHandler(int signo) } } - /* log, cleanup, and abort */ - xorg_backtrace(); + ErrorF("Fatal signal received in thread 0x%x\n", pthread_self()); #ifdef SA_SIGINFO if (sip->si_code == SI_USER) { @@ -144,6 +141,9 @@ OsSigHandler(int signo) } #endif + /* log, cleanup, and abort */ + xorg_backtrace(); + FatalError("Caught signal %d (%s). Server aborting\n", signo, strsignal(signo)); } @@ -160,30 +160,33 @@ OsInit(void) if (!been_here) { #if !defined(WIN32) || defined(__CYGWIN__) - struct sigaction act, oact; - int i; - - int siglist[] = { SIGSEGV, SIGQUIT, SIGILL, SIGFPE, SIGBUS, - SIGSYS, - SIGXCPU, - SIGXFSZ, + if (install_os_signal_handler) { + struct sigaction act, oact; + int i; + + int siglist[] = { SIGSEGV, SIGQUIT, SIGILL, SIGFPE, SIGBUS, + SIGSYS, + SIGXCPU, + SIGXFSZ, #ifdef SIGEMT - SIGEMT, + SIGEMT, #endif - 0 /* must be last */ - }; - sigemptyset(&act.sa_mask); + 0 /* must be last */ + }; + sigemptyset(&act.sa_mask); #ifdef SA_SIGINFO - act.sa_sigaction = OsSigHandler; - act.sa_flags = SA_SIGINFO; + act.sa_sigaction = OsSigHandler; + act.sa_flags = SA_SIGINFO; #else - act.sa_handler = OsSigHandler; - act.sa_flags = 0; + act.sa_handler = OsSigHandler; + act.sa_flags = 0; #endif - for (i = 0; siglist[i] != 0; i++) { - if (sigaction(siglist[i], &act, &oact)) { - ErrorF("failed to install signal handler for signal %d: %s\n", - siglist[i], strerror(errno)); + for (i = 0; siglist[i] != 0; i++) { + if (sigaction(siglist[i], &act, &oact)) { + ErrorF + ("failed to install signal handler for signal %d: %s\n", + siglist[i], strerror(errno)); + } } } #endif /* !WIN32 || __CYGWIN__ */ @@ -224,40 +227,7 @@ OsInit(void) # elif !defined(__CYGWIN__) fclose(stdin); fclose(stdout); -# endif - /* - * If a write of zero bytes to stderr returns non-zero, i.e. -1, - * then writing to stderr failed, and we'll write somewhere else - * instead. (Apparently this never happens in the Real World.) - */ - if (write(2, fname, 0) == -1) { - FILE *err; - - if (strlen(display) + strlen(ADMPATH) + 1 < sizeof fname) - snprintf(fname, sizeof(fname), ADMPATH, display); - else - strcpy(fname, devnull); - /* - * uses stdio to avoid os dependencies here, - * a real os would use - * open (fname, O_WRONLY|O_APPEND|O_CREAT, 0666) - */ - if (!(err = fopen(fname, "a+"))) - err = fopen(devnull, "w"); - if (err && (fileno(err) != 2)) { - dup2(fileno(err), 2); - fclose(err); - } -#if defined(SYSV) || defined(SVR4) || defined(WIN32) || defined(__CYGWIN__) - { - static char buf[BUFSIZ]; - - setvbuf(stderr, buf, _IOLBF, BUFSIZ); - } -#else - setlinebuf(stderr); #endif - } #endif /* !XQUARTZ */ #if !defined(WIN32) || defined(__CYGWIN__) diff --git a/os/utils.c b/os/utils.c index 608ee6ab0..d3391215b 100644 --- a/os/utils.c +++ b/os/utils.c @@ -122,6 +122,8 @@ __stdcall unsigned long GetTickCount(void); #include "picture.h" +Bool install_os_signal_handler = TRUE; + Bool noTestExtensions; #ifdef COMPOSITE @@ -253,7 +255,7 @@ UnlockServer(void) #else /* LOCK_SERVER */ static Bool StillLocking = FALSE; static char LockFile[PATH_MAX]; -static Bool nolock = FALSE; +Bool nolock = FALSE; /* * LockServer -- @@ -547,6 +549,7 @@ UseMsg(void) #ifdef RLIMIT_STACK ErrorF("-ls int limit stack space to N Kb\n"); #endif + ErrorF("-notrapsignals disable catching of fatal signals\n"); #ifdef LOCK_SERVER ErrorF("-nolock disable the locking mechanism\n"); #endif @@ -639,6 +642,7 @@ ProcessCommandLine(int argc, char *argv[]) else if (argv[i][0] == ':') { /* initialize display */ display = argv[i]; + explicit_display = TRUE; display++; if (!VerifyDisplayName(display)) { ErrorF("Bad display name: %s\n", display); @@ -709,7 +713,6 @@ ProcessCommandLine(int argc, char *argv[]) else if (strcmp(argv[i], "-displayfd") == 0) { if (++i < argc) { displayfd = atoi(argv[i]); - display = NULL; #ifdef LOCK_SERVER nolock = TRUE; #endif @@ -792,6 +795,9 @@ ProcessCommandLine(int argc, char *argv[]) UseMsg(); } #endif + else if (strcmp(argv[i], "-notrapsignals") == 0) { + install_os_signal_handler = FALSE; + } #ifdef LOCK_SERVER else if (strcmp(argv[i], "-nolock") == 0) { #if !defined(WIN32) && !defined(__CYGWIN__) @@ -930,6 +936,7 @@ ProcessCommandLine(int argc, char *argv[]) } else if (strcmp(argv[i], "-schedInterval") == 0) { if (++i < argc) { + SmartScheduleDisable = FALSE; SmartScheduleInterval = atoi(argv[i]); SmartScheduleSlice = SmartScheduleInterval; } @@ -938,6 +945,7 @@ ProcessCommandLine(int argc, char *argv[]) } else if (strcmp(argv[i], "-schedMax") == 0) { if (++i < argc) { + SmartScheduleDisable = FALSE; SmartScheduleMaxSlice = atoi(argv[i]); } else @@ -1335,6 +1343,26 @@ OsAbort(void) * as well. As it is now, xkbcomp messages don't end up in the log file. */ +#ifdef __CYGWIN__ +#include <process.h> +int +System(const char *command) +{ + int status; + + if (!command) + return 1; + + DebugF("System: `%s'\n", command); + + /* + Use spawnl() rather than execl() to implement System() on cygwin to + avoid fork emulation overhead and brittleness + */ + status = spawnl(_P_WAIT, "/bin/sh", "sh", "-c", command, (char *) NULL); + return status; +} +#else int System(const char *command) { @@ -1376,6 +1404,7 @@ System(const char *command) return p == -1 ? -1 : status; } +#endif static struct pid { struct pid *next; @@ -1687,6 +1716,17 @@ System(const char *cmdline) return dwExitCode; } +#elif defined(__CYGWIN__) +const char* +Win32TempDir(void) +{ + if (getenv("TEMP") != NULL) + return getenv("TEMP"); + else if (getenv("TMP") != NULL) + return getenv("TMP"); + else + return "/tmp"; +} #endif /* diff --git a/pseudoramiX/pseudoramiX.h b/pseudoramiX/pseudoramiX.h index f063919dd..5393062ee 100644 --- a/pseudoramiX/pseudoramiX.h +++ b/pseudoramiX/pseudoramiX.h @@ -2,8 +2,6 @@ * Minimal implementation of PanoramiX/Xinerama */ -extern int noPseudoramiXExtension; - void PseudoramiXAddScreen(int x, int y, int w, int h); void diff --git a/randr/rrxinerama.c b/randr/rrxinerama.c index 76d728c70..128459850 100644 --- a/randr/rrxinerama.c +++ b/randr/rrxinerama.c @@ -84,6 +84,8 @@ static int ProcRRXineramaIsActive(ClientPtr client); static int ProcRRXineramaQueryScreens(ClientPtr client); static int SProcRRXineramaDispatch(ClientPtr client); +Bool noRRXineramaExtension = FALSE; + /* Proc */ int @@ -480,6 +482,9 @@ RRXineramaExtensionInit(void) return; #endif + if (noRRXineramaExtension) + return; + /* * Xinerama isn't capable enough to have multiple protocol screens each * with their own output geometry. So if there's more than one protocol diff --git a/xkb/ddxLoad.c b/xkb/ddxLoad.c index d462957f4..bcfe04d8e 100644 --- a/xkb/ddxLoad.c +++ b/xkb/ddxLoad.c @@ -44,6 +44,7 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE. #include <xkbsrv.h> #include <X11/extensions/XI.h> #include "xkb.h" +#include "os.h" /* * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is @@ -104,7 +105,7 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb, const char *xkbbindir = emptystring; const char *xkbbindirsep = emptystring; -#ifdef WIN32 +#if defined(WIN32) || defined(__CYGWIN__) /* WIN32 has no popen. The input must be stored in a file which is used as input for xkbcomp. xkbcomp does not read from stdin. */ char tmpname[PATH_MAX]; @@ -117,9 +118,9 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb, OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir)); -#ifdef WIN32 +#if defined(WIN32) || defined(__CYGWIN__) strcpy(tmpname, Win32TempDir()); - strcat(tmpname, "\\xkb_XXXXXX"); + strcat(tmpname, PATHSEPARATOR "xkb_XXXXXX"); (void) mktemp(tmpname); #endif @@ -158,7 +159,7 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb, return FALSE; } -#ifndef WIN32 +#if !defined(WIN32) && !defined(__CYGWIN__) out = Popen(buf, "w"); #else out = fopen(tmpname, "w"); @@ -172,7 +173,7 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb, } #endif XkbWriteXKBKeymapForNames(out, names, xkb, want, need); -#ifndef WIN32 +#if !defined(WIN32) && !defined(__CYGWIN__) if (Pclose(out) == 0) #else if (fclose(out) == 0 && System(buf) >= 0) @@ -184,14 +185,14 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb, strlcpy(nameRtrn, keymap, nameRtrnLen); } free(buf); -#ifdef WIN32 +#if defined(WIN32) || defined(__CYGWIN__) unlink(tmpname); #endif return TRUE; } else LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap); -#ifdef WIN32 +#if defined(WIN32) || defined(__CYGWIN__) /* remove the temporary file */ unlink(tmpname); #endif |