From 114517ca2014f21586487d79a7362b44af6b3540 Mon Sep 17 00:00:00 2001 From: patthoyts Date: Wed, 7 Jan 2009 00:25:43 +0000 Subject: [Bug 1847002] On Windows a grab can be bypassed using the taskbar. This prevents that by handling the keyboard activation message and the system menu commands when grabs are present. --- ChangeLog | 4 +++ win/tkWinWm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 84 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 270d415..342dbd6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-01-07 Pat Thoyts + + * win/tkWinWm.c: prevent grabs being bypassed on Windows [Bug 1847002] + 2009-01-06 Jan Nijtmans * generic/tk.h: A few const -> CONST86 modifications, improving diff --git a/win/tkWinWm.c b/win/tkWinWm.c index 89fe23e..9267049 100644 --- a/win/tkWinWm.c +++ b/win/tkWinWm.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinWm.c,v 1.134 2008/12/09 21:22:56 dgp Exp $ + * RCS: @(#) $Id: tkWinWm.c,v 1.135 2009/01/07 00:25:43 patthoyts Exp $ */ #include "tkWinInt.h" @@ -34,12 +34,16 @@ /* * Event structure for synthetic activation events. These events are placed on - * the event queue whenever a toplevel gets a WM_MOUSEACTIVATE message. + * the event queue whenever a toplevel gets a WM_MOUSEACTIVATE message or + * a WM_ACTIVATE. If the window is being moved (*flagPtr will be true) + * then the handling of this event must be delayed until the operation + * has completed to avoid a premature WM_EXITSIZEMOVE event. */ typedef struct ActivateEvent { Tcl_Event ev; TkWindow *winPtr; + int *flagPtr; } ActivateEvent; /* @@ -418,6 +422,7 @@ TCL_DECLARE_MUTEX(winWmMutex) static int ActivateWindow(Tcl_Event *evPtr, int flags); static void ConfigureTopLevel(WINDOWPOS *pos); static void GenerateConfigureNotify(TkWindow *winPtr); +static void GenerateActivateEvent(TkWindow *winPtr, int *flagPtr); static void GetMaxSize(WmInfo *wmPtr, int *maxWidthPtr, int *maxHeightPtr); static void GetMinSize(WmInfo *wmPtr, @@ -7755,7 +7760,7 @@ WmProc( * after leaving move/size mode. Note that * this mechanism assumes move/size is only * one level deep. */ - LRESULT result; + LRESULT result = 0; TkWindow *winPtr = NULL; switch (message) { @@ -7779,6 +7784,20 @@ WmProc( break; case WM_ACTIVATE: + if ( WA_ACTIVE == LOWORD(wParam) ) { + winPtr = GetTopLevel(hwnd); + if (winPtr && (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)) { + /* + * There is a grab in progress so queue an Activate event + */ + + GenerateActivateEvent(winPtr, &inMoveSize); + result = 0; + goto done; + } + } + /* fall through */ + case WM_EXITSIZEMOVE: if (inMoveSize) { inMoveSize = 0; @@ -7881,8 +7900,6 @@ WmProc( } case WM_MOUSEACTIVATE: { - ActivateEvent *eventPtr; - winPtr = GetTopLevel((HWND) wParam); if (winPtr && (TkGrabState(winPtr) != TK_GRAB_EXCLUDED)) { /* @@ -7902,10 +7919,7 @@ WmProc( */ if (winPtr) { - eventPtr = (ActivateEvent *) ckalloc(sizeof(ActivateEvent)); - eventPtr->ev.proc = ActivateWindow; - eventPtr->winPtr = winPtr; - Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_TAIL); + GenerateActivateEvent(winPtr, &inMoveSize); } result = MA_NOACTIVATE; goto done; @@ -7934,6 +7948,24 @@ WmProc( winPtr = GetTopLevel(hwnd); switch(message) { case WM_SYSCOMMAND: + /* + * If there is a grab in effect then ignore the minimize command + * If there is a grab in effect and this window is outside the + * grab tree then ignore all system commands. [Bug 1847002] + */ + + if (winPtr) { + int cmd = wParam & 0xfff0; + int grab = TkGrabState(winPtr); + if (grab != TK_GRAB_NONE && SC_MINIMIZE == cmd) + goto done; + if (grab == TK_GRAB_EXCLUDED + && !(SC_MOVE == cmd || SC_SIZE == cmd)) { + goto done; + } + } + /* fall through */ + case WM_INITMENU: case WM_COMMAND: case WM_MENUCHAR: @@ -7941,20 +7973,21 @@ WmProc( case WM_DRAWITEM: case WM_MENUSELECT: case WM_ENTERIDLE: - case WM_INITMENUPOPUP: { - HWND hMenuHWnd = Tk_GetEmbeddedMenuHWND((Tk_Window) winPtr); + case WM_INITMENUPOPUP: + if (winPtr) { + HWND hMenuHWnd = Tk_GetEmbeddedMenuHWND((Tk_Window) winPtr); - if (hMenuHWnd) { - if (SendMessage(hMenuHWnd, message, wParam, lParam)) { + if (hMenuHWnd) { + if (SendMessage(hMenuHWnd, message, wParam, lParam)) { + goto done; + } + } else if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, + &result)) { goto done; } - } else if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, - &result)) { - goto done; } break; } - } if (winPtr && winPtr->window) { HWND child = Tk_GetHWND(winPtr->window); @@ -8109,6 +8142,25 @@ TkpGetWrapperWindow( /* *---------------------------------------------------------------------- * + * GenerateActivateEvent -- + * + * This function is called to activate a Tk window. + */ + +static void +GenerateActivateEvent(TkWindow * winPtr, int *flagPtr) +{ + ActivateEvent *eventPtr; + eventPtr = (ActivateEvent *)ckalloc(sizeof(ActivateEvent)); + eventPtr->ev.proc = ActivateWindow; + eventPtr->winPtr = winPtr; + eventPtr->flagPtr = flagPtr; + Tcl_QueueEvent((Tcl_Event *)eventPtr, TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * * ActivateWindow -- * * This function is called when an ActivateEvent is processed. @@ -8127,13 +8179,22 @@ ActivateWindow( Tcl_Event *evPtr, /* Pointer to ActivateEvent. */ int flags) /* Notifier event mask. */ { - TkWindow *winPtr; + ActivateEvent *eventPtr = (ActivateEvent *)evPtr; + TkWindow *winPtr = eventPtr->winPtr; if (! (flags & TCL_WINDOW_EVENTS)) { return 0; } - winPtr = ((ActivateEvent *) evPtr)->winPtr; + /* + * If the toplevel is in the middle of a move or size operation then + * we must delay handling of this event to avoid stealing the focus + * while the window manage is in control. + */ + + if (eventPtr->flagPtr && *eventPtr->flagPtr) { + return 0; + } /* * If the window is excluded by a grab, call SetFocus on the grabbed -- cgit v0.12