vlcwindowless_xcb.cpp 4.63 KB
Newer Older
Ludovic Fauvet's avatar
Ludovic Fauvet committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*****************************************************************************
 * vlcwindowless_XCB.cpp: a VLC plugin for Mozilla (XCB windowless)
 *****************************************************************************
 * Copyright © 2012 VideoLAN
 * $Id$
 *
 * Authors: Ludovic Fauvet <etix@videolan.org>
 *
 * This program 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 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

24 25 26 27
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Ludovic Fauvet's avatar
Ludovic Fauvet committed
28 29
#include "vlcwindowless_xcb.h"

30
#include <X11/Xlib-xcb.h>
31
#include <xcb/xcb.h>
Ludovic Fauvet's avatar
Ludovic Fauvet committed
32 33 34 35 36
#include <xcb/xproto.h>
#include <cstring>
#include <cstdlib>

VlcWindowlessXCB::VlcWindowlessXCB(NPP instance, NPuint16_t mode) :
37
    VlcWindowlessBase(instance, mode), m_conn(0), m_colormap(0)
Ludovic Fauvet's avatar
Ludovic Fauvet committed
38 39 40 41 42
{
}

VlcWindowlessXCB::~VlcWindowlessXCB()
{
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
}

bool VlcWindowlessXCB::initXCB()
{
    NPSetWindowCallbackStruct *info =
            static_cast<NPSetWindowCallbackStruct *>(npwindow.ws_info);

    if (!info) {
        /* NPP_SetWindow has not been called yet */
        return false;
    }

    m_conn = XGetXCBConnection(info->display);
    m_colormap = info->colormap;

    return true;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
59 60 61 62 63 64 65 66
}

void VlcWindowlessXCB::drawBackground(xcb_drawable_t drawable)
{
    /* Obtain the background color */
    unsigned r = 0, g = 0, b = 0;
    HTMLColor2RGB(get_options().get_bg_color().c_str(), &r, &g, &b);
    xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(m_conn,
67
            xcb_alloc_color(m_conn, m_colormap,
Ludovic Fauvet's avatar
Ludovic Fauvet committed
68 69 70 71 72 73 74 75
                            (uint16_t) r << 8,
                            (uint16_t) g << 8,
                            (uint16_t) b << 8), NULL);
    uint32_t colorpixel = reply->pixel;
    free(reply);

    /* Prepare to fill the background */
    xcb_gcontext_t background = xcb_generate_id(m_conn);
76 77
    uint32_t        mask       = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
    uint32_t        values[2]  = {colorpixel, 0};
Ludovic Fauvet's avatar
Ludovic Fauvet committed
78 79
    xcb_create_gc(m_conn, background, drawable, mask, values);
    xcb_rectangle_t rect;
80 81
    rect.x = npwindow.x;
    rect.y = npwindow.y;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95
    rect.width = npwindow.width;
    rect.height = npwindow.height;

    /* Fill the background */
    xcb_poly_fill_rectangle(m_conn, drawable, background, 1, &rect);
    xcb_free_gc(m_conn, background);
}

bool VlcWindowlessXCB::handle_event(void *event)
{
    XEvent *xevent = static_cast<XEvent *>(event);
    switch (xevent->type) {
    case GraphicsExpose:

96 97
        xcb_gcontext_t gc;
        xcb_void_cookie_t cookie;
98
        xcb_generic_error_t *err;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
99 100
        XGraphicsExposeEvent *xgeevent = reinterpret_cast<XGraphicsExposeEvent *>(xevent);

101 102 103
        /* Initialize xcb connection if necessary */
        if (!m_conn)
            if (!initXCB()) break;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
104 105 106

        drawBackground(xgeevent->drawable);

107 108 109
        /* Validate video buffer size */
        if (m_frame_buf.empty() ||
            m_frame_buf.size() < m_media_width * m_media_height * DEF_PIXEL_BYTES)
Ludovic Fauvet's avatar
Ludovic Fauvet committed
110 111 112
            break;

        /* Compute the position of the video */
113 114
        int left = npwindow.x + (npwindow.width  - m_media_width)  / 2;
        int top  = npwindow.y + (npwindow.height - m_media_height) / 2;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
115

116
        gc = xcb_generate_id(m_conn);
Ludovic Fauvet's avatar
Ludovic Fauvet committed
117 118
        xcb_create_gc(m_conn, gc, xgeevent->drawable, 0, NULL);

119 120 121 122 123 124 125 126 127 128 129
        /* Push the frame in X11 */
        cookie = xcb_put_image_checked(
                    m_conn,
                    XCB_IMAGE_FORMAT_Z_PIXMAP,
                    xgeevent->drawable,
                    gc,
                    m_media_width,
                    m_media_height,
                    left, top,
                    0, 24,
                    m_media_width * m_media_height * 4,
130
                    (const uint8_t *)&m_frame_buf[0]);
131

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
132
        if ((err = xcb_request_check(m_conn, cookie)))
133 134 135 136 137
        {
            fprintf(stderr, "Unable to put picture into drawable. Error %d\n",
                            err->error_code);
            free(err);
        }
Ludovic Fauvet's avatar
Ludovic Fauvet committed
138 139 140 141 142 143 144

        /* Flush the the connection */
        xcb_flush(m_conn);
        xcb_free_gc(m_conn, gc);
    }
    return VlcWindowlessBase::handle_event(event);
}