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
This commit is contained in:
		| @ -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) | ||||
| 	{ | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Руслан Ижбулатов
					Руслан Ижбулатов