x11.c 18.8 KB
Newer Older
1
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
2
 * @file x11.c
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 * @brief X C Bindings video output module for VLC media player
 */
/*****************************************************************************
 * Copyright © 2009 Rémi Denis-Courmont
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2.0
 * of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdlib.h>
#include <assert.h>

30
31
32
#include <sys/types.h>
#include <sys/shm.h>

33
#include <xcb/xcb.h>
34
35
#include <xcb/shm.h>

36
37
38
39
40
41
42
43
#include <xcb/xcb_aux.h>
#include <xcb/xcb_image.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout.h>
#include <vlc_window.h>

44
45
#include "xcb_vlc.h"

46
47
48
49
50
#define DISPLAY_TEXT N_("X11 display")
#define DISPLAY_LONGTEXT N_( \
    "X11 hardware display to use. By default VLC will " \
    "use the value of the DISPLAY environment variable.")

51
52
53
54
#define SHM_TEXT N_("Use shared memory")
#define SHM_LONGTEXT N_( \
    "Use shared memory to communicate between VLC and the X server.")

55
56
57
58
59
60
61
static int  Open (vlc_object_t *);
static void Close (vlc_object_t *);

/*
 * Module descriptor
 */
vlc_module_begin ()
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
62
63
    set_shortname (N_("XCB"))
    set_description (N_("(Experimental) XCB video output"))
64
65
66
67
68
69
70
    set_category (CAT_VIDEO)
    set_subcategory (SUBCAT_VIDEO_VOUT)
    set_capability ("video output", 0)
    set_callbacks (Open, Close)

    add_string ("x11-display", NULL, NULL,
                DISPLAY_TEXT, DISPLAY_LONGTEXT, true)
71
    add_bool ("x11-shm", true, NULL, SHM_TEXT, SHM_LONGTEXT, true)
72
73
74
75
76
77
78
79
vlc_module_end ()

struct vout_sys_t
{
    xcb_connection_t *conn;
    xcb_screen_t *screen;
    vout_window_t *embed; /* VLC window (when windowed) */

80
    xcb_visualid_t vid; /* selected visual */
81
    xcb_window_t parent; /* parent X window */
82
    xcb_colormap_t cmap; /* colormap for selected visual */
83
84
    xcb_window_t window; /* drawable X window */
    xcb_gcontext_t gc; /* context to put images */
85
    bool shm; /* whether to use MIT-SHM */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
86
    uint8_t bpp; /* bits per pixel */
87
    uint8_t pad; /* scanline pad */
88
    uint8_t byte_order; /* server byte order */
89
90
91
92
};

static int Init (vout_thread_t *);
static void Deinit (vout_thread_t *);
93
static void Render (vout_thread_t *, picture_t *);
94
95
96
static void Display (vout_thread_t *, picture_t *);
static int Manage (vout_thread_t *);

97
int CheckError (vout_thread_t *vout, const char *str, xcb_void_cookie_t ck)
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
{
    xcb_generic_error_t *err;

    err = xcb_request_check (vout->p_sys->conn, ck);
    if (err)
    {
        msg_Err (vout, "%s: X11 error %d", str, err->error_code);
        return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}

#define p_vout vout

/**
 * Probe the X server.
 */
static int Open (vlc_object_t *obj)
{
    vout_thread_t *vout = (vout_thread_t *)obj;
    vout_sys_t *p_sys = malloc (sizeof (*p_sys));
    if (p_sys == NULL)
        return VLC_ENOMEM;

    vout->p_sys = p_sys;
    p_sys->conn = NULL;
    p_sys->embed = NULL;

    /* Connect to X */
    char *display = var_CreateGetNonEmptyString (vout, "x11-display");
    int snum;
    p_sys->conn = xcb_connect (display, &snum);
    if (xcb_connection_has_error (p_sys->conn) /*== NULL*/)
    {
        msg_Err (vout, "cannot connect to X server %s",
                 display ? display : "");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
134
        free (display);
135
136
        goto error;
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
137
    free (display);
138

139
    const xcb_setup_t *setup = xcb_get_setup (p_sys->conn);
140
    p_sys->byte_order = setup->image_byte_order;
141

142
143
144
145
    /* Get the preferred screen */
    xcb_screen_t *scr = xcb_aux_get_screen (p_sys->conn, snum);
    p_sys->screen = scr;
    assert (p_sys->screen);
146
    msg_Dbg (vout, "using screen %d", snum);
147

148
149
150
151
    /* Determine our video format. Normally, this is done in pf_init(), but
     * this plugin always uses the same format for a given X11 screen. */
    uint8_t depth = 0;
    bool gray = true;
152
153
154
    for (const xcb_format_t *fmt = xcb_setup_pixmap_formats (setup),
             *end = fmt + xcb_setup_pixmap_formats_length (setup);
         fmt < end; fmt++)
155
    {
156
157
158
159
        vlc_fourcc_t chroma = 0;

        if (fmt->depth < depth)
            continue; /* We already found a better format! */
160

161
        /* Check that the pixmap format is supported by VLC. */
162
163
164
165
        switch (fmt->depth)
        {
          case 24:
            if (fmt->bits_per_pixel == 32)
166
                chroma = VLC_FOURCC ('R', 'V', '3', '2');
167
            else if (fmt->bits_per_pixel == 24)
168
                chroma = VLC_FOURCC ('R', 'V', '2', '4');
169
170
171
172
173
174
            else
                continue;
            break;
          case 16:
            if (fmt->bits_per_pixel != 16)
                continue;
175
            chroma = VLC_FOURCC ('R', 'V', '1', '6');
176
            break;
177
178
179
          case 15:
            if (fmt->bits_per_pixel != 16)
                continue;
180
            chroma = VLC_FOURCC ('R', 'V', '1', '5');
181
            break;
182
183
184
          case 8:
            if (fmt->bits_per_pixel != 8)
                continue;
185
            chroma = VLC_FOURCC ('R', 'G', 'B', '2');
186
            break;
187
188
          default:
            continue;
189
190
191
        }
        if ((fmt->bits_per_pixel << 4) % fmt->scanline_pad)
            continue; /* VLC pads lines to 16 pixels internally */
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

        /* Byte sex is a non-issue for 8-bits. It can be worked around with
         * RGB masks for 24-bits. Too bad for 15-bits and 16-bits. */
#ifdef WORDS_BIGENDIAN
# define ORDER XCB_IMAGE_ORDER_MSB_FIRST
#else
# define ORDER XCB_IMAGE_ORDER_LSB_FIRST
#endif
        if (fmt->bits_per_pixel == 16 && setup->image_byte_order != ORDER)
            continue;

        /* Check that the selected screen supports this depth */
        xcb_depth_iterator_t it = xcb_screen_allowed_depths_iterator (scr);
        while (it.rem > 0 && it.data->depth != fmt->depth)
             xcb_depth_next (&it);
        if (!it.rem)
            continue; /* Depth not supported on this screen */

        /* Find a visual type for the selected depth */
        const xcb_visualtype_t *vt = xcb_depth_visuals (it.data);
        xcb_visualid_t vid = 0;
        for (int i = xcb_depth_visuals_length (it.data); (i > 0) && !vid; i--)
        {
            if (vt->_class == XCB_VISUAL_CLASS_TRUE_COLOR)
            {
                msg_Dbg (vout,
                         "using TrueColor %"PRIu8"-bits visual ID 0x%0"PRIx32,
                         fmt->depth, vt->visual_id);
                vid = vt->visual_id;
                gray = false;
                break;
            }
            if (fmt->depth == 8 && vt->_class == XCB_VISUAL_CLASS_STATIC_GRAY)
            {
                if (!gray)
                    continue; /* Prefer color over gray scale */
                vid = vt->visual_id;
                chroma = VLC_FOURCC ('G', 'R', 'E', 'Y');
                msg_Dbg (vout,
                         "using static gray 8-bits visual ID 0x%x"PRIx32,
                         vt->visual_id);
                break;
            }
        }

        if (!vid)
            continue; /* The screen does not *really* support this depth */

        vout->fmt_out.i_chroma = vout->output.i_chroma = chroma;
        if (!gray)
        {
            vout->output.i_rmask = vt->red_mask;
            vout->output.i_gmask = vt->green_mask;
            vout->output.i_bmask = vt->blue_mask;
        }
        p_sys->vid = vid;
248
249
        p_sys->bpp = fmt->bits_per_pixel;
        p_sys->pad = fmt->scanline_pad;
250
251

        depth = fmt->depth;
252
    }
253

254
    if (depth == 0)
255
256
257
    {
        msg_Err (vout, "no supported pixmap formats");
        goto error;
258
    }
259

260
261
    msg_Dbg (vout, "using %"PRIu8" bits per pixels (line pad: %"PRIu8")",
             p_sys->bpp, p_sys->pad);
262

263
    /* Create colormap (needed to select non-default visual) */
264
265
266
267
268
269
270
271
    if (p_sys->vid != scr->root_visual)
    {
        p_sys->cmap = xcb_generate_id (p_sys->conn);
        xcb_create_colormap (p_sys->conn, XCB_COLORMAP_ALLOC_NONE,
                             p_sys->cmap, scr->root, p_sys->vid);
    }
    else
        p_sys->cmap = scr->default_colormap;
272

273
    /* Check shared memory support */
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    p_sys->shm = var_CreateGetBool (vout, "x11-shm") > 0;
    if (p_sys->shm)
    {
        xcb_shm_query_version_cookie_t ck;
        xcb_shm_query_version_reply_t *r;
        xcb_generic_error_t *err;

        ck = xcb_shm_query_version (p_sys->conn);
        r = xcb_shm_query_version_reply (p_sys->conn, ck, &err);
        if (!r)
        {
            msg_Err (vout, "shared memory (MIT-SHM) not available");
            msg_Warn (vout, "display will be slow");
            p_sys->shm = false;
        }
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
291
292
293
294
295
296
297
298
299
300
    /* Get window */
    /* FIXME: WTH to put as initial width/height values??? */
    p_sys->embed = vout_RequestXWindow (vout, &(int){ 0 }, &(int){ 0 },
                                        &(unsigned){ 0 }, &(unsigned){ 0 });
    if (p_sys->embed == NULL)
    {
        msg_Err (vout, "parent window not available");
        goto error;
    }

301
302
    vout->pf_init = Init;
    vout->pf_end = Deinit;
303
    vout->pf_render = Render;
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    vout->pf_display = Display;
    vout->pf_manage = Manage;
    return VLC_SUCCESS;

error:
    Close (obj);
    return VLC_EGENERIC;
}


/**
 * Disconnect from the X server.
 */
static void Close (vlc_object_t *obj)
{
    vout_thread_t *vout = (vout_thread_t *)obj;
    vout_sys_t *p_sys = vout->p_sys;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
322
323
    if (p_sys->embed)
        vout_ReleaseWindow (p_sys->embed);
324
    /* colormap is garbage-ollected by X (?) */
325
326
327
328
329
    if (p_sys->conn)
        xcb_disconnect (p_sys->conn);
    free (p_sys);
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
330
331
struct picture_sys_t
{
332
333
334
335
    xcb_connection_t *conn; /* Shared connection to X server */
    xcb_image_t *image;  /* Picture buffer */
    xcb_image_t *native; /* Rendered picture buffer (in X server format) */
    xcb_shm_seg_t segment; /* Shared memory segment X ID */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
336
337
};

338
#define SHM_ERR ((void *)(intptr_t)(-1))
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352

static int PictureInit (vout_thread_t *vout, picture_t *pic)
{
    vout_sys_t *p_sys = vout->p_sys;
    picture_sys_t *priv = malloc (sizeof (*p_sys));

    if (priv == NULL)
        return VLC_ENOMEM;

    assert (pic->i_status == FREE_PICTURE);
    vout_InitPicture (vout, pic, vout->output.i_chroma,
                      vout->output.i_width, vout->output.i_height,
                      vout->output.i_aspect);

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
    void *shm = SHM_ERR;
    const size_t size = pic->p->i_pitch * pic->p->i_lines;

    if (p_sys->shm)
    {   /* Allocate shared memory segment */
        int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0700);

        if (id == -1)
        {
            msg_Err (vout, "shared memory allocation error: %m");
            goto error;
        }

        /* Attach the segment to VLC */
        shm = shmat (id, NULL, 0 /* read/write */);
        if (shm == SHM_ERR)
        {
            msg_Err (vout, "shared memory attachment error: %m");
            shmctl (id, IPC_RMID, 0);
            goto error;
        }

        /* Attach the segment to X */
        xcb_void_cookie_t ck;

        priv->segment = xcb_generate_id (p_sys->conn);
        ck = xcb_shm_attach_checked (p_sys->conn, priv->segment, id, 1);
        shmctl (id, IPC_RMID, 0);

        if (CheckError (vout, "shared memory server-side error", ck))
        {
            msg_Info (vout, "using buggy X (remote) server? SSH?");
            shmdt (shm);
            shm = SHM_ERR;
        }
    }
389
390
    else
        priv->segment = 0;
391

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
392
393
394
395
396
    const unsigned real_width = pic->p->i_pitch / (p_sys->bpp >> 3);
    /* FIXME: anyway to getthing more intuitive than that?? */

    xcb_image_t *img;
    img = xcb_image_create (real_width, pic->p->i_lines,
397
                            XCB_IMAGE_FORMAT_Z_PIXMAP, p_sys->pad,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
398
                            p_sys->screen->root_depth, p_sys->bpp, p_sys->bpp,
399
                            p_sys->byte_order, XCB_IMAGE_ORDER_MSB_FIRST,
400
401
402
                            NULL,
                            (shm != SHM_ERR) ? size : 0,
                            (shm != SHM_ERR) ? shm : NULL);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
403
404

    if (img == NULL)
405
406
407
408
409
410
    {
        if (shm != SHM_ERR)
            xcb_shm_detach (p_sys->conn, priv->segment);
        goto error;
    }
    if (shm != SHM_ERR && xcb_image_native (p_sys->conn, img, 0) == NULL)
411
        msg_Warn (vout, "incompatible X server image format");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
412

413
    priv->conn = p_sys->conn;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
414
    priv->image = img;
415
    priv->native = NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
416
417
418
419
420
421
422
    pic->p_sys = priv;
    pic->p->p_pixels = img->data;
    pic->i_status = DESTROYED_PICTURE;
    pic->i_type = DIRECT_PICTURE;
    return VLC_SUCCESS;

error:
423
424
    if (shm != SHM_ERR)
        shmdt (shm);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
425
    free (priv);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
426
427
428
429
430
431
432
    return VLC_EGENERIC;
}


/**
 * Release picture private data
 */
433
static void PictureDeinit (picture_t *pic)
434
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
435
436
    struct picture_sys_t *p_sys = pic->p_sys;

437
438
439
440
441
    if (p_sys->segment != 0)
    {
        xcb_shm_detach (p_sys->conn, p_sys->segment);
        shmdt (p_sys->image->data);
    }
442
443
    if ((p_sys->native != NULL) && (p_sys->native != p_sys->image))
        xcb_image_destroy (p_sys->native);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
444
445
    xcb_image_destroy (p_sys->image);
    free (p_sys);
446
447
448
449
450
451
452
453
454
455
456
}

/**
 * Allocate drawable window and picture buffers.
 */
static int Init (vout_thread_t *vout)
{
    vout_sys_t *p_sys = vout->p_sys;
    const xcb_screen_t *screen = p_sys->screen;
    unsigned x, y, width, height;

Laurent Aimar's avatar
Laurent Aimar committed
457
458
    I_OUTPUTPICTURES = 0;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
459
    /* Determine parent window and size */
460
461
462
463
464
465
466
467
    if (vout->b_fullscreen)
    {
        p_sys->parent = screen->root;
        width = screen->width_in_pixels;
        height = screen->height_in_pixels;
    }
    else
    {
468
        p_sys->parent = p_sys->embed->handle.xid;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

        /* Subscribe to parent window resize events */
        const uint32_t value = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
        xcb_change_window_attributes (p_sys->conn, p_sys->parent,
                                      XCB_CW_EVENT_MASK, &value);

        xcb_get_geometry_cookie_t ck;
        ck = xcb_get_geometry (p_sys->conn, p_sys->parent);

        xcb_get_geometry_reply_t *geo;
        xcb_generic_error_t *err;
        geo = xcb_get_geometry_reply (p_sys->conn, ck, &err);
        width = geo->width;
        height = geo->height;
        free (geo);
484
485
486
    }

    vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
487

488
    /* FIXME: I don't get the subtlety between output and fmt_out here */
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
    vout->fmt_out.i_visible_width = width;
    vout->fmt_out.i_visible_height = height;
    vout->fmt_out.i_sar_num = vout->fmt_out.i_sar_den = 1;

    vout->output.i_width = vout->fmt_out.i_width =
        width * vout->fmt_in.i_width / vout->fmt_in.i_visible_width;
    vout->output.i_height = vout->fmt_out.i_height =
        height * vout->fmt_in.i_height / vout->fmt_in.i_visible_height;
    vout->fmt_out.i_x_offset =
        width * vout->fmt_in.i_x_offset / vout->fmt_in.i_visible_width;
    p_vout->fmt_out.i_y_offset =
        height * vout->fmt_in.i_y_offset / vout->fmt_in.i_visible_height;

    assert (height > 0);
    vout->output.i_aspect = vout->fmt_out.i_aspect =
        width * VOUT_ASPECT_FACTOR / height;
505
506

    /* Create window */
507
508
    const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK
                        | XCB_CW_COLORMAP;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
509
    const uint32_t values[] = {
510
511
512
513
514
        /* XCB_CW_BACK_PIXEL */
        screen->black_pixel,
        /* XCB_CW_EVENT_MASK */
        XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
        XCB_EVENT_MASK_POINTER_MOTION,
515
516
        /* XCB_CW_COLORMAP */
        p_sys->cmap,
517
    };
518
519
520
521
522
523
    xcb_void_cookie_t c;
    xcb_window_t window = xcb_generate_id (p_sys->conn);

    c = xcb_create_window_checked (p_sys->conn, screen->root_depth, window,
                                   p_sys->parent, x, y, width, height, 0,
                                   XCB_WINDOW_CLASS_INPUT_OUTPUT,
524
                                   p_sys->vid, mask, values);
525
526
    if (CheckError (vout, "cannot create X11 window", c))
        goto error;
527
    p_sys->window = window;
528
529
530
531
532
533
534
535
536
537
    msg_Dbg (vout, "using X11 window %08"PRIx32, p_sys->window);
    xcb_map_window (p_sys->conn, window);

    /* Create graphic context (I wonder why the heck do we need this) */
    p_sys->gc = xcb_generate_id (p_sys->conn);
    xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL);
    msg_Dbg (vout, "using X11 graphic context %08"PRIx32, p_sys->gc);
    xcb_flush (p_sys->conn);

    /* Allocate picture buffers */
538
539
    I_OUTPUTPICTURES = 0;
    for (size_t index = 0; I_OUTPUTPICTURES < 2; index++)
540
    {
541
        picture_t *pic = vout->p_picture + index;
542

543
544
545
546
        if (index > sizeof (vout->p_picture) / sizeof (pic))
            break;
        if (pic->i_status != FREE_PICTURE)
            continue;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
547
548
        if (PictureInit (vout, pic))
            break;
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
        PP_OUTPUTPICTURE[I_OUTPUTPICTURES++] = pic;
    }

    return VLC_SUCCESS;

error:
    Deinit (vout);
    return VLC_EGENERIC;
}

/**
 * Free picture buffers.
 */
static void Deinit (vout_thread_t *vout)
{
    vout_sys_t *p_sys = vout->p_sys;

Laurent Aimar's avatar
Laurent Aimar committed
566
567
    for (int i = 0; i < I_OUTPUTPICTURES; i++)
        PictureDeinit (PP_OUTPUTPICTURE[i]);
568
569
570
571
572

    xcb_unmap_window (p_sys->conn, p_sys->window);
    xcb_destroy_window (p_sys->conn, p_sys->window);
}

573
574
575
576
577
578
579
580
581
582
583
584
585
586
/**
 * Prepares an image ahead of display.
 */
static void Render (vout_thread_t *vout, picture_t *pic)
{
    vout_sys_t *p_sys = vout->p_sys;
    picture_sys_t *priv = pic->p_sys;

    if ((priv->native != NULL) && (priv->native != priv->image))
        xcb_image_destroy (priv->native);
    priv->native = xcb_image_native (p_sys->conn, priv->image, 1);
}


587
588
589
590
591
592
/**
 * Sends an image to the X server.
 */
static void Display (vout_thread_t *vout, picture_t *pic)
{
    vout_sys_t *p_sys = vout->p_sys;
593
    picture_sys_t *priv = pic->p_sys;
594
    xcb_image_t *img = priv->image, *native = priv->native;
595

596
    if ((native == img) && (img->base == NULL))
597
    {
598
599
600
601
602
603
604
605
        xcb_shm_segment_info_t info = {
            .shmseg = priv->segment,
            .shmid = -1, /* lost track of it, unimportant */
            .shmaddr = img->data,
        };

        xcb_image_shm_put (p_sys->conn, p_sys->window, p_sys->gc, img, info,
                        0, 0, 0, 0, img->width, img->height, 0);
606
    }
607
    else
608
    if (native != NULL)
609
610
        xcb_image_put (p_sys->conn, p_sys->window, p_sys->gc, native, 0, 0, 0);
    xcb_flush (p_sys->conn);
611
612
613
614
615
616
617
618
619
620
621
}

/**
 * Process incoming X events.
 */
static int Manage (vout_thread_t *vout)
{
    vout_sys_t *p_sys = vout->p_sys;
    xcb_generic_event_t *ev;

    while ((ev = xcb_poll_for_event (p_sys->conn)) != NULL)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
622
        ProcessEvent (vout, p_sys->conn, p_sys->window, ev);
623
624
625
626
627
628
629
630

    if (xcb_connection_has_error (p_sys->conn))
    {
        msg_Err (vout, "X server failure");
        return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}