From 78ee5962c6fdeb0d13ccb55f970ff6efcf43eb49 Mon Sep 17 00:00:00 2001 From: Richard Frith-MacDonald Date: Thu, 6 Mar 2008 06:19:02 +0000 Subject: [PATCH] fixups for implementation of window levels support git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@26218 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 10 ++ Source/win32/WIN32Server.m | 83 +++++++++------ Source/win32/w32_movesize.m | 205 +++++++++++++++++++++++------------- 3 files changed, 192 insertions(+), 106 deletions(-) diff --git a/ChangeLog b/ChangeLog index c0f0817..5bc4735 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-03-06 Richard Frith-Macdonald + + * Source\win32\WIN32Server.m: Improve window level code ... when moving + a window to the top of a level, jump it right to the top of the window + z-order so that it is above any non-gnustep windows. + * Source\win32\w32_movesize.m: If a window is jumped to the top of the + z-order and hence breaks the level rules, use a bubble sort to get + the windows back in level order by raising any windows which are + lower than they should be. + 2008-03-05 Richard Frith-Macdonald * Headers\win32\WIN32Server.h: Add fields to track window level/ordering diff --git a/Source/win32/WIN32Server.m b/Source/win32/WIN32Server.m index 0280e75..d1dc46f 100644 --- a/Source/win32/WIN32Server.m +++ b/Source/win32/WIN32Server.m @@ -1036,6 +1036,11 @@ NSLog(@"Callback"); } } + flag = SW_SHOW; + if (IsIconic((HWND)winNum)) + flag = SW_RESTORE; + ShowWindow((HWND)winNum, flag); + win = (WIN_INTERN *)GetWindowLong((HWND)winNum, GWL_USERDATA); if (op == NSWindowOut) @@ -1080,11 +1085,6 @@ NSLog(@"Callback"); } } - flag = SW_SHOW; - if (IsIconic((HWND)winNum)) - flag = SW_RESTORE; - ShowWindow((HWND)winNum, flag); - if (win->level <= NSDesktopWindowLevel) { // For desktop level, put this at the bottom of the z-order @@ -1135,9 +1135,27 @@ NSLog(@"Callback"); otherWin, other->level); if (other->level >= win->level) { - if (other->level > win->level - || op == NSWindowBelow - || foreground == otherWin) + if (other->level > win->level) + { + /* On windows, there is no notion of levels, so + * native apps will automatically move to the + * very top of the stack (above our alert panels etc) + * + * So to cope with this, when we move to the top + * of a level, we assume there may be native apps + * above us and we set otherWin=0 to move to the + * very top of the stack past them. + * + * We rely on the fact that we have code in the + * window positioning notification to rearrange + * (sort) all the windows into level order if + * moving this window to the top messes up the + * level ordering. + */ + otherWin = 0; + break; + } + if (op == NSWindowBelow || foreground == otherWin) { break; } @@ -1167,37 +1185,38 @@ NSLog(@"Callback"); SetWindowPos((HWND)winNum, (HWND)otherWin, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); -#if 1 -{ - NSString *s = @"Window list:\n"; - - otherWin = (int)GetDesktopWindow(); - otherWin = (int)GetWindow((HWND)otherWin, GW_CHILD); - if (otherWin > 0) + /* For debug log window stack. + */ + if (GSDebugSet(@"WTrace") == YES) { - otherWin = (int)GetWindow((HWND)otherWin, GW_HWNDLAST); - } - while (otherWin > 0) - { - TCHAR buf[32]; + NSString *s = @"Window list:\n"; - otherWin = (int)GetNextWindow((HWND)otherWin, GW_HWNDPREV); - - if (otherWin > 0 && otherWin != winNum - && GetClassName((HWND)otherWin, buf, 32) == 18 - && strncmp(buf, "GNUstepWindowClass", 18) == 0) + otherWin = (int)GetDesktopWindow(); + otherWin = (int)GetWindow((HWND)otherWin, GW_CHILD); + if (otherWin > 0) { - other = (WIN_INTERN *)GetWindowLong((HWND)otherWin, GWL_USERDATA); - if (other->orderedIn == YES) + otherWin = (int)GetWindow((HWND)otherWin, GW_HWNDLAST); + } + while (otherWin > 0) + { + TCHAR buf[32]; + + otherWin = (int)GetNextWindow((HWND)otherWin, GW_HWNDPREV); + + if (otherWin > 0 + && GetClassName((HWND)otherWin, buf, 32) == 18 + && strncmp(buf, "GNUstepWindowClass", 18) == 0) { - s = [s stringByAppendingFormat: - @"%d (%d)\n", otherWin, other->level]; + other = (WIN_INTERN *)GetWindowLong((HWND)otherWin, GWL_USERDATA); + if (other->orderedIn == YES) + { + s = [s stringByAppendingFormat: + @"%d (%d)\n", otherWin, other->level]; + } } } + NSDebugLLog(@"WTrace", @"orderwindow: %@", s); } - NSDebugLLog(@"WTrace", @"orderwindow: %@", s); -} -#endif } - (void) movewindow: (NSPoint)loc : (int)winNum diff --git a/Source/win32/w32_movesize.m b/Source/win32/w32_movesize.m index 5001576..e73f939 100644 --- a/Source/win32/w32_movesize.m +++ b/Source/win32/w32_movesize.m @@ -252,84 +252,141 @@ - (void) decodeWM_WINDOWPOSCHANGEDParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd { -#if 0 -/* FIXME we really want to ensure that windows stay in the correct - * level order. When we change ordering programmatically using - * orderwindow::: that's OK, but if someone else reorders our - * windows, how do we cope? - * Perhaps we should veto/adjust ordering before it happens, or - * perhaps we should re-order here? - */ - if ((inf->flags & SWP_NOZORDER) == 0) - { - /* If this window has been moved to the front, we need to move - * any other higher level windows to follow it. - */ - win = (WIN_INTERN *)GetWindowLong(hwnd, GWL_USERDATA); - if (win->level > NSDesktopWindowLevel) - { - int otherWin; - int levelToMove = NSDesktopWindowlevel; - - /* Start searching from bottom of window list... - * The last child of the desktop. - */ - otherWin = (int)GetDesktopWindow(); - otherWin = (int)GetWindow((HWND)otherWin, GW_CHILD); - if (otherWin > 0) - { - otherWin = (int)GetWindow((HWND)otherWin, GW_HWNDLAST); - } - while (otherWin > 0) - { - TCHAR buf[32]; - - otherWin = (int)GetNextWindow((HWND)otherWin, GW_HWNDPREV); - if (otherWin == 0 || otherWin == (int)hwnd) - { - break; // No higher level windows below this - } - if (GetClassName((HWND)otherWin, buf, 32) == 18 - && strncmp(buf, "GNUstepWindowClass", 18) == 0) - { - other = (WIN_INTERN *)GetWindowLong((HWND)otherWin, - GWL_USERDATA); - if (other->orderedIn == YES) - { - BOOL moveThisWindow = NO; - - if (levelToMove > NSDesktopWindowLevel) - { - if (other->level == levelToMove) - { - moveThisWindow = YES; - } - } - else if (other->level > win->level) - { - levelToMove = other->level; - moveThisWindow = YES; - } - if (moveThisWidnow == YES) - { - SetWindowPos((HWND)otherWin, HWND_TOP, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); - } - } - } - } - } - } -#endif -} - -- (void) decodeWM_WINDOWPOSCHANGINGParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd -{ - WIN_INTERN *win; WINDOWPOS *inf = (WINDOWPOS*)lParam; if ((inf->flags & SWP_NOZORDER) == 0) { + HWND hi; + HWND lo; + WIN_INTERN *hInf; + WIN_INTERN *lInf; + + /* For debugging, log current window stack. + */ + if (GSDebugSet(@"WTrace") == YES) + { + NSString *s = @"Window list:\n"; + + hi = GetDesktopWindow(); + hi = GetWindow(hi, GW_CHILD); + if (hi > 0) + { + hi = GetWindow(hi, GW_HWNDLAST); + } + while (hi > 0) + { + TCHAR buf[32]; + + hi = GetNextWindow(hi, GW_HWNDPREV); + + if (hi > 0 + && GetClassName(hi, buf, 32) == 18 + && strncmp(buf, "GNUstepWindowClass", 18) == 0) + { + hInf = (WIN_INTERN *)GetWindowLong(hi, GWL_USERDATA); + if (hInf->orderedIn == YES) + { + s = [s stringByAppendingFormat: + @"%d (%d)\n", hi, hInf->level]; + } + } + } + NSLog(@"window pos changed: %@", s); + } + + /* This window has changed its z-order, so we take the opportunity + * to check that all the GNUstep windows are in the correct order + * of their levels. + * We do this as a simple bubble sort ...swapping over a pait of + * windows if we find any pair in the list which are in the wrong + * order. This sort has the virtue of being simple and of + * maintaining window order within a level. ... but may be too slow. + */ + hi = GetDesktopWindow(); + hi = GetWindow(hi, GW_CHILD); + while (hi > 0) + { + TCHAR buf[32]; + + /* Find a GNUstep window which is ordered in and above desktop + */ + while (hi > 0) + { + if (GetClassName(hi, buf, 32) == 18 + && strncmp(buf, "GNUstepWindowClass", 18) == 0 + && (hInf = (WIN_INTERN *)GetWindowLong(hi, GWL_USERDATA)) + && hInf->level > NSDesktopWindowLevel + && hInf->orderedIn == YES) + { + break; + } + hi = GetNextWindow(hi, GW_HWNDNEXT); + } + + if (hi > 0) + { + NSDebugLLog(@"WTrace", @"sort hi %d (%d)", hi, hInf->level); + /* Find the next (lower in z-order) GNUstep window which + * is ordered in and above desktop + */ + lo = GetNextWindow(hi, GW_HWNDNEXT); + while (lo > 0) + { + if (GetClassName(lo, buf, 32) == 18 + && strncmp(buf, "GNUstepWindowClass", 18) == 0 + && (lInf = (WIN_INTERN *)GetWindowLong(lo, GWL_USERDATA)) + && lInf->level > NSDesktopWindowLevel + && lInf->orderedIn == YES) + { + break; + } + lo = GetNextWindow(lo, GW_HWNDNEXT); + } + + if (lo > 0) + { + NSDebugLLog(@"WTrace", @"sort lo %d (%d)", lo, lInf->level); + /* Check to see if the higher of the two windows should + * actually be lower. + */ + if (hInf->level < lInf->level) + { + HWND higher; + + /* Insert the low window before the high one. + * ie after the window preceding the high one. + */ + higher = GetNextWindow(hi, GW_HWNDPREV); + if (higher == 0) + { + higher = HWND_TOP; + } +NSDebugLLog(@"WTrace", @"swap %d (%d) with %d (%d)", + hi, hInf->level, lo, lInf->level); + SetWindowPos(lo, higher, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + + /* Done this iteration of the sort ... the next + * iteration takes place when we get notified + * that the swap we have just donew is complete. + */ + break; + } + } + hi = lo; + } + } + } +} + +- (void) decodeWM_WINDOWPOSCHANGINGParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd +{ + WINDOWPOS *inf = (WINDOWPOS*)lParam; + + if ((inf->flags & SWP_NOZORDER) == 0) + { + WIN_INTERN *win; + /* desktop level windows should stay at the bottom of the * window list, so we can simply override any re-ordering * to ensure that they are at the bottom unless another