Re: transient windows on win32
- From: "Charles Reilly" <gtk-devel-list 2005 charlesreilly com>
- To: gtk-devel-list gnome org
- Cc: Tor Lillqvist <tml iki fi>
- Subject: Re: transient windows on win32
- Date: Sun, 4 Sep 2005 21:00:07 +0100 (BST)
In diff -pu2 format as requested. The directory names (cvs and
ownerManagement) are irrelevant.
--- cvs\gdkwindow-win32.h Sun Sep 04 17:33:52 2005
+++ ownerManagement\gdkwindow-win32.h Sat Sep 03 20:59:39 2005
@@ -68,4 +68,7 @@ struct _GdkWindowImplWin32
{
GdkDrawableImplWin32 parent_instance;
+ GdkWindow *owner_window;
+
+ gboolean skips_taskbar;
gint width;
--- cvs\gdkwindow-win32.c Sun Sep 04 17:33:31 2005
+++ ownerManagement\gdkwindow-win32.c Sun Sep 04 17:37:38 2005
@@ -85,4 +85,12 @@ static void gdk_window_impl_win32_init
static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class
*klass);
static void gdk_window_impl_win32_finalize (GObject
*object);
+static void gdk_window_win32_set_window_ownership(GdkWindow* window,
+ gboolean is_owner_minimized);
+static GdkFilterReturn gdk_window_win32_owner_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data);
+static GdkFilterReturn gdk_window_win32_owned_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data);
static gpointer parent_class = NULL;
@@ -661,4 +669,8 @@ gdk_window_new_internal (GdkWindow *
}
+ // If the window is not a child then its parent is its owner
+ if ((dwStyle & WS_CHILDWINDOW) == 0)
+ impl->owner_window = parent;
+
_gdk_window_init_position (GDK_WINDOW (private));
@@ -885,4 +897,6 @@ void
gdk_window_destroy_notify (GdkWindow *window)
{
+ GdkWindowImplWin32 *impl;
+
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
@@ -893,4 +907,13 @@ gdk_window_destroy_notify (GdkWindow *wi
(GDK_WINDOW_DESTROYED (window) ? " (destroyed)" : "")));
+ // Ideally, this would be handled in
gdk_window_win32_owned_window_filter but
+ // the filter list isn't reentrant, so we remove the owner window
filter here
+ impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+ if (impl->owner_window)
+ {
+ gdk_window_remove_filter(impl->owner_window,
gdk_window_win32_owner_window_filter, window);
+ impl->owner_window = NULL;
+ }
+
if (!GDK_WINDOW_DESTROYED (window))
{
@@ -1778,12 +1801,73 @@ gdk_window_set_role (GdkWindow *window
}
+static GdkFilterReturn
+gdk_window_win32_owner_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data)
+{
+ MSG *msg = (MSG *) xev;
+ // This is a window owned by the window that received the message
+ GdkWindow *window = (GdkWindow*)data;
+ GdkWindowImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (msg->message == WM_ACTIVATE)
+ {
+ if (LOWORD(msg->wParam) == WA_INACTIVE)
+ gdk_window_win32_set_window_ownership(window, HIWORD(msg->wParam));
+ }
+ else if (msg->message == WM_SIZE)
+ {
+ if ((msg->wParam == SIZE_MAXIMIZED) || (msg->wParam == SIZE_RESTORED))
+ gdk_window_win32_set_window_ownership(window, FALSE);
+ }
+ else if (msg->message == WM_DESTROY)
+ {
+ impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+ gdk_window_remove_filter(impl->owner_window,
gdk_window_win32_owner_window_filter, window);
+ impl->owner_window = NULL;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static GdkFilterReturn
+gdk_window_win32_owned_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data)
+{
+ MSG *msg = (MSG *) xev;
+ GdkWindow* window = event->any.window;
+ GdkWindowImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (msg->message == WM_SHOWWINDOW)
+ {
+ if (!msg->wParam && (msg->lParam == SW_PARENTCLOSING))
+ {
+ gdk_window_win32_set_window_ownership(window, TRUE);
+ }
+ }
+ else if (msg->message == WM_DESTROY)
+ {
+ gdk_window_remove_filter(window,
gdk_window_win32_owned_window_filter, 0);
+ // We can't remove the other filter here because the filter list isn't
reentrant.
+ // This is handled in gdk_window_destroy_notify
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
void
gdk_window_set_transient_for (GdkWindow *window,
GdkWindow *parent)
{
- HWND window_id, parent_id;
+ gboolean is_minimized = FALSE;
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail ((parent == NULL) || GDK_IS_WINDOW (parent));
GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %p: %p\n",
@@ -1800,16 +1884,107 @@ gdk_window_set_transient_for (GdkWindow
}
- window_id = GDK_WINDOW_HWND (window);
- parent_id = GDK_WINDOW_HWND (parent);
+ // This may be called several times, but the gdk_window_add_filter
function
+ // discards duplicate entries.
+ gdk_window_add_filter(window, gdk_window_win32_owned_window_filter, 0);
- /* This changes the *owner* of the window, despite the misleading
- * name. (Owner and parent are unrelated concepts.) At least that's
- * what people who seem to know what they talk about say on
- * USENET. Search on Google.
- */
- SetLastError (0);
- if (SetWindowLong (window_id, GWL_HWNDPARENT, (long) parent_id) == 0 &&
- GetLastError () != 0)
- WIN32_API_FAILED ("SetWindowLong");
+ GdkWindowImplWin32 *impl;
+ impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+
+ if (impl->owner_window != parent)
+ {
+ if (NULL != impl->owner_window)
+ {
+ // Remove the previous filter on the parent window
+ gdk_window_remove_filter(impl->owner_window,
gdk_window_win32_owner_window_filter, window);
+ }
+
+ impl->owner_window = parent;
+
+ if (NULL != parent)
+ {
+ // Set a filter on the parent window so that when it's restored
+ // this window gets hooked up again.
+ gdk_window_add_filter(parent, gdk_window_win32_owner_window_filter,
window);
+ }
+ }
+
+ if (parent)
+ {
+ is_minimized = IsIconic(GDK_WINDOW_HWND (parent));
+ }
+
+ // This window is unlikely to get a new transient if it's minimized,
+ // but it can happen if you right-click on a minimized application
+ // and choose close; the "do you want to save" dialog is shown.
+ // Note that that code is broken because it positions the dialog
+ // off screen.
+ gdk_window_win32_set_window_ownership(window, is_minimized);
+}
+
+// Set window ownership based on the taskbar hint, whether it's transient
+// and whether the owner is minimizing.
+// This is a lot of bother. The problem is with the Windows taskbar. If
+// you minimize an owner window but don't let Windows hide the owned
+// windows, then when you click on one of the owned windows the taskbar
+// starts treating it as the application window. So if you click on
+// the taskbar button the application window doesn't reappear. We fix
+// this by disconnecting owned windows from their owners when the owners
+// are minimized. The gdk_window_win32_restore_transients function
+// reattaches owned windows to their owner when the owner is restored.
+static void
+gdk_window_win32_set_window_ownership(GdkWindow* window, gboolean
is_owner_minimized)
+{
+ GdkWindowImplWin32 *impl;
+ static GdkWindow *owner = 0;
+ GdkWindowAttr wa;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl);
+
+ if (!is_owner_minimized && impl->owner_window)
+ {
+ g_return_if_fail (GDK_IS_WINDOW (impl->owner_window));
+
+ SetWindowLong(GDK_WINDOW_HWND (window), GWL_HWNDPARENT, (LONG_PTR)
GDK_WINDOW_HWND (impl->owner_window));
+ // Ensure the owner is behind the owned window
+ SetWindowPos(GDK_WINDOW_HWND (impl->owner_window), GDK_WINDOW_HWND
(window), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ else if (impl->skips_taskbar || (is_owner_minimized && impl->owner_window))
+ {
+ // Don't overwrite an existing owner unless it's minimizing
+ if (!(impl->owner_window && is_owner_minimized))
+ {
+ if (GetWindowLong(GDK_WINDOW_HWND (window), GWL_HWNDPARENT) != NULL)
+ return;
+ }
+
+ if (NULL == owner)
+ {
+ // Create an invisible window to act as the owner. The variable
is static
+ // so it gets reused.
+ wa.window_type = GDK_WINDOW_TEMP;
+ wa.wclass = GDK_INPUT_OUTPUT;
+ wa.width = wa.height = 1;
+ wa.event_mask = 0;
+ owner = gdk_window_new_internal (NULL, &wa, 0, TRUE);
+ }
+
+ SetWindowLongPtr (GDK_WINDOW_HWND (window), GWL_HWNDPARENT,
+ (LONG_PTR) GDK_WINDOW_HWND (owner));
+
+#if 0 /* Should we also turn off the minimize and maximize buttons? */
+ SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE,
+ GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE) &
~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU));
+ SetWindowPos (GDK_WINDOW_HWND (window), NULL,
+ 0, 0, 0, 0,
+ SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+#endif
+ }
+ else
+ {
+ SetWindowLong(GDK_WINDOW_HWND (window), GWL_HWNDPARENT, 0);
+ }
}
@@ -3153,6 +3328,6 @@ gdk_window_set_skip_taskbar_hint (GdkWin
gboolean skips_taskbar)
{
- static GdkWindow *owner = NULL;
- GdkWindowAttr wa;
+ GdkWindowImplWin32 *impl;
+ gboolean is_minimized = FALSE;
g_return_if_fail (GDK_IS_WINDOW (window));
@@ -3162,31 +3337,13 @@ gdk_window_set_skip_taskbar_hint (GdkWin
skips_taskbar ? "TRUE" : "FALSE"));
- if (skips_taskbar)
- {
- if (owner == NULL)
- {
- wa.window_type = GDK_WINDOW_TEMP;
- wa.wclass = GDK_INPUT_OUTPUT;
- wa.width = wa.height = 1;
- wa.event_mask = 0;
- owner = gdk_window_new_internal (NULL, &wa, 0, TRUE);
- }
+ impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl);
+ impl->skips_taskbar = skips_taskbar;
- SetWindowLong (GDK_WINDOW_HWND (window), GWL_HWNDPARENT,
- (long) GDK_WINDOW_HWND (owner));
+ if (impl->owner_window)
+ {
+ is_minimized = IsIconic(GDK_WINDOW_HWND (impl->owner_window));
+ }
-#if 0 /* Should we also turn off the minimize and maximize buttons? */
- SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE,
- GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE) &
~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU));
- SetWindowPos (GDK_WINDOW_HWND (window), NULL,
- 0, 0, 0, 0,
- SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
- SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
-#endif
- }
- else
- {
- SetWindowLong (GDK_WINDOW_HWND (window), GWL_HWNDPARENT, 0);
- }
+ gdk_window_win32_set_window_ownership(window, is_minimized);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]