[gtk+] GDK W32: Implement show_window_menu()



commit cea8c29a267808c7252eed4f36547153509db308
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 1ade31a..3e69161 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1910,6 +1910,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)
@@ -2859,6 +2930,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 b3f89d3..8bed5cb 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 bedf535..833df2a 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
@@ -4197,6 +4224,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]