summaryrefslogtreecommitdiffstats
path: root/libvo
diff options
context:
space:
mode:
authorwm4 <wm4@mplayer2.org>2011-10-22 02:11:14 +0200
committerwm4 <wm4@mplayer2.org>2012-03-17 20:58:16 +0100
commit2449cbde2c31e1429fd8507880d68721cf95efe1 (patch)
tree7d880a6d9143843732d9318d01bc673bc33bda8b /libvo
parent1dc73836d97af2a6bd83f0ab3a9e7b6dd5a28ae1 (diff)
downloadmpv-2449cbde2c31e1429fd8507880d68721cf95efe1.tar.bz2
mpv-2449cbde2c31e1429fd8507880d68721cf95efe1.tar.xz
win32: fix window creation and size handling
This commit fixes various issues with the way the window position and size is setup. Most importantly, it fixes some bugs with restoring from fullscreen state. Rename create_rendering_context() to reinit_window_state(). This function doesn't create anything, it just sets the window bounds and styles. Do not use vo_dx/dy for the window position, as video_out.c overwrites it with each vo_config() call. Use private variables window_x/y instead. A big cause for issues was that reinit_window_state() accidentally cleared the WS_VISIBLE style. I suspect that the API call to temporarily hide the window was a hack to deal with this. Another bug was that the window style was changed without calling SetWindowPos with SWP_FRAMECHANGED (as the MSDN documentation says). Properly initialize window position and size on vo_config following the same rules as the x11 backend: - Never change the window position. The window position should be kept, as the user might move the window, and resetting the window position e.g. during ordered chapter playback is not desired. - Never change the window size, unless the size of the video changes. These rules don't apply to fullscreen. When switching from fullscreen to windowed mode, the backend should restore the previous windowed size and position. When the VO was reconfigured during playback (vo_config() etc.), the saved window position and size should be changed according to the rules above, even if the window was in fullscreen mode during reconfiguring. Note that these rules might be perceived as awkward by some users: if you play multiple files with different resolutions, the window won't be centered when playing the files after the first. This is not a bug.
Diffstat (limited to 'libvo')
-rw-r--r--libvo/w32_common.c157
1 files changed, 109 insertions, 48 deletions
diff --git a/libvo/w32_common.c b/libvo/w32_common.c
index 475327ce5c..a1565efde0 100644
--- a/libvo/w32_common.c
+++ b/libvo/w32_common.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <limits.h>
+#include <assert.h>
#include <windows.h>
#include <windowsx.h>
@@ -47,12 +48,21 @@ static const char classname[] = "MPlayer - The Movie Player";
int vo_vm = 0;
static int depthonscreen;
-// last non-fullscreen extends
+// last non-fullscreen extends (updated only on fullscreen or on initialization)
static int prev_width;
static int prev_height;
static int prev_x;
static int prev_y;
+// whether the window position and size were intialized
+static bool window_bounds_initialized;
+
+static bool current_fs;
+
+static int window_x;
+static int window_y;
+
+// video size
static uint32_t o_dwidth;
static uint32_t o_dheight;
@@ -107,14 +117,17 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
p.x = 0;
p.y = 0;
ClientToScreen(vo_window, &p);
- vo_dx = p.x;
- vo_dy = p.y;
+ vo_dx = window_x = p.x;
+ vo_dy = window_y = p.y;
+ mp_msg(MSGT_VO, MSGL_V, "[vo] move window: %d:%d\n", vo_dx, vo_dy);
break;
case WM_SIZE:
event_flags |= VO_EVENT_RESIZE;
GetClientRect(vo_window, &r);
vo_dwidth = r.right;
vo_dheight = r.bottom;
+ mp_msg(MSGT_VO, MSGL_V, "[vo] resize window: %d:%d\n",
+ vo_dwidth, vo_dheight);
break;
case WM_WINDOWPOSCHANGING:
if (vo_keepaspect && !vo_fs && WinID < 0) {
@@ -230,8 +243,8 @@ int vo_w32_check_events(void) {
}
p.x = 0; p.y = 0;
ClientToScreen(vo_window, &p);
- if (p.x != vo_dx || p.y != vo_dy) {
- vo_dx = p.x; vo_dy = p.y;
+ if (p.x != window_x || p.y != window_y) {
+ window_x = p.x; window_y = p.y;
event_flags |= VO_EVENT_MOVE;
}
res = GetClientRect(WIN_ID_TO_HWND(WinID), &r);
@@ -348,19 +361,30 @@ static void changeMode(void) {
static void resetMode(void) {
if (vo_vm)
- ChangeDisplaySettings(0, 0);
+ ChangeDisplaySettings(0, 0);
}
-static int createRenderingContext(void) {
+// Update the window position, size, and border style from vo_* values.
+static int reinit_window_state(void) {
+ const LONG NO_FRAME = WS_POPUP;
+ const LONG FRAME = WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
HWND layer = HWND_NOTOPMOST;
RECT r;
- int style = (vo_border && !vo_fs) ?
- (WS_OVERLAPPEDWINDOW | WS_SIZEBOX) : WS_POPUP;
if (WinID >= 0)
return 1;
- if (vo_fs || vo_ontop) layer = HWND_TOPMOST;
+ bool toggle_fs = current_fs != vo_fs;
+ current_fs = vo_fs;
+
+ LONG style = GetWindowLong(vo_window, GWL_STYLE);
+ style &= ~(NO_FRAME | FRAME);
+ style |= (vo_border && !vo_fs) ? FRAME : NO_FRAME;
+
+ if (vo_fs || vo_ontop)
+ layer = HWND_TOPMOST;
+
+ // xxx not sure if this can trigger any unwanted messages (WM_MOVE/WM_SIZE)
if (vo_fs) {
changeMode();
while (ShowCursor(0) >= 0) /**/ ;
@@ -369,37 +393,53 @@ static int createRenderingContext(void) {
while (ShowCursor(1) < 0) /**/ ;
}
updateScreenProperties();
- ShowWindow(vo_window, SW_HIDE);
- SetWindowLong(vo_window, GWL_STYLE, style);
+
if (vo_fs) {
- prev_width = vo_dwidth;
- prev_height = vo_dheight;
- prev_x = vo_dx;
- prev_y = vo_dy;
+ // Save window position and size when switching to fullscreen.
+ if (toggle_fs) {
+ prev_width = vo_dwidth;
+ prev_height = vo_dheight;
+ prev_x = window_x;
+ prev_y = window_y;
+ mp_msg(MSGT_VO, MSGL_V, "[vo] save window bounds: %d:%d:%d:%d\n",
+ prev_x, prev_y, prev_width, prev_height);
+ }
vo_dwidth = vo_screenwidth;
vo_dheight = vo_screenheight;
- vo_dx = xinerama_x;
- vo_dy = xinerama_y;
+ window_x = xinerama_x;
+ window_y = xinerama_y;
} else {
- // make sure there are no "stale" resize events
- // that would set vo_d* to wrong values
- vo_w32_check_events();
- vo_dwidth = prev_width;
- vo_dheight = prev_height;
- vo_dx = prev_x;
- vo_dy = prev_y;
- // HACK around what probably is a windows focus bug:
- // when pressing 'f' on the console, then 'f' again to
- // return to windowed mode, any input into the video
- // window is lost forever.
- SetFocus(vo_window);
+ if (toggle_fs) {
+ // Restore window position and size when switching from fullscreen.
+ mp_msg(MSGT_VO, MSGL_V, "[vo] restore window bounds: %d:%d:%d:%d\n",
+ prev_x, prev_y, prev_width, prev_height);
+ vo_dwidth = prev_width;
+ vo_dheight = prev_height;
+ window_x = prev_x;
+ window_y = prev_y;
+ }
}
- r.left = vo_dx;
+
+ r.left = window_x;
r.right = r.left + vo_dwidth;
- r.top = vo_dy;
+ r.top = window_y;
r.bottom = r.top + vo_dheight;
AdjustWindowRect(&r, style, 0);
- SetWindowPos(vo_window, layer, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_SHOWWINDOW);
+
+ mp_msg(MSGT_VO, MSGL_V, "[vo] reset window bounds: %ld:%ld:%ld:%ld\n",
+ r.left, r.top, r.right - r.left, r.bottom - r.top);
+
+ SetWindowLong(vo_window, GWL_STYLE, style);
+ SetWindowPos(vo_window, layer, r.left, r.top, r.right - r.left,
+ r.bottom - r.top, SWP_FRAMECHANGED);
+ // For some reason, moving SWP_SHOWWINDOW to a second call works better
+ // with wine: returning from fullscreen doesn't cause a bogus resize to
+ // screen size.
+ // It's not needed on Windows XP or wine with a virtual desktop.
+ // It doesn't seem to have any negative effects.
+ SetWindowPos(vo_window, NULL, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
+
return 1;
}
@@ -409,10 +449,6 @@ static int createRenderingContext(void) {
* This function should be called in libvo's "config" callback.
* It configures a window and shows it on the screen.
*
- * Global libvo variables changed:
- * vo_fs
- * vo_vm
- *
* \return 1 - Success, 0 - Failure
*/
int vo_w32_config(uint32_t width, uint32_t height, uint32_t flags) {
@@ -442,21 +478,45 @@ int vo_w32_config(uint32_t width, uint32_t height, uint32_t flags) {
// we already have a fully initialized window, so nothing needs to be done
if (flags & VOFLAG_HIDDEN)
return 1;
- // store original size for videomode switching
+
+ bool reset_size = !(o_dwidth == width && o_dheight == height);
+
o_dwidth = width;
o_dheight = height;
+ // the desired size is ignored in wid mode, it always matches the window size.
if (WinID < 0) {
- // the desired size is ignored in wid mode, it always matches the window size.
- prev_width = vo_dwidth = width;
- prev_height = vo_dheight = height;
- prev_x = vo_dx;
- prev_y = vo_dy;
+ if (window_bounds_initialized) {
+ // restore vo_dwidth/vo_dheight, which are reset against our will
+ // in vo_config()
+ RECT r;
+ GetClientRect(vo_window, &r);
+ vo_dwidth = r.right;
+ vo_dheight = r.bottom;
+ // restore these as well, xxx change vo_directx instead to query
+ // the window bounds instead of using this
+ vo_dx = window_x;
+ vo_dy = window_y;
+ } else {
+ // first vo_config call; vo_config() will always set vo_dx/dy so
+ // that the window is centered on the screen, and this is the only
+ // time we actually want to use vo_dy/dy (this is not sane, and
+ // video_out.h should provide a function to query the initial
+ // window position instead)
+ window_bounds_initialized = true;
+ reset_size = true;
+ window_x = prev_x = vo_dx;
+ window_y = prev_y = vo_dy;
+ }
+ if (reset_size) {
+ prev_width = vo_dwidth = width;
+ prev_height = vo_dheight = height;
+ }
}
vo_fs = flags & VOFLAG_FULLSCREEN;
vo_vm = flags & VOFLAG_MODESWITCHING;
- return createRenderingContext();
+ return reinit_window_state();
}
/**
@@ -505,7 +565,7 @@ int vo_w32_init(void) {
mplayerIcon = LoadIcon(0, IDI_APPLICATION);
{
- WNDCLASSEX wcex = { sizeof wcex, CS_OWNDC | CS_DBLCLKS, WndProc, 0, 0, hInstance, mplayerIcon, LoadCursor(0, IDC_ARROW), NULL, 0, classname, mplayerIcon };
+ WNDCLASSEX wcex = { sizeof wcex, CS_OWNDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, mplayerIcon, LoadCursor(0, IDC_ARROW), NULL, 0, classname, mplayerIcon };
if (!RegisterClassEx(&wcex)) {
mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to register window class!\n");
@@ -569,7 +629,7 @@ int vo_w32_init(void) {
void vo_w32_fullscreen(void) {
vo_fs = !vo_fs;
- createRenderingContext();
+ reinit_window_state();
}
/**
@@ -582,7 +642,7 @@ void vo_w32_fullscreen(void) {
*/
void vo_w32_border(void) {
vo_border = !vo_border;
- createRenderingContext();
+ reinit_window_state();
}
/**
@@ -597,7 +657,7 @@ void vo_w32_ontop( void )
{
vo_ontop = !vo_ontop;
if (!vo_fs) {
- createRenderingContext();
+ reinit_window_state();
}
}
@@ -618,6 +678,7 @@ void vo_w32_uninit(void) {
DestroyWindow(vo_window);
vo_window = 0;
UnregisterClass(classname, 0);
+ o_dwidth = o_dheight = 0;
}
/**