switch_ratio may not work with some filter chains
[mplayer/greg.git] / libvo / x11_common.c
blob0cf9c166c054d9c2d8cb57ea773e93d35e44cdd9
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <inttypes.h>
7 #include "config.h"
8 #include "mp_msg.h"
9 #include "x11_common.h"
11 #ifdef X11_FULLSCREEN
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/mman.h>
16 #include <signal.h>
17 #include <assert.h>
19 #include "video_out.h"
20 #include "aspect.h"
21 #include "geometry.h"
22 #include "help_mp.h"
23 #include "../osdep/timer.h"
25 #include <X11/Xmd.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
30 #ifdef HAVE_XDPMS
31 #include <X11/extensions/dpms.h>
32 #endif
34 #ifdef HAVE_XINERAMA
35 #include <X11/extensions/Xinerama.h>
36 #endif
38 #ifdef HAVE_XF86VM
39 #include <X11/extensions/xf86vmode.h>
40 #include <X11/XF86keysym.h>
41 #endif
43 #ifdef HAVE_XV
44 #include <X11/extensions/Xv.h>
45 #include <X11/extensions/Xvlib.h>
46 #endif
48 #include "../input/input.h"
49 #include "../input/mouse.h"
51 #ifdef HAVE_NEW_GUI
52 #include "../Gui/interface.h"
53 #include "../mplayer.h"
54 #endif
56 #define WIN_LAYER_ONBOTTOM 2
57 #define WIN_LAYER_NORMAL 4
58 #define WIN_LAYER_ONTOP 6
59 #define WIN_LAYER_ABOVE_DOCK 10
61 int fs_layer = WIN_LAYER_ABOVE_DOCK;
62 static int orig_layer = 0;
63 static int old_gravity = NorthWestGravity;
65 int stop_xscreensaver = 0;
67 static int dpms_disabled = 0;
68 static int timeout_save = 0;
69 static int kdescreensaver_was_running = 0;
71 char *mDisplayName = NULL;
72 Display *mDisplay = NULL;
73 Window mRootWin;
74 int mScreen;
75 int mLocalDisplay;
77 /* output window id */
78 int WinID = -1;
79 int vo_mouse_autohide = 0;
80 int vo_wm_type = 0;
81 int vo_fs_type = 0; // needs to be accessible for GUI X11 code
82 static int vo_fs_flip = 0;
83 char **vo_fstype_list;
85 /* if equal to 1 means that WM is a metacity (broken as hell) */
86 int metacity_hack = 0;
88 static Atom XA_NET_SUPPORTED;
89 static Atom XA_NET_WM_STATE;
90 static Atom XA_NET_WM_STATE_FULLSCREEN;
91 static Atom XA_NET_WM_STATE_ABOVE;
92 static Atom XA_NET_WM_STATE_STAYS_ON_TOP;
93 static Atom XA_NET_WM_STATE_BELOW;
94 static Atom XA_NET_WM_PID;
95 static Atom XA_WIN_PROTOCOLS;
96 static Atom XA_WIN_LAYER;
97 static Atom XA_WIN_HINTS;
98 static Atom XA_BLACKBOX_PID;
100 #define XA_INIT(x) XA##x = XInternAtom(mDisplay, #x, False)
102 static int vo_old_x = 0;
103 static int vo_old_y = 0;
104 static int vo_old_width = 0;
105 static int vo_old_height = 0;
107 #ifdef HAVE_XINERAMA
108 int xinerama_screen = 0;
109 int xinerama_x = 0;
110 int xinerama_y = 0;
111 #endif
112 #ifdef HAVE_XF86VM
113 XF86VidModeModeInfo **vidmodes = NULL;
114 XF86VidModeModeLine modeline;
115 #endif
117 static int vo_x11_get_fs_type(int supported);
121 * Sends the EWMH fullscreen state event.
123 * action: could be on of _NET_WM_STATE_REMOVE -- remove state
124 * _NET_WM_STATE_ADD -- add state
125 * _NET_WM_STATE_TOGGLE -- toggle
127 void vo_x11_ewmh_fullscreen(int action)
129 assert(action == _NET_WM_STATE_REMOVE ||
130 action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE);
132 if (vo_fs_type & vo_wm_FULLSCREEN)
134 XEvent xev;
136 /* init X event structure for _NET_WM_FULLSCREEN client msg */
137 xev.xclient.type = ClientMessage;
138 xev.xclient.serial = 0;
139 xev.xclient.send_event = True;
140 xev.xclient.message_type = XInternAtom(mDisplay,
141 "_NET_WM_STATE", False);
142 xev.xclient.window = vo_window;
143 xev.xclient.format = 32;
144 xev.xclient.data.l[0] = action;
145 xev.xclient.data.l[1] = XInternAtom(mDisplay,
146 "_NET_WM_STATE_FULLSCREEN",
147 False);
148 xev.xclient.data.l[2] = 0;
149 xev.xclient.data.l[3] = 0;
150 xev.xclient.data.l[4] = 0;
152 /* finally send that damn thing */
153 if (!XSendEvent(mDisplay, DefaultRootWindow(mDisplay), False,
154 SubstructureRedirectMask | SubstructureNotifyMask,
155 &xev))
157 mp_msg(MSGT_VO, MSGL_ERR, MSGTR_EwmhFullscreenStateFailed);
162 void vo_hidecursor(Display * disp, Window win)
164 Cursor no_ptr;
165 Pixmap bm_no;
166 XColor black, dummy;
167 Colormap colormap;
168 static unsigned char bm_no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
170 if (WinID == 0)
171 return; // do not hide, if we're playing at rootwin
173 colormap = DefaultColormap(disp, DefaultScreen(disp));
174 XAllocNamedColor(disp, colormap, "black", &black, &dummy);
175 bm_no = XCreateBitmapFromData(disp, win, bm_no_data, 8, 8);
176 no_ptr = XCreatePixmapCursor(disp, bm_no, bm_no, &black, &black, 0, 0);
177 XDefineCursor(disp, win, no_ptr);
178 XFreeCursor(disp, no_ptr);
179 if (bm_no != None)
180 XFreePixmap(disp, bm_no);
183 void vo_showcursor(Display * disp, Window win)
185 if (WinID == 0)
186 return;
187 XDefineCursor(disp, win, 0);
190 static int x11_errorhandler(Display * display, XErrorEvent * event)
192 #define MSGLEN 60
193 char msg[MSGLEN];
195 XGetErrorText(display, event->error_code, (char *) &msg, MSGLEN);
197 mp_msg(MSGT_VO, MSGL_ERR, "X11 error: %s\n", msg);
199 mp_msg(MSGT_VO, MSGL_V,
200 "Type: %x, display: %x, resourceid: %x, serial: %x\n",
201 event->type, event->display, event->resourceid, event->serial);
202 mp_msg(MSGT_VO, MSGL_V,
203 "Error code: %x, request code: %x, minor code: %x\n",
204 event->error_code, event->request_code, event->minor_code);
206 abort();
207 //exit_player("X11 error");
208 #undef MSGLEN
211 void fstype_help(void)
213 mp_msg(MSGT_VO, MSGL_INFO, MSGTR_AvailableFsType);
215 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "none",
216 "don't set fullscreen window layer");
217 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "layer",
218 "use _WIN_LAYER hint with default layer");
219 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "layer=<0..15>",
220 "use _WIN_LAYER hint with a given layer number");
221 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "netwm",
222 "force NETWM style");
223 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "above",
224 "use _NETWM_STATE_ABOVE hint if available");
225 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "below",
226 "use _NETWM_STATE_BELOW hint if available");
227 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "fullscreen",
228 "use _NETWM_STATE_FULLSCREEN hint if availale");
229 mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "stays_on_top",
230 "use _NETWM_STATE_STAYS_ON_TOP hint if available");
231 mp_msg(MSGT_VO, MSGL_INFO,
232 "You can also negate the settings with simply putting '-' in the beginning");
235 static void fstype_dump(int fstype)
237 if (fstype)
239 mp_msg(MSGT_VO, MSGL_V, "[x11] Current fstype setting honours");
240 if (fstype & vo_wm_LAYER)
241 mp_msg(MSGT_VO, MSGL_V, " LAYER");
242 if (fstype & vo_wm_FULLSCREEN)
243 mp_msg(MSGT_VO, MSGL_V, " FULLSCREEN");
244 if (fstype & vo_wm_STAYS_ON_TOP)
245 mp_msg(MSGT_VO, MSGL_V, " STAYS_ON_TOP");
246 if (fstype & vo_wm_ABOVE)
247 mp_msg(MSGT_VO, MSGL_V, " ABOVE");
248 if (fstype & vo_wm_BELOW)
249 mp_msg(MSGT_VO, MSGL_V, " BELOW");
250 mp_msg(MSGT_VO, MSGL_V, " X atoms\n");
251 } else
252 mp_msg(MSGT_VO, MSGL_V,
253 "[x11] Current fstype setting doesn't honour any X atoms\n");
256 static int net_wm_support_state_test(Atom atom)
258 #define NET_WM_STATE_TEST(x) { if (atom == XA_NET_WM_STATE_##x) { mp_msg( MSGT_VO,MSGL_V, "[x11] Detected wm supports " #x " state.\n" ); return vo_wm_##x; } }
260 NET_WM_STATE_TEST(FULLSCREEN);
261 NET_WM_STATE_TEST(ABOVE);
262 NET_WM_STATE_TEST(STAYS_ON_TOP);
263 NET_WM_STATE_TEST(BELOW);
264 return 0;
267 static int x11_get_property(Atom type, Atom ** args, unsigned long *nitems)
269 int format;
270 unsigned long bytesafter;
272 return (Success ==
273 XGetWindowProperty(mDisplay, mRootWin, type, 0, 16384, False,
274 AnyPropertyType, &type, &format, nitems,
275 &bytesafter, (unsigned char **) args)
276 && *nitems > 0);
279 static int vo_wm_detect(void)
281 int i;
282 int wm = 0;
283 unsigned long nitems;
284 Atom *args = NULL;
286 if (WinID >= 0)
287 return 0;
289 // -- supports layers
290 if (x11_get_property(XA_WIN_PROTOCOLS, &args, &nitems))
292 mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports layers.\n");
293 for (i = 0; i < nitems; i++)
295 if (args[i] == XA_WIN_LAYER)
297 wm |= vo_wm_LAYER;
298 metacity_hack |= 1;
299 } else
300 // metacity is the only manager I know which reports support only for _WIN_LAYER
301 // hint in _WIN_PROTOCOLS (what's more support for it is broken)
302 metacity_hack |= 2;
304 XFree(args);
305 if (wm && (metacity_hack == 1))
307 // metacity reports that it supports layers, but it is not really truth :-)
308 wm ^= vo_wm_LAYER;
309 mp_msg(MSGT_VO, MSGL_V,
310 "[x11] Using workaround for Metacity bugs.\n");
313 // --- netwm
314 if (x11_get_property(XA_NET_SUPPORTED, &args, &nitems))
316 mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports NetWM.\n");
317 for (i = 0; i < nitems; i++)
318 wm |= net_wm_support_state_test(args[i]);
319 XFree(args);
320 #if 0
321 // ugly hack for broken OpenBox _NET_WM_STATE_FULLSCREEN support
322 // (in their implementation it only changes internal state of window, nothing more!!!)
323 if (wm & vo_wm_FULLSCREEN)
325 if (x11_get_property(XA_BLACKBOX_PID, &args, &nitems))
327 mp_msg(MSGT_VO, MSGL_V,
328 "[x11] Detected wm is a broken OpenBox.\n");
329 wm ^= vo_wm_FULLSCREEN;
331 XFree(args);
333 #endif
336 if (wm == 0)
337 mp_msg(MSGT_VO, MSGL_V, "[x11] Unknown wm type...\n");
338 return wm;
341 static void init_atoms(void)
343 XA_INIT(_NET_SUPPORTED);
344 XA_INIT(_NET_WM_STATE);
345 XA_INIT(_NET_WM_STATE_FULLSCREEN);
346 XA_INIT(_NET_WM_STATE_ABOVE);
347 XA_INIT(_NET_WM_STATE_STAYS_ON_TOP);
348 XA_INIT(_NET_WM_STATE_BELOW);
349 XA_INIT(_NET_WM_PID);
350 XA_INIT(_WIN_PROTOCOLS);
351 XA_INIT(_WIN_LAYER);
352 XA_INIT(_WIN_HINTS);
353 XA_INIT(_BLACKBOX_PID);
356 int vo_init(void)
358 // int mScreen;
359 int depth, bpp;
360 unsigned int mask;
362 // char * DisplayName = ":0.0";
363 // Display * mDisplay;
364 XImage *mXImage = NULL;
366 // Window mRootWin;
367 XWindowAttributes attribs;
368 char *dispName;
370 if (vo_rootwin)
371 WinID = 0; // use root win
373 if (vo_depthonscreen)
374 return 1; // already called
376 XSetErrorHandler(x11_errorhandler);
378 #if 0
379 if (!mDisplayName)
380 if (!(mDisplayName = getenv("DISPLAY")))
381 mDisplayName = strdup(":0.0");
382 #else
383 dispName = XDisplayName(mDisplayName);
384 #endif
386 mp_msg(MSGT_VO, MSGL_V, "X11 opening display: %s\n", dispName);
388 mDisplay = XOpenDisplay(dispName);
389 if (!mDisplay)
391 mp_msg(MSGT_VO, MSGL_ERR,
392 "vo: couldn't open the X11 display (%s)!\n", dispName);
393 return 0;
395 mScreen = DefaultScreen(mDisplay); // Screen ID.
396 mRootWin = RootWindow(mDisplay, mScreen); // Root window ID.
398 init_atoms();
400 #ifdef HAVE_XINERAMA
401 if (XineramaIsActive(mDisplay))
403 XineramaScreenInfo *screens;
404 int num_screens;
406 screens = XineramaQueryScreens(mDisplay, &num_screens);
407 if (xinerama_screen >= num_screens)
408 xinerama_screen = 0;
409 if (!vo_screenwidth)
410 vo_screenwidth = screens[xinerama_screen].width;
411 if (!vo_screenheight)
412 vo_screenheight = screens[xinerama_screen].height;
413 xinerama_x = screens[xinerama_screen].x_org;
414 xinerama_y = screens[xinerama_screen].y_org;
416 XFree(screens);
417 } else
418 #endif
419 #ifdef HAVE_XF86VM
421 int clock;
423 XF86VidModeGetModeLine(mDisplay, mScreen, &clock, &modeline);
424 if (!vo_screenwidth)
425 vo_screenwidth = modeline.hdisplay;
426 if (!vo_screenheight)
427 vo_screenheight = modeline.vdisplay;
429 #endif
431 if (!vo_screenwidth)
432 vo_screenwidth = DisplayWidth(mDisplay, mScreen);
433 if (!vo_screenheight)
434 vo_screenheight = DisplayHeight(mDisplay, mScreen);
436 // get color depth (from root window, or the best visual):
437 XGetWindowAttributes(mDisplay, mRootWin, &attribs);
438 depth = attribs.depth;
440 if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
442 Visual *visual;
444 depth = vo_find_depth_from_visuals(mDisplay, mScreen, &visual);
445 if (depth != -1)
446 mXImage = XCreateImage(mDisplay, visual, depth, ZPixmap,
447 0, NULL, 1, 1, 8, 1);
448 } else
449 mXImage =
450 XGetImage(mDisplay, mRootWin, 0, 0, 1, 1, AllPlanes, ZPixmap);
452 vo_depthonscreen = depth; // display depth on screen
454 // get bits/pixel from XImage structure:
455 if (mXImage == NULL)
457 mask = 0;
458 } else
461 * for the depth==24 case, the XImage structures might use
462 * 24 or 32 bits of data per pixel. The global variable
463 * vo_depthonscreen stores the amount of data per pixel in the
464 * XImage structure!
466 * Maybe we should rename vo_depthonscreen to (or add) vo_bpp?
468 bpp = mXImage->bits_per_pixel;
469 if ((vo_depthonscreen + 7) / 8 != (bpp + 7) / 8)
470 vo_depthonscreen = bpp; // by A'rpi
471 mask =
472 mXImage->red_mask | mXImage->green_mask | mXImage->blue_mask;
473 mp_msg(MSGT_VO, MSGL_V,
474 "vo: X11 color mask: %X (R:%lX G:%lX B:%lX)\n", mask,
475 mXImage->red_mask, mXImage->green_mask, mXImage->blue_mask);
476 XDestroyImage(mXImage);
478 if (((vo_depthonscreen + 7) / 8) == 2)
480 if (mask == 0x7FFF)
481 vo_depthonscreen = 15;
482 else if (mask == 0xFFFF)
483 vo_depthonscreen = 16;
485 // XCloseDisplay( mDisplay );
486 /* slightly improved local display detection AST */
487 if (strncmp(dispName, "unix:", 5) == 0)
488 dispName += 4;
489 else if (strncmp(dispName, "localhost:", 10) == 0)
490 dispName += 9;
491 if (*dispName == ':' && atoi(dispName + 1) < 10)
492 mLocalDisplay = 1;
493 else
494 mLocalDisplay = 0;
495 mp_msg(MSGT_VO, MSGL_INFO,
496 "vo: X11 running at %dx%d with depth %d and %d bpp (\"%s\" => %s display)\n",
497 vo_screenwidth, vo_screenheight, depth, vo_depthonscreen,
498 dispName, mLocalDisplay ? "local" : "remote");
500 vo_wm_type = vo_wm_detect();
502 vo_fs_type = vo_x11_get_fs_type(vo_wm_type);
504 fstype_dump(vo_fs_type);
506 saver_off(mDisplay);
507 return 1;
510 void vo_uninit(void)
512 if (!mDisplay)
514 mp_msg(MSGT_VO, MSGL_V,
515 "vo: x11 uninit called but X11 not inited..\n");
516 return;
518 // if( !vo_depthonscreen ) return;
519 mp_msg(MSGT_VO, MSGL_V, "vo: uninit ...\n");
520 XSetErrorHandler(NULL);
521 XCloseDisplay(mDisplay);
522 vo_depthonscreen = 0;
523 mDisplay = NULL;
526 #include "../osdep/keycodes.h"
527 #include "wskeys.h"
529 extern void mplayer_put_key(int code);
531 #ifdef XF86XK_AudioPause
532 void vo_x11_putkey_ext(int keysym)
534 switch (keysym)
536 case XF86XK_AudioPause:
537 mplayer_put_key(KEY_XF86_PAUSE);
538 break;
539 case XF86XK_AudioStop:
540 mplayer_put_key(KEY_XF86_STOP);
541 break;
542 case XF86XK_AudioPrev:
543 mplayer_put_key(KEY_XF86_PREV);
544 break;
545 case XF86XK_AudioNext:
546 mplayer_put_key(KEY_XF86_NEXT);
547 break;
548 default:
549 break;
552 #endif
554 void vo_x11_putkey(int key)
556 switch (key)
558 case wsLeft:
559 mplayer_put_key(KEY_LEFT);
560 break;
561 case wsRight:
562 mplayer_put_key(KEY_RIGHT);
563 break;
564 case wsUp:
565 mplayer_put_key(KEY_UP);
566 break;
567 case wsDown:
568 mplayer_put_key(KEY_DOWN);
569 break;
570 case wsSpace:
571 mplayer_put_key(' ');
572 break;
573 case wsEscape:
574 mplayer_put_key(KEY_ESC);
575 break;
576 case wsEnter:
577 mplayer_put_key(KEY_ENTER);
578 break;
579 case wsBackSpace:
580 mplayer_put_key(KEY_BS);
581 break;
582 case wsDelete:
583 mplayer_put_key(KEY_DELETE);
584 break;
585 case wsInsert:
586 mplayer_put_key(KEY_INSERT);
587 break;
588 case wsHome:
589 mplayer_put_key(KEY_HOME);
590 break;
591 case wsEnd:
592 mplayer_put_key(KEY_END);
593 break;
594 case wsPageUp:
595 mplayer_put_key(KEY_PAGE_UP);
596 break;
597 case wsPageDown:
598 mplayer_put_key(KEY_PAGE_DOWN);
599 break;
600 case wsF1:
601 mplayer_put_key(KEY_F + 1);
602 break;
603 case wsF2:
604 mplayer_put_key(KEY_F + 2);
605 break;
606 case wsF3:
607 mplayer_put_key(KEY_F + 3);
608 break;
609 case wsF4:
610 mplayer_put_key(KEY_F + 4);
611 break;
612 case wsF5:
613 mplayer_put_key(KEY_F + 5);
614 break;
615 case wsF6:
616 mplayer_put_key(KEY_F + 6);
617 break;
618 case wsF7:
619 mplayer_put_key(KEY_F + 7);
620 break;
621 case wsF8:
622 mplayer_put_key(KEY_F + 8);
623 break;
624 case wsF9:
625 mplayer_put_key(KEY_F + 9);
626 break;
627 case wsF10:
628 mplayer_put_key(KEY_F + 10);
629 break;
630 case wsF11:
631 mplayer_put_key(KEY_F + 11);
632 break;
633 case wsF12:
634 mplayer_put_key(KEY_F + 12);
635 break;
636 case wsq:
637 case wsQ:
638 mplayer_put_key('q');
639 break;
640 case wsp:
641 case wsP:
642 mplayer_put_key('p');
643 break;
644 case wsMinus:
645 case wsGrayMinus:
646 mplayer_put_key('-');
647 break;
648 case wsPlus:
649 case wsGrayPlus:
650 mplayer_put_key('+');
651 break;
652 case wsGrayMul:
653 case wsMul:
654 mplayer_put_key('*');
655 break;
656 case wsGrayDiv:
657 case wsDiv:
658 mplayer_put_key('/');
659 break;
660 case wsLess:
661 mplayer_put_key('<');
662 break;
663 case wsMore:
664 mplayer_put_key('>');
665 break;
666 case wsGray0:
667 mplayer_put_key(KEY_KP0);
668 break;
669 case wsGrayEnd:
670 case wsGray1:
671 mplayer_put_key(KEY_KP1);
672 break;
673 case wsGrayDown:
674 case wsGray2:
675 mplayer_put_key(KEY_KP2);
676 break;
677 case wsGrayPgDn:
678 case wsGray3:
679 mplayer_put_key(KEY_KP3);
680 break;
681 case wsGrayLeft:
682 case wsGray4:
683 mplayer_put_key(KEY_KP4);
684 break;
685 case wsGray5Dup:
686 case wsGray5:
687 mplayer_put_key(KEY_KP5);
688 break;
689 case wsGrayRight:
690 case wsGray6:
691 mplayer_put_key(KEY_KP6);
692 break;
693 case wsGrayHome:
694 case wsGray7:
695 mplayer_put_key(KEY_KP7);
696 break;
697 case wsGrayUp:
698 case wsGray8:
699 mplayer_put_key(KEY_KP8);
700 break;
701 case wsGrayPgUp:
702 case wsGray9:
703 mplayer_put_key(KEY_KP9);
704 break;
705 case wsGrayDecimal:
706 mplayer_put_key(KEY_KPDEC);
707 break;
708 case wsGrayInsert:
709 mplayer_put_key(KEY_KPINS);
710 break;
711 case wsGrayDelete:
712 mplayer_put_key(KEY_KPDEL);
713 break;
714 case wsGrayEnter:
715 mplayer_put_key(KEY_KPENTER);
716 break;
717 case wsm:
718 case wsM:
719 mplayer_put_key('m');
720 break;
721 case wso:
722 case wsO:
723 mplayer_put_key('o');
724 break;
726 case wsGrave:
727 mplayer_put_key('`');
728 break;
729 case wsTilde:
730 mplayer_put_key('~');
731 break;
732 case wsExclSign:
733 mplayer_put_key('!');
734 break;
735 case wsAt:
736 mplayer_put_key('@');
737 break;
738 case wsHash:
739 mplayer_put_key('#');
740 break;
741 case wsDollar:
742 mplayer_put_key('$');
743 break;
744 case wsPercent:
745 mplayer_put_key('%');
746 break;
747 case wsCircumflex:
748 mplayer_put_key('^');
749 break;
750 case wsAmpersand:
751 mplayer_put_key('&');
752 break;
753 case wsobracket:
754 mplayer_put_key('(');
755 break;
756 case wscbracket:
757 mplayer_put_key(')');
758 break;
759 case wsUnder:
760 mplayer_put_key('_');
761 break;
762 case wsocbracket:
763 mplayer_put_key('{');
764 break;
765 case wsccbracket:
766 mplayer_put_key('}');
767 break;
768 case wsColon:
769 mplayer_put_key(':');
770 break;
771 case wsSemicolon:
772 mplayer_put_key(';');
773 break;
774 case wsDblQuote:
775 mplayer_put_key('\"');
776 break;
777 case wsAcute:
778 mplayer_put_key('\'');
779 break;
780 case wsComma:
781 mplayer_put_key(',');
782 break;
783 case wsPoint:
784 mplayer_put_key('.');
785 break;
786 case wsQuestSign:
787 mplayer_put_key('?');
788 break;
789 case wsBSlash:
790 mplayer_put_key('\\');
791 break;
792 case wsPipe:
793 mplayer_put_key('|');
794 break;
795 case wsEqual:
796 mplayer_put_key('=');
797 break;
798 case wsosbrackets:
799 mplayer_put_key('[');
800 break;
801 case wscsbrackets:
802 mplayer_put_key(']');
803 break;
806 default:
807 if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') ||
808 (key >= '0' && key <= '9'))
809 mplayer_put_key(key);
815 // ----- Motif header: -------
817 #define MWM_HINTS_FUNCTIONS (1L << 0)
818 #define MWM_HINTS_DECORATIONS (1L << 1)
819 #define MWM_HINTS_INPUT_MODE (1L << 2)
820 #define MWM_HINTS_STATUS (1L << 3)
822 #define MWM_FUNC_ALL (1L << 0)
823 #define MWM_FUNC_RESIZE (1L << 1)
824 #define MWM_FUNC_MOVE (1L << 2)
825 #define MWM_FUNC_MINIMIZE (1L << 3)
826 #define MWM_FUNC_MAXIMIZE (1L << 4)
827 #define MWM_FUNC_CLOSE (1L << 5)
829 #define MWM_DECOR_ALL (1L << 0)
830 #define MWM_DECOR_BORDER (1L << 1)
831 #define MWM_DECOR_RESIZEH (1L << 2)
832 #define MWM_DECOR_TITLE (1L << 3)
833 #define MWM_DECOR_MENU (1L << 4)
834 #define MWM_DECOR_MINIMIZE (1L << 5)
835 #define MWM_DECOR_MAXIMIZE (1L << 6)
837 #define MWM_INPUT_MODELESS 0
838 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
839 #define MWM_INPUT_SYSTEM_MODAL 2
840 #define MWM_INPUT_FULL_APPLICATION_MODAL 3
841 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
843 #define MWM_TEAROFF_WINDOW (1L<<0)
845 typedef struct
847 long flags;
848 long functions;
849 long decorations;
850 long input_mode;
851 long state;
852 } MotifWmHints;
854 extern MotifWmHints vo_MotifWmHints;
855 extern Atom vo_MotifHints;
856 extern int vo_depthonscreen;
857 extern int vo_screenwidth;
858 extern int vo_screenheight;
860 static MotifWmHints vo_MotifWmHints;
861 static Atom vo_MotifHints = None;
863 void vo_x11_decoration(Display * vo_Display, Window w, int d)
865 static unsigned int olddecor = MWM_DECOR_ALL;
866 static unsigned int oldfuncs =
867 MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE |
868 MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
869 Atom mtype;
870 int mformat;
871 unsigned long mn, mb;
873 if (!WinID)
874 return;
876 if (vo_fsmode & 8)
878 XSetTransientForHint(vo_Display, w,
879 RootWindow(vo_Display, mScreen));
882 vo_MotifHints = XInternAtom(vo_Display, "_MOTIF_WM_HINTS", 0);
883 if (vo_MotifHints != None)
885 if (!d)
887 MotifWmHints *mhints = NULL;
889 XGetWindowProperty(vo_Display, w, vo_MotifHints, 0, 20, False,
890 vo_MotifHints, &mtype, &mformat, &mn,
891 &mb, (unsigned char **) &mhints);
892 if (mhints)
894 if (mhints->flags & MWM_HINTS_DECORATIONS)
895 olddecor = mhints->decorations;
896 if (mhints->flags & MWM_HINTS_FUNCTIONS)
897 oldfuncs = mhints->functions;
898 XFree(mhints);
902 memset(&vo_MotifWmHints, 0, sizeof(MotifWmHints));
903 vo_MotifWmHints.flags =
904 MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
905 if (d)
907 vo_MotifWmHints.functions = oldfuncs;
908 d = olddecor;
910 #if 0
911 vo_MotifWmHints.decorations =
912 d | ((vo_fsmode & 2) ? 0 : MWM_DECOR_MENU);
913 #else
914 vo_MotifWmHints.decorations =
915 d | ((vo_fsmode & 2) ? MWM_DECOR_MENU : 0);
916 #endif
917 XChangeProperty(vo_Display, w, vo_MotifHints, vo_MotifHints, 32,
918 PropModeReplace,
919 (unsigned char *) &vo_MotifWmHints,
920 (vo_fsmode & 4) ? 4 : 5);
924 void vo_x11_classhint(Display * display, Window window, char *name)
926 XClassHint wmClass;
927 pid_t pid = getpid();
929 wmClass.res_name = name;
930 wmClass.res_class = "MPlayer";
931 XSetClassHint(display, window, &wmClass);
932 XChangeProperty(display, window, XA_NET_WM_PID, XA_CARDINAL, 32,
933 PropModeReplace, (unsigned char *) &pid, 1);
936 Window vo_window = None;
937 GC vo_gc = NULL;
938 GC f_gc = NULL;
939 XSizeHints vo_hint;
941 #ifdef HAVE_NEW_GUI
942 void vo_setwindow(Window w, GC g)
944 vo_window = w;
945 vo_gc = g;
947 #endif
949 void vo_x11_uninit()
951 saver_on(mDisplay);
952 if (vo_window != None)
953 vo_showcursor(mDisplay, vo_window);
955 if (f_gc)
957 XFreeGC(mDisplay, f_gc);
958 f_gc = NULL;
960 #ifdef HAVE_NEW_GUI
961 /* destroy window only if it's not controlled by GUI */
962 if (!use_gui)
963 #endif
965 if (vo_gc)
967 XSetBackground(mDisplay, vo_gc, 0);
968 XFreeGC(mDisplay, vo_gc);
969 vo_gc = NULL;
971 if (vo_window != None)
973 XClearWindow(mDisplay, vo_window);
974 if (WinID < 0)
976 XEvent xev;
978 XUnmapWindow(mDisplay, vo_window);
979 XDestroyWindow(mDisplay, vo_window);
982 XNextEvent(mDisplay, &xev);
984 while (xev.type != DestroyNotify
985 || xev.xdestroywindow.event != vo_window);
987 vo_window = None;
989 vo_fs = 0;
990 vo_old_width = vo_old_height = 0;
994 int vo_mouse_timer_const = 30;
995 static int vo_mouse_counter = 30;
997 int vo_x11_check_events(Display * mydisplay)
999 int ret = 0;
1000 XEvent Event;
1001 char buf[100];
1002 KeySym keySym;
1003 static XComposeStatus stat;
1005 // unsigned long vo_KeyTable[512];
1007 if ((vo_mouse_autohide) && (--vo_mouse_counter == 0))
1008 vo_hidecursor(mydisplay, vo_window);
1010 while (XPending(mydisplay))
1012 XNextEvent(mydisplay, &Event);
1013 #ifdef HAVE_NEW_GUI
1014 if (use_gui)
1016 guiGetEvent(0, (char *) &Event);
1017 if (vo_window != Event.xany.window)
1018 continue;
1020 #endif
1021 // printf("\rEvent.type=%X \n",Event.type);
1022 switch (Event.type)
1024 case Expose:
1025 ret |= VO_EVENT_EXPOSE;
1026 break;
1027 case ConfigureNotify:
1028 // if (!vo_fs && (Event.xconfigure.width == vo_screenwidth || Event.xconfigure.height == vo_screenheight)) break;
1029 // if (vo_fs && Event.xconfigure.width != vo_screenwidth && Event.xconfigure.height != vo_screenheight) break;
1030 if (vo_window == None)
1031 break;
1032 vo_dwidth = Event.xconfigure.width;
1033 vo_dheight = Event.xconfigure.height;
1034 #if 0
1035 /* when resizing, x and y are zero :( */
1036 vo_dx = Event.xconfigure.x;
1037 vo_dy = Event.xconfigure.y;
1038 #else
1040 Window root;
1041 int foo;
1042 Window win;
1044 XGetGeometry(mydisplay, vo_window, &root, &foo, &foo,
1045 &foo /*width */ , &foo /*height */ , &foo,
1046 &foo);
1047 XTranslateCoordinates(mydisplay, vo_window, root, 0, 0,
1048 &vo_dx, &vo_dy, &win);
1050 #endif
1051 ret |= VO_EVENT_RESIZE;
1052 break;
1053 case KeyPress:
1055 int key;
1057 XLookupString(&Event.xkey, buf, sizeof(buf), &keySym,
1058 &stat);
1059 #ifdef XF86XK_AudioPause
1060 vo_x11_putkey_ext(keySym);
1061 #endif
1062 key =
1063 ((keySym & 0xff00) !=
1064 0 ? ((keySym & 0x00ff) + 256) : (keySym));
1065 #ifdef HAVE_NEW_GUI
1066 if ((use_gui) && (key == wsEnter))
1067 break;
1068 #endif
1069 vo_x11_putkey(key);
1070 ret |= VO_EVENT_KEYPRESS;
1072 break;
1073 case MotionNotify:
1074 if (vo_mouse_autohide)
1076 vo_showcursor(mydisplay, vo_window);
1077 vo_mouse_counter = vo_mouse_timer_const;
1079 break;
1080 case ButtonPress:
1081 if (vo_mouse_autohide)
1083 vo_showcursor(mydisplay, vo_window);
1084 vo_mouse_counter = vo_mouse_timer_const;
1086 // Ignore mouse whell press event
1087 if (Event.xbutton.button > 3)
1089 mplayer_put_key(MOUSE_BTN0 + Event.xbutton.button - 1);
1090 break;
1092 #ifdef HAVE_NEW_GUI
1093 // Ignor mouse button 1 - 3 under gui
1094 if (use_gui && (Event.xbutton.button >= 1)
1095 && (Event.xbutton.button <= 3))
1096 break;
1097 #endif
1098 mplayer_put_key((MOUSE_BTN0 + Event.xbutton.button -
1099 1) | MP_KEY_DOWN);
1100 break;
1101 case ButtonRelease:
1102 if (vo_mouse_autohide)
1104 vo_showcursor(mydisplay, vo_window);
1105 vo_mouse_counter = vo_mouse_timer_const;
1107 #ifdef HAVE_NEW_GUI
1108 // Ignor mouse button 1 - 3 under gui
1109 if (use_gui && (Event.xbutton.button >= 1)
1110 && (Event.xbutton.button <= 3))
1111 break;
1112 #endif
1113 mplayer_put_key(MOUSE_BTN0 + Event.xbutton.button - 1);
1114 break;
1115 case PropertyNotify:
1117 char *name =
1118 XGetAtomName(mydisplay, Event.xproperty.atom);
1120 if (!name)
1121 break;
1123 // fprintf(stderr,"[ws] PropertyNotify ( 0x%x ) %s ( 0x%x )\n",vo_window,name,Event.xproperty.atom );
1125 XFree(name);
1127 break;
1128 case MapNotify:
1129 vo_hint.win_gravity = old_gravity;
1130 XSetWMNormalHints(mDisplay, vo_window, &vo_hint);
1131 vo_fs_flip = 0;
1132 break;
1135 return ret;
1138 void vo_x11_sizehint(int x, int y, int width, int height, int max)
1140 vo_hint.flags = PPosition | PSize | PWinGravity;
1141 if (vo_keepaspect)
1143 vo_hint.flags |= PAspect;
1144 vo_hint.min_aspect.x = width;
1145 vo_hint.min_aspect.y = height;
1146 vo_hint.max_aspect.x = width;
1147 vo_hint.max_aspect.y = height;
1150 vo_hint.x = x;
1151 vo_hint.y = y;
1152 vo_hint.width = width;
1153 vo_hint.height = height;
1154 if (max)
1156 vo_hint.max_width = width;
1157 vo_hint.max_height = height;
1158 vo_hint.flags |= PMaxSize;
1159 } else
1161 vo_hint.max_width = 0;
1162 vo_hint.max_height = 0;
1165 // set min height/width to 4 to avoid off by one errors
1166 // and because mga_vid requires a minial size of 4 pixel
1167 vo_hint.min_width = vo_hint.min_height = 4;
1168 vo_hint.flags |= PMinSize;
1170 vo_hint.win_gravity = StaticGravity;
1171 XSetWMNormalHints(mDisplay, vo_window, &vo_hint);
1174 static int vo_x11_get_gnome_layer(Display * mDisplay, Window win)
1176 Atom type;
1177 int format;
1178 unsigned long nitems;
1179 unsigned long bytesafter;
1180 unsigned short *args = NULL;
1182 if (XGetWindowProperty(mDisplay, win, XA_WIN_LAYER, 0, 16384,
1183 False, AnyPropertyType, &type, &format, &nitems,
1184 &bytesafter,
1185 (unsigned char **) &args) == Success
1186 && nitems > 0 && args)
1188 mp_msg(MSGT_VO, MSGL_V, "[x11] original window layer is %d.\n",
1189 *args);
1190 return *args;
1192 return WIN_LAYER_NORMAL;
1196 Window vo_x11_create_smooth_window(Display * mDisplay, Window mRoot,
1197 Visual * vis, int x, int y,
1198 unsigned int width, unsigned int height,
1199 int depth, Colormap col_map)
1201 unsigned long xswamask = CWBackingStore | CWBorderPixel;
1202 XSetWindowAttributes xswa;
1203 Window ret_win;
1205 if (col_map != CopyFromParent)
1207 xswa.colormap = col_map;
1208 xswamask |= CWColormap;
1210 xswa.background_pixel = 0;
1211 xswa.border_pixel = 0;
1212 xswa.backing_store = Always;
1213 xswa.bit_gravity = StaticGravity;
1215 ret_win =
1216 XCreateWindow(mDisplay, mRootWin, x, y, width, height, 0, depth,
1217 CopyFromParent, vis, xswamask, &xswa);
1218 if (!f_gc)
1219 f_gc = XCreateGC(mDisplay, ret_win, 0, 0);
1220 XSetForeground(mDisplay, f_gc, 0);
1222 return ret_win;
1226 void vo_x11_clearwindow_part(Display * mDisplay, Window vo_window,
1227 int img_width, int img_height, int use_fs)
1229 int u_dheight, u_dwidth, left_ov, left_ov2;
1231 if (!f_gc)
1232 return;
1234 u_dheight = use_fs ? vo_screenheight : vo_dheight;
1235 u_dwidth = use_fs ? vo_screenwidth : vo_dwidth;
1236 if ((u_dheight <= img_height) && (u_dwidth <= img_width))
1237 return;
1239 left_ov = (u_dheight - img_height) / 2;
1240 left_ov2 = (u_dwidth - img_width) / 2;
1242 XFillRectangle(mDisplay, vo_window, f_gc, 0, 0, u_dwidth, left_ov);
1243 XFillRectangle(mDisplay, vo_window, f_gc, 0, u_dheight - left_ov - 1,
1244 u_dwidth, left_ov + 1);
1246 if (u_dwidth > img_width)
1248 XFillRectangle(mDisplay, vo_window, f_gc, 0, left_ov, left_ov2,
1249 img_height);
1250 XFillRectangle(mDisplay, vo_window, f_gc, u_dwidth - left_ov2 - 1,
1251 left_ov, left_ov2, img_height);
1254 XFlush(mDisplay);
1257 void vo_x11_clearwindow(Display * mDisplay, Window vo_window)
1259 if (!f_gc)
1260 return;
1261 XFillRectangle(mDisplay, vo_window, f_gc, 0, 0, vo_screenwidth,
1262 vo_screenheight);
1264 XFlush(mDisplay);
1268 void vo_x11_setlayer(Display * mDisplay, Window vo_window, int layer)
1270 if (WinID >= 0)
1271 return;
1273 if (vo_fs_type & vo_wm_LAYER)
1275 XClientMessageEvent xev;
1277 if (!orig_layer)
1278 orig_layer = vo_x11_get_gnome_layer(mDisplay, vo_window);
1280 memset(&xev, 0, sizeof(xev));
1281 xev.type = ClientMessage;
1282 xev.display = mDisplay;
1283 xev.window = vo_window;
1284 xev.message_type = XA_WIN_LAYER;
1285 xev.format = 32;
1286 xev.data.l[0] = layer ? fs_layer : orig_layer; // if not fullscreen, stay on default layer
1287 xev.data.l[1] = CurrentTime;
1288 mp_msg(MSGT_VO, MSGL_V,
1289 "[x11] Layered style stay on top (layer %d).\n",
1290 xev.data.l[0]);
1291 XSendEvent(mDisplay, mRootWin, False, SubstructureNotifyMask,
1292 (XEvent *) & xev);
1293 } else if (vo_fs_type & vo_wm_NETWM)
1295 XClientMessageEvent xev;
1296 char *state;
1298 memset(&xev, 0, sizeof(xev));
1299 xev.type = ClientMessage;
1300 xev.message_type = XA_NET_WM_STATE;
1301 xev.display = mDisplay;
1302 xev.window = vo_window;
1303 xev.format = 32;
1304 xev.data.l[0] = layer;
1306 if (vo_fs_type & vo_wm_STAYS_ON_TOP)
1307 xev.data.l[1] = XA_NET_WM_STATE_STAYS_ON_TOP;
1308 else if (vo_fs_type & vo_wm_ABOVE)
1309 xev.data.l[1] = XA_NET_WM_STATE_ABOVE;
1310 else if (vo_fs_type & vo_wm_FULLSCREEN)
1311 xev.data.l[1] = XA_NET_WM_STATE_FULLSCREEN;
1312 else if (vo_fs_type & vo_wm_BELOW)
1313 // This is not fallback. We can safely assume that situation where
1314 // only NETWM_STATE_BELOW is supported and others not, doesn't exist.
1315 xev.data.l[1] = XA_NET_WM_STATE_BELOW;
1317 XSendEvent(mDisplay, mRootWin, False, SubstructureRedirectMask,
1318 (XEvent *) & xev);
1319 state = XGetAtomName(mDisplay, xev.data.l[1]);
1320 mp_msg(MSGT_VO, MSGL_V,
1321 "[x11] NET style stay on top (layer %d). Using state %s.\n",
1322 layer, state);
1323 XFree(state);
1327 static int vo_x11_get_fs_type(int supported)
1329 int i;
1330 int type = supported;
1332 if (vo_fstype_list)
1334 i = 0;
1335 for (i = 0; vo_fstype_list[i]; i++)
1337 int neg = 0;
1338 char *arg = vo_fstype_list[i];
1340 if (vo_fstype_list[i][0] == '-')
1342 neg = 1;
1343 arg = vo_fstype_list[i] + 1;
1346 if (!strncmp(arg, "layer", 5))
1348 if (!neg && (arg[5] == '='))
1350 char *endptr = NULL;
1351 int layer = strtol(vo_fstype_list[i] + 6, &endptr, 10);
1353 if (endptr && *endptr == '\0' && layer >= 0
1354 && layer <= 15)
1355 fs_layer = layer;
1357 if (neg)
1358 type &= ~vo_wm_LAYER;
1359 else
1360 type |= vo_wm_LAYER;
1361 } else if (!strcmp(arg, "above"))
1363 if (neg)
1364 type &= ~vo_wm_ABOVE;
1365 else
1366 type |= vo_wm_ABOVE;
1367 } else if (!strcmp(arg, "fullscreen"))
1369 if (neg)
1370 type &= ~vo_wm_FULLSCREEN;
1371 else
1372 type |= vo_wm_FULLSCREEN;
1373 } else if (!strcmp(arg, "stays_on_top"))
1375 if (neg)
1376 type &= ~vo_wm_STAYS_ON_TOP;
1377 else
1378 type |= vo_wm_STAYS_ON_TOP;
1379 } else if (!strcmp(arg, "below"))
1381 if (neg)
1382 type &= ~vo_wm_BELOW;
1383 else
1384 type |= vo_wm_BELOW;
1385 } else if (!strcmp(arg, "netwm"))
1387 if (neg)
1388 type &= ~vo_wm_NETWM;
1389 else
1390 type |= vo_wm_NETWM;
1391 } else if (!strcmp(arg, "none"))
1392 return 0;
1396 return type;
1399 void vo_x11_fullscreen(void)
1401 int x, y, w, h;
1403 if (WinID >= 0 || vo_fs_flip)
1404 return;
1406 if (vo_fs)
1408 // fs->win
1409 if ( ! (vo_fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs
1411 if (vo_dwidth != vo_screenwidth && vo_dheight != vo_screenheight)
1412 return;
1413 x = vo_old_x;
1414 y = vo_old_y;
1415 w = vo_old_width;
1416 h = vo_old_height;
1419 vo_x11_ewmh_fullscreen(_NET_WM_STATE_REMOVE); // removes fullscreen state if wm supports EWMH
1420 vo_fs = VO_FALSE;
1421 } else
1423 // win->fs
1424 vo_x11_ewmh_fullscreen(_NET_WM_STATE_ADD); // sends fullscreen state to be added if wm supports EWMH
1426 vo_fs = VO_TRUE;
1427 if ( ! (vo_fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs
1429 if (vo_old_width &&
1430 (vo_dwidth == vo_screenwidth && vo_dwidth != vo_old_width) &&
1431 (vo_dheight == vo_screenheight && vo_dheight != vo_old_height))
1432 return;
1433 vo_old_x = vo_dx;
1434 vo_old_y = vo_dy;
1435 vo_old_width = vo_dwidth;
1436 vo_old_height = vo_dheight;
1437 x = 0;
1438 y = 0;
1439 w = vo_screenwidth;
1440 h = vo_screenheight;
1444 long dummy;
1446 XGetWMNormalHints(mDisplay, vo_window, &vo_hint, &dummy);
1447 if (!(vo_hint.flags & PWinGravity))
1448 old_gravity = NorthWestGravity;
1449 else
1450 old_gravity = vo_hint.win_gravity;
1452 if (vo_wm_type == 0 && !(vo_fsmode & 16))
1454 XUnmapWindow(mDisplay, vo_window); // required for MWM
1455 XWithdrawWindow(mDisplay, vo_window, mScreen);
1456 vo_fs_flip = 1;
1459 if ( ! (vo_fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs
1461 vo_x11_decoration(mDisplay, vo_window, (vo_fs) ? 0 : 1);
1462 vo_x11_sizehint(x, y, w, h, 0);
1463 vo_x11_setlayer(mDisplay, vo_window, vo_fs);
1465 if ((!(vo_fs)) & vo_ontop)
1466 vo_x11_setlayer(mDisplay, vo_window, vo_ontop);
1468 XMoveResizeWindow(mDisplay, vo_window, x, y, w, h);
1470 #ifdef HAVE_XINERAMA
1471 vo_x11_xinerama_move(mDisplay, vo_window);
1472 #endif
1474 XMapRaised(mDisplay, vo_window);
1475 XRaiseWindow(mDisplay, vo_window);
1476 XFlush(mDisplay);
1479 void vo_x11_ontop(void)
1481 vo_ontop = (!(vo_ontop));
1483 vo_x11_setlayer(mDisplay, vo_window, vo_ontop);
1487 * XScreensaver stuff
1490 static int got_badwindow;
1491 static XErrorHandler old_handler;
1493 static int badwindow_handler(Display * dpy, XErrorEvent * error)
1495 if (error->error_code != BadWindow)
1496 return (*old_handler) (dpy, error);
1498 got_badwindow = True;
1499 return 0;
1502 static Window find_xscreensaver_window(Display * dpy)
1504 int i;
1505 Window root = RootWindowOfScreen(DefaultScreenOfDisplay(dpy));
1506 Window root2, parent, *kids;
1507 Window retval = 0;
1508 Atom xs_version;
1509 unsigned int nkids = 0;
1511 xs_version = XInternAtom(dpy, "_SCREENSAVER_VERSION", True);
1513 if (!(xs_version != None &&
1514 XQueryTree(dpy, root, &root2, &parent, &kids, &nkids) &&
1515 kids && nkids))
1516 return 0;
1518 old_handler = XSetErrorHandler(badwindow_handler);
1520 for (i = 0; i < nkids; i++)
1522 Atom type;
1523 int format;
1524 unsigned long nitems, bytesafter;
1525 char *v;
1526 int status;
1528 got_badwindow = False;
1529 status =
1530 XGetWindowProperty(dpy, kids[i], xs_version, 0, 200, False,
1531 XA_STRING, &type, &format, &nitems,
1532 &bytesafter, (unsigned char **) &v);
1533 XSync(dpy, False);
1534 if (got_badwindow)
1535 status = BadWindow;
1537 if (status == Success && type != None)
1539 retval = kids[i];
1540 break;
1543 XFree(kids);
1544 XSetErrorHandler(old_handler);
1546 return retval;
1549 static Window xs_windowid = 0;
1550 static Atom deactivate;
1551 static Atom screensaver;
1553 static unsigned int time_last;
1555 void xscreensaver_heartbeat(void)
1557 unsigned int time = GetTimerMS();
1558 XEvent ev;
1560 if (mDisplay && xs_windowid &&
1561 ((time - time_last) > 30000 || (time - time_last) < 0))
1563 time_last = time;
1565 ev.xany.type = ClientMessage;
1566 ev.xclient.display = mDisplay;
1567 ev.xclient.window = xs_windowid;
1568 ev.xclient.message_type = screensaver;
1569 ev.xclient.format = 32;
1570 memset(&ev.xclient.data, 0, sizeof(ev.xclient.data));
1571 ev.xclient.data.l[0] = (long) deactivate;
1573 mp_msg(MSGT_VO, MSGL_DBG2, "Pinging xscreensaver.\n");
1574 XSendEvent(mDisplay, xs_windowid, False, 0L, &ev);
1575 XSync(mDisplay, False);
1579 static void xscreensaver_disable(Display * dpy)
1581 mp_msg(MSGT_VO, MSGL_DBG2, "xscreensaver_disable()\n");
1583 xs_windowid = find_xscreensaver_window(dpy);
1584 if (!xs_windowid)
1586 mp_msg(MSGT_VO, MSGL_INFO,
1587 "xscreensaver_disable: Could not find xscreensaver window.\n");
1588 return;
1590 mp_msg(MSGT_VO, MSGL_INFO,
1591 "xscreensaver_disable: xscreensaver wid=%d.\n", xs_windowid);
1593 deactivate = XInternAtom(dpy, "DEACTIVATE", False);
1594 screensaver = XInternAtom(dpy, "SCREENSAVER", False);
1597 static void xscreensaver_enable(void)
1599 xs_windowid = 0;
1603 * End of XScreensaver stuff
1606 void saver_on(Display * mDisplay)
1609 #ifdef HAVE_XDPMS
1610 int nothing;
1612 if (dpms_disabled)
1614 if (DPMSQueryExtension(mDisplay, &nothing, &nothing))
1616 if (!DPMSEnable(mDisplay))
1617 { // restoring power saving settings
1618 mp_msg(MSGT_VO, MSGL_WARN, "DPMS not available?\n");
1619 } else
1621 // DPMS does not seem to be enabled unless we call DPMSInfo
1622 BOOL onoff;
1623 CARD16 state;
1625 DPMSForceLevel(mDisplay, DPMSModeOn);
1626 DPMSInfo(mDisplay, &state, &onoff);
1627 if (onoff)
1629 mp_msg(MSGT_VO, MSGL_INFO,
1630 "Successfully enabled DPMS\n");
1631 } else
1633 mp_msg(MSGT_VO, MSGL_WARN, "Could not enable DPMS\n");
1637 dpms_disabled = 0;
1639 #endif
1641 if (timeout_save)
1643 int dummy, interval, prefer_blank, allow_exp;
1645 XGetScreenSaver(mDisplay, &dummy, &interval, &prefer_blank,
1646 &allow_exp);
1647 XSetScreenSaver(mDisplay, timeout_save, interval, prefer_blank,
1648 allow_exp);
1649 XGetScreenSaver(mDisplay, &timeout_save, &interval, &prefer_blank,
1650 &allow_exp);
1651 timeout_save = 0;
1654 if (stop_xscreensaver)
1655 xscreensaver_enable();
1656 if (kdescreensaver_was_running && stop_xscreensaver)
1658 system
1659 ("dcop kdesktop KScreensaverIface enable true 2>/dev/null >/dev/null");
1660 kdescreensaver_was_running = 0;
1666 void saver_off(Display * mDisplay)
1669 int interval, prefer_blank, allow_exp;
1671 #ifdef HAVE_XDPMS
1672 int nothing;
1674 if (DPMSQueryExtension(mDisplay, &nothing, &nothing))
1676 BOOL onoff;
1677 CARD16 state;
1679 DPMSInfo(mDisplay, &state, &onoff);
1680 if (onoff)
1682 Status stat;
1684 mp_msg(MSGT_VO, MSGL_INFO, "Disabling DPMS\n");
1685 dpms_disabled = 1;
1686 stat = DPMSDisable(mDisplay); // monitor powersave off
1687 mp_msg(MSGT_VO, MSGL_V, "DPMSDisable stat: %d\n", stat);
1690 #endif
1691 if (!timeout_save)
1693 XGetScreenSaver(mDisplay, &timeout_save, &interval, &prefer_blank,
1694 &allow_exp);
1695 if (timeout_save)
1696 XSetScreenSaver(mDisplay, 0, interval, prefer_blank,
1697 allow_exp);
1699 // turning off screensaver
1700 if (stop_xscreensaver)
1701 xscreensaver_disable(mDisplay);
1702 if (stop_xscreensaver && !kdescreensaver_was_running)
1704 kdescreensaver_was_running =
1705 (system
1706 ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null | sed 's/1/true/g' | grep true 2>/dev/null >/dev/null")
1707 == 0);
1708 if (kdescreensaver_was_running)
1709 system
1710 ("dcop kdesktop KScreensaverIface enable false 2>/dev/null >/dev/null");
1714 static XErrorHandler old_handler = NULL;
1715 static int selectinput_err = 0;
1716 static int x11_selectinput_errorhandler(Display * display,
1717 XErrorEvent * event)
1719 if (event->error_code == BadAccess)
1721 selectinput_err = 1;
1722 mp_msg(MSGT_VO, MSGL_ERR,
1723 "X11 error: BadAccess during XSelectInput Call\n");
1724 mp_msg(MSGT_VO, MSGL_ERR,
1725 "X11 error: The 'ButtonPressMask' mask of specified window has probably already used by another appication (see man XSelectInput)\n");
1726 /* If you think mplayer should shutdown with this error, comments out following line */
1727 return 0;
1729 if (old_handler != NULL)
1730 old_handler(display, event);
1731 else
1732 x11_errorhandler(display, event);
1733 return 0;
1736 void vo_x11_selectinput_witherr(Display * display, Window w,
1737 long event_mask)
1739 XSync(display, False);
1740 old_handler = XSetErrorHandler(x11_selectinput_errorhandler);
1741 selectinput_err = 0;
1742 if (vo_nomouse_input)
1744 XSelectInput(display, w,
1745 event_mask &
1746 (~(ButtonPressMask | ButtonReleaseMask)));
1747 } else
1749 XSelectInput(display, w, event_mask);
1751 XSync(display, False);
1752 XSetErrorHandler(old_handler);
1753 if (selectinput_err)
1755 mp_msg(MSGT_VO, MSGL_ERR,
1756 "X11 error: MPlayer discards mouse control (reconfiguring)\n");
1757 XSelectInput(display, w,
1758 event_mask &
1760 (ButtonPressMask | ButtonReleaseMask |
1761 PointerMotionMask)));
1765 #ifdef HAVE_XINERAMA
1766 void vo_x11_xinerama_move(Display * dsp, Window w)
1768 if (XineramaIsActive(dsp) && !geometry_xy_changed)
1770 /* printf("XXXX Xinerama screen: x: %hd y: %hd\n",xinerama_x,xinerama_y); */
1771 XMoveWindow(dsp, w, xinerama_x, xinerama_y);
1774 #endif
1776 #ifdef HAVE_XF86VM
1777 void vo_vm_switch(uint32_t X, uint32_t Y, int *modeline_width,
1778 int *modeline_height)
1780 unsigned int vm_event, vm_error;
1781 unsigned int vm_ver, vm_rev;
1782 int i, j, have_vm = 0;
1784 int modecount;
1786 if (XF86VidModeQueryExtension(mDisplay, &vm_event, &vm_error))
1788 XF86VidModeQueryVersion(mDisplay, &vm_ver, &vm_rev);
1789 mp_msg(MSGT_VO, MSGL_V, "XF86VidMode Extension v%i.%i\n", vm_ver,
1790 vm_rev);
1791 have_vm = 1;
1792 } else
1793 mp_msg(MSGT_VO, MSGL_WARN,
1794 "XF86VidMode Extenstion not available.\n");
1796 if (have_vm)
1798 if (vidmodes == NULL)
1799 XF86VidModeGetAllModeLines(mDisplay, mScreen, &modecount,
1800 &vidmodes);
1801 j = 0;
1802 *modeline_width = vidmodes[0]->hdisplay;
1803 *modeline_height = vidmodes[0]->vdisplay;
1805 for (i = 1; i < modecount; i++)
1806 if ((vidmodes[i]->hdisplay >= X)
1807 && (vidmodes[i]->vdisplay >= Y))
1808 if ((vidmodes[i]->hdisplay <= *modeline_width)
1809 && (vidmodes[i]->vdisplay <= *modeline_height))
1811 *modeline_width = vidmodes[i]->hdisplay;
1812 *modeline_height = vidmodes[i]->vdisplay;
1813 j = i;
1816 mp_msg(MSGT_VO, MSGL_INFO,
1817 "XF86VM: Selected video mode %dx%d for image size %dx%d.\n",
1818 *modeline_width, *modeline_height, X, Y);
1819 XF86VidModeLockModeSwitch(mDisplay, mScreen, 0);
1820 XF86VidModeSwitchToMode(mDisplay, mScreen, vidmodes[j]);
1821 XF86VidModeSwitchToMode(mDisplay, mScreen, vidmodes[j]);
1822 X = (vo_screenwidth - *modeline_width) / 2;
1823 Y = (vo_screenheight - *modeline_height) / 2;
1824 XF86VidModeSetViewPort(mDisplay, mScreen, X, Y);
1828 void vo_vm_close(Display * dpy)
1830 #ifdef HAVE_NEW_GUI
1831 if (vidmodes != NULL && vo_window != None)
1832 #else
1833 if (vidmodes != NULL)
1834 #endif
1836 int i, modecount;
1837 int screen;
1839 screen = DefaultScreen(dpy);
1841 free(vidmodes);
1842 vidmodes = NULL;
1843 XF86VidModeGetAllModeLines(mDisplay, mScreen, &modecount,
1844 &vidmodes);
1845 for (i = 0; i < modecount; i++)
1846 if ((vidmodes[i]->hdisplay == vo_screenwidth)
1847 && (vidmodes[i]->vdisplay == vo_screenheight))
1849 mp_msg(MSGT_VO, MSGL_INFO,
1850 "Returning to original mode %dx%d\n",
1851 vo_screenwidth, vo_screenheight);
1852 break;
1855 XF86VidModeSwitchToMode(dpy, screen, vidmodes[i]);
1856 XF86VidModeSwitchToMode(dpy, screen, vidmodes[i]);
1857 free(vidmodes);
1858 vidmodes = NULL;
1861 #endif
1863 #endif /* X11_FULLSCREEN */
1867 * Scan the available visuals on this Display/Screen. Try to find
1868 * the 'best' available TrueColor visual that has a decent color
1869 * depth (at least 15bit). If there are multiple visuals with depth
1870 * >= 15bit, we prefer visuals with a smaller color depth.
1872 int vo_find_depth_from_visuals(Display * dpy, int screen,
1873 Visual ** visual_return)
1875 XVisualInfo visual_tmpl;
1876 XVisualInfo *visuals;
1877 int nvisuals, i;
1878 int bestvisual = -1;
1879 int bestvisual_depth = -1;
1881 visual_tmpl.screen = screen;
1882 visual_tmpl.class = TrueColor;
1883 visuals = XGetVisualInfo(dpy,
1884 VisualScreenMask | VisualClassMask,
1885 &visual_tmpl, &nvisuals);
1886 if (visuals != NULL)
1888 for (i = 0; i < nvisuals; i++)
1890 mp_msg(MSGT_VO, MSGL_V,
1891 "vo: X11 truecolor visual %#x, depth %d, R:%lX G:%lX B:%lX\n",
1892 visuals[i].visualid, visuals[i].depth,
1893 visuals[i].red_mask, visuals[i].green_mask,
1894 visuals[i].blue_mask);
1896 * save the visual index and it's depth, if this is the first
1897 * truecolor visul, or a visual that is 'preferred' over the
1898 * previous 'best' visual
1900 if (bestvisual_depth == -1
1901 || (visuals[i].depth >= 15
1902 && (visuals[i].depth < bestvisual_depth
1903 || bestvisual_depth < 15)))
1905 bestvisual = i;
1906 bestvisual_depth = visuals[i].depth;
1910 if (bestvisual != -1 && visual_return != NULL)
1911 *visual_return = visuals[bestvisual].visual;
1913 XFree(visuals);
1915 return bestvisual_depth;
1919 static Colormap cmap = None;
1920 static XColor cols[256];
1921 static int cm_size, red_mask, green_mask, blue_mask;
1924 Colormap vo_x11_create_colormap(XVisualInfo * vinfo)
1926 unsigned k, r, g, b, ru, gu, bu, m, rv, gv, bv, rvu, gvu, bvu;
1928 if (vinfo->class != DirectColor)
1929 return XCreateColormap(mDisplay, mRootWin, vinfo->visual,
1930 AllocNone);
1932 /* can this function get called twice or more? */
1933 if (cmap)
1934 return cmap;
1935 cm_size = vinfo->colormap_size;
1936 red_mask = vinfo->red_mask;
1937 green_mask = vinfo->green_mask;
1938 blue_mask = vinfo->blue_mask;
1939 ru = (red_mask & (red_mask - 1)) ^ red_mask;
1940 gu = (green_mask & (green_mask - 1)) ^ green_mask;
1941 bu = (blue_mask & (blue_mask - 1)) ^ blue_mask;
1942 rvu = 65536ull * ru / (red_mask + ru);
1943 gvu = 65536ull * gu / (green_mask + gu);
1944 bvu = 65536ull * bu / (blue_mask + bu);
1945 r = g = b = 0;
1946 rv = gv = bv = 0;
1947 m = DoRed | DoGreen | DoBlue;
1948 for (k = 0; k < cm_size; k++)
1950 int t;
1952 cols[k].pixel = r | g | b;
1953 cols[k].red = rv;
1954 cols[k].green = gv;
1955 cols[k].blue = bv;
1956 cols[k].flags = m;
1957 t = (r + ru) & red_mask;
1958 if (t < r)
1959 m &= ~DoRed;
1960 r = t;
1961 t = (g + gu) & green_mask;
1962 if (t < g)
1963 m &= ~DoGreen;
1964 g = t;
1965 t = (b + bu) & blue_mask;
1966 if (t < b)
1967 m &= ~DoBlue;
1968 b = t;
1969 rv += rvu;
1970 gv += gvu;
1971 bv += bvu;
1973 cmap = XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocAll);
1974 XStoreColors(mDisplay, cmap, cols, cm_size);
1975 return cmap;
1979 * Via colormaps/gamma ramps we can do gamma, brightness, contrast,
1980 * hue and red/green/blue intensity, but we cannot do saturation.
1981 * Currently only gamma, brightness and contrast are implemented.
1982 * Is there sufficient interest for hue and/or red/green/blue intensity?
1984 /* these values have range [-100,100] and are initially 0 */
1985 static int vo_gamma = 0;
1986 static int vo_brightness = 0;
1987 static int vo_contrast = 0;
1990 uint32_t vo_x11_set_equalizer(char *name, int value)
1992 float gamma, brightness, contrast;
1993 float rf, gf, bf;
1994 int k;
1997 * IMPLEMENTME: consider using XF86VidModeSetGammaRamp in the case
1998 * of TrueColor-ed window but be careful:
1999 * unlike the colormaps, which are private for the X client
2000 * who created them and thus automatically destroyed on client
2001 * disconnect, this gamma ramp is a system-wide (X-server-wide)
2002 * setting and _must_ be restored before the process exit.
2003 * Unforunately when the process crashes (or get killed
2004 * for some reason) it is impossible to restore the setting,
2005 * and such behaviour could be rather annoying for the users.
2007 if (cmap == None)
2008 return VO_NOTAVAIL;
2010 if (!strcasecmp(name, "brightness"))
2011 vo_brightness = value;
2012 else if (!strcasecmp(name, "contrast"))
2013 vo_contrast = value;
2014 else if (!strcasecmp(name, "gamma"))
2015 vo_gamma = value;
2016 else
2017 return VO_NOTIMPL;
2019 brightness = 0.01 * vo_brightness;
2020 contrast = tan(0.0095 * (vo_contrast + 100) * M_PI / 4);
2021 gamma = pow(2, -0.02 * vo_gamma);
2023 rf = (float) ((red_mask & (red_mask - 1)) ^ red_mask) / red_mask;
2024 gf = (float) ((green_mask & (green_mask - 1)) ^ green_mask) /
2025 green_mask;
2026 bf = (float) ((blue_mask & (blue_mask - 1)) ^ blue_mask) / blue_mask;
2028 /* now recalculate the colormap using the newly set value */
2029 for (k = 0; k < cm_size; k++)
2031 float s;
2033 s = pow(rf * k, gamma);
2034 s = (s - 0.5) * contrast + 0.5;
2035 s += brightness;
2036 if (s < 0)
2037 s = 0;
2038 if (s > 1)
2039 s = 1;
2040 cols[k].red = (unsigned short) (s * 65535);
2042 s = pow(gf * k, gamma);
2043 s = (s - 0.5) * contrast + 0.5;
2044 s += brightness;
2045 if (s < 0)
2046 s = 0;
2047 if (s > 1)
2048 s = 1;
2049 cols[k].green = (unsigned short) (s * 65535);
2051 s = pow(bf * k, gamma);
2052 s = (s - 0.5) * contrast + 0.5;
2053 s += brightness;
2054 if (s < 0)
2055 s = 0;
2056 if (s > 1)
2057 s = 1;
2058 cols[k].blue = (unsigned short) (s * 65535);
2061 XStoreColors(mDisplay, cmap, cols, cm_size);
2062 XFlush(mDisplay);
2063 return VO_TRUE;
2066 uint32_t vo_x11_get_equalizer(char *name, int *value)
2068 if (cmap == None)
2069 return VO_NOTAVAIL;
2070 if (!strcasecmp(name, "brightness"))
2071 *value = vo_brightness;
2072 else if (!strcasecmp(name, "contrast"))
2073 *value = vo_contrast;
2074 else if (!strcasecmp(name, "gamma"))
2075 *value = vo_gamma;
2076 else
2077 return VO_NOTIMPL;
2078 return VO_TRUE;
2081 #ifdef HAVE_XV
2082 int vo_xv_set_eq(uint32_t xv_port, char *name, int value)
2084 XvAttribute *attributes;
2085 int i, howmany, xv_atom;
2087 mp_dbg(MSGT_VO, MSGL_V, "xv_set_eq called! (%s, %d)\n", name, value);
2089 /* get available attributes */
2090 attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
2091 for (i = 0; i < howmany && attributes; i++)
2092 if (attributes[i].flags & XvSettable)
2094 xv_atom = XInternAtom(mDisplay, attributes[i].name, True);
2095 /* since we have SET_DEFAULTS first in our list, we can check if it's available
2096 then trigger it if it's ok so that the other values are at default upon query */
2097 if (xv_atom != None)
2099 int hue = 0, port_value, port_min, port_max;
2101 if (!strcmp(attributes[i].name, "XV_BRIGHTNESS") &&
2102 (!strcasecmp(name, "brightness")))
2103 port_value = value;
2104 else if (!strcmp(attributes[i].name, "XV_CONTRAST") &&
2105 (!strcasecmp(name, "contrast")))
2106 port_value = value;
2107 else if (!strcmp(attributes[i].name, "XV_SATURATION") &&
2108 (!strcasecmp(name, "saturation")))
2109 port_value = value;
2110 else if (!strcmp(attributes[i].name, "XV_HUE") &&
2111 (!strcasecmp(name, "hue")))
2113 port_value = value;
2114 hue = 1;
2115 } else
2116 /* Note: since 22.01.2002 GATOS supports these attrs for radeons (NK) */
2117 if (!strcmp(attributes[i].name, "XV_RED_INTENSITY") &&
2118 (!strcasecmp(name, "red_intensity")))
2119 port_value = value;
2120 else if (!strcmp(attributes[i].name, "XV_GREEN_INTENSITY")
2121 && (!strcasecmp(name, "green_intensity")))
2122 port_value = value;
2123 else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY")
2124 && (!strcasecmp(name, "blue_intensity")))
2125 port_value = value;
2126 else
2127 continue;
2129 port_min = attributes[i].min_value;
2130 port_max = attributes[i].max_value;
2132 /* nvidia hue workaround */
2133 if (hue && port_min == 0 && port_max == 360)
2135 port_value =
2136 (port_value >=
2137 0) ? (port_value - 100) : (port_value + 100);
2139 // -100 -> min
2140 // 0 -> (max+min)/2
2141 // +100 -> max
2142 port_value =
2143 (port_value + 100) * (port_max - port_min) / 200 +
2144 port_min;
2145 XvSetPortAttribute(mDisplay, xv_port, xv_atom, port_value);
2146 return (VO_TRUE);
2149 return (VO_FALSE);
2152 int vo_xv_get_eq(uint32_t xv_port, char *name, int *value)
2155 XvAttribute *attributes;
2156 int i, howmany, xv_atom;
2158 /* get available attributes */
2159 attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
2160 for (i = 0; i < howmany && attributes; i++)
2161 if (attributes[i].flags & XvGettable)
2163 xv_atom = XInternAtom(mDisplay, attributes[i].name, True);
2164 /* since we have SET_DEFAULTS first in our list, we can check if it's available
2165 then trigger it if it's ok so that the other values are at default upon query */
2166 if (xv_atom != None)
2168 int val, port_value = 0, port_min, port_max;
2170 XvGetPortAttribute(mDisplay, xv_port, xv_atom,
2171 &port_value);
2173 port_min = attributes[i].min_value;
2174 port_max = attributes[i].max_value;
2175 val =
2176 (port_value - port_min) * 200 / (port_max - port_min) -
2177 100;
2179 if (!strcmp(attributes[i].name, "XV_BRIGHTNESS") &&
2180 (!strcasecmp(name, "brightness")))
2181 *value = val;
2182 else if (!strcmp(attributes[i].name, "XV_CONTRAST") &&
2183 (!strcasecmp(name, "contrast")))
2184 *value = val;
2185 else if (!strcmp(attributes[i].name, "XV_SATURATION") &&
2186 (!strcasecmp(name, "saturation")))
2187 *value = val;
2188 else if (!strcmp(attributes[i].name, "XV_HUE") &&
2189 (!strcasecmp(name, "hue")))
2191 /* nasty nvidia detect */
2192 if (port_min == 0 && port_max == 360)
2193 *value = (val >= 0) ? (val - 100) : (val + 100);
2194 else
2195 *value = val;
2196 } else
2197 /* Note: since 22.01.2002 GATOS supports these attrs for radeons (NK) */
2198 if (!strcmp(attributes[i].name, "XV_RED_INTENSITY") &&
2199 (!strcasecmp(name, "red_intensity")))
2200 *value = val;
2201 else if (!strcmp(attributes[i].name, "XV_GREEN_INTENSITY")
2202 && (!strcasecmp(name, "green_intensity")))
2203 *value = val;
2204 else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY")
2205 && (!strcasecmp(name, "blue_intensity")))
2206 *value = val;
2207 else
2208 continue;
2210 mp_dbg(MSGT_VO, MSGL_V, "xv_get_eq called! (%s, %d)\n",
2211 name, *value);
2212 return (VO_TRUE);
2215 return (VO_FALSE);
2218 #endif