diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index 04c17b702..d6b5e4fd9 100644 --- a/hw/xwin/InitOutput.c +++ b/hw/xwin/InitOutput.c @@ -186,6 +186,25 @@ ddxBeforeReset(void) } #endif +int +main(int argc, char *argv[], char *envp[]) +{ + int iReturn; + + /* Create & acquire the termination mutex */ + iReturn = pthread_mutex_init(&g_pmTerminating, NULL); + if (iReturn != 0) { + ErrorF("ddxMain - pthread_mutex_init () failed: %d\n", iReturn); + } + + iReturn = pthread_mutex_lock(&g_pmTerminating); + if (iReturn != 0) { + ErrorF("ddxMain - pthread_mutex_lock () failed: %d\n", iReturn); + } + + return dix_main(argc, argv, envp); +} + /* See Porting Layer Definition - p. 57 */ void ddxGiveUp(enum ExitCode error) @@ -243,6 +262,19 @@ ddxGiveUp(enum ExitCode error) /* Tell Windows that we want to end the app */ PostQuitMessage(0); + + { + winDebug("ddxGiveUp - Releasing termination mutex\n"); + + int iReturn = pthread_mutex_unlock(&g_pmTerminating); + + if (iReturn != 0) { + ErrorF("winMsgWindowProc - pthread_mutex_unlock () failed: %d\n", + iReturn); + } + } + + winDebug("ddxGiveUp - End\n"); } /* See Porting Layer Definition - p. 57 */ @@ -962,6 +994,10 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) /* Store the instance handle */ g_hInstance = GetModuleHandle(NULL); + /* Create the messaging window */ + if (serverGeneration == 1) + winCreateMsgWindowThread(); + /* Initialize each screen */ for (i = 0; i < g_iNumScreens; ++i) { /* Initialize the screen */ diff --git a/hw/xwin/Makefile.am b/hw/xwin/Makefile.am index 90812abb0..74a4243c2 100644 --- a/hw/xwin/Makefile.am +++ b/hw/xwin/Makefile.am @@ -92,6 +92,7 @@ SRCS = InitInput.c \ winmonitors.c \ winmouse.c \ winmsg.c \ + winmsgwindow.c \ winmultiwindowclass.c \ winmultiwindowicons.c \ winprefs.c \ diff --git a/hw/xwin/win.h b/hw/xwin/win.h index fa774bc00..dd6ed02ac 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -1402,6 +1402,12 @@ winDoRandRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight); +/* + * winmsgwindow.c + */ +Bool +winCreateMsgWindowThread(void); + /* * END DDX and DIX Function Prototypes */ diff --git a/hw/xwin/winglobals.c b/hw/xwin/winglobals.c index b34d1a751..b3ca29592 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; +pthread_mutex_t g_pmTerminating = PTHREAD_MUTEX_INITIALIZER; #ifdef XWIN_CLIPBOARD /* diff --git a/hw/xwin/winglobals.h b/hw/xwin/winglobals.h index d2e2ba2b4..e7e2f7e20 100644 --- a/hw/xwin/winglobals.h +++ b/hw/xwin/winglobals.h @@ -90,4 +90,6 @@ extern Bool g_fButton[3]; extern Bool g_fNoConfigureWindow; #endif +extern pthread_mutex_t g_pmTerminating; + #endif /* WINGLOBALS_H */ diff --git a/hw/xwin/winmsgwindow.c b/hw/xwin/winmsgwindow.c new file mode 100644 index 000000000..8067c693c --- /dev/null +++ b/hw/xwin/winmsgwindow.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) Jon TURNEY 2011 + * + * 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 "win.h" + +/* + * This is the messaging window, a hidden top-level window. We never do anything + * with it, but other programs may send messages to it. + */ + +/* + * winMsgWindowProc - Window procedure for msg window + */ + +static +LRESULT CALLBACK +winMsgWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ +#if CYGDEBUG + winDebugWin32Message("winMsgWindowProc", hwnd, message, wParam, lParam); +#endif + + switch (message) { + case WM_ENDSESSION: + if (!wParam) + return 0; /* shutdown is being cancelled */ + + /* + Send a WM_GIVEUP message to the X server thread so it wakes up if + blocked in select(), performs GiveUp(), and then notices that GiveUp() + has set the DE_TERMINATE flag so exits the msg dispatch loop. + */ + { + ScreenPtr pScreen = screenInfo.screens[0]; + + winScreenPriv(pScreen); + PostMessage(pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); + } + + /* + This process will be terminated by the system almost immediately + after the last thread with a message queue returns from processing + WM_ENDSESSION, so we cannot rely on any code executing after this + message is processed and need to wait here until ddxGiveUp() is called + and releases the termination mutex to guarantee that the lock file and + unix domain sockets have been removed + + ofc, Microsoft doesn't document this under WM_ENDSESSION, you are supposed + to read the source of CRSS to find out how it works :-) + + http://blogs.msdn.com/b/michen/archive/2008/04/04/application-termination-when-user-logs-off.aspx + */ + { + int iReturn = pthread_mutex_lock(&g_pmTerminating); + + if (iReturn != 0) { + ErrorF("winMsgWindowProc - pthread_mutex_lock () failed: %d\n", + iReturn); + } + winDebug + ("winMsgWindowProc - WM_ENDSESSION termination lock acquired\n"); + } + + return 0; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +static HWND +winCreateMsgWindow(void) +{ + HWND hwndMsg; + wATOM winClass; + + // register window class + { + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(WNDCLASSEX); + wcx.style = CS_HREDRAW | CS_VREDRAW; + wcx.lpfnWndProc = winMsgWindowProc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = g_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = 0; + wcx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = WINDOW_CLASS_X_MSG; + wcx.hIconSm = NULL; + winClass = RegisterClassEx(&wcx); + } + + // Create the msg window. + hwndMsg = CreateWindowEx(0, // no extended styles + WINDOW_CLASS_X_MSG, // class name + "XWin Msg Window", // window name + WS_OVERLAPPEDWINDOW, // overlapped window + CW_USEDEFAULT, // default horizontal position + CW_USEDEFAULT, // default vertical position + CW_USEDEFAULT, // default width + CW_USEDEFAULT, // default height + (HWND) NULL, // no parent or owner window + (HMENU) NULL, // class menu used + GetModuleHandle(NULL), // instance handle + NULL); // no window creation data + + if (!hwndMsg) { + ErrorF("winCreateMsgWindow - Create msg window failed\n"); + return NULL; + } + + winDebug("winCreateMsgWindow - Created msg window hwnd 0x%x\n", hwndMsg); + + return hwndMsg; +} + +static void * +winMsgWindowThreadProc(void *arg) +{ + HWND hwndMsg; + + winDebug("winMsgWindowThreadProc - Hello\n"); + + hwndMsg = winCreateMsgWindow(); + if (hwndMsg) { + MSG msg; + + /* Pump the msg window message queue */ + while (GetMessage(&msg, hwndMsg, 0, 0) > 0) { +#if CYGDEBUG + winDebugWin32Message("winMsgWindowThread", msg.hwnd, msg.message, + msg.wParam, msg.lParam); +#endif + DispatchMessage(&msg); + } + } + + winDebug("winMsgWindowThreadProc - Exit\n"); + + return NULL; +} + +Bool +winCreateMsgWindowThread(void) +{ + pthread_t ptMsgWindowThreadProc; + + /* Spawn a thread for the msg window */ + if (pthread_create(&ptMsgWindowThreadProc, + NULL, winMsgWindowThreadProc, NULL)) { + /* Bail if thread creation failed */ + ErrorF("winCreateMsgWindow - pthread_create failed.\n"); + return FALSE; + } + + return TRUE; +} diff --git a/hw/xwin/winwindow.h b/hw/xwin/winwindow.h index 25826ecc7..7e6bd565c 100644 --- a/hw/xwin/winwindow.h +++ b/hw/xwin/winwindow.h @@ -49,6 +49,7 @@ #define WINDOW_TITLE_XDMCP "%s:%s.%d" #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_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 c7509ea19..f93072c2f 100644 --- a/hw/xwin/winwndproc.c +++ b/hw/xwin/winwndproc.c @@ -1221,7 +1221,6 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; - case WM_ENDSESSION: case WM_GIVEUP: /* Tell X that we are giving up */ #ifdef XWIN_MULTIWINDOW