Improved vout behavior on crop/ar/zoom changes (close #3641).
[vlc/solaris.git] / src / video_output / display.c
blobfa92cf80e24f9e973300744cfdd748e465c68f03
1 /*****************************************************************************
2 * display.c: "vout display" managment
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
5 * $Id$
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
32 #include <vlc_common.h>
33 #include <vlc_video_splitter.h>
34 #include <vlc_vout_display.h>
35 #include <vlc_vout.h>
37 #include <libvlc.h>
39 #include "display.h"
41 #include "event.h"
43 /* It must be present as long as a vout_display_t must be created using a dummy
44 * vout (as an opengl provider) */
45 #define ALLOW_DUMMY_VOUT
47 static void SplitterClose(vout_display_t *vd);
49 /*****************************************************************************
50 * FIXME/TODO see how to have direct rendering here (interact with vout.c)
51 *****************************************************************************/
52 static picture_t *VideoBufferNew(filter_t *filter)
54 vout_display_t *vd = (vout_display_t*)filter->p_owner;
55 const video_format_t *fmt = &filter->fmt_out.video;
57 assert(vd->fmt.i_chroma == fmt->i_chroma &&
58 vd->fmt.i_width == fmt->i_width &&
59 vd->fmt.i_height == fmt->i_height);
61 picture_pool_t *pool = vout_display_Pool(vd, 1);
62 if (!pool)
63 return NULL;
64 return picture_pool_Get(pool);
66 static void VideoBufferDelete(filter_t *filter, picture_t *picture)
68 VLC_UNUSED(filter);
69 picture_Release(picture);
72 static int FilterAllocationInit(filter_t *filter, void *vd)
74 filter->pf_video_buffer_new = VideoBufferNew;
75 filter->pf_video_buffer_del = VideoBufferDelete;
76 filter->p_owner = vd;
78 return VLC_SUCCESS;
80 static void FilterAllocationClean(filter_t *filter)
82 filter->pf_video_buffer_new = NULL;
83 filter->pf_video_buffer_del = NULL;
84 filter->p_owner = NULL;
87 /*****************************************************************************
89 *****************************************************************************/
91 /**
92 * It creates a new vout_display_t using the given configuration.
94 static vout_display_t *vout_display_New(vlc_object_t *obj,
95 const char *module, bool load_module,
96 const video_format_t *fmt,
97 const vout_display_cfg_t *cfg,
98 vout_display_owner_t *owner)
100 /* */
101 vout_display_t *vd = vlc_object_create(obj, sizeof(*vd));
103 /* */
104 video_format_Copy(&vd->source, fmt);
106 /* Picture buffer does not have the concept of aspect ratio */
107 video_format_Copy(&vd->fmt, fmt);
108 vd->fmt.i_sar_num = 0;
109 vd->fmt.i_sar_den = 0;
111 vd->info.is_slow = false;
112 vd->info.has_double_click = false;
113 vd->info.has_hide_mouse = false;
114 vd->info.has_pictures_invalid = false;
116 vd->cfg = cfg;
117 vd->pool = NULL;
118 vd->prepare = NULL;
119 vd->display = NULL;
120 vd->control = NULL;
121 vd->manage = NULL;
122 vd->sys = NULL;
124 vd->owner = *owner;
126 vlc_object_attach(vd, obj);
128 if (load_module) {
129 vd->module = module_need(vd, "vout display", module, module && *module != '\0');
130 if (!vd->module) {
131 vlc_object_release(vd);
132 return NULL;
134 } else {
135 vd->module = NULL;
137 return vd;
141 * It deletes a vout_display_t
143 static void vout_display_Delete(vout_display_t *vd)
145 if (vd->module)
146 module_unneed(vd, vd->module);
148 vlc_object_release(vd);
152 * It controls a vout_display_t
154 static int vout_display_Control(vout_display_t *vd, int query, ...)
156 va_list args;
157 int result;
159 va_start(args, query);
160 result = vd->control(vd, query, args);
161 va_end(args);
163 return result;
165 static void vout_display_Manage(vout_display_t *vd)
167 if (vd->manage)
168 vd->manage(vd);
171 /* */
172 void vout_display_GetDefaultDisplaySize(unsigned *width, unsigned *height,
173 const video_format_t *source,
174 const vout_display_cfg_t *cfg)
176 if (cfg->display.width > 0 && cfg->display.height > 0) {
177 *width = cfg->display.width;
178 *height = cfg->display.height;
179 } else if (cfg->display.width > 0) {
180 *width = cfg->display.width;
181 *height = (int64_t)source->i_visible_height * source->i_sar_den * cfg->display.width * cfg->display.sar.num /
182 source->i_visible_width / source->i_sar_num / cfg->display.sar.den;
183 } else if (cfg->display.height > 0) {
184 *width = (int64_t)source->i_visible_width * source->i_sar_num * cfg->display.height * cfg->display.sar.den /
185 source->i_visible_height / source->i_sar_den / cfg->display.sar.num;
186 *height = cfg->display.height;
187 } else if (source->i_sar_num >= source->i_sar_den) {
188 *width = (int64_t)source->i_visible_width * source->i_sar_num * cfg->display.sar.den / source->i_sar_den / cfg->display.sar.num;
189 *height = source->i_visible_height;
190 } else {
191 *width = source->i_visible_width;
192 *height = (int64_t)source->i_visible_height * source->i_sar_den * cfg->display.sar.num / source->i_sar_num / cfg->display.sar.den;
195 *width = *width * cfg->zoom.num / cfg->zoom.den;
196 *height = *height * cfg->zoom.num / cfg->zoom.den;
199 /* */
200 void vout_display_PlacePicture(vout_display_place_t *place,
201 const video_format_t *source,
202 const vout_display_cfg_t *cfg,
203 bool do_clipping)
205 /* */
206 memset(place, 0, sizeof(*place));
207 if (cfg->display.width <= 0 || cfg->display.height <= 0)
208 return;
210 /* */
211 unsigned display_width;
212 unsigned display_height;
214 if (cfg->is_display_filled) {
215 display_width = cfg->display.width;
216 display_height = cfg->display.height;
217 } else {
218 vout_display_cfg_t cfg_tmp = *cfg;
220 cfg_tmp.display.width = 0;
221 cfg_tmp.display.height = 0;
222 vout_display_GetDefaultDisplaySize(&display_width, &display_height,
223 source, &cfg_tmp);
225 if (do_clipping) {
226 display_width = __MIN(display_width, cfg->display.width);
227 display_height = __MIN(display_height, cfg->display.height);
231 const unsigned width = source->i_visible_width;
232 const unsigned height = source->i_visible_height;
233 /* Compute the height if we use the width to fill up display_width */
234 const int64_t scaled_height = (int64_t)height * display_width * cfg->display.sar.num * source->i_sar_den / width / source->i_sar_num / cfg->display.sar.den;
235 /* And the same but switching width/height */
236 const int64_t scaled_width = (int64_t)width * display_height * cfg->display.sar.den * source->i_sar_num / height / source->i_sar_den / cfg->display.sar.num;
238 /* We keep the solution that avoid filling outside the display */
239 if (scaled_width <= cfg->display.width) {
240 place->width = scaled_width;
241 place->height = display_height;
242 } else {
243 place->width = display_width;
244 place->height = scaled_height;
247 /* Compute position */
248 switch (cfg->align.horizontal) {
249 case VOUT_DISPLAY_ALIGN_LEFT:
250 place->x = 0;
251 break;
252 case VOUT_DISPLAY_ALIGN_RIGHT:
253 place->x = cfg->display.width - place->width;
254 break;
255 default:
256 place->x = (cfg->display.width - place->width) / 2;
257 break;
260 switch (cfg->align.vertical) {
261 case VOUT_DISPLAY_ALIGN_TOP:
262 place->y = 0;
263 break;
264 case VOUT_DISPLAY_ALIGN_BOTTOM:
265 place->y = cfg->display.height - place->height;
266 break;
267 default:
268 place->y = (cfg->display.height - place->height) / 2;
269 break;
273 struct vout_display_owner_sys_t {
274 vout_thread_t *vout;
275 bool is_wrapper; /* Is the current display a wrapper */
276 vout_display_t *wrapper; /* Vout display wrapper */
278 /* */
279 vout_display_cfg_t cfg;
280 unsigned wm_state_initial;
281 struct {
282 unsigned num;
283 unsigned den;
284 } sar_initial;
286 /* */
287 int width_saved;
288 int height_saved;
290 struct {
291 unsigned num;
292 unsigned den;
293 } crop_saved;
295 /* */
296 bool ch_display_filled;
297 bool is_display_filled;
299 bool ch_zoom;
300 struct {
301 int num;
302 int den;
303 } zoom;
305 bool ch_wm_state;
306 unsigned wm_state;
308 bool ch_sar;
309 struct {
310 unsigned num;
311 unsigned den;
312 } sar;
314 bool ch_crop;
315 struct {
316 unsigned x;
317 unsigned y;
318 unsigned width;
319 unsigned height;
320 unsigned num;
321 unsigned den;
322 } crop;
324 /* */
325 video_format_t source;
326 filter_chain_t *filters;
328 /* Lock protecting the variables used by
329 * VoutDisplayEvent(ie vout_display_SendEvent) */
330 vlc_mutex_t lock;
332 /* mouse state */
333 struct {
334 vlc_mouse_t state;
336 mtime_t last_pressed;
337 mtime_t last_moved;
338 bool is_hidden;
339 bool ch_activity;
341 /* */
342 mtime_t double_click_timeout;
343 mtime_t hide_timeout;
344 } mouse;
346 bool reset_pictures;
348 bool ch_fullscreen;
349 bool is_fullscreen;
351 bool ch_display_size;
352 int display_width;
353 int display_height;
354 bool display_is_fullscreen;
355 bool display_is_forced;
357 int fit_window;
359 #ifdef ALLOW_DUMMY_VOUT
360 vlc_mouse_t vout_mouse;
361 #endif
364 static void DummyVoutSendDisplayEventMouse(vout_thread_t *, vlc_mouse_t *fallback, const vlc_mouse_t *m);
366 static void VoutDisplayCreateRender(vout_display_t *vd)
368 vout_display_owner_sys_t *osys = vd->owner.sys;
370 osys->filters = NULL;
372 video_format_t v_src = vd->source;
373 v_src.i_sar_num = 0;
374 v_src.i_sar_den = 0;
376 video_format_t v_dst = vd->fmt;
377 v_dst.i_sar_num = 0;
378 v_dst.i_sar_den = 0;
380 video_format_t v_dst_cmp = v_dst;
381 if ((v_src.i_chroma == VLC_CODEC_J420 && v_dst.i_chroma == VLC_CODEC_I420) ||
382 (v_src.i_chroma == VLC_CODEC_J422 && v_dst.i_chroma == VLC_CODEC_I422) ||
383 (v_src.i_chroma == VLC_CODEC_J440 && v_dst.i_chroma == VLC_CODEC_I440) ||
384 (v_src.i_chroma == VLC_CODEC_J444 && v_dst.i_chroma == VLC_CODEC_I444))
385 v_dst_cmp.i_chroma = v_src.i_chroma;
387 const bool convert = memcmp(&v_src, &v_dst_cmp, sizeof(v_src)) != 0;
388 if (!convert)
389 return;
391 msg_Dbg(vd, "A filter to adapt decoder to display is needed");
393 osys->filters = filter_chain_New(vd, "video filter2", false,
394 FilterAllocationInit,
395 FilterAllocationClean, vd);
396 assert(osys->filters); /* TODO critical */
398 /* */
399 es_format_t src;
400 es_format_InitFromVideo(&src, &v_src);
402 /* */
403 es_format_t dst;
405 filter_t *filter;
406 for (int i = 0; i < 1 + (v_dst_cmp.i_chroma != v_dst.i_chroma); i++) {
408 es_format_InitFromVideo(&dst, i == 0 ? &v_dst : &v_dst_cmp);
410 filter_chain_Reset(osys->filters, &src, &dst);
411 filter = filter_chain_AppendFilter(osys->filters,
412 NULL, NULL, &src, &dst);
413 if (filter)
414 break;
416 if (!filter)
418 msg_Err(vd, "VoutDisplayCreateRender FAILED");
419 /* TODO */
420 assert(0);
424 static void VoutDisplayDestroyRender(vout_display_t *vd)
426 vout_display_owner_sys_t *osys = vd->owner.sys;
428 if (osys->filters)
429 filter_chain_Delete(osys->filters);
432 static void VoutDisplayResetRender(vout_display_t *vd)
434 VoutDisplayDestroyRender(vd);
435 VoutDisplayCreateRender(vd);
437 static void VoutDisplayEventMouse(vout_display_t *vd, int event, va_list args)
439 vout_display_owner_sys_t *osys = vd->owner.sys;
441 vlc_mutex_lock(&osys->lock);
443 /* */
444 vlc_mouse_t m = osys->mouse.state;
445 bool is_ignored = false;
447 switch (event) {
448 case VOUT_DISPLAY_EVENT_MOUSE_STATE: {
449 const int x = (int)va_arg(args, int);
450 const int y = (int)va_arg(args, int);
451 const int button_mask = (int)va_arg(args, int);
453 vlc_mouse_Init(&m);
454 m.i_x = x;
455 m.i_y = y;
456 m.i_pressed = button_mask;
457 break;
459 case VOUT_DISPLAY_EVENT_MOUSE_MOVED: {
460 const int x = (int)va_arg(args, int);
461 const int y = (int)va_arg(args, int);
462 if (x != osys->mouse.state.i_x || y != osys->mouse.state.i_y) {
463 //msg_Dbg(vd, "VoutDisplayEvent 'mouse' @%d,%d", x, y);
465 m.i_x = x;
466 m.i_y = y;
467 m.b_double_click = false;
468 } else {
469 is_ignored = true;
471 break;
473 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED:
474 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED: {
475 const int button = (int)va_arg(args, int);
476 const int button_mask = 1 << button;
478 /* Ignore inconsistent event */
479 if ((event == VOUT_DISPLAY_EVENT_MOUSE_PRESSED && (osys->mouse.state.i_pressed & button_mask)) ||
480 (event == VOUT_DISPLAY_EVENT_MOUSE_RELEASED && !(osys->mouse.state.i_pressed & button_mask))) {
481 is_ignored = true;
482 break;
485 /* */
486 msg_Dbg(vd, "VoutDisplayEvent 'mouse button' %d t=%d", button, event);
488 m.b_double_click = false;
489 if (event == VOUT_DISPLAY_EVENT_MOUSE_PRESSED)
490 m.i_pressed |= button_mask;
491 else
492 m.i_pressed &= ~button_mask;
493 break;
495 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK:
496 msg_Dbg(vd, "VoutDisplayEvent 'double click'");
498 m.b_double_click = true;
499 break;
500 default:
501 assert(0);
504 if (is_ignored) {
505 vlc_mutex_unlock(&osys->lock);
506 return;
509 /* Emulate double-click if needed */
510 if (!vd->info.has_double_click &&
511 vlc_mouse_HasPressed(&osys->mouse.state, &m, MOUSE_BUTTON_LEFT)) {
512 const mtime_t i_date = mdate();
514 if (i_date - osys->mouse.last_pressed < osys->mouse.double_click_timeout ) {
515 m.b_double_click = true;
516 osys->mouse.last_pressed = 0;
517 } else {
518 osys->mouse.last_pressed = mdate();
522 /* */
523 osys->mouse.state = m;
525 /* */
526 osys->mouse.ch_activity = true;
527 if (!vd->info.has_hide_mouse)
528 osys->mouse.last_moved = mdate();
530 /* */
531 vlc_mutex_unlock(&osys->lock);
533 /* */
534 vout_SendEventMouseVisible(osys->vout);
535 #ifdef ALLOW_DUMMY_VOUT
536 DummyVoutSendDisplayEventMouse(osys->vout, &osys->vout_mouse, &m);
537 #else
538 vout_SendDisplayEventMouse(osys->vout, &m);
539 #endif
542 static void VoutDisplayEvent(vout_display_t *vd, int event, va_list args)
544 vout_display_owner_sys_t *osys = vd->owner.sys;
546 switch (event) {
547 case VOUT_DISPLAY_EVENT_CLOSE: {
548 msg_Dbg(vd, "VoutDisplayEvent 'close'");
549 vout_SendEventClose(osys->vout);
550 break;
552 case VOUT_DISPLAY_EVENT_KEY: {
553 const int key = (int)va_arg(args, int);
554 msg_Dbg(vd, "VoutDisplayEvent 'key' 0x%2.2x", key);
555 vout_SendEventKey(osys->vout, key);
556 break;
558 case VOUT_DISPLAY_EVENT_MOUSE_STATE:
559 case VOUT_DISPLAY_EVENT_MOUSE_MOVED:
560 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED:
561 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED:
562 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK:
563 VoutDisplayEventMouse(vd, event, args);
564 break;
566 case VOUT_DISPLAY_EVENT_FULLSCREEN: {
567 const int is_fullscreen = (int)va_arg(args, int);
569 msg_Dbg(vd, "VoutDisplayEvent 'fullscreen' %d", is_fullscreen);
571 vlc_mutex_lock(&osys->lock);
572 if (!is_fullscreen != !osys->is_fullscreen) {
573 osys->ch_fullscreen = true;
574 osys->is_fullscreen = is_fullscreen;
576 vlc_mutex_unlock(&osys->lock);
577 break;
580 case VOUT_DISPLAY_EVENT_WINDOW_STATE: {
581 const unsigned state = va_arg(args, unsigned);
583 msg_Dbg(vd, "VoutDisplayEvent 'window state' %u", state);
585 vlc_mutex_lock(&osys->lock);
586 if (state != osys->wm_state) {
587 osys->ch_wm_state = true;
588 osys->wm_state = state;
590 vlc_mutex_unlock(&osys->lock);
591 break;
594 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE: {
595 const int width = (int)va_arg(args, int);
596 const int height = (int)va_arg(args, int);
597 const bool is_fullscreen = (bool)va_arg(args, int);
598 msg_Dbg(vd, "VoutDisplayEvent 'resize' %dx%d %s",
599 width, height, is_fullscreen ? "fullscreen" : "window");
601 /* */
602 vlc_mutex_lock(&osys->lock);
604 osys->ch_display_size = true;
605 osys->display_width = width;
606 osys->display_height = height;
607 osys->display_is_fullscreen = is_fullscreen;
608 osys->display_is_forced = false;
610 vlc_mutex_unlock(&osys->lock);
611 break;
614 case VOUT_DISPLAY_EVENT_PICTURES_INVALID: {
615 msg_Warn(vd, "VoutDisplayEvent 'pictures invalid'");
617 /* */
618 assert(vd->info.has_pictures_invalid);
620 vlc_mutex_lock(&osys->lock);
621 osys->reset_pictures = true;
622 vlc_mutex_unlock(&osys->lock);
623 break;
625 default:
626 msg_Err(vd, "VoutDisplayEvent received event %d", event);
627 /* TODO add an assert when all event are handled */
628 break;
632 static vout_window_t *VoutDisplayNewWindow(vout_display_t *vd, const vout_window_cfg_t *cfg)
634 vout_display_owner_sys_t *osys = vd->owner.sys;
636 return vout_NewDisplayWindow(osys->vout, vd, cfg);
638 static void VoutDisplayDelWindow(vout_display_t *vd, vout_window_t *window)
640 vout_display_owner_sys_t *osys = vd->owner.sys;
642 vout_DeleteDisplayWindow(osys->vout, vd, window);
645 static void VoutDisplayFitWindow(vout_display_t *vd, bool default_size)
647 vout_display_owner_sys_t *osys = vd->owner.sys;
648 vout_display_cfg_t cfg = osys->cfg;
650 if (!cfg.is_display_filled)
651 return;
653 cfg.display.width = 0;
654 if (default_size) {
655 cfg.display.height = 0;
656 } else {
657 cfg.display.height = osys->height_saved;
658 cfg.zoom.num = 1;
659 cfg.zoom.den = 1;
662 unsigned display_width;
663 unsigned display_height;
664 vout_display_GetDefaultDisplaySize(&display_width, &display_height,
665 &vd->source, &cfg);
667 vlc_mutex_lock(&osys->lock);
669 osys->ch_display_size = true;
670 osys->display_width = display_width;
671 osys->display_height = display_height;
672 osys->display_is_fullscreen = osys->cfg.is_fullscreen;
673 osys->display_is_forced = true;
675 vlc_mutex_unlock(&osys->lock);
678 void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures)
680 vout_display_owner_sys_t *osys = vd->owner.sys;
682 vout_display_Manage(vd);
684 /* Handle mouse timeout */
685 const mtime_t date = mdate();
686 bool hide_mouse = false;
688 vlc_mutex_lock(&osys->lock);
690 if (!osys->mouse.is_hidden &&
691 osys->mouse.last_moved + osys->mouse.hide_timeout < date) {
692 osys->mouse.is_hidden = hide_mouse = true;
693 } else if (osys->mouse.ch_activity) {
694 osys->mouse.is_hidden = false;
696 osys->mouse.ch_activity = false;
697 vlc_mutex_unlock(&osys->lock);
699 if (hide_mouse) {
700 if (!vd->info.has_hide_mouse) {
701 msg_Dbg(vd, "auto hidding mouse");
702 vout_display_Control(vd, VOUT_DISPLAY_HIDE_MOUSE);
704 vout_SendEventMouseHidden(osys->vout);
707 bool reset_render = false;
708 for (;;) {
710 vlc_mutex_lock(&osys->lock);
712 bool ch_fullscreen = osys->ch_fullscreen;
713 bool is_fullscreen = osys->is_fullscreen;
714 osys->ch_fullscreen = false;
716 bool ch_wm_state = osys->ch_wm_state;
717 unsigned wm_state = osys->wm_state;
718 osys->ch_wm_state = false;
720 bool ch_display_size = osys->ch_display_size;
721 int display_width = osys->display_width;
722 int display_height = osys->display_height;
723 bool display_is_fullscreen = osys->display_is_fullscreen;
724 bool display_is_forced = osys->display_is_forced;
725 osys->ch_display_size = false;
727 bool reset_pictures;
728 if (allow_reset_pictures) {
729 reset_pictures = osys->reset_pictures;
730 osys->reset_pictures = false;
731 } else {
732 reset_pictures = false;
735 vlc_mutex_unlock(&osys->lock);
737 if (!ch_fullscreen &&
738 !ch_display_size &&
739 !reset_pictures &&
740 !osys->ch_display_filled &&
741 !osys->ch_zoom &&
742 !ch_wm_state &&
743 !osys->ch_sar &&
744 !osys->ch_crop) {
746 if (!osys->cfg.is_fullscreen && osys->fit_window != 0) {
747 VoutDisplayFitWindow(vd, osys->fit_window == -1);
748 osys->fit_window = 0;
749 continue;
751 break;
754 /* */
755 if (ch_fullscreen) {
756 vout_display_cfg_t cfg = osys->cfg;
758 cfg.is_fullscreen = is_fullscreen;
759 cfg.display.width = cfg.is_fullscreen ? 0 : osys->width_saved;
760 cfg.display.height = cfg.is_fullscreen ? 0 : osys->height_saved;
762 if (vout_display_Control(vd, VOUT_DISPLAY_CHANGE_FULLSCREEN, &cfg)) {
763 msg_Err(vd, "Failed to set fullscreen");
764 is_fullscreen = osys->cfg.is_fullscreen;
766 osys->cfg.is_fullscreen = is_fullscreen;
768 /* */
769 vout_SendEventFullscreen(osys->vout, osys->cfg.is_fullscreen);
772 /* */
773 if (ch_display_size) {
774 vout_display_cfg_t cfg = osys->cfg;
775 cfg.display.width = display_width;
776 cfg.display.height = display_height;
778 if (!cfg.is_fullscreen != !display_is_fullscreen ||
779 vout_display_Control(vd, VOUT_DISPLAY_CHANGE_DISPLAY_SIZE, &cfg, display_is_forced)) {
780 if (!cfg.is_fullscreen == !display_is_fullscreen)
781 msg_Err(vd, "Failed to resize display");
783 /* We ignore the resized */
784 display_width = osys->cfg.display.width;
785 display_height = osys->cfg.display.height;
787 osys->cfg.display.width = display_width;
788 osys->cfg.display.height = display_height;
790 if (!display_is_fullscreen) {
791 osys->width_saved = display_width;
792 osys->height_saved = display_height;
795 /* */
796 if (osys->ch_display_filled) {
797 vout_display_cfg_t cfg = osys->cfg;
799 cfg.is_display_filled = osys->is_display_filled;
801 if (vout_display_Control(vd, VOUT_DISPLAY_CHANGE_DISPLAY_FILLED, &cfg)) {
802 msg_Err(vd, "Failed to change display filled state");
803 osys->is_display_filled = osys->cfg.is_display_filled;
805 osys->cfg.is_display_filled = osys->is_display_filled;
806 osys->ch_display_filled = false;
808 vout_SendEventDisplayFilled(osys->vout, osys->cfg.is_display_filled);
810 /* */
811 if (osys->ch_zoom) {
812 vout_display_cfg_t cfg = osys->cfg;
814 cfg.zoom.num = osys->zoom.num;
815 cfg.zoom.den = osys->zoom.den;
817 if (10 * cfg.zoom.num <= cfg.zoom.den) {
818 cfg.zoom.num = 1;
819 cfg.zoom.den = 10;
820 } else if (cfg.zoom.num >= 10 * cfg.zoom.den) {
821 cfg.zoom.num = 10;
822 cfg.zoom.den = 1;
825 if (vout_display_Control(vd, VOUT_DISPLAY_CHANGE_ZOOM, &cfg)) {
826 msg_Err(vd, "Failed to change zoom");
827 osys->zoom.num = osys->cfg.zoom.num;
828 osys->zoom.den = osys->cfg.zoom.den;
829 } else {
830 osys->fit_window = -1;
833 osys->cfg.zoom.num = osys->zoom.num;
834 osys->cfg.zoom.den = osys->zoom.den;
835 osys->ch_zoom = false;
837 vout_SendEventZoom(osys->vout, osys->cfg.zoom.num, osys->cfg.zoom.den);
839 /* */
840 if (ch_wm_state) {
841 if (vout_display_Control(vd, VOUT_DISPLAY_CHANGE_WINDOW_STATE, wm_state)) {
842 msg_Err(vd, "Failed to set on top");
843 wm_state = osys->wm_state;
845 osys->wm_state_initial = wm_state;
847 /* */
848 vout_SendEventOnTop(osys->vout, osys->wm_state_initial);
850 /* */
851 if (osys->ch_sar) {
852 video_format_t source = vd->source;
854 if (osys->sar.num > 0 && osys->sar.den > 0) {
855 source.i_sar_num = osys->sar.num;
856 source.i_sar_den = osys->sar.den;
857 } else {
858 source.i_sar_num = osys->source.i_sar_num;
859 source.i_sar_den = osys->source.i_sar_den;
862 if (vout_display_Control(vd, VOUT_DISPLAY_CHANGE_SOURCE_ASPECT, &source)) {
863 /* There nothing much we can do. The only reason a vout display
864 * does not support it is because it need the core to add black border
865 * to the video for it.
866 * TODO add black borders ?
868 msg_Err(vd, "Failed to change source AR");
869 source = vd->source;
870 } else if (!osys->fit_window) {
871 osys->fit_window = 1;
873 vd->source = source;
874 osys->sar.num = source.i_sar_num;
875 osys->sar.den = source.i_sar_den;
876 osys->ch_sar = false;
878 /* */
879 if (osys->sar.num == osys->source.i_sar_num &&
880 osys->sar.den == osys->source.i_sar_den)
882 vout_SendEventSourceAspect(osys->vout, 0, 0);
884 else
886 unsigned dar_num, dar_den;
887 vlc_ureduce( &dar_num, &dar_den,
888 osys->sar.num * vd->source.i_visible_width,
889 osys->sar.den * vd->source.i_visible_height,
890 65536);
891 vout_SendEventSourceAspect(osys->vout, dar_num, dar_den);
894 /* */
895 if (osys->ch_crop) {
896 video_format_t source = vd->source;
897 unsigned crop_num = osys->crop.num;
898 unsigned crop_den = osys->crop.den;
900 source.i_x_offset = osys->crop.x;
901 source.i_y_offset = osys->crop.y;
902 source.i_visible_width = osys->crop.width;
903 source.i_visible_height = osys->crop.height;
905 /* */
906 const bool is_valid = source.i_x_offset < source.i_width &&
907 source.i_y_offset < source.i_height &&
908 source.i_x_offset + source.i_visible_width <= source.i_width &&
909 source.i_y_offset + source.i_visible_height <= source.i_height &&
910 source.i_visible_width > 0 && source.i_visible_height > 0;
912 if (!is_valid || vout_display_Control(vd, VOUT_DISPLAY_CHANGE_SOURCE_CROP, &source)) {
913 if (is_valid)
914 msg_Err(vd, "Failed to change source crop TODO implement crop at core");
915 else
916 msg_Err(vd, "Invalid crop requested");
918 source = vd->source;
919 crop_num = osys->crop_saved.num;
920 crop_den = osys->crop_saved.den;
921 /* FIXME implement cropping in the core if not supported by the
922 * vout module (easy)
924 } else if (!osys->fit_window) {
925 osys->fit_window = 1;
927 vd->source = source;
928 osys->crop.x = source.i_x_offset;
929 osys->crop.y = source.i_y_offset;
930 osys->crop.width = source.i_visible_width;
931 osys->crop.height = source.i_visible_height;
932 osys->crop.num = crop_num;
933 osys->crop.den = crop_den;
934 osys->ch_crop = false;
936 /* TODO fix when a ratio is used (complicated). */
937 const unsigned left = osys->crop.x - osys->source.i_x_offset;
938 const unsigned top = osys->crop.y - osys->source.i_y_offset;
939 const unsigned right = osys->source.i_visible_width - (osys->crop.width + osys->crop.x);
940 const unsigned bottom = osys->source.i_visible_height - (osys->crop.height + osys->crop.y);
941 vout_SendEventSourceCrop(osys->vout,
942 osys->crop.num, osys->crop.den,
943 left, top, right, bottom);
946 /* */
947 if (reset_pictures) {
948 if (vout_display_Control(vd, VOUT_DISPLAY_RESET_PICTURES)) {
949 /* FIXME what to do here ? */
950 msg_Err(vd, "Failed to reset pictures (probably fatal)");
952 reset_render = true;
955 if (reset_render)
956 VoutDisplayResetRender(vd);
959 bool vout_AreDisplayPicturesInvalid(vout_display_t *vd)
961 vout_display_owner_sys_t *osys = vd->owner.sys;
963 vlc_mutex_lock(&osys->lock);
964 const bool reset_pictures = osys->reset_pictures;
965 vlc_mutex_unlock(&osys->lock);
967 return reset_pictures;
970 bool vout_IsDisplayFiltered(vout_display_t *vd)
972 vout_display_owner_sys_t *osys = vd->owner.sys;
974 return osys->filters != NULL;
977 picture_t *vout_FilterDisplay(vout_display_t *vd, picture_t *picture)
979 vout_display_owner_sys_t *osys = vd->owner.sys;
981 assert(osys->filters);
982 return filter_chain_VideoFilter(osys->filters, picture);
985 void vout_SetDisplayFullscreen(vout_display_t *vd, bool is_fullscreen)
987 vout_display_owner_sys_t *osys = vd->owner.sys;
989 vlc_mutex_lock(&osys->lock);
990 if (!osys->is_fullscreen != !is_fullscreen) {
991 osys->ch_fullscreen = true;
992 osys->is_fullscreen = is_fullscreen;
994 vlc_mutex_unlock(&osys->lock);
997 void vout_SetDisplayFilled(vout_display_t *vd, bool is_filled)
999 vout_display_owner_sys_t *osys = vd->owner.sys;
1001 if (!osys->is_display_filled != !is_filled) {
1002 osys->ch_display_filled = true;
1003 osys->is_display_filled = is_filled;
1007 void vout_SetDisplayZoom(vout_display_t *vd, int num, int den)
1009 vout_display_owner_sys_t *osys = vd->owner.sys;
1011 if (osys->is_display_filled ||
1012 osys->zoom.num != num || osys->zoom.den != den) {
1013 osys->ch_zoom = true;
1014 osys->zoom.num = num;
1015 osys->zoom.den = den;
1019 void vout_SetWindowState(vout_display_t *vd, unsigned state)
1021 vout_display_owner_sys_t *osys = vd->owner.sys;
1023 vlc_mutex_lock(&osys->lock);
1024 if (osys->wm_state != state) {
1025 osys->ch_wm_state = true;
1026 osys->wm_state = state;
1028 vlc_mutex_unlock(&osys->lock);
1031 void vout_SetDisplayAspect(vout_display_t *vd, unsigned sar_num, unsigned sar_den)
1033 vout_display_owner_sys_t *osys = vd->owner.sys;
1035 if (osys->sar.num != sar_num || osys->sar.den != sar_den) {
1036 osys->ch_sar = true;
1037 osys->sar.num = sar_num;
1038 osys->sar.den = sar_den;
1041 void vout_SetDisplayCrop(vout_display_t *vd,
1042 unsigned crop_num, unsigned crop_den,
1043 unsigned x, unsigned y, unsigned width, unsigned height)
1045 vout_display_owner_sys_t *osys = vd->owner.sys;
1047 if (osys->crop.x != x || osys->crop.y != y ||
1048 osys->crop.width != width || osys->crop.height != height) {
1050 osys->crop.x = x;
1051 osys->crop.y = y;
1052 osys->crop.width = width;
1053 osys->crop.height = height;
1054 osys->crop.num = crop_num;
1055 osys->crop.den = crop_den;
1057 osys->ch_crop = true;
1060 vout_opengl_t *vout_GetDisplayOpengl(vout_display_t *vd)
1062 vout_opengl_t *gl;
1063 if (vout_display_Control(vd, VOUT_DISPLAY_GET_OPENGL, &gl))
1064 return NULL;
1065 return gl;
1068 static vout_display_t *DisplayNew(vout_thread_t *vout,
1069 const video_format_t *source_org,
1070 const vout_display_state_t *state,
1071 const char *module,
1072 bool is_wrapper, vout_display_t *wrapper,
1073 mtime_t double_click_timeout,
1074 mtime_t hide_timeout,
1075 const vout_display_owner_t *owner_ptr)
1077 /* */
1078 vout_display_owner_sys_t *osys = calloc(1, sizeof(*osys));
1079 vout_display_cfg_t *cfg = &osys->cfg;
1081 *cfg = state->cfg;
1082 osys->wm_state_initial = VOUT_WINDOW_STATE_NORMAL;
1083 osys->sar_initial.num = state->sar.num;
1084 osys->sar_initial.den = state->sar.den;
1085 vout_display_GetDefaultDisplaySize(&cfg->display.width, &cfg->display.height,
1086 source_org, cfg);
1088 osys->vout = vout;
1089 osys->is_wrapper = is_wrapper;
1090 osys->wrapper = wrapper;
1092 vlc_mutex_init(&osys->lock);
1094 vlc_mouse_Init(&osys->mouse.state);
1095 osys->mouse.last_moved = mdate();
1096 osys->mouse.double_click_timeout = double_click_timeout;
1097 osys->mouse.hide_timeout = hide_timeout;
1098 osys->is_fullscreen = cfg->is_fullscreen;
1099 osys->width_saved =
1100 osys->display_width = cfg->display.width;
1101 osys->height_saved =
1102 osys->display_height = cfg->display.height;
1103 osys->is_display_filled = cfg->is_display_filled;
1104 osys->zoom.num = cfg->zoom.num;
1105 osys->zoom.den = cfg->zoom.den;
1106 osys->wm_state = state->is_on_top ? VOUT_WINDOW_STATE_ABOVE
1107 : VOUT_WINDOW_STATE_NORMAL;
1108 osys->fit_window = 0;
1110 osys->source = *source_org;
1112 video_format_t source = *source_org;
1114 source.i_x_offset =
1115 osys->crop.x = 0;
1116 source.i_y_offset =
1117 osys->crop.y = 0;
1118 source.i_visible_width =
1119 osys->crop.width = source.i_width;
1120 source.i_visible_height =
1121 osys->crop.height = source.i_height;
1122 osys->crop_saved.num = 0;
1123 osys->crop_saved.den = 0;
1124 osys->crop.num = 0;
1125 osys->crop.den = 0;
1127 osys->sar.num = osys->sar_initial.num ? osys->sar_initial.num : source.i_sar_num;
1128 osys->sar.den = osys->sar_initial.den ? osys->sar_initial.den : source.i_sar_den;
1129 #ifdef ALLOW_DUMMY_VOUT
1130 vlc_mouse_Init(&osys->vout_mouse);
1131 #endif
1133 vout_display_owner_t owner;
1134 if (owner_ptr) {
1135 owner = *owner_ptr;
1136 } else {
1137 owner.event = VoutDisplayEvent;
1138 owner.window_new = VoutDisplayNewWindow;
1139 owner.window_del = VoutDisplayDelWindow;
1141 owner.sys = osys;
1143 /* */
1144 vout_display_t *p_display = vout_display_New(VLC_OBJECT(vout),
1145 module, !is_wrapper,
1146 &source, cfg, &owner);
1147 if (!p_display) {
1148 free(osys);
1149 return NULL;
1152 VoutDisplayCreateRender(p_display);
1154 /* Setup delayed request */
1155 if (osys->sar.num != source_org->i_sar_num ||
1156 osys->sar.den != source_org->i_sar_den)
1157 osys->ch_sar = true;
1158 if (osys->wm_state != osys->wm_state_initial)
1159 osys->ch_wm_state = true;
1160 if (osys->crop.x != source_org->i_x_offset ||
1161 osys->crop.y != source_org->i_y_offset ||
1162 osys->crop.width != source_org->i_visible_width ||
1163 osys->crop.height != source_org->i_visible_height)
1164 osys->ch_crop = true;
1166 return p_display;
1169 void vout_DeleteDisplay(vout_display_t *vd, vout_display_state_t *state)
1171 vout_display_owner_sys_t *osys = vd->owner.sys;
1173 if (state) {
1174 if (!osys->is_wrapper )
1175 state->cfg = osys->cfg;
1176 state->is_on_top = (osys->wm_state & VOUT_WINDOW_STATE_ABOVE) != 0;
1177 state->sar.num = osys->sar_initial.num;
1178 state->sar.den = osys->sar_initial.den;
1181 VoutDisplayDestroyRender(vd);
1182 if (osys->is_wrapper)
1183 SplitterClose(vd);
1184 vout_display_Delete(vd);
1185 vlc_mutex_destroy(&osys->lock);
1186 free(osys);
1189 /*****************************************************************************
1191 *****************************************************************************/
1192 vout_display_t *vout_NewDisplay(vout_thread_t *vout,
1193 const video_format_t *source,
1194 const vout_display_state_t *state,
1195 const char *module,
1196 mtime_t double_click_timeout,
1197 mtime_t hide_timeout)
1199 return DisplayNew(vout, source, state, module, false, NULL,
1200 double_click_timeout, hide_timeout, NULL);
1203 static void SplitterClose(vout_display_t *vd)
1205 VLC_UNUSED(vd);
1206 assert(0);
1209 #if 0
1210 /*****************************************************************************
1212 *****************************************************************************/
1213 struct vout_display_sys_t {
1214 video_splitter_t *splitter;
1216 /* */
1217 int count;
1218 picture_t **picture;
1219 vout_display_t **display;
1221 struct video_splitter_owner_t {
1222 vout_display_t *wrapper;
1225 static vout_window_t *SplitterNewWindow(vout_display_t *vd, const vout_window_cfg_t *cfg_ptr)
1227 vout_display_owner_sys_t *osys = vd->owner.sys;
1229 vout_window_cfg_t cfg = *cfg_ptr;
1230 cfg.is_standalone = true;
1231 cfg.x += 0;//output->window.i_x; FIXME
1232 cfg.y += 0;//output->window.i_y;
1234 return vout_NewDisplayWindow(osys->vout, vd, &cfg);
1236 static void SplitterDelWindow(vout_display_t *vd, vout_window_t *window)
1238 vout_display_owner_sys_t *osys = vd->owner.sys;
1240 vout_DeleteDisplayWindow(osys->vout, vd, window);
1242 static void SplitterEvent(vout_display_t *vd, int event, va_list args)
1244 vout_display_owner_sys_t *osys = vd->owner.sys;
1246 switch (event) {
1247 #if 0
1248 case VOUT_DISPLAY_EVENT_MOUSE_STATE:
1249 case VOUT_DISPLAY_EVENT_MOUSE_MOVED:
1250 case VOUT_DISPLAY_EVENT_MOUSE_PRESSED:
1251 case VOUT_DISPLAY_EVENT_MOUSE_RELEASED:
1252 /* TODO */
1253 break;
1254 #endif
1255 case VOUT_DISPLAY_EVENT_MOUSE_DOUBLE_CLICK:
1256 case VOUT_DISPLAY_EVENT_KEY:
1257 case VOUT_DISPLAY_EVENT_CLOSE:
1258 case VOUT_DISPLAY_EVENT_FULLSCREEN:
1259 case VOUT_DISPLAY_EVENT_DISPLAY_SIZE:
1260 case VOUT_DISPLAY_EVENT_PICTURES_INVALID:
1261 VoutDisplayEvent(vd, event, args);
1262 break;
1264 default:
1265 msg_Err(vd, "SplitterEvent TODO");
1266 break;
1270 static picture_t *SplitterGet(vout_display_t *vd)
1272 /* TODO pool ? */
1273 return picture_NewFromFormat(&vd->fmt);
1275 static void SplitterPrepare(vout_display_t *vd, picture_t *picture)
1277 vout_display_sys_t *sys = vd->sys;
1279 picture_Hold(picture);
1281 if (video_splitter_Filter(sys->splitter, sys->picture, picture)) {
1282 for (int i = 0; i < sys->count; i++)
1283 sys->picture[i] = NULL;
1284 picture_Release(picture);
1285 return;
1288 for (int i = 0; i < sys->count; i++) {
1289 /* */
1290 /* FIXME now vout_FilterDisplay already return a direct buffer FIXME */
1291 sys->picture[i] = vout_FilterDisplay(sys->display[i], sys->picture[i]);
1292 if (!sys->picture[i])
1293 continue;
1295 /* */
1296 picture_t *direct = vout_display_Get(sys->display[i]);
1297 if (!direct) {
1298 msg_Err(vd, "Failed to get a direct buffer");
1299 picture_Release(sys->picture[i]);
1300 sys->picture[i] = NULL;
1301 continue;
1304 /* FIXME not always needed (easy when there is a osys->filters) */
1305 picture_Copy(direct, sys->picture[i]);
1306 picture_Release(sys->picture[i]);
1307 sys->picture[i] = direct;
1309 vout_display_Prepare(sys->display[i], sys->picture[i]);
1312 static void SplitterDisplay(vout_display_t *vd, picture_t *picture)
1314 vout_display_sys_t *sys = vd->sys;
1316 for (int i = 0; i < sys->count; i++) {
1317 if (sys->picture[i])
1318 vout_display_Display(sys->display[i], sys->picture[i]);
1320 picture_Release(picture);
1322 static int SplitterControl(vout_display_t *vd, int query, va_list args)
1324 return VLC_EGENERIC;
1326 static void SplitterManage(vout_display_t *vd)
1328 vout_display_sys_t *sys = vd->sys;
1330 for (int i = 0; i < sys->count; i++)
1331 vout_ManageDisplay(sys->display[i]);
1334 static int SplitterPictureNew(video_splitter_t *splitter, picture_t *picture[])
1336 vout_display_sys_t *wsys = splitter->p_owner->wrapper->sys;
1338 for (int i = 0; i < wsys->count; i++) {
1339 /* TODO pool ? */
1340 picture[i] = picture_NewFromFormat(&wsys->display[i]->source);
1341 if (!picture[i]) {
1342 for (int j = 0; j < i; j++)
1343 picture_Release(picture[j]);
1344 return VLC_EGENERIC;
1347 return VLC_SUCCESS;
1349 static void SplitterPictureDel(video_splitter_t *splitter, picture_t *picture[])
1351 vout_display_sys_t *wsys = splitter->p_owner->wrapper->sys;
1353 for (int i = 0; i < wsys->count; i++)
1354 picture_Release(picture[i]);
1356 static void SplitterClose(vout_display_t *vd)
1358 vout_display_sys_t *sys = vd->sys;
1360 /* */
1361 video_splitter_t *splitter = sys->splitter;
1362 free(splitter->p_owner);
1363 video_splitter_Delete(splitter);
1365 /* */
1366 for (int i = 0; i < sys->count; i++)
1367 vout_DeleteDisplay(sys->display[i], NULL);
1368 TAB_CLEAN(sys->count, sys->display);
1369 free(sys->picture);
1371 free(sys);
1374 vout_display_t *vout_NewSplitter(vout_thread_t *vout,
1375 const video_format_t *source,
1376 const vout_display_state_t *state,
1377 const char *module,
1378 const char *splitter_module,
1379 mtime_t double_click_timeout,
1380 mtime_t hide_timeout)
1382 video_splitter_t *splitter =
1383 video_splitter_New(VLC_OBJECT(vout), splitter_module, source);
1384 if (!splitter)
1385 return NULL;
1387 /* */
1388 vout_display_t *wrapper =
1389 DisplayNew(vout, source, state, module, true, NULL,
1390 double_click_timeout, hide_timeout, NULL);
1391 if (!wrapper) {
1392 video_splitter_Delete(splitter);
1393 return NULL;
1395 vout_display_sys_t *sys = malloc(sizeof(*sys));
1396 if (!sys)
1397 abort();
1398 sys->picture = calloc(splitter->i_output, sizeof(*sys->picture));
1399 if (!sys->picture )
1400 abort();
1401 sys->splitter = splitter;
1403 wrapper->get = SplitterGet;
1404 wrapper->prepare = SplitterPrepare;
1405 wrapper->display = SplitterDisplay;
1406 wrapper->control = SplitterControl;
1407 wrapper->manage = SplitterManage;
1408 wrapper->sys = sys;
1410 /* */
1411 video_splitter_owner_t *owner = malloc(sizeof(*owner));
1412 if (!owner)
1413 abort();
1414 owner->wrapper = wrapper;
1415 splitter->p_owner = owner;
1416 splitter->pf_picture_new = SplitterPictureNew;
1417 splitter->pf_picture_del = SplitterPictureDel;
1419 /* */
1420 TAB_INIT(sys->count, sys->display);
1421 for (int i = 0; i < splitter->i_output; i++) {
1422 vout_display_owner_t owner;
1424 owner.event = SplitterEvent;
1425 owner.window_new = SplitterNewWindow;
1426 owner.window_del = SplitterDelWindow;
1428 const video_splitter_output_t *output = &splitter->p_output[i];
1429 vout_display_state_t ostate;
1431 memset(&ostate, 0, sizeof(ostate));
1432 ostate.cfg.is_fullscreen = false;
1433 ostate.cfg.display = state->cfg.display;
1434 ostate.cfg.align.horizontal = 0; /* TODO */
1435 ostate.cfg.align.vertical = 0; /* TODO */
1436 ostate.cfg.is_display_filled = true;
1437 ostate.cfg.zoom.num = 1;
1438 ostate.cfg.zoom.den = 1;
1440 vout_display_t *vd = DisplayNew(vout, &output->fmt, &ostate,
1441 output->psz_module ? output->psz_module : module,
1442 false, wrapper,
1443 double_click_timeout, hide_timeout, &owner);
1444 if (!vd) {
1445 vout_DeleteDisplay(wrapper, NULL);
1446 return NULL;
1448 TAB_APPEND(sys->count, sys->display, vd);
1451 return wrapper;
1453 #endif
1455 /*****************************************************************************
1456 * TODO move out
1457 *****************************************************************************/
1458 #include "vout_internal.h"
1459 void vout_SendDisplayEventMouse(vout_thread_t *vout, const vlc_mouse_t *m)
1461 if (vlc_mouse_HasMoved(&vout->p->mouse, m)) {
1462 vout_SendEventMouseMoved(vout, m->i_x, m->i_y);
1464 if (vlc_mouse_HasButton(&vout->p->mouse, m)) {
1465 static const int buttons[] = {
1466 MOUSE_BUTTON_LEFT,
1467 MOUSE_BUTTON_CENTER,
1468 MOUSE_BUTTON_RIGHT,
1469 MOUSE_BUTTON_WHEEL_UP,
1470 MOUSE_BUTTON_WHEEL_DOWN,
1473 for (int i = 0; buttons[i] >= 0; i++) {
1474 const int button = buttons[i];
1475 if (vlc_mouse_HasPressed(&vout->p->mouse, m, button))
1476 vout_SendEventMousePressed(vout, button);
1477 else if (vlc_mouse_HasReleased(&vout->p->mouse, m, button))
1478 vout_SendEventMouseReleased(vout, button);
1481 if (m->b_double_click)
1482 vout_SendEventMouseDoubleClick(vout);
1483 vout->p->mouse = *m;
1485 #ifdef ALLOW_DUMMY_VOUT
1486 static void DummyVoutSendDisplayEventMouse(vout_thread_t *vout, vlc_mouse_t *fallback, const vlc_mouse_t *m)
1488 vout_thread_sys_t p;
1490 if (!vout->p) {
1491 p.mouse = *fallback;
1492 vout->p = &p;
1494 vout_SendDisplayEventMouse(vout, m);
1495 if (vout->p == &p) {
1496 *fallback = p.mouse;
1497 vout->p = NULL;
1500 #endif
1501 vout_window_t * vout_NewDisplayWindow(vout_thread_t *vout, vout_display_t *vd, const vout_window_cfg_t *cfg)
1503 VLC_UNUSED(vd);
1504 vout_window_cfg_t cfg_override = *cfg;
1506 if( !var_InheritBool( vout, "embedded-video" ) )
1507 cfg_override.is_standalone = true;
1509 return vout_window_New(VLC_OBJECT(vout), NULL, &cfg_override);
1511 void vout_DeleteDisplayWindow(vout_thread_t *vout, vout_display_t *vd, vout_window_t *window)
1513 VLC_UNUSED(vout);
1514 VLC_UNUSED(vd);
1515 vout_window_Delete(window);