vlcwindowless_xcb.cpp 4.59 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 24 25
/*****************************************************************************
 * 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.
 *****************************************************************************/

#include "vlcwindowless_xcb.h"

26
#include <X11/Xlib-xcb.h>
27
#include <xcb/xcb.h>
Ludovic Fauvet's avatar
Ludovic Fauvet committed
28 29 30 31 32
#include <xcb/xproto.h>
#include <cstring>
#include <cstdlib>

VlcWindowlessXCB::VlcWindowlessXCB(NPP instance, NPuint16_t mode) :
33
    VlcWindowlessBase(instance, mode), m_conn(0), m_colormap(0)
Ludovic Fauvet's avatar
Ludovic Fauvet committed
34 35 36 37 38
{
}

VlcWindowlessXCB::~VlcWindowlessXCB()
{
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
}

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
55 56 57 58 59 60 61 62
}

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,
63
            xcb_alloc_color(m_conn, m_colormap,
Ludovic Fauvet's avatar
Ludovic Fauvet committed
64 65 66 67 68 69 70 71
                            (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);
72 73
    uint32_t        mask       = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
    uint32_t        values[2]  = {colorpixel, 0};
Ludovic Fauvet's avatar
Ludovic Fauvet committed
74 75
    xcb_create_gc(m_conn, background, drawable, mask, values);
    xcb_rectangle_t rect;
76 77
    rect.x = npwindow.x;
    rect.y = npwindow.y;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91
    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:

92 93
        xcb_gcontext_t gc;
        xcb_void_cookie_t cookie;
94
        xcb_generic_error_t *err;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
95 96
        XGraphicsExposeEvent *xgeevent = reinterpret_cast<XGraphicsExposeEvent *>(xevent);

97 98 99
        /* Initialize xcb connection if necessary */
        if (!m_conn)
            if (!initXCB()) break;
Ludovic Fauvet's avatar
Ludovic Fauvet committed
100 101 102

        drawBackground(xgeevent->drawable);

103 104 105
        /* 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
106 107 108
            break;

        /* Compute the position of the video */
109 110
        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
111

112
        gc = xcb_generate_id(m_conn);
Ludovic Fauvet's avatar
Ludovic Fauvet committed
113 114
        xcb_create_gc(m_conn, gc, xgeevent->drawable, 0, NULL);

115 116 117 118 119 120 121 122 123 124 125
        /* 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,
126
                    (const uint8_t *)&m_frame_buf[0]);
127

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

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