summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/out/w32_common.c282
1 files changed, 151 insertions, 131 deletions
diff --git a/video/out/w32_common.c b/video/out/w32_common.c
index f0a568dbcb..feeae81462 100644
--- a/video/out/w32_common.c
+++ b/video/out/w32_common.c
@@ -126,6 +126,9 @@ struct vo_w32_state {
// UTF-16 decoding state for WM_CHAR and VK_PACKET
int high_surrogate;
+ // Whether to fit the window on screen on next window state updating
+ bool fit_on_screen;
+
ITaskbarList2 *taskbar_list;
ITaskbarList3 *taskbar_list3;
UINT tbtnCreatedMsg;
@@ -604,6 +607,9 @@ static void update_playback_state(struct vo_w32_state *w32)
static bool snap_to_screen_edges(struct vo_w32_state *w32, RECT *rc)
{
+ if (w32->parent || w32->current_fs || IsMaximized(w32->window))
+ return false;
+
if (!w32->opts->snap_window) {
w32->snapped = false;
return false;
@@ -751,127 +757,148 @@ static DWORD update_style(struct vo_w32_state *w32, DWORD style)
return style;
}
-// Update the window title, position, size, and border style.
-static void reinit_window_state(struct vo_w32_state *w32)
+static void update_window_style(struct vo_w32_state *w32)
{
- HWND layer = HWND_NOTOPMOST;
- RECT r;
-
if (w32->parent)
return;
- bool new_fs = w32->toggle_fs ? !w32->current_fs : w32->opts->fullscreen;
- bool toggle_fs = w32->current_fs != new_fs;
- w32->current_fs = new_fs;
- w32->toggle_fs = false;
+ // SetWindowLongPtr can trigger a WM_SIZE event, so window rect
+ // has to be saved now and restored after setting the new style.
+ const RECT wr = w32->windowrc;
+ const DWORD style = GetWindowLongPtrW(w32->window, GWL_STYLE);
+ SetWindowLongPtrW(w32->window, GWL_STYLE, update_style(w32, style));
+ w32->windowrc = wr;
+}
- if (w32->taskbar_list) {
- ITaskbarList2_MarkFullscreenWindow(w32->taskbar_list,
- w32->window, w32->current_fs);
+// Adjust rc size and position if its size is larger than rc2.
+// returns true if the rectangle was modified.
+static bool fit_rect(RECT *rc, RECT *rc2)
+{
+ // Calculate old size and maximum new size
+ int o_w = rect_w(*rc), o_h = rect_h(*rc);
+ int n_w = rect_w(*rc2), n_h = rect_h(*rc2);
+ if (o_w <= n_w && o_h <= n_h)
+ return false;
+
+ // Apply letterboxing
+ const float o_asp = o_w / (float)MPMAX(o_h, 1);
+ const float n_asp = n_w / (float)MPMAX(n_h, 1);
+ if (o_asp > n_asp) {
+ n_h = n_w / o_asp;
+ } else {
+ n_w = n_h * o_asp;
}
- DWORD style = update_style(w32, GetWindowLongPtrW(w32->window, GWL_STYLE));
+ // Calculate new position and save the rect
+ const int x = rc->left + o_w / 2 - n_w / 2;
+ const int y = rc->top + o_h / 2 - n_h / 2;
+ SetRect(rc, x, y, x + n_w, y + n_h);
+ return true;
+}
- if (w32->opts->ontop)
- layer = HWND_TOPMOST;
+// Adjust window size and position if its size is larger than the screen size.
+static void fit_window_on_screen(struct vo_w32_state *w32)
+{
+ if (w32->parent || w32->current_fs || IsMaximized(w32->window))
+ return;
- // xxx not sure if this can trigger any unwanted messages (WM_MOVE/WM_SIZE)
- update_screen_rect(w32);
+ RECT screen = w32->screenrc;
+ if (w32->opts->border && w32->opts->fit_border)
+ subtract_window_borders(w32->window, &screen);
- if (w32->current_fs) {
- // Save window position and size when switching to fullscreen.
- if (toggle_fs) {
- w32->prev_windowrc = w32->windowrc;
- MP_VERBOSE(w32, "save window bounds: %d:%d:%d:%d\n",
- (int)w32->windowrc.left, (int)w32->windowrc.top,
- (int)rect_w(w32->windowrc), (int)rect_h(w32->windowrc));
- }
- w32->windowrc = w32->screenrc;
- } else {
- // Restore window position and size when switching from fullscreen.
- if (toggle_fs) {
- w32->windowrc = w32->prev_windowrc;
- MP_VERBOSE(w32, "restore window bounds: %d:%d:%d:%d\n",
- (int)w32->windowrc.left, (int)w32->windowrc.top,
- (int)rect_w(w32->windowrc), (int)rect_h(w32->windowrc));
- }
+ if (fit_rect(&w32->windowrc, &screen)) {
+ MP_VERBOSE(w32, "adjusted window bounds: %d:%d:%d:%d\n",
+ (int)w32->windowrc.left, (int)w32->windowrc.top,
+ (int)rect_w(w32->windowrc), (int)rect_h(w32->windowrc));
}
+}
- r = w32->windowrc;
- SetWindowLongPtrW(w32->window, GWL_STYLE, style);
-
- RECT cr = r;
- add_window_borders(w32->window, &r);
- // Check on client area size instead of window size on --fit-border=no
- long o_w;
- long o_h;
- if( w32->opts->fit_border ) {
- o_w = r.right - r.left;
- o_h = r.bottom - r.top;
- } else {
- o_w = cr.right - cr.left;
- o_h = cr.bottom - cr.top;
+// Calculate new fullscreen state and change window size and position.
+// returns true if fullscreen state was changed.
+static bool update_fullscreen_state(struct vo_w32_state *w32)
+{
+ if (w32->parent)
+ return false;
+
+ bool new_fs = w32->opts->fullscreen;
+ if (w32->toggle_fs) {
+ new_fs = !w32->current_fs;
+ w32->toggle_fs = false;
}
- const int screen_w = rect_w(w32->screenrc);
- const int screen_h = rect_h(w32->screenrc);
+ bool toggle_fs = w32->current_fs != new_fs;
+ w32->current_fs = new_fs;
- if ( !w32->current_fs && ( o_w > screen_w || o_h > screen_h ) )
- {
- MP_VERBOSE(w32, "requested window size larger than the screen\n");
- // Use the aspect of the client area, not the full window size.
- // Basically, try to compute the maximum window size.
- long n_w;
- long n_h;
- if( w32->opts->fit_border ) {
- n_w = screen_w - (r.right - cr.right) - (cr.left - r.left);
- n_h = screen_h - (r.bottom - cr.bottom) - (cr.top - r.top);
- } else {
- n_w = screen_w;
- n_h = screen_h;
- }
- // Letterbox
- double asp = (cr.right - cr.left) / (double)(cr.bottom - cr.top);
- double s_asp = n_w / (double)n_h;
- if (asp > s_asp) {
- n_h = n_w / asp;
+ update_screen_rect(w32);
+
+ if (toggle_fs) {
+ RECT rc;
+ char msg[50];
+ if (w32->current_fs) {
+ // Save window rect when switching to fullscreen.
+ rc = w32->prev_windowrc = w32->windowrc;
+ sprintf(msg, "save window bounds");
} else {
- n_w = n_h * asp;
+ // Restore window rect when switching from fullscreen.
+ rc = w32->windowrc = w32->prev_windowrc;
+ sprintf(msg, "restore window bounds");
}
- // Save new size
- w32->windowrc.right = w32->windowrc.left + n_w;
- w32->windowrc.bottom = w32->windowrc.top + n_h;
- // Get old window center
- long o_cx = r.left + (r.right - r.left) / 2;
- long o_cy = r.top + (r.bottom - r.top) / 2;
- // Add window borders to the new window size
- r = (RECT){.right = n_w, .bottom = n_h};
- add_window_borders(w32->window, &r);
- // Get top and left border size for client area position calculation
- long b_top = -r.top;
- long b_left = -r.left;
- // Center the final window around the old window center
- n_w = r.right - r.left;
- n_h = r.bottom - r.top;
- r.left = o_cx - n_w / 2;
- r.top = o_cy - n_h / 2;
- r.right = r.left + n_w;
- r.bottom = r.top + n_h;
- // Save new client area position
- OffsetRect(&w32->windowrc, r.left + b_left - w32->windowrc.left,
- r.top + b_top - w32->windowrc.top);
+ MP_VERBOSE(w32, "%s: %d:%d:%d:%d\n", msg,
+ (int)rc.left, (int)rc.top, (int)rect_w(rc), (int)rect_h(rc));
}
+ if (w32->current_fs)
+ w32->windowrc = w32->screenrc;
+
MP_VERBOSE(w32, "reset window bounds: %d:%d:%d:%d\n",
- (int) r.left, (int) r.top, (int)(r.right - r.left),
- (int)(r.bottom - r.top));
+ (int)w32->windowrc.left, (int)w32->windowrc.top,
+ (int)rect_w(w32->windowrc), (int)rect_h(w32->windowrc));
+ return toggle_fs;
+}
+
+static void update_window_state(struct vo_w32_state *w32)
+{
+ if (w32->parent)
+ return;
- SetWindowPos(w32->window, layer, r.left, r.top, r.right - r.left,
- r.bottom - r.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
+ RECT wr = w32->windowrc;
+ add_window_borders(w32->window, &wr);
+
+ SetWindowPos(w32->window, w32->opts->ontop ? HWND_TOPMOST : HWND_NOTOPMOST,
+ wr.left, wr.top, rect_w(wr), rect_h(wr),
+ SWP_FRAMECHANGED | SWP_SHOWWINDOW);
+
+ // Notify the taskbar about the fullscreen state only after the window
+ // is visible, to make sure the taskbar item has already been created
+ if (w32->taskbar_list) {
+ ITaskbarList2_MarkFullscreenWindow(w32->taskbar_list,
+ w32->window, w32->current_fs);
+ }
signal_events(w32, VO_EVENT_RESIZE);
}
+static void reinit_window_state(struct vo_w32_state *w32)
+{
+ if (w32->parent)
+ return;
+
+ // The order matters: fs state should be updated prior to changing styles
+ bool toggle_fs = update_fullscreen_state(w32);
+ update_window_style(w32);
+
+ // Assume that the window has already been fit on screen before switching fs
+ if (!toggle_fs || w32->fit_on_screen) {
+ fit_window_on_screen(w32);
+ // The fullscreen state might still be active, so set the flag
+ // to fit on screen next time the window leaves the fullscreen.
+ w32->fit_on_screen = w32->current_fs;
+ }
+
+ // Show and activate the window after all window state parameters were set
+ update_window_state(w32);
+}
+
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
@@ -916,7 +943,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
case WM_MOVING: {
w32->moving = true;
RECT *rc = (RECT*)lParam;
- if (!w32->current_fs && !w32->parent && snap_to_screen_edges(w32, rc))
+ if (snap_to_screen_edges(w32, rc))
return TRUE;
break;
}
@@ -1261,50 +1288,41 @@ static void gui_thread_reconfig(void *ptr)
bool reset_size = w32->o_dwidth != vo->dwidth ||
w32->o_dheight != vo->dheight;
- bool pos_init = false;
w32->o_dwidth = vo->dwidth;
w32->o_dheight = vo->dheight;
- // the desired size is ignored in wid mode, it always matches the window size.
- if (!w32->parent) {
- if (w32->window_bounds_initialized) {
- // restore vo_dwidth/vo_dheight, which are reset against our will
- // in vo_config()
- RECT r;
- GetClientRect(w32->window, &r);
- vo->dwidth = r.right;
- vo->dheight = r.bottom;
- } else {
- w32->window_bounds_initialized = true;
- reset_size = true;
- pos_init = true;
- w32->windowrc.left = w32->prev_windowrc.left = geo.win.x0;
- w32->windowrc.top = w32->prev_windowrc.top = geo.win.y0;
- }
+ if (!w32->parent && !w32->window_bounds_initialized) {
+ SetRect(&w32->windowrc, geo.win.x0, geo.win.y0,
+ geo.win.x0 + vo->dwidth, geo.win.y0 + vo->dheight);
+ w32->prev_windowrc = w32->windowrc;
+ w32->window_bounds_initialized = true;
+ w32->fit_on_screen = true;
+ goto finish;
+ }
- if (reset_size) {
- vo->dwidth = w32->o_dwidth;
- vo->dheight = w32->o_dheight;
- w32->prev_windowrc.right = w32->prev_windowrc.left + vo->dwidth;
- w32->prev_windowrc.bottom = w32->prev_windowrc.top + vo->dheight;
- }
- } else {
+ // The rect which size is going to be modified.
+ RECT *rc = &w32->windowrc;
+
+ // The desired size always matches the window size in wid mode.
+ if (!reset_size || w32->parent) {
RECT r;
GetClientRect(w32->window, &r);
+ // Restore vo_dwidth and vo_dheight, which were reset in vo_config()
vo->dwidth = r.right;
vo->dheight = r.bottom;
+ } else {
+ if (w32->current_fs)
+ rc = &w32->prev_windowrc;
+ w32->fit_on_screen = true;
}
- // Recenter window around old position on new video size
- // excluding the case when initial position handled by win_state.
- if (!pos_init) {
- w32->windowrc.left += rect_w(w32->windowrc) / 2 - vo->dwidth / 2;
- w32->windowrc.top += rect_h(w32->windowrc) / 2 - vo->dheight / 2;
- }
- w32->windowrc.right = w32->windowrc.left + vo->dwidth;
- w32->windowrc.bottom = w32->windowrc.top + vo->dheight;
+ // Save new window size and position.
+ const int x = rc->left + rect_w(*rc) / 2 - vo->dwidth / 2;
+ const int y = rc->top + rect_h(*rc) / 2 - vo->dheight / 2;
+ SetRect(rc, x, y, x + vo->dwidth, y + vo->dheight);
+finish:
reinit_window_state(w32);
}
@@ -1538,10 +1556,11 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
reinit_window_state(w32);
return VO_TRUE;
case VOCTRL_ONTOP:
- reinit_window_state(w32);
+ update_window_state(w32);
return VO_TRUE;
case VOCTRL_BORDER:
- reinit_window_state(w32);
+ update_window_style(w32);
+ update_window_state(w32);
return VO_TRUE;
case VOCTRL_GET_FULLSCREEN:
*(bool *)arg = w32->current_fs;
@@ -1568,6 +1587,7 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
const int y = rc->top + rect_h(*rc) / 2 - s[1] / 2;
SetRect(rc, x, y, x + s[0], y + s[1]);
+ w32->fit_on_screen = true;
reinit_window_state(w32);
return VO_TRUE;
}