Add explanatory comments to the #endif part of multiple inclusion guards.
[mplayer/greg.git] / libvo / w32_common.c
blob9712d3af9d7a8bd0f107ddccca384e865cfe2c39
1 #include <stdio.h>
2 #include <limits.h>
3 #include <windows.h>
4 #include <windowsx.h>
6 #include "osdep/keycodes.h"
7 #include "input/input.h"
8 #include "input/mouse.h"
9 #include "mp_msg.h"
10 #include "video_out.h"
11 #include "aspect.h"
12 #include "w32_common.h"
13 #include "mp_fifo.h"
15 extern int enable_mouse_movements;
17 #ifndef MONITOR_DEFAULTTOPRIMARY
18 #define MONITOR_DEFAULTTOPRIMARY 1
19 #endif
21 static const char* classname = "MPlayer - Media player for Win32";
22 int vo_vm = 0;
24 // last non-fullscreen extends
25 int prev_width;
26 int prev_height;
27 int prev_x;
28 int prev_y;
30 uint32_t o_dwidth;
31 uint32_t o_dheight;
33 static HINSTANCE hInstance;
34 #define vo_window vo_w32_window
35 HWND vo_window = 0;
36 static int event_flags;
37 static int mon_cnt;
39 static HMONITOR (WINAPI* myMonitorFromWindow)(HWND, DWORD);
40 static BOOL (WINAPI* myGetMonitorInfo)(HMONITOR, LPMONITORINFO);
41 static BOOL (WINAPI* myEnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
43 static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
44 RECT r;
45 POINT p;
46 switch (message) {
47 case WM_PAINT:
48 event_flags |= VO_EVENT_EXPOSE;
49 break;
50 case WM_MOVE:
51 p.x = 0;
52 p.y = 0;
53 ClientToScreen(vo_window, &p);
54 vo_dx = p.x;
55 vo_dy = p.y;
56 break;
57 case WM_SIZE:
58 event_flags |= VO_EVENT_RESIZE;
59 GetClientRect(vo_window, &r);
60 vo_dwidth = r.right;
61 vo_dheight = r.bottom;
62 break;
63 case WM_WINDOWPOSCHANGING:
64 return 0;
65 case WM_CLOSE:
66 mplayer_put_key(KEY_CLOSE_WIN);
67 break;
68 case WM_SYSCOMMAND:
69 switch (wParam) {
70 case SC_SCREENSAVE:
71 case SC_MONITORPOWER:
72 mp_msg(MSGT_VO, MSGL_V, "vo: win32: killing screensaver\n");
73 return 0;
75 break;
76 case WM_KEYDOWN:
77 switch (wParam) {
78 case VK_LEFT: mplayer_put_key(KEY_LEFT); break;
79 case VK_UP: mplayer_put_key(KEY_UP); break;
80 case VK_RIGHT: mplayer_put_key(KEY_RIGHT); break;
81 case VK_DOWN: mplayer_put_key(KEY_DOWN); break;
82 case VK_TAB: mplayer_put_key(KEY_TAB); break;
83 case VK_CONTROL: mplayer_put_key(KEY_CTRL); break;
84 case VK_BACK: mplayer_put_key(KEY_BS); break;
85 case VK_DELETE: mplayer_put_key(KEY_DELETE); break;
86 case VK_INSERT: mplayer_put_key(KEY_INSERT); break;
87 case VK_HOME: mplayer_put_key(KEY_HOME); break;
88 case VK_END: mplayer_put_key(KEY_END); break;
89 case VK_PRIOR: mplayer_put_key(KEY_PAGE_UP); break;
90 case VK_NEXT: mplayer_put_key(KEY_PAGE_DOWN); break;
91 case VK_ESCAPE: mplayer_put_key(KEY_ESC); break;
93 break;
94 case WM_CHAR:
95 mplayer_put_key(wParam);
96 break;
97 case WM_LBUTTONDOWN:
98 if (!vo_nomouse_input && (vo_fs || (wParam & MK_CONTROL))) {
99 mplayer_put_key(MOUSE_BTN0);
100 break;
102 if (!vo_fs) {
103 ReleaseCapture();
104 SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
105 return 0;
107 break;
108 case WM_MBUTTONDOWN:
109 if (!vo_nomouse_input)
110 mplayer_put_key(MOUSE_BTN1);
111 break;
112 case WM_RBUTTONDOWN:
113 if (!vo_nomouse_input)
114 mplayer_put_key(MOUSE_BTN2);
115 break;
116 case WM_MOUSEMOVE:
117 if (enable_mouse_movements) {
118 char cmd_str[40];
119 snprintf(cmd_str, sizeof(cmd_str), "set_mouse_pos %i %i",
120 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
121 mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
123 break;
124 case WM_MOUSEWHEEL:
125 if (!vo_nomouse_input) {
126 int x = GET_WHEEL_DELTA_WPARAM(wParam);
127 if (x > 0)
128 mplayer_put_key(MOUSE_BTN3);
129 else
130 mplayer_put_key(MOUSE_BTN4);
131 break;
135 return DefWindowProc(hWnd, message, wParam, lParam);
138 int vo_w32_check_events(void) {
139 MSG msg;
140 event_flags = 0;
141 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
142 TranslateMessage(&msg);
143 DispatchMessage(&msg);
145 if (WinID >= 0) {
146 RECT r;
147 GetClientRect(vo_window, &r);
148 if (r.right != vo_dwidth || r.bottom != vo_dheight)
149 event_flags |= VO_EVENT_RESIZE;
150 vo_dwidth = r.right;
151 vo_dheight = r.bottom;
154 return event_flags;
157 static BOOL CALLBACK mon_enum(HMONITOR hmon, HDC hdc, LPRECT r, LPARAM p) {
158 // this defaults to the last screen if specified number does not exist
159 xinerama_x = r->left;
160 xinerama_y = r->top;
161 vo_screenwidth = r->right - r->left;
162 vo_screenheight = r->bottom - r->top;
163 if (mon_cnt == xinerama_screen)
164 return FALSE;
165 mon_cnt++;
166 return TRUE;
169 void w32_update_xinerama_info(void) {
170 xinerama_x = xinerama_y = 0;
171 if (xinerama_screen < -1) {
172 int tmp;
173 xinerama_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
174 xinerama_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
175 tmp = GetSystemMetrics(SM_CXVIRTUALSCREEN);
176 if (tmp) vo_screenwidth = tmp;
177 tmp = GetSystemMetrics(SM_CYVIRTUALSCREEN);
178 if (tmp) vo_screenheight = tmp;
179 } else if (xinerama_screen == -1 && myMonitorFromWindow && myGetMonitorInfo) {
180 MONITORINFO mi;
181 HMONITOR m = myMonitorFromWindow(vo_window, MONITOR_DEFAULTTOPRIMARY);
182 mi.cbSize = sizeof(mi);
183 myGetMonitorInfo(m, &mi);
184 xinerama_x = mi.rcMonitor.left;
185 xinerama_y = mi.rcMonitor.top;
186 vo_screenwidth = mi.rcMonitor.right - mi.rcMonitor.left;
187 vo_screenheight = mi.rcMonitor.bottom - mi.rcMonitor.top;
188 } else if (xinerama_screen > 0 && myEnumDisplayMonitors) {
189 mon_cnt = 0;
190 myEnumDisplayMonitors(NULL, NULL, mon_enum, 0);
192 aspect_save_screenres(vo_screenwidth, vo_screenheight);
195 static void updateScreenProperties() {
196 DEVMODE dm;
197 dm.dmSize = sizeof dm;
198 dm.dmDriverExtra = 0;
199 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
200 if (!EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm)) {
201 mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to enumerate display settings!\n");
202 return;
205 vo_screenwidth = dm.dmPelsWidth;
206 vo_screenheight = dm.dmPelsHeight;
207 vo_depthonscreen = dm.dmBitsPerPel;
208 w32_update_xinerama_info();
211 static void changeMode(void) {
212 DEVMODE dm;
213 dm.dmSize = sizeof dm;
214 dm.dmDriverExtra = 0;
216 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
217 dm.dmBitsPerPel = vo_depthonscreen;
218 dm.dmPelsWidth = vo_screenwidth;
219 dm.dmPelsHeight = vo_screenheight;
221 if (vo_vm) {
222 int bestMode = -1;
223 int bestScore = INT_MAX;
224 int i;
225 for (i = 0; EnumDisplaySettings(0, i, &dm); ++i) {
226 int score = (dm.dmPelsWidth - o_dwidth) * (dm.dmPelsHeight - o_dheight);
227 if (dm.dmBitsPerPel != vo_depthonscreen) continue;
228 if (dm.dmPelsWidth < o_dwidth) continue;
229 if (dm.dmPelsHeight < o_dheight) continue;
231 if (score < bestScore) {
232 bestScore = score;
233 bestMode = i;
237 if (bestMode != -1)
238 EnumDisplaySettings(0, bestMode, &dm);
240 ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
244 static void resetMode(void) {
245 if (vo_vm)
246 ChangeDisplaySettings(0, 0);
249 static int createRenderingContext(void) {
250 HWND layer = HWND_NOTOPMOST;
251 PIXELFORMATDESCRIPTOR pfd;
252 HDC vo_hdc = GetDC(vo_window);
253 RECT r;
254 int pf;
255 if (WinID < 0) {
256 int style = (vo_border && !vo_fs) ?
257 (WS_OVERLAPPEDWINDOW | WS_SIZEBOX) : WS_POPUP;
259 if (vo_fs || vo_ontop) layer = HWND_TOPMOST;
260 if (vo_fs) {
261 changeMode();
262 while (ShowCursor(0) >= 0) /**/ ;
263 } else {
264 resetMode();
265 while (ShowCursor(1) < 0) /**/ ;
267 updateScreenProperties();
268 ShowWindow(vo_window, SW_HIDE);
269 SetWindowLong(vo_window, GWL_STYLE, style);
270 if (vo_fs) {
271 prev_width = vo_dwidth;
272 prev_height = vo_dheight;
273 prev_x = vo_dx;
274 prev_y = vo_dy;
275 vo_dwidth = vo_screenwidth;
276 vo_dheight = vo_screenheight;
277 vo_dx = xinerama_x;
278 vo_dy = xinerama_y;
279 } else {
280 // make sure there are no "stale" resize events
281 // that would set vo_d* to wrong values
282 vo_w32_check_events();
283 vo_dwidth = prev_width;
284 vo_dheight = prev_height;
285 vo_dx = prev_x;
286 vo_dy = prev_y;
287 // HACK around what probably is a windows focus bug:
288 // when pressing 'f' on the console, then 'f' again to
289 // return to windowed mode, any input into the video
290 // window is lost forever.
291 SetFocus(vo_window);
293 r.left = vo_dx;
294 r.right = r.left + vo_dwidth;
295 r.top = vo_dy;
296 r.bottom = r.top + vo_dheight;
297 AdjustWindowRect(&r, style, 0);
298 SetWindowPos(vo_window, layer, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_SHOWWINDOW);
301 memset(&pfd, 0, sizeof pfd);
302 pfd.nSize = sizeof pfd;
303 pfd.nVersion = 1;
304 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
305 pfd.iPixelType = PFD_TYPE_RGBA;
306 pfd.cColorBits = 24;
307 pfd.iLayerType = PFD_MAIN_PLANE;
308 pf = ChoosePixelFormat(vo_hdc, &pfd);
309 if (!pf) {
310 mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to select a valid pixel format!\n");
311 ReleaseDC(vo_window, vo_hdc);
312 return 0;
315 SetPixelFormat(vo_hdc, pf, &pfd);
317 mp_msg(MSGT_VO, MSGL_V, "vo: win32: running at %dx%d with depth %d\n", vo_screenwidth, vo_screenheight, vo_depthonscreen);
319 ReleaseDC(vo_window, vo_hdc);
320 return 1;
323 int vo_w32_config(uint32_t width, uint32_t height, uint32_t flags) {
324 // store original size for videomode switching
325 o_dwidth = width;
326 o_dheight = height;
328 prev_width = vo_dwidth = width;
329 prev_height = vo_dheight = height;
330 prev_x = vo_dx;
331 prev_y = vo_dy;
333 vo_fs = flags & VOFLAG_FULLSCREEN;
334 vo_vm = flags & VOFLAG_MODESWITCHING;
335 return createRenderingContext();
338 int vo_w32_init(void) {
339 HICON mplayerIcon = 0;
340 char exedir[MAX_PATH];
341 HINSTANCE user32;
343 if (vo_window)
344 return 1;
346 hInstance = GetModuleHandle(0);
348 if (GetModuleFileName(0, exedir, MAX_PATH))
349 mplayerIcon = ExtractIcon(hInstance, exedir, 0);
350 if (!mplayerIcon)
351 mplayerIcon = LoadIcon(0, IDI_APPLICATION);
354 WNDCLASSEX wcex = { sizeof wcex, CS_OWNDC, WndProc, 0, 0, hInstance, mplayerIcon, LoadCursor(0, IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), 0, classname, mplayerIcon };
356 if (!RegisterClassEx(&wcex)) {
357 mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to register window class!\n");
358 return 0;
362 if (WinID >= 0)
363 vo_window = WinID;
364 else {
365 vo_window = CreateWindowEx(0, classname, classname,
366 vo_border ? (WS_OVERLAPPEDWINDOW | WS_SIZEBOX) : WS_POPUP,
367 CW_USEDEFAULT, 0, 100, 100, 0, 0, hInstance, 0);
368 if (!vo_window) {
369 mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to create window!\n");
370 return 0;
374 myMonitorFromWindow = NULL;
375 myGetMonitorInfo = NULL;
376 myEnumDisplayMonitors = NULL;
377 user32 = GetModuleHandle("user32.dll");
378 if (user32) {
379 myMonitorFromWindow = GetProcAddress(user32, "MonitorFromWindow");
380 myGetMonitorInfo = GetProcAddress(user32, "GetMonitorInfoA");
381 myEnumDisplayMonitors = GetProcAddress(user32, "EnumDisplayMonitors");
383 updateScreenProperties();
385 return 1;
388 void vo_w32_fullscreen(void) {
389 vo_fs = !vo_fs;
391 createRenderingContext();
394 void vo_w32_border() {
395 vo_border = !vo_border;
396 createRenderingContext();
399 void vo_w32_ontop( void )
401 vo_ontop = !vo_ontop;
402 if (!vo_fs) {
403 HWND layer = HWND_NOTOPMOST;
404 if (vo_ontop) layer = HWND_TOPMOST;
405 SetWindowPos(vo_window, layer, (vo_screenwidth - vo_dwidth) / 2, (vo_screenheight - vo_dheight) / 2, vo_dwidth, vo_dheight, SWP_SHOWWINDOW);
409 void vo_w32_uninit() {
410 mp_msg(MSGT_VO, MSGL_V, "vo: win32: uninit\n");
411 resetMode();
412 ShowCursor(1);
413 vo_depthonscreen = 0;
414 if (WinID < 0)
415 DestroyWindow(vo_window);
416 vo_window = 0;
417 UnregisterClass(classname, 0);