Revert OSD flicker fixes done better in another branch
[mplayer.git] / libvo / vo_xv.c
blob7b1aeabd8e82509304f75446ba50cfdd5ce243bb
1 /* vo_xv.c, X11 Xv interface */
3 // Number of buffers _FOR_DOUBLEBUFFERING_MODE_
4 // Use option -double to enable double buffering! (default: single buffer)
5 #define NUM_BUFFERS 3
7 /*
8 Buffer allocation:
10 -nodr:
11 1: TEMP
12 2: 2*TEMP
14 -dr:
15 1: TEMP
16 3: 2*STATIC+TEMP
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "help_mp.h"
26 #include "video_out.h"
27 #include "video_out_internal.h"
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <errno.h>
34 #include "x11_common.h"
36 #include "fastmemcpy.h"
37 #include "sub.h"
38 #include "aspect.h"
40 #include "subopt-helper.h"
42 #include "input/input.h"
44 #ifdef CONFIG_GUI
45 #include "gui/interface.h"
46 #endif
48 #include "libavutil/common.h"
50 static const vo_info_t info = {
51 "X11/Xv",
52 "xv",
53 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
57 const LIBVO_EXTERN(xv)
58 #ifdef HAVE_SHM
59 #include <sys/ipc.h>
60 #include <sys/shm.h>
61 #include <X11/extensions/XShm.h>
63 static XShmSegmentInfo Shminfo[NUM_BUFFERS];
64 static int Shmem_Flag;
65 #endif
67 // Note: depends on the inclusion of X11/extensions/XShm.h
68 #include <X11/extensions/Xv.h>
69 #include <X11/extensions/Xvlib.h>
71 // FIXME: dynamically allocate this stuff
72 static void allocate_xvimage(int);
73 static unsigned int ver, rel, req, ev, err;
74 static unsigned int formats, adaptors, xv_format;
75 static XvAdaptorInfo *ai = NULL;
76 static XvImageFormatValues *fo=NULL;
78 static int current_buf = 0;
79 static int current_ip_buf = 0;
80 static int num_buffers = 1; // default
81 static int visible_buf = -1; // -1 means: no buffer was drawn yet
82 static XvImage *xvimage[NUM_BUFFERS];
85 static uint32_t image_width;
86 static uint32_t image_height;
87 static uint32_t image_format;
89 static int int_pause;
91 static uint32_t drwX, drwY;
92 static uint32_t max_width = 0, max_height = 0; // zero means: not set
94 static void (*draw_alpha_fnc) (int x0, int y0, int w, int h,
95 unsigned char *src, unsigned char *srca,
96 int stride);
98 static void draw_alpha_yv12(int x0, int y0, int w, int h,
99 unsigned char *src, unsigned char *srca,
100 int stride)
102 x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
103 vo_draw_alpha_yv12(w, h, src, srca, stride,
104 xvimage[current_buf]->data +
105 xvimage[current_buf]->offsets[0] +
106 xvimage[current_buf]->pitches[0] * y0 + x0,
107 xvimage[current_buf]->pitches[0]);
110 static void draw_alpha_yuy2(int x0, int y0, int w, int h,
111 unsigned char *src, unsigned char *srca,
112 int stride)
114 x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
115 vo_draw_alpha_yuy2(w, h, src, srca, stride,
116 xvimage[current_buf]->data +
117 xvimage[current_buf]->offsets[0] +
118 xvimage[current_buf]->pitches[0] * y0 + 2 * x0,
119 xvimage[current_buf]->pitches[0]);
122 static void draw_alpha_uyvy(int x0, int y0, int w, int h,
123 unsigned char *src, unsigned char *srca,
124 int stride)
126 x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
127 vo_draw_alpha_yuy2(w, h, src, srca, stride,
128 xvimage[current_buf]->data +
129 xvimage[current_buf]->offsets[0] +
130 xvimage[current_buf]->pitches[0] * y0 + 2 * x0 + 1,
131 xvimage[current_buf]->pitches[0]);
134 static void draw_alpha_null(int x0, int y0, int w, int h,
135 unsigned char *src, unsigned char *srca,
136 int stride)
141 static void deallocate_xvimage(int foo);
144 * connect to server, create and map window,
145 * allocate colors and (shared) memory
147 static int config(uint32_t width, uint32_t height, uint32_t d_width,
148 uint32_t d_height, uint32_t flags, char *title,
149 uint32_t format)
151 XVisualInfo vinfo;
152 XSetWindowAttributes xswa;
153 XWindowAttributes attribs;
154 unsigned long xswamask;
155 int depth;
157 #ifdef CONFIG_XF86VM
158 int vm = flags & VOFLAG_MODESWITCHING;
159 #endif
161 image_height = height;
162 image_width = width;
163 image_format = format;
165 if ((max_width != 0 && max_height != 0) &&
166 (image_width > max_width || image_height > max_height))
168 mp_msg( MSGT_VO, MSGL_ERR, MSGTR_VO_XV_ImagedimTooHigh,
169 image_width, image_height, max_width, max_height);
170 return -1;
173 int_pause = 0;
174 visible_buf = -1;
176 num_buffers =
177 vo_doublebuffering ? (vo_directrendering ? NUM_BUFFERS : 2) : 1;
179 /* check image formats */
181 unsigned int i;
183 xv_format = 0;
184 for (i = 0; i < formats; i++)
186 mp_msg(MSGT_VO, MSGL_V,
187 "Xvideo image format: 0x%x (%4.4s) %s\n", fo[i].id,
188 (char *) &fo[i].id,
189 (fo[i].format == XvPacked) ? "packed" : "planar");
190 if (fo[i].id == format)
191 xv_format = fo[i].id;
193 if (!xv_format)
194 return -1;
197 #ifdef CONFIG_GUI
198 if (use_gui)
199 guiGetEvent(guiSetShVideo, 0); // the GUI will set up / resize the window
200 else
201 #endif
203 #ifdef CONFIG_XF86VM
204 if (vm)
206 vo_vm_switch();
208 #endif
209 XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay),
210 &attribs);
211 depth = attribs.depth;
212 if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
213 depth = 24;
214 XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &vinfo);
216 xswa.background_pixel = 0;
217 if (xv_ck_info.method == CK_METHOD_BACKGROUND)
219 xswa.background_pixel = xv_colorkey;
221 xswa.border_pixel = 0;
222 xswamask = CWBackPixel | CWBorderPixel;
224 vo_x11_create_vo_window(&vinfo, vo_dx, vo_dy, vo_dwidth, vo_dheight,
225 flags, CopyFromParent, "xv", title);
226 XChangeWindowAttributes(mDisplay, vo_window, xswamask, &xswa);
228 #ifdef CONFIG_XF86VM
229 if (vm)
231 /* Grab the mouse pointer in our window */
232 if (vo_grabpointer)
233 XGrabPointer(mDisplay, vo_window, True, 0,
234 GrabModeAsync, GrabModeAsync,
235 vo_window, None, CurrentTime);
236 XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
238 #endif
241 mp_msg(MSGT_VO, MSGL_V, "using Xvideo port %d for hw scaling\n",
242 xv_port);
244 switch (xv_format)
246 case IMGFMT_YV12:
247 case IMGFMT_I420:
248 case IMGFMT_IYUV:
249 draw_alpha_fnc = draw_alpha_yv12;
250 break;
251 case IMGFMT_YUY2:
252 case IMGFMT_YVYU:
253 draw_alpha_fnc = draw_alpha_yuy2;
254 break;
255 case IMGFMT_UYVY:
256 draw_alpha_fnc = draw_alpha_uyvy;
257 break;
258 default:
259 draw_alpha_fnc = draw_alpha_null;
262 if (vo_config_count)
263 for (current_buf = 0; current_buf < num_buffers; ++current_buf)
264 deallocate_xvimage(current_buf);
266 for (current_buf = 0; current_buf < num_buffers; ++current_buf)
267 allocate_xvimage(current_buf);
269 current_buf = 0;
270 current_ip_buf = 0;
272 if ((flags & VOFLAG_FULLSCREEN) && WinID <= 0) vo_fs = 1;
273 vo_calc_drwXY(&drwX, &drwY);
275 panscan_calc();
277 vo_xv_draw_colorkey(drwX - (vo_panscan_x >> 1),
278 drwY - (vo_panscan_y >> 1),
279 vo_dwidth + vo_panscan_x - 1,
280 vo_dheight + vo_panscan_y - 1);
282 mp_msg(MSGT_VO, MSGL_V, "[xv] dx: %d dy: %d dw: %d dh: %d\n", drwX,
283 drwY, vo_dwidth, vo_dheight);
285 return 0;
288 static void allocate_xvimage(int foo)
291 * allocate XvImages. FIXME: no error checking, without
292 * mit-shm this will bomb... trzing to fix ::atmos
294 #ifdef HAVE_SHM
295 if (mLocalDisplay && XShmQueryExtension(mDisplay))
296 Shmem_Flag = 1;
297 else
299 Shmem_Flag = 0;
300 mp_msg(MSGT_VO, MSGL_INFO,
301 MSGTR_LIBVO_XV_SharedMemoryNotSupported);
303 if (Shmem_Flag)
305 xvimage[foo] =
306 (XvImage *) XvShmCreateImage(mDisplay, xv_port, xv_format,
307 NULL, image_width, image_height,
308 &Shminfo[foo]);
310 Shminfo[foo].shmid =
311 shmget(IPC_PRIVATE, xvimage[foo]->data_size, IPC_CREAT | 0777);
312 Shminfo[foo].shmaddr = (char *) shmat(Shminfo[foo].shmid, 0, 0);
313 Shminfo[foo].readOnly = False;
315 xvimage[foo]->data = Shminfo[foo].shmaddr;
316 XShmAttach(mDisplay, &Shminfo[foo]);
317 XSync(mDisplay, False);
318 shmctl(Shminfo[foo].shmid, IPC_RMID, 0);
319 } else
320 #endif
322 xvimage[foo] =
323 (XvImage *) XvCreateImage(mDisplay, xv_port, xv_format, NULL,
324 image_width, image_height);
325 xvimage[foo]->data = malloc(xvimage[foo]->data_size);
326 XSync(mDisplay, False);
328 memset(xvimage[foo]->data, 128, xvimage[foo]->data_size);
329 return;
332 static void deallocate_xvimage(int foo)
334 #ifdef HAVE_SHM
335 if (Shmem_Flag)
337 XShmDetach(mDisplay, &Shminfo[foo]);
338 shmdt(Shminfo[foo].shmaddr);
339 } else
340 #endif
342 free(xvimage[foo]->data);
344 XFree(xvimage[foo]);
346 XSync(mDisplay, False);
347 return;
350 static inline void put_xvimage( XvImage * xvi )
352 #ifdef HAVE_SHM
353 if (Shmem_Flag)
355 XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc,
356 xvi, 0, 0, image_width,
357 image_height, drwX - (vo_panscan_x >> 1),
358 drwY - (vo_panscan_y >> 1), vo_dwidth + vo_panscan_x,
359 vo_dheight + vo_panscan_y,
360 False);
361 } else
362 #endif
364 XvPutImage(mDisplay, xv_port, vo_window, vo_gc,
365 xvi, 0, 0, image_width, image_height,
366 drwX - (vo_panscan_x >> 1), drwY - (vo_panscan_y >> 1),
367 vo_dwidth + vo_panscan_x,
368 vo_dheight + vo_panscan_y);
372 static void check_events(void)
374 int e = vo_x11_check_events(mDisplay);
376 if (e & VO_EVENT_RESIZE)
378 vo_calc_drwXY(&drwX, &drwY);
381 if (e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE)
383 vo_xv_draw_colorkey(drwX - (vo_panscan_x >> 1),
384 drwY - (vo_panscan_y >> 1),
385 vo_dwidth + vo_panscan_x - 1,
386 vo_dheight + vo_panscan_y - 1);
389 if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && int_pause)
391 /* did we already draw a buffer */
392 if ( visible_buf != -1 )
394 /* redraw the last visible buffer */
395 put_xvimage( xvimage[visible_buf] );
400 static void draw_osd(void)
402 vo_draw_text(image_width -
403 image_width * vo_panscan_x / (vo_dwidth + vo_panscan_x),
404 image_height, draw_alpha_fnc);
407 static void flip_page(void)
409 put_xvimage( xvimage[current_buf] );
411 /* remember the currently visible buffer */
412 visible_buf = current_buf;
414 if (num_buffers > 1)
416 current_buf =
417 vo_directrendering ? 0 : ((current_buf + 1) % num_buffers);
418 XFlush(mDisplay);
419 } else
420 XSync(mDisplay, False);
421 return;
424 static int draw_slice(uint8_t * image[], int stride[], int w, int h,
425 int x, int y)
427 uint8_t *dst;
429 dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[0] +
430 xvimage[current_buf]->pitches[0] * y + x;
431 memcpy_pic(dst, image[0], w, h, xvimage[current_buf]->pitches[0],
432 stride[0]);
434 x /= 2;
435 y /= 2;
436 w /= 2;
437 h /= 2;
439 dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[1] +
440 xvimage[current_buf]->pitches[1] * y + x;
441 if (image_format != IMGFMT_YV12)
442 memcpy_pic(dst, image[1], w, h, xvimage[current_buf]->pitches[1],
443 stride[1]);
444 else
445 memcpy_pic(dst, image[2], w, h, xvimage[current_buf]->pitches[1],
446 stride[2]);
448 dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[2] +
449 xvimage[current_buf]->pitches[2] * y + x;
450 if (image_format == IMGFMT_YV12)
451 memcpy_pic(dst, image[1], w, h, xvimage[current_buf]->pitches[1],
452 stride[1]);
453 else
454 memcpy_pic(dst, image[2], w, h, xvimage[current_buf]->pitches[1],
455 stride[2]);
457 return 0;
460 static int draw_frame(uint8_t * src[])
462 return VO_ERROR;
465 static uint32_t draw_image(mp_image_t * mpi)
467 if (mpi->flags & MP_IMGFLAG_DIRECT)
469 // direct rendering:
470 current_buf = (int) (mpi->priv); // hack!
471 return VO_TRUE;
473 if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
474 return VO_TRUE; // done
475 if (mpi->flags & MP_IMGFLAG_PLANAR)
477 draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0);
478 return VO_TRUE;
480 if (mpi->flags & MP_IMGFLAG_YUV)
482 // packed YUV:
483 memcpy_pic(xvimage[current_buf]->data +
484 xvimage[current_buf]->offsets[0], mpi->planes[0],
485 mpi->w * (mpi->bpp / 8), mpi->h,
486 xvimage[current_buf]->pitches[0], mpi->stride[0]);
487 return VO_TRUE;
489 return VO_FALSE; // not (yet) supported
492 static uint32_t get_image(mp_image_t * mpi)
494 int buf = current_buf; // we shouldn't change current_buf unless we do DR!
496 if (mpi->type == MP_IMGTYPE_STATIC && num_buffers > 1)
497 return VO_FALSE; // it is not static
498 if (mpi->imgfmt != image_format)
499 return VO_FALSE; // needs conversion :(
500 // if(mpi->flags&MP_IMGFLAG_READABLE) return VO_FALSE; // slow video ram
501 if (mpi->flags & MP_IMGFLAG_READABLE &&
502 (mpi->type == MP_IMGTYPE_IPB || mpi->type == MP_IMGTYPE_IP))
504 // reference (I/P) frame of IP or IPB:
505 if (num_buffers < 2)
506 return VO_FALSE; // not enough
507 current_ip_buf ^= 1;
508 // for IPB with 2 buffers we can DR only one of the 2 P frames:
509 if (mpi->type == MP_IMGTYPE_IPB && num_buffers < 3
510 && current_ip_buf)
511 return VO_FALSE;
512 buf = current_ip_buf;
513 if (mpi->type == MP_IMGTYPE_IPB)
514 ++buf; // preserve space for B
516 if (mpi->height > xvimage[buf]->height)
517 return VO_FALSE; //buffer to small
518 if (mpi->width * (mpi->bpp / 8) > xvimage[buf]->pitches[0])
519 return VO_FALSE; //buffer to small
520 if ((mpi->flags & (MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_ACCEPT_WIDTH))
521 || (mpi->width * (mpi->bpp / 8) == xvimage[buf]->pitches[0]))
523 current_buf = buf;
524 mpi->planes[0] =
525 xvimage[current_buf]->data + xvimage[current_buf]->offsets[0];
526 mpi->stride[0] = xvimage[current_buf]->pitches[0];
527 mpi->width = mpi->stride[0] / (mpi->bpp / 8);
528 if (mpi->flags & MP_IMGFLAG_PLANAR)
530 if (mpi->flags & MP_IMGFLAG_SWAPPED)
532 // I420
533 mpi->planes[1] =
534 xvimage[current_buf]->data +
535 xvimage[current_buf]->offsets[1];
536 mpi->planes[2] =
537 xvimage[current_buf]->data +
538 xvimage[current_buf]->offsets[2];
539 mpi->stride[1] = xvimage[current_buf]->pitches[1];
540 mpi->stride[2] = xvimage[current_buf]->pitches[2];
541 } else
543 // YV12
544 mpi->planes[1] =
545 xvimage[current_buf]->data +
546 xvimage[current_buf]->offsets[2];
547 mpi->planes[2] =
548 xvimage[current_buf]->data +
549 xvimage[current_buf]->offsets[1];
550 mpi->stride[1] = xvimage[current_buf]->pitches[2];
551 mpi->stride[2] = xvimage[current_buf]->pitches[1];
554 mpi->flags |= MP_IMGFLAG_DIRECT;
555 mpi->priv = (void *) current_buf;
556 // printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n");
557 return VO_TRUE;
559 return VO_FALSE;
562 static int query_format(uint32_t format)
564 uint32_t i;
565 int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN
567 /* check image formats */
568 for (i = 0; i < formats; i++)
570 if (fo[i].id == format)
571 return flag; //xv_format = fo[i].id;
573 return 0;
576 static void uninit(void)
578 int i;
580 if (!vo_config_count)
581 return;
582 visible_buf = -1;
583 XvFreeAdaptorInfo(ai);
584 ai = NULL;
585 if(fo){
586 XFree(fo);
587 fo=NULL;
589 for (i = 0; i < num_buffers; i++)
590 deallocate_xvimage(i);
591 #ifdef CONFIG_XF86VM
592 vo_vm_close();
593 #endif
594 mp_input_rm_event_fd(ConnectionNumber(mDisplay));
595 vo_x11_uninit();
598 static int preinit(const char *arg)
600 XvPortID xv_p;
601 int busy_ports = 0;
602 unsigned int i;
603 strarg_t ck_src_arg = { 0, NULL };
604 strarg_t ck_method_arg = { 0, NULL };
605 int xv_adaptor = -1;
607 opt_t subopts[] =
609 /* name arg type arg var test */
610 { "port", OPT_ARG_INT, &xv_port, (opt_test_f)int_pos },
611 { "adaptor", OPT_ARG_INT, &xv_adaptor, (opt_test_f)int_non_neg },
612 { "ck", OPT_ARG_STR, &ck_src_arg, xv_test_ck },
613 { "ck-method", OPT_ARG_STR, &ck_method_arg, xv_test_ckm },
614 { NULL }
617 xv_port = 0;
619 /* parse suboptions */
620 if ( subopt_parse( arg, subopts ) != 0 )
622 return -1;
625 /* modify colorkey settings according to the given options */
626 xv_setup_colorkeyhandling( ck_method_arg.str, ck_src_arg.str );
628 if (!vo_init())
629 return -1;
631 /* check for Xvideo extension */
632 if (Success != XvQueryExtension(mDisplay, &ver, &rel, &req, &ev, &err))
634 mp_msg(MSGT_VO, MSGL_ERR,
635 MSGTR_LIBVO_XV_XvNotSupportedByX11);
636 return -1;
639 /* check for Xvideo support */
640 if (Success !=
641 XvQueryAdaptors(mDisplay, DefaultRootWindow(mDisplay), &adaptors,
642 &ai))
644 mp_msg(MSGT_VO, MSGL_ERR, MSGTR_LIBVO_XV_XvQueryAdaptorsFailed);
645 return -1;
648 /* check adaptors */
649 if (xv_port)
651 int port_found;
653 for (port_found = 0, i = 0; !port_found && i < adaptors; i++)
655 if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask))
657 for (xv_p = ai[i].base_id;
658 xv_p < ai[i].base_id + ai[i].num_ports; ++xv_p)
660 if (xv_p == xv_port)
662 port_found = 1;
663 break;
668 if (port_found)
670 if (XvGrabPort(mDisplay, xv_port, CurrentTime))
671 xv_port = 0;
672 } else
674 mp_msg(MSGT_VO, MSGL_WARN,
675 MSGTR_LIBVO_XV_InvalidPortParameter);
676 xv_port = 0;
680 for (i = 0; i < adaptors && xv_port == 0; i++)
682 /* check if adaptor number has been specified */
683 if (xv_adaptor != -1 && xv_adaptor != i)
684 continue;
686 if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask))
688 for (xv_p = ai[i].base_id;
689 xv_p < ai[i].base_id + ai[i].num_ports; ++xv_p)
690 if (!XvGrabPort(mDisplay, xv_p, CurrentTime))
692 xv_port = xv_p;
693 mp_msg(MSGT_VO, MSGL_V,
694 "[VO_XV] Using Xv Adapter #%d (%s)\n",
695 i, ai[i].name);
696 break;
697 } else
699 mp_msg(MSGT_VO, MSGL_WARN,
700 MSGTR_LIBVO_XV_CouldNotGrabPort, (int) xv_p);
701 ++busy_ports;
705 if (!xv_port)
707 if (busy_ports)
708 mp_msg(MSGT_VO, MSGL_ERR,
709 MSGTR_LIBVO_XV_CouldNotFindFreePort);
710 else
711 mp_msg(MSGT_VO, MSGL_ERR,
712 MSGTR_LIBVO_XV_NoXvideoSupport);
713 return -1;
716 if ( !vo_xv_init_colorkey() )
718 return -1; // bail out, colorkey setup failed
720 vo_xv_enable_vsync();
721 vo_xv_get_max_img_dim( &max_width, &max_height );
723 fo = XvListImageFormats(mDisplay, xv_port, (int *) &formats);
725 mp_input_add_event_fd(ConnectionNumber(mDisplay), check_events);
726 return 0;
729 static int control(uint32_t request, void *data, ...)
731 switch (request)
733 case VOCTRL_PAUSE:
734 return int_pause = 1;
735 case VOCTRL_RESUME:
736 return int_pause = 0;
737 case VOCTRL_QUERY_FORMAT:
738 return query_format(*((uint32_t *) data));
739 case VOCTRL_GET_IMAGE:
740 return get_image(data);
741 case VOCTRL_DRAW_IMAGE:
742 return draw_image(data);
743 case VOCTRL_GUISUPPORT:
744 return VO_TRUE;
745 case VOCTRL_GET_PANSCAN:
746 if (!vo_config_count || !vo_fs)
747 return VO_FALSE;
748 return VO_TRUE;
749 case VOCTRL_FULLSCREEN:
750 vo_x11_fullscreen();
751 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
752 case VOCTRL_SET_PANSCAN:
753 if ((vo_fs && (vo_panscan != vo_panscan_amount))
754 || (!vo_fs && vo_panscan_amount))
756 int old_y = vo_panscan_y;
758 panscan_calc();
760 if (old_y != vo_panscan_y)
762 vo_x11_clearwindow_part(mDisplay, vo_window,
763 vo_dwidth + vo_panscan_x - 1,
764 vo_dheight + vo_panscan_y - 1,
766 vo_xv_draw_colorkey(drwX - (vo_panscan_x >> 1),
767 drwY - (vo_panscan_y >> 1),
768 vo_dwidth + vo_panscan_x - 1,
769 vo_dheight + vo_panscan_y - 1);
770 flip_page();
773 return VO_TRUE;
774 case VOCTRL_SET_EQUALIZER:
776 va_list ap;
777 int value;
779 va_start(ap, data);
780 value = va_arg(ap, int);
782 va_end(ap);
784 return vo_xv_set_eq(xv_port, data, value);
786 case VOCTRL_GET_EQUALIZER:
788 va_list ap;
789 int *value;
791 va_start(ap, data);
792 value = va_arg(ap, int *);
794 va_end(ap);
796 return vo_xv_get_eq(xv_port, data, value);
798 case VOCTRL_ONTOP:
799 vo_x11_ontop();
800 return VO_TRUE;
801 case VOCTRL_UPDATE_SCREENINFO:
802 update_xinerama_info();
803 return VO_TRUE;
805 return VO_NOTIMPL;