a3c7668cc4e1463d9d9edc08399bc5ed2838071e
[vlc.git] / modules / video_output / drawable.c
1 /**
2  * @file drawable.c
3  * @brief Legacy monolithic LibVLC video window provider
4  */
5 /*****************************************************************************
6  * Copyright © 2009 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2.0
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdarg.h>
28 #include <assert.h>
29
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_vout_window.h>
33
34 static int  Open (vlc_object_t *);
35 static void Close(vlc_object_t *);
36
37 #define XID_TEXT N_("ID of the video output X window")
38 #define XID_LONGTEXT N_( \
39     "VLC can embed its video output in an existing X11 window. " \
40     "This is the X identifier of that window (0 means none).")
41
42 /*
43  * Module descriptor
44  */
45 vlc_module_begin ()
46     set_shortname (N_("Drawable"))
47     set_description (N_("Embedded window video"))
48     set_category (CAT_VIDEO)
49     set_subcategory (SUBCAT_VIDEO_VOUT)
50     set_capability ("vout window xid", 70)
51     set_callbacks (Open, Close)
52     add_integer ("drawable-xid", 0, NULL, XID_TEXT, XID_LONGTEXT, true)
53         change_unsaveable ()
54     //add_integer ("drawable-hwnd", 0, NULL, HWN_TEXT, HWND_LONGTEXT, true) /* How to ? */
55     //    change_unsaveable ()
56 vlc_module_end ()
57
58 static int Control (vout_window_t *, int, va_list);
59
60 /* TODO: move to vlc_variables.h */
61 static inline void *var_GetAddress (vlc_object_t *o, const char *name)
62 {
63     vlc_value_t val;
64     return var_Get (o, name, &val) ? NULL : val.p_address;
65 }
66
67 static vlc_mutex_t serializer = VLC_STATIC_MUTEX;
68
69 /**
70  * Find the drawable set by libvlc application.
71  */
72 static int Open (vlc_object_t *obj)
73 {
74     vout_window_t *wnd = (vout_window_t *)obj;
75     const char *varname;
76     bool ptr;
77
78     switch (wnd->cfg->type)
79     {
80     case VOUT_WINDOW_TYPE_XID:
81         varname = "drawable-xid";
82         ptr = false;
83         break;
84     case VOUT_WINDOW_TYPE_HWND:
85         varname = "drawable-hwnd";
86         ptr = true;
87         break;
88     default:
89         return VLC_EGENERIC;
90     }
91
92     void **used, *val;
93     size_t n = 0;
94
95     if (var_Create (obj->p_libvlc, "drawables-in-use", VLC_VAR_ADDRESS)
96      || var_Create (obj, varname, VLC_VAR_DOINHERIT
97                                   | (ptr ? VLC_VAR_ADDRESS : VLC_VAR_INTEGER)))
98         return VLC_ENOMEM;
99
100     if (ptr)
101         val = var_GetAddress (obj, varname);
102     else
103         val = (void *)(uintptr_t)var_GetInteger (obj, varname);
104     var_Destroy (obj, varname);
105
106     /* Keep a list of busy drawables, so we don't overlap videos if there are
107      * more than one video track in the stream. */
108     vlc_mutex_lock (&serializer);
109     /* TODO: per-type list of busy drawables */
110     used = var_GetAddress (VLC_OBJECT (obj->p_libvlc), "drawables-in-use");
111     if (used != NULL)
112     {
113         while (used[n] != NULL)
114         {
115             if (used[n] == val)
116                 goto skip;
117             n++;
118         }
119     }
120
121     used = realloc (used, sizeof (*used) * (n + 2));
122     if (used != NULL)
123     {
124         used[n] = val;
125         used[n + 1] = NULL;
126         var_SetAddress (obj->p_libvlc, "drawables-in-use", used);
127     }
128     else
129     {
130 skip:
131         msg_Warn (wnd, "drawable %p is busy", val);
132         val = NULL;
133     }
134     vlc_mutex_unlock (&serializer);
135
136     if (val == NULL)
137         return VLC_EGENERIC;
138
139     if (ptr)
140         wnd->handle.hwnd = val;
141     else
142         wnd->handle.xid = (uintptr_t)val;
143
144     /* FIXME: check that X server matches --x11-display (if specified) */
145     /* FIXME: get window size (in platform-dependent ways) */
146
147     wnd->control = Control;
148     wnd->sys = val;
149     return VLC_SUCCESS;
150 }
151
152 /**
153  * Release the drawable.
154  */
155 static void Close (vlc_object_t *obj)
156 {
157     vout_window_t *wnd = (vout_window_t *)obj;
158     void **used, *val = wnd->sys;
159     size_t n = 0;
160
161     /* Remove this drawable from the list of busy ones */
162     vlc_mutex_lock (&serializer);
163     used = var_GetAddress (VLC_OBJECT (obj->p_libvlc), "drawables-in-use");
164     assert (used);
165     while (used[n] != val)
166     {
167         assert (used[n]);
168         n++;
169     }
170     do
171         used[n] = used[n + 1];
172     while (used[++n] != NULL);
173
174     if (n == 0)
175       /* should not be needed (var_Destroy...) but better safe than sorry: */
176          var_SetAddress (obj->p_libvlc, "drawables-in-use", NULL);
177     vlc_mutex_unlock (&serializer);
178
179     if (n == 0)
180         free (used);
181     /* Variables are reference-counted... */
182     var_Destroy (obj->p_libvlc, "drawables-in-use");
183 }
184
185
186 static int Control (vout_window_t *wnd, int query, va_list ap)
187 {
188     switch (query)
189     {
190         case VOUT_WINDOW_SET_SIZE:   /* not allowed */
191         case VOUT_WINDOW_SET_ON_TOP: /* not allowed either, would be ugly */
192             return VLC_EGENERIC;
193         default:
194             msg_Warn (wnd, "unsupported control query %d", query);
195             return VLC_EGENERIC;
196     }
197 }
198