diff --git a/ChangeLog b/ChangeLog index 466bbd2cf6..763978c2ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-02-05 Cody Russell + + * gdk/win32/gdkevents-win32.c + * gdk/win32/gdkwindow-win32.[ch]: Force non-modal transient dialogs + to iconify with their parents on Win32. Maintain a list of transient + children, and whenever a window is hidden or restored we now do the + same thing to all connected transient windows above and below the + current window in the chain. See comment under WM_ACTIVATE for the + reasons why. (#164537, #371036, #405178) + 2008-01-16 Matthias Clasen Merge from trunk: diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 88afdcfcff..521d41698a 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -1335,6 +1335,37 @@ apply_filters (GdkWindow *window, return result; } +static void +show_window_recurse (GdkWindow *window, gboolean hide_window) +{ + GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + GSList *children = impl->transient_children; + GdkWindow *child = NULL; + + if (!impl->changing_state) + { + impl->changing_state = TRUE; + + if (children != NULL) + { + while (children != NULL) + { + child = children->data; + show_window_recurse (child, hide_window); + + children = g_slist_next (children); + } + } + + if (!hide_window) + ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE); + else + ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE); + + impl->changing_state = FALSE; + } +} + static gboolean gdk_window_is_ancestor (GdkWindow *ancestor, GdkWindow *window) @@ -2896,16 +2927,18 @@ gdk_event_translate (MSG *msg, { SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner)); } + + if (p_grab_window == window) + { + gdk_pointer_ungrab (msg->time); + } + + if (k_grab_window == window) + { + gdk_keyboard_ungrab (msg->time); + } } - if (event->any.type == GDK_UNMAP && - p_grab_window == window) - gdk_pointer_ungrab (msg->time); - - if (event->any.type == GDK_UNMAP && - k_grab_window == window) - gdk_keyboard_ungrab (msg->time); - return_val = TRUE; break; @@ -3402,6 +3435,49 @@ gdk_event_translate (MSG *msg, #ifdef HAVE_WINTAB case WM_ACTIVATE: + ; + + /* + * On Windows, transient windows will not have their own taskbar entries. + * Because of this, we must hide and restore groups of transients in both + * directions. That is, all transient children must be hidden or restored + * with this window, but if this window's transient owner also has a + * transient owner then this window's transient owner must be hidden/restored + * with this one. And etc, up the chain until we hit an ancestor that has no + * transient owner. + * + * It would be a good idea if applications don't chain transient windows + * together. There's a limit to how much evil GTK can try to shield you + * from. + */ + GdkWindow *tmp_window = NULL; + GdkWindowImplWin32 *tmp_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + + while (tmp_impl->transient_owner != NULL) + { + tmp_window = tmp_impl->transient_owner; + tmp_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (tmp_window)->impl); + } + + if (tmp_window == NULL) + tmp_window = window; + + if (LOWORD (msg->wParam) == WA_INACTIVE && HIWORD (msg->wParam)) + { + if (!tmp_impl->changing_state) + { + show_window_recurse (tmp_window, TRUE); + } + } + else if (LOWORD (msg->wParam) == WA_ACTIVE && HIWORD (msg->wParam)) + { + if (!tmp_impl->changing_state) + { + show_window_recurse (tmp_window, FALSE); + } + } + + /* Bring any tablet contexts to the top of the overlap order when * one of our windows is activated. * NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index d017813131..3b5ad15101 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -157,6 +157,9 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl) impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; impl->extension_events_selected = FALSE; impl->transient_owner = NULL; + impl->transient_children = NULL; + impl->num_transients = 0; + impl->changing_state = FALSE; } static void @@ -871,6 +874,7 @@ _gdk_windowing_window_destroy (GdkWindow *window, { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (private->impl); + GSList *tmp; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -880,6 +884,19 @@ _gdk_windowing_window_destroy (GdkWindow *window, if (private->extension_events != 0) _gdk_input_window_destroy (window); + /* Remove all our transient children */ + tmp = window_impl->transient_children; + while (tmp != NULL) + { + GdkWindow *child = tmp->data; + GdkWindowImplWin32 *child_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (child)->impl); + + child_impl->transient_owner = NULL; + tmp = g_slist_next (tmp); + } + g_slist_free (window_impl->transient_children); + window_impl->transient_children = NULL; + /* Remove ourself from our transient owner */ if (window_impl->transient_owner != NULL) { @@ -1977,6 +1994,8 @@ gdk_window_set_transient_for (GdkWindow *window, { HWND window_id, parent_id; GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + GdkWindowImplWin32 *parent_impl = NULL; + GSList *item; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1999,7 +2018,32 @@ gdk_window_set_transient_for (GdkWindow *window, return; } - window_impl->transient_owner = parent; + if (parent == NULL) + { + GdkWindowImplWin32 *trans_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window_impl->transient_owner)->impl); + if (trans_impl->transient_children != NULL) + { + item = g_slist_find (trans_impl->transient_children, window); + item->data = NULL; + trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item); + trans_impl->num_transients--; + + if (!trans_impl->num_transients) + { + trans_impl->transient_children = NULL; + } + } + + window_impl->transient_owner = NULL; + } + else + { + parent_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (parent)->impl); + + parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window); + parent_impl->num_transients++; + window_impl->transient_owner = parent; + } /* This changes the *owner* of the window, despite the misleading * name. (Owner and parent are unrelated concepts.) At least that's @@ -2964,7 +3008,7 @@ QueryTree (HWND hwnd, gint *nchildren) { guint i, n; - HWND child; + HWND child = NULL; n = 0; do { @@ -3448,7 +3492,7 @@ gdk_window_set_modal_hint (GdkWindow *window, private->modal_hint = modal; -#if 0 +#if 1 /* Not sure about this one.. -- Cody */ if (GDK_WINDOW_IS_MAPPED (window)) API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), @@ -3467,6 +3511,9 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window, g_return_if_fail (GDK_IS_WINDOW (window)); + // ### TODO: Need to figure out what to do here. + return; + GDK_NOTE (MISC, g_print ("gdk_window_set_skip_taskbar_hint: %p: %s\n", GDK_WINDOW_HWND (window), skips_taskbar ? "TRUE" : "FALSE")); diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index 8a697565a4..8583ab35f3 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -88,6 +88,9 @@ struct _GdkWindowImplWin32 gboolean extension_events_selected; GdkWindow *transient_owner; + GSList *transient_children; + gint num_transients; + gboolean changing_state; }; struct _GdkWindowImplWin32Class