path: root/video
diff options
authorJames Ross-Gowan <>2017-07-03 23:29:14 +1000
committerJames Ross-Gowan <>2017-07-04 23:08:40 +1000
commit91079c0e2ba4e02ae923720d6a30b497a2dcec91 (patch)
treef5867b233049c19149beb74701b7137a6dd33c52 /video
parentabe01fd18a341c5c163d4ce8f019ca366feec628 (diff)
w32_common: use sent messages to wake up the Win32 thread
Instead of PostMessage, use SendNotifyMessage from the SendMessage family of functions to wake up the Win32 thread from the VO thread. When a message is sent rather than posted between threads, it ends up in a different queue which is processed before posted messages and can be processed in more places. This prevents a playback glitch when clicking on the titlebar, but not moving the window. With PostMessage-based wakeups, VOCTRLs could be delayed for up to 500ms after the user clicks on the titlebar, but with SendNotifyMessage, they still complete in under a millisecond. Also, instead of handling WM_USER, process the dispatch queue before every message. This ensures the dispatch queue is processed as soon as possible. WM_NULL is used to wake up the window procedure in case there are no other messages being processed.
Diffstat (limited to 'video')
1 files changed, 12 insertions, 5 deletions
diff --git a/video/out/w32_common.c b/video/out/w32_common.c
index fedd03965c..221f0b37dc 100644
--- a/video/out/w32_common.c
+++ b/video/out/w32_common.c
@@ -445,7 +445,14 @@ static void signal_events(struct vo_w32_state *w32, int events)
static void wakeup_gui_thread(void *ctx)
struct vo_w32_state *w32 = ctx;
- PostMessage(w32->window, WM_USER, 0, 0);
+ // Wake up the window procedure (which processes the dispatch queue)
+ if (GetWindowThreadProcessId(w32->window, NULL) == GetCurrentThreadId()) {
+ PostMessageW(w32->window, WM_NULL, 0, 0);
+ } else {
+ // Use a sent message when cross-thread, since the queue of sent
+ // messages is processed in some cases when posted messages are blocked
+ SendNotifyMessageW(w32->window, WM_NULL, 0, 0);
+ }
static double get_refresh_rate_from_gdi(const wchar_t *device)
@@ -888,11 +895,11 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)w32);
+ // The dispatch queue should be processed as soon as possible to prevent
+ // playback glitches, since it is likely blocking the VO thread
+ mp_dispatch_queue_process(w32->dispatch, 0);
switch (message) {
- case WM_USER:
- // This message is used to wakeup the GUI thread, see wakeup_gui_thread.
- mp_dispatch_queue_process(w32->dispatch, 0);
- break;
case WM_ERASEBKGND: // no need to erase background separately
return 1;
case WM_PAINT: