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