From 80423e5b5534e6e648c53db931c27c74867898e1 Mon Sep 17 00:00:00 2001 From: James Ross-Gowan Date: Sat, 28 Dec 2019 02:12:44 +1100 Subject: [PATCH] w32_common: support minimized and maximized properties Add support for setting window-minimized and window-maximized in Windows. The minimized and maximized state can be set independently. When the window is minimized, the value of window-maximized will determine whether the window is restored to the maximized state or not. Changing state is done with ShowWindow(), which has commands that change the window state and activate it (eg. SW_RESTORE) and commands that change the window state without activating it (eg. SW_SHOWNOACTIVATE.) It would be nice if we could use commands that don't activate the window, so scripts could change the window state in the backrgound without bringing it to the foreground, but there are some problems with that. There is no command to maximize a window without activating it, so SW_MAXIMIZE is used instead. Also, restoring a window from minimize without activating it seems buggy. On my Windows 10 1909 PC, it always moves the window to the back of the z-order. SW_RESTORE is used instead of SW_SHOWNOACTIVATE because of this. This also changes the way the window is initially shown. Previously, the window was made visible as a consequence of the SWP_SHOWWINDOW flag in the first call to SetWindowPos. In order to set the initial minimized or maximized state of the window, the window is shown with the ShowWindow function instead, where the ShowWindow command is determined by whether the window should be initially maximized or minimized. Even when showing the window normally, we should still call ShowWindow with the SW_SHOW command instead of using SetWindowPos, since the first call a process makes to ShowWindow(SW_SHOW) has special behaviour where it uses the show command in the process' STARTUPINFO instead of the command passed to the function, which should fix #5724. Note: While changes to window-minimized while in fullscreen mode should work as expected, changing window-maximized while in fullscreen does not work and won't result in the window changing state, even after leaving fullscreen. For this to work correctly, the fullscreen logic needs to be changed to apply the new maximized state on leaving fullscreen. Fixes: #5724 Fixes: #7351 --- video/out/w32_common.c | 95 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/video/out/w32_common.c b/video/out/w32_common.c index c641039e88..4965324d38 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -867,6 +867,57 @@ static bool update_fullscreen_state(struct vo_w32_state *w32) return toggle_fs; } +static void update_minimized_state(struct vo_w32_state *w32) +{ + if (w32->parent) + return; + + if (!!IsMinimized(w32->window) != w32->opts->window_minimized) { + if (w32->opts->window_minimized) { + ShowWindow(w32->window, SW_SHOWMINNOACTIVE); + } else { + ShowWindow(w32->window, SW_RESTORE); + } + } +} + +static void update_maximized_state(struct vo_w32_state *w32) +{ + if (w32->parent) + return; + + // Don't change the maximized state in fullscreen for now. In future, this + // should be made to apply the maximized state on leaving fullscreen. + if (w32->current_fs) + return; + + WINDOWPLACEMENT wp = { .length = sizeof wp }; + GetWindowPlacement(w32->window, &wp); + + if (wp.showCmd == SW_SHOWMINIMIZED) { + // When the window is minimized, setting this property just changes + // whether it will be maximized when it's restored + if (w32->opts->window_maximized) { + wp.flags |= WPF_RESTORETOMAXIMIZED; + } else { + wp.flags &= ~WPF_RESTORETOMAXIMIZED; + } + SetWindowPlacement(w32->window, &wp); + } else if ((wp.showCmd == SW_SHOWMAXIMIZED) != w32->opts->window_maximized) { + if (w32->opts->window_maximized) { + ShowWindow(w32->window, SW_SHOWMAXIMIZED); + } else { + ShowWindow(w32->window, SW_SHOWNOACTIVATE); + } + } +} + +static bool is_visible(HWND window) +{ + // Unlike IsWindowVisible, this doesn't check the window's parents + return GetWindowLongPtrW(window, GWL_STYLE) & WS_VISIBLE; +} + static void update_window_state(struct vo_w32_state *w32) { if (w32->parent) @@ -877,7 +928,19 @@ static void update_window_state(struct vo_w32_state *w32) SetWindowPos(w32->window, w32->opts->ontop ? HWND_TOPMOST : HWND_NOTOPMOST, wr.left, wr.top, rect_w(wr), rect_h(wr), - SWP_FRAMECHANGED | SWP_SHOWWINDOW); + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOOWNERZORDER); + + // Show the window if it's not yet visible + if (!is_visible(w32->window)) { + if (w32->opts->window_minimized) { + ShowWindow(w32->window, SW_SHOWMINIMIZED); + update_maximized_state(w32); // Set the WPF_RESTORETOMAXIMIZED flag + } else if (w32->opts->window_maximized) { + ShowWindow(w32->window, SW_SHOWMAXIMIZED); + } else { + ShowWindow(w32->window, SW_SHOW); + } + } // Notify the taskbar about the fullscreen state only after the window // is visible, to make sure the taskbar item has already been created @@ -990,10 +1053,28 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, MP_VERBOSE(w32, "resize window: %d:%d\n", w, h); } - // Window may have been minimized or restored - w32->opts->window_minimized = IsIconic(w32->window); - m_config_cache_write_opt(w32->opts_cache, - &w32->opts->window_minimized); + // Window may have been minimized, maximized or restored + if (is_visible(w32->window)) { + WINDOWPLACEMENT wp = { .length = sizeof wp }; + GetWindowPlacement(w32->window, &wp); + + bool is_minimized = wp.showCmd == SW_SHOWMINIMIZED; + if (w32->opts->window_minimized != is_minimized) { + w32->opts->window_minimized = is_minimized; + m_config_cache_write_opt(w32->opts_cache, + &w32->opts->window_minimized); + } + + bool is_maximized = wp.showCmd == SW_SHOWMAXIMIZED || + (wp.showCmd == SW_SHOWMINIMIZED && + (wp.flags & WPF_RESTORETOMAXIMIZED)); + if (w32->opts->window_maximized != is_maximized) { + w32->opts->window_maximized = is_maximized; + m_config_cache_write_opt(w32->opts_cache, + &w32->opts->window_maximized); + } + } + signal_events(w32, VO_EVENT_WIN_STATE); update_display_info(w32); @@ -1584,6 +1665,10 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg) } else if (changed_option == &vo_opts->border) { update_window_style(w32); update_window_state(w32); + } else if (changed_option == &vo_opts->window_minimized) { + update_minimized_state(w32); + } else if (changed_option == &vo_opts->window_maximized) { + update_maximized_state(w32); } }