[gtk+/gtk-3-20] GDK W32: Implement show_window_menu()
- From: Руслан Ижбулатов <ruslanizhb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gtk-3-20] GDK W32: Implement show_window_menu()
- Date: Tue, 29 Mar 2016 15:12:48 +0000 (UTC)
commit a4c63393514a5c4e6192a7218d81ea486050429a
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date: Fri Mar 18 04:51:52 2016 +0000
GDK W32: Implement show_window_menu()
This is achieved by sending undocumented message WM_SYSMENU
to the window.
Before doing that, the window is given WS_SYSMENU style
(to enable window menu) and some combination of
WS_MAXIMIZEBOX (for "Mazimize" item)
WS_MINIMIZEBOX (for "Minimize" item)
WS_SIZEBOX (for "Size" item)
depending on which operations are currently permissible.
WM_SYSMENU is processed by DefWindowProc(), which results
in showing the window menu. We remove extra styles
at the first opportunity (WM_INITMENU message), as they
alter the way our window is rendered.
https://bugzilla.gnome.org/show_bug.cgi?id=763851
gdk/win32/gdkevents-win32.c | 95 ++++++++++++++++++++++++++++++++++++++++++
gdk/win32/gdkprivate-win32.h | 12 +++++
gdk/win32/gdkwindow-win32.c | 29 +++++++++++++
gdk/win32/gdkwindow-win32.h | 11 +++++
4 files changed, 147 insertions(+), 0 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 3ed2840..9efca50 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1907,6 +1907,77 @@ ensure_stacking_on_activate_app (MSG *msg,
}
}
+static gboolean
+handle_wm_sysmenu (GdkWindow *window, MSG *msg, gint *ret_valp)
+{
+ GdkWindowImplWin32 *impl;
+ LONG_PTR style, tmp_style;
+ gboolean maximized, minimized;
+ LONG_PTR additional_styles;
+
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ style = GetWindowLongPtr (msg->hwnd, GWL_STYLE);
+
+ maximized = IsZoomed (msg->hwnd);
+ minimized = IsIconic (msg->hwnd);
+ additional_styles = 0;
+
+ if (!(style & WS_SYSMENU))
+ additional_styles |= WS_SYSMENU;
+
+ if (!maximized && !(style & WS_MAXIMIZEBOX))
+ additional_styles |= WS_MAXIMIZEBOX;
+
+ if (!minimized && !(style & WS_MINIMIZEBOX))
+ additional_styles |= WS_MINIMIZEBOX;
+
+ if (!minimized && !maximized && !(style & WS_SIZEBOX))
+ additional_styles |= WS_SIZEBOX;
+
+ if (additional_styles == 0)
+ /* The caller will eventually pass this to DefWindowProc (),
+ * only without the style dance, which isn't needed, as it turns out.
+ */
+ return FALSE;
+
+ /* Note: This code will enable resizing, maximizing and minimizing windows
+ * via window menu even if these are non-CSD windows that were explicitly
+ * forbidden from doing this by removing the appropriate styles,
+ * or if these are CSD windows that were explicitly forbidden from doing
+ * this by removing appropriate decorations from the headerbar and/or
+ * changing hints or properties.
+ *
+ * If doing this for non-CSD windows is not desired,
+ * do a _gdk_win32_window_lacks_wm_decorations() check and return FALSE
+ * if it doesn't pass.
+ *
+ * If doing this for CSD windows with disabled decorations is not desired,
+ * tough luck - GDK can't know which CSD decorations are enabled, and which
+ * are not.
+ *
+ * If doing this for CSD windows with particular hints is not desired,
+ * check window hints here and return FALSE (DefWindowProc() will return
+ * FALSE later) or set *ret_valp to 0 and return TRUE.
+ */
+ tmp_style = style | additional_styles;
+ GDK_NOTE (EVENTS, g_print (" Handling WM_SYSMENU: style 0x%lx -> 0x%lx\n", style, tmp_style));
+ impl->have_temp_styles = TRUE;
+ impl->temp_styles = additional_styles;
+ SetWindowLongPtr (msg->hwnd, GWL_STYLE, tmp_style);
+
+ *ret_valp = DefWindowProc (msg->hwnd, msg->message, msg->wParam, msg->lParam);
+
+ tmp_style = GetWindowLongPtr (msg->hwnd, GWL_STYLE);
+ style = tmp_style & ~additional_styles;
+
+ GDK_NOTE (EVENTS, g_print (" Handling WM_SYSMENU: style 0x%lx <- 0x%lx\n", style, tmp_style));
+ SetWindowLongPtr (msg->hwnd, GWL_STYLE, style);
+ impl->have_temp_styles = FALSE;
+
+ return TRUE;
+}
+
gboolean
_gdk_win32_window_fill_min_max_info (GdkWindow *window,
MINMAXINFO *mmi)
@@ -2856,6 +2927,30 @@ gdk_event_translate (MSG *msg,
}
break;
+ case WM_SYSMENU:
+ return_val = handle_wm_sysmenu (window, msg, ret_valp);
+ break;
+
+ case WM_INITMENU:
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (impl->have_temp_styles)
+ {
+ LONG_PTR window_style;
+
+ window_style = GetWindowLongPtr (GDK_WINDOW_HWND (window),
+ GWL_STYLE);
+ /* Handling WM_SYSMENU added extra styles to this window,
+ * remove them now.
+ */
+ window_style &= ~impl->temp_styles;
+ SetWindowLongPtr (GDK_WINDOW_HWND (window),
+ GWL_STYLE,
+ window_style);
+ }
+
+ break;
+
case WM_SYSCOMMAND:
switch (msg->wParam)
{
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index 5be53ab..86abd99 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -97,6 +97,18 @@
#define WM_MOUSEHWHEEL 0x20E
#endif
+/* According to
+ * http://blog.airesoft.co.uk/2009/11/wm_messages/
+ * this is the actual internal name MS uses for this undocumented message.
+ * According to
+ * https://bugs.winehq.org/show_bug.cgi?id=15055
+ * wParam is 0
+ * lParam is a pair of virtual desktop coordinates for the popup
+ */
+#ifndef WM_SYSMENU
+#define WM_SYSMENU 0x313
+#endif
+
#ifndef CF_DIBV5
#define CF_DIBV5 17
#endif
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index d2d0be5..afba8c1 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -3968,6 +3968,33 @@ gdk_win32_window_is_win32 (GdkWindow *window)
return GDK_WINDOW_IS_WIN32 (window);
}
+static gboolean
+gdk_win32_window_show_window_menu (GdkWindow *window,
+ GdkEvent *event)
+{
+ double event_x, event_y;
+ gint x, y;
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_END:
+ break;
+ default:
+ return FALSE;
+ }
+
+ gdk_event_get_root_coords (event, &event_x, &event_y);
+ x = event_x - _gdk_offset_x;
+ y = event_y - _gdk_offset_y;
+
+ SendMessage (GDK_WINDOW_HWND (window), WM_SYSMENU, 0, MAKELPARAM (x, y));
+
+ return TRUE;
+}
+
/**
* _gdk_win32_acquire_dc
* @impl: a Win32 #GdkWindowImplWin32 implementation
@@ -4272,6 +4299,8 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
//impl_class->beep = gdk_x11_window_beep;
+
+ impl_class->show_window_menu = gdk_win32_window_show_window_menu;
impl_class->focus = gdk_win32_window_focus;
impl_class->set_type_hint = gdk_win32_window_set_type_hint;
impl_class->get_type_hint = gdk_win32_window_get_type_hint;
diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h
index c8ddd14..5aa6a49 100644
--- a/gdk/win32/gdkwindow-win32.h
+++ b/gdk/win32/gdkwindow-win32.h
@@ -141,6 +141,11 @@ struct _GdkWindowImplWin32
*/
guint layered : 1;
+ /* If TRUE, the @temp_styles is set to the styles that were temporarily
+ * added to this window.
+ */
+ guint have_temp_styles : 1;
+
/* GDK does not keep window contents around, it just draws new
* stuff over the window where changes occurred.
* cache_surface retains old window contents, because
@@ -173,6 +178,12 @@ struct _GdkWindowImplWin32
/* No. of windows to force layered windows off */
guint suppress_layered;
+
+ /* Temporary styles that this window got for the purpose of
+ * handling WM_SYSMENU.
+ * They are removed at the first opportunity (usually WM_INITMENU).
+ */
+ LONG_PTR temp_styles;
};
struct _GdkWindowImplWin32Class
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]