diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 1ade31ae91..3e69161107 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 b3f89d3ff9..8bed5cbfa7 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 bedf5351ea..833df2ad7c 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 c8ddd1445d..5aa6a49314 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