]> git.sesse.net Git - vlc/blob - modules/video_output/xcb/window.c
Set a name for the video window
[vlc] / modules / video_output / xcb / window.c
1 /**
2  * @file window.c
3  * @brief X C Bindings window provider module for VLC media player
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 #include <poll.h>
30
31 #include <xcb/xcb.h>
32 #include <xcb/xcb_aux.h>
33 typedef xcb_atom_t Atom;
34 #include <X11/Xatom.h> /* XA_WM_NAME */
35
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_window.h>
39
40 #include "xcb_vlc.h"
41
42 #define DISPLAY_TEXT N_("X11 display")
43 #define DISPLAY_LONGTEXT N_( \
44     "X11 hardware display to use. By default VLC will " \
45     "use the value of the DISPLAY environment variable.")
46
47 static int  Open (vlc_object_t *);
48 static void Close (vlc_object_t *);
49
50 /*
51  * Module descriptor
52  */
53 vlc_module_begin ()
54     set_shortname (N_("XCB window"))
55     set_description (N_("(Experimental) XCB video window"))
56     set_category (CAT_VIDEO)
57     set_subcategory (SUBCAT_VIDEO_VOUT)
58     set_capability ("xwindow", 10)
59     set_callbacks (Open, Close)
60
61     add_string ("x11-display", NULL, NULL,
62                 DISPLAY_TEXT, DISPLAY_LONGTEXT, true)
63 vlc_module_end ()
64
65 static int Control (vout_window_t *, int, va_list ap);
66 static void *Thread (void *);
67
68 struct vout_window_sys_t
69 {
70     xcb_connection_t *conn;
71     key_handler_t *keys;
72     vlc_thread_t thread;
73 };
74
75 static inline
76 void set_ascii_prop (xcb_connection_t *conn, xcb_window_t window,
77                      xcb_atom_t atom, const char *value)
78 {
79     xcb_change_property (conn, XCB_PROP_MODE_REPLACE, window, atom,
80                          XA_STRING, 8, strlen (value), value);
81 }
82
83 /**
84  * Create an X11 window.
85  */
86 static int Open (vlc_object_t *obj)
87 {
88     vout_window_t *wnd = (vout_window_t *)obj;
89     vout_window_sys_t *p_sys = malloc (sizeof (*p_sys));
90     xcb_generic_error_t *err;
91     xcb_void_cookie_t ck;
92
93     if (p_sys == NULL)
94         return VLC_ENOMEM;
95
96     /* Connect to X */
97     char *display = var_CreateGetNonEmptyString (wnd, "x11-display");
98     int snum;
99
100     xcb_connection_t *conn = xcb_connect (display, &snum);
101     free (display);
102     if (xcb_connection_has_error (conn) /*== NULL*/)
103         goto error;
104
105     /* Create window */
106     xcb_screen_t *scr = xcb_aux_get_screen (conn, snum);
107     const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
108     uint32_t values[2] = {
109         /* XCB_CW_BACK_PIXEL */
110         scr->black_pixel,
111         /* XCB_CW_EVENT_MASK */
112         XCB_EVENT_MASK_KEY_PRESS,
113     };
114
115     xcb_window_t window = xcb_generate_id (conn);
116     ck = xcb_create_window_checked (conn, scr->root_depth, window, scr->root,
117                                     0, 0, wnd->width, wnd->height, 0,
118                                     XCB_WINDOW_CLASS_INPUT_OUTPUT,
119                                     scr->root_visual, mask, values);
120     err = xcb_request_check (conn, ck);
121     if (err)
122     {
123         msg_Err (wnd, "creating window: X11 error %d", err->error_code);
124         goto error;
125     }
126
127     /* Plain ASCII localization of VLC for ICCCM window name */
128     set_ascii_prop (conn, window, XA_WM_NAME,
129                     pgettext ("ASCII VLC media player", "VLC media player"));
130     set_ascii_prop (conn, window, XA_WM_ICON_NAME,
131                     pgettext ("ASCII VLC", "VLC"));
132
133     wnd->handle.xid = window;
134     wnd->p_sys = p_sys;
135     wnd->control = Control;
136
137     p_sys->conn = conn;
138     p_sys->keys = CreateKeyHandler (obj, conn);
139
140     if ((p_sys->keys != NULL)
141      && vlc_clone (&p_sys->thread, Thread, wnd, VLC_THREAD_PRIORITY_LOW))
142         DestroyKeyHandler (p_sys->keys);
143
144     /* Make sure the window is ready */
145     xcb_map_window (conn, window);
146     xcb_flush (conn);
147
148     return VLC_SUCCESS;
149
150 error:
151     xcb_disconnect (conn);
152     free (p_sys);
153     return VLC_EGENERIC;
154 }
155
156
157 /**
158  * Destroys the X11 window.
159  */
160 static void Close (vlc_object_t *obj)
161 {
162     vout_window_t *wnd = (vout_window_t *)obj;
163     vout_window_sys_t *p_sys = wnd->p_sys;
164     xcb_connection_t *conn = p_sys->conn;
165     xcb_window_t window = wnd->handle.xid;
166
167     if (p_sys->keys)
168     {
169         vlc_cancel (p_sys->thread);
170         vlc_join (p_sys->thread, NULL);
171         DestroyKeyHandler (p_sys->keys);
172     }
173     xcb_unmap_window (conn, window);
174     xcb_destroy_window (conn, window);
175     xcb_disconnect (conn);
176     free (p_sys);
177 }
178
179
180 static void *Thread (void *data)
181 {
182     vout_window_t *wnd = data;
183     vout_window_sys_t *p_sys = wnd->p_sys;
184     xcb_connection_t *conn = p_sys->conn;
185
186     int fd = xcb_get_file_descriptor (conn);
187     if (fd == -1)
188         return NULL;
189
190     for (;;)
191     {
192         xcb_generic_event_t *ev;
193         struct pollfd ufd = { .fd = fd, .events = POLLIN, };
194
195         poll (&ufd, 1, -1);
196
197         int canc = vlc_savecancel ();
198         while ((ev = xcb_poll_for_event (conn)) != NULL)
199         {
200             if (ProcessKeyEvent (p_sys->keys, ev) == 0)
201                 continue;
202             msg_Dbg (wnd, "unhandled event: %"PRIu8, ev->response_type);
203             free (ev);
204         }
205         vlc_restorecancel (canc);
206
207         if (xcb_connection_has_error (conn))
208         {
209             msg_Err (wnd, "X server failure");
210             break;
211         }
212     }
213     return NULL;
214 }
215
216 #include <vlc_vout.h>
217
218 static int Control (vout_window_t *wnd, int cmd, va_list ap)
219 {
220     vout_window_sys_t *p_sys = wnd->p_sys;
221     xcb_connection_t *conn = p_sys->conn;
222
223     switch (cmd)
224     {
225         case VOUT_SET_SIZE:
226         {
227             unsigned width = va_arg (ap, unsigned);
228             unsigned height = va_arg (ap, unsigned);
229             const uint32_t values[] = { width, height, };
230
231             xcb_configure_window (conn, wnd->handle.xid,
232                                   XCB_CONFIG_WINDOW_WIDTH |
233                                   XCB_CONFIG_WINDOW_HEIGHT, values);
234             xcb_flush (conn);
235             break;
236         }
237
238         default:
239             msg_Err (wnd, "request %d not implemented", cmd);
240             return VLC_EGENERIC;
241     }
242     return VLC_SUCCESS;
243 }
244