1 /*****************************************************************************
2  * window.c: "vout window" management
3  *****************************************************************************
4  * Copyright (C) 2009 Laurent Aimar
5  * $Id: 36aaa9d04602c311cd2ba678f675ca612c13678b $
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
31 
32 #include <vlc_common.h>
33 #include <vlc_vout_window.h>
34 #include <vlc_modules.h>
35 #include "inhibit.h"
36 #include <libvlc.h>
37 
38 typedef struct
39 {
40     vout_window_t wnd;
41     module_t *module;
42     vlc_inhibit_t *inhibit;
43 } window_t;
44 
vout_window_start(void * func,va_list ap)45 static int vout_window_start(void *func, va_list ap)
46 {
47     int (*activate)(vout_window_t *, const vout_window_cfg_t *) = func;
48     vout_window_t *wnd = va_arg(ap, vout_window_t *);
49     const vout_window_cfg_t *cfg = va_arg(ap, const vout_window_cfg_t *);
50 
51     return activate(wnd, cfg);
52 }
53 
vout_window_New(vlc_object_t * obj,const char * module,const vout_window_cfg_t * cfg,const vout_window_owner_t * owner)54 vout_window_t *vout_window_New(vlc_object_t *obj, const char *module,
55                                const vout_window_cfg_t *cfg,
56                                const vout_window_owner_t *owner)
57 {
58     window_t *w = vlc_custom_create(obj, sizeof(*w), "window");
59     vout_window_t *window = &w->wnd;
60 
61     memset(&window->handle, 0, sizeof(window->handle));
62     window->info.has_double_click = false;
63     window->control = NULL;
64     window->sys = NULL;
65 
66     if (owner != NULL)
67         window->owner = *owner;
68     else
69         window->owner.resized = NULL;
70 
71     w->module = vlc_module_load(window, "vout window", module,
72                                 module && *module,
73                                 vout_window_start, window, cfg);
74     if (!w->module) {
75         vlc_object_release(window);
76         return NULL;
77     }
78 
79     /* Hook for screensaver inhibition */
80     if (var_InheritBool(obj, "disable-screensaver") &&
81         (window->type == VOUT_WINDOW_TYPE_XID || window->type == VOUT_WINDOW_TYPE_HWND
82       || window->type == VOUT_WINDOW_TYPE_WAYLAND))
83     {
84         w->inhibit = vlc_inhibit_Create(VLC_OBJECT (window));
85         if (w->inhibit != NULL)
86             vlc_inhibit_Set(w->inhibit, VLC_INHIBIT_VIDEO);
87     }
88     else
89         w->inhibit = NULL;
90     return window;
91 }
92 
vout_window_stop(void * func,va_list ap)93 static void vout_window_stop(void *func, va_list ap)
94 {
95     int (*deactivate)(vout_window_t *) = func;
96     vout_window_t *wnd = va_arg(ap, vout_window_t *);
97 
98     deactivate(wnd);
99 }
100 
vout_window_Delete(vout_window_t * window)101 void vout_window_Delete(vout_window_t *window)
102 {
103     if (!window)
104         return;
105 
106     window_t *w = (window_t *)window;
107     if (w->inhibit)
108     {
109         vlc_inhibit_Set (w->inhibit, VLC_INHIBIT_NONE);
110         vlc_inhibit_Destroy (w->inhibit);
111     }
112 
113     vlc_module_unload(window, w->module, vout_window_stop, window);
114     vlc_object_release(window);
115 }
116 
vout_window_SetInhibition(vout_window_t * window,bool enabled)117 void vout_window_SetInhibition(vout_window_t *window, bool enabled)
118 {
119     window_t *w = (window_t *)window;
120     unsigned flags = enabled ? VLC_INHIBIT_VIDEO : VLC_INHIBIT_NONE;
121 
122     if (w->inhibit != NULL)
123         vlc_inhibit_Set(w->inhibit, flags);
124 }
125 
126 /* Video output display integration */
127 #include <vlc_vout.h>
128 #include <vlc_vout_display.h>
129 #include "window.h"
130 #include "event.h"
131 
132 typedef struct vout_display_window
133 {
134     vout_display_t *vd;
135     unsigned width;
136     unsigned height;
137 
138     vlc_mutex_t lock;
139 } vout_display_window_t;
140 
vout_display_window_ResizeNotify(vout_window_t * window,unsigned width,unsigned height)141 static void vout_display_window_ResizeNotify(vout_window_t *window,
142                                              unsigned width, unsigned height)
143 {
144     vout_display_window_t *state = window->owner.sys;
145 
146     msg_Dbg(window, "resized to %ux%u", width, height);
147     vlc_mutex_lock(&state->lock);
148     state->width = width;
149     state->height = height;
150 
151     if (state->vd != NULL)
152         vout_display_SendEventDisplaySize(state->vd, width, height);
153     vlc_mutex_unlock(&state->lock);
154 }
155 
vout_display_window_CloseNotify(vout_window_t * window)156 static void vout_display_window_CloseNotify(vout_window_t *window)
157 {
158     vout_thread_t *vout = (vout_thread_t *)window->obj.parent;
159 
160     vout_SendEventClose(vout);
161 }
162 
vout_display_window_MouseEvent(vout_window_t * window,const vout_window_mouse_event_t * mouse)163 static void vout_display_window_MouseEvent(vout_window_t *window,
164                                            const vout_window_mouse_event_t *mouse)
165 {
166     vout_thread_t *vout = (vout_thread_t *)window->obj.parent;
167     vout_WindowMouseEvent(vout, mouse);
168 }
169 
170 /**
171  * Creates a video window, initially without any attached display.
172  */
vout_display_window_New(vout_thread_t * vout,const vout_window_cfg_t * cfg)173 vout_window_t *vout_display_window_New(vout_thread_t *vout,
174                                        const vout_window_cfg_t *cfg)
175 {
176     vout_display_window_t *state = malloc(sizeof (*state));
177     if (state == NULL)
178         return NULL;
179 
180     state->vd = NULL;
181     state->width = cfg->width;
182     state->height = cfg->height;
183     vlc_mutex_init(&state->lock);
184 
185     vout_window_owner_t owner = {
186         .sys = state,
187         .resized = vout_display_window_ResizeNotify,
188         .closed = vout_display_window_CloseNotify,
189         .mouse_event = vout_display_window_MouseEvent,
190     };
191     vout_window_t *window;
192 
193     window = vout_window_New((vlc_object_t *)vout, "$window", cfg, &owner);
194     if (window == NULL) {
195         vlc_mutex_destroy(&state->lock);
196         free(state);
197     }
198     return window;
199 }
200 
201 /**
202  * Attaches a window to a display. Window events will be dispatched to the
203  * display until they are detached.
204  */
vout_display_window_Attach(vout_window_t * window,vout_display_t * vd)205 void vout_display_window_Attach(vout_window_t *window, vout_display_t *vd)
206 {
207     vout_display_window_t *state = window->owner.sys;
208 
209     vout_window_SetSize(window,
210                         vd->cfg->display.width, vd->cfg->display.height);
211 
212     vlc_mutex_lock(&state->lock);
213     state->vd = vd;
214 
215     vout_display_SendEventDisplaySize(vd, state->width, state->height);
216     vlc_mutex_unlock(&state->lock);
217 }
218 
219 /**
220  * Detaches a window from a display. Window events will no longer be dispatched
221  * (except those that do not need a display).
222  */
vout_display_window_Detach(vout_window_t * window)223 void vout_display_window_Detach(vout_window_t *window)
224 {
225     vout_display_window_t *state = window->owner.sys;
226 
227     vlc_mutex_lock(&state->lock);
228     state->vd = NULL;
229     vlc_mutex_unlock(&state->lock);
230 }
231 
232 /**
233  * Destroys a video window.
234  * \note The window must be detached.
235  */
vout_display_window_Delete(vout_window_t * window)236 void vout_display_window_Delete(vout_window_t *window)
237 {
238     vout_display_window_t *state = window->owner.sys;
239 
240     vout_window_Delete(window);
241 
242     assert(state->vd == NULL);
243     vlc_mutex_destroy(&state->lock);
244     free(state);
245 }
246