diff --git a/video/out/w32_common.c b/video/out/w32_common.c index 14ebc6980122c..0dabe98d1e445 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -320,26 +320,6 @@ static LRESULT borderless_nchittest(struct vo_w32_state *w32, int x, int y) return HTCLIENT; } -// turn a WMSZ_* input value in v into the border that should be resized -// take into consideration which borders are snapped to avoid detaching -// returns: 0=left, 1=top, 2=right, 3=bottom, -1=undefined -static int get_resize_border(struct vo_w32_state *w32, int v) -{ - switch (v) { - case WMSZ_LEFT: - case WMSZ_RIGHT: - return w32->snapped_bottom ? 1 : 3; - case WMSZ_TOP: - case WMSZ_BOTTOM: - return w32->snapped_right ? 0 : 2; - case WMSZ_TOPLEFT: return 1; - case WMSZ_TOPRIGHT: return 1; - case WMSZ_BOTTOMLEFT: return 3; - case WMSZ_BOTTOMRIGHT: return 3; - default: return -1; - } -} - static bool key_state(int vk) { return GetKeyState(vk) & 0x8000; @@ -1264,6 +1244,68 @@ static void update_ime_enabled(struct vo_w32_state *w32, bool enable) } } +static void handle_sizing(struct vo_w32_state *w32, int edge, RECT *rc) +{ + RECT wa = get_working_area(w32); + RECT wr; + if (GetWindowRect(w32->window, &wr)) + adjust_working_area_for_extended_frame(&wa, &wr, w32->window); + + bool drag_l = edge == WMSZ_LEFT || edge == WMSZ_TOPLEFT || edge == WMSZ_BOTTOMLEFT; + bool drag_r = edge == WMSZ_RIGHT || edge == WMSZ_TOPRIGHT || edge == WMSZ_BOTTOMRIGHT; + bool drag_t = edge == WMSZ_TOP || edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT; + bool drag_b = edge == WMSZ_BOTTOM || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_BOTTOMRIGHT; + + // Clamp to working area + if (drag_l) + rc->left = MPMAX(rc->right - rect_w(wa), rc->left); + if (drag_r) + rc->right = MPMIN(rc->left + rect_w(wa), rc->right); + if (drag_t) + rc->top = MPMAX(rc->bottom - rect_h(wa), rc->top); + if (drag_b) + rc->bottom = MPMIN(rc->top + rect_h(wa), rc->bottom); + + // Windows added title-bar docking (drag top edge to the top of working area), + // and it seems to send WM_SIZING with edge (wParam) set to 9 when undocking + // the window by dragging. This is not documented, and not even an WMSZ_* + // value in 10.0.26100.7705 SDK. However, it does restore window size before + // docking, so we don't have to do anything here. + if (!drag_l && !drag_r && !drag_t && !drag_b) + return; + + bool keep_aspect = w32->opts->keepaspect && w32->opts->keepaspect_window; + if (!keep_aspect || !w32->o_dwidth || !w32->o_dheight) + return; + + RECT wb = {0}; + add_window_borders(w32, w32->window, &wb); + LONG max_w = rect_w(wa) - rect_w(wb), max_h = rect_h(wa) - rect_h(wb); + LONG c_w = rect_w(*rc) - rect_w(wb), c_h = rect_h(*rc) - rect_h(wb); + if ((drag_t || drag_b) && !drag_l && !drag_r) { + c_w = c_h * w32->o_dwidth / w32->o_dheight; + if (c_w > max_w) { + c_w = max_w; + c_h = c_w * w32->o_dheight / w32->o_dwidth; + } + } else { + c_h = c_w * w32->o_dheight / w32->o_dwidth; + if (c_h > max_h) { + c_h = max_h; + c_w = c_h * w32->o_dwidth / w32->o_dheight; + } + } + LONG w_w = c_w + rect_w(wb), w_h = c_h + rect_h(wb); + if (drag_l || (!drag_r && w32->snapped_right)) + rc->left = rc->right - w_w; + else + rc->right = rc->left + w_w; + if (drag_t || (!drag_b && w32->snapped_bottom)) + rc->top = rc->bottom - w_h; + else + rc->bottom = rc->top + w_h; +} + static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1408,27 +1450,10 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, break; } case WM_SIZING: - if (w32->opts->keepaspect && w32->opts->keepaspect_window && - !w32->current_fs && !w32->parent && w32->o_dwidth && w32->o_dheight) - { - RECT *rc = (RECT*)lParam; - // get client area of the windows if it had the rect rc - // (subtracting the window borders) - RECT r = *rc; - subtract_window_borders(w32, w32->window, &r); - int c_w = rect_w(r), c_h = rect_h(r); - double aspect = w32->o_dwidth / (double)w32->o_dheight; - int d_w = roundl(c_h * aspect - c_w); - int d_h = roundl(c_w / aspect - c_h); - int d_corners[4] = { d_w, d_h, -d_w, -d_h }; - int corners[4] = { rc->left, rc->top, rc->right, rc->bottom }; - int corner = get_resize_border(w32, wParam); - if (corner >= 0) - corners[corner] -= d_corners[corner]; - *rc = (RECT) { corners[0], corners[1], corners[2], corners[3] }; - return TRUE; - } - break; + if (w32->parent || w32->current_fs) + break; + handle_sizing(w32, wParam, (RECT *)lParam); + return TRUE; case WM_DPICHANGED: update_display_info(w32);