x11_display.cpp 13.1 KB
Newer Older
1 2 3
/*****************************************************************************
 * x11_display.cpp
 *****************************************************************************
4
 * Copyright (C) 2003 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8
 *          Olivier Teulière <ipkiss@via.ecp.fr>
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24 25 26
 *****************************************************************************/

#ifdef X11_SKINS

27
#include <X11/Xlib.h>
28 29 30 31 32 33
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>

#include "x11_display.hpp"
#include "../src/logger.hpp"

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
// Macro to compute a pixel value
#define PUT_PIXEL(value, r, g, b, type) \
    value = \
        ( ((type)r >> m_redRightShift) << m_redLeftShift ) | \
        ( ((type)g >> m_greenRightShift) << m_greenLeftShift ) | \
        ( ((type)b >> m_blueRightShift) << m_blueLeftShift );

// Macro to blend a pixel with another color
#define BLEND_PIXEL(value, r, g, b, a, type) \
    uint16_t temp; \
    temp = ((uint8_t)((value >> m_redLeftShift) << m_redRightShift)); \
    uint8_t red = r + ( temp * (255 - a) ) / 255; \
    temp = ((uint8_t)((value >> m_greenLeftShift) << m_greenRightShift)); \
    uint8_t green = g + ( temp * (255 - a) ) / 255; \
    temp = ((uint8_t)((value >> m_blueLeftShift) << m_blueRightShift)); \
    uint8_t blue = b + ( temp * (255 - a) ) / 255; \
    PUT_PIXEL(value, red, green, blue, type)

52 53

X11Display::X11Display( intf_thread_t *pIntf ): SkinObject( pIntf ),
54
    m_mainWindow( 0 ), m_gc( NULL ), m_colormap( 0 )
55
{
56
    char *psz_display = var_CreateGetNonEmptyString( pIntf, "x11-display" );
57
    // Open a connection to the X Server
58 59
    m_pDisplay = XOpenDisplay( psz_display );
    free( psz_display );
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74
    if( m_pDisplay == NULL )
    {
        MSG_ERR( "Cannot open display" );
        return;
    }

    // Load the XShape extension
    int event, error;
    XShapeQueryExtension( m_pDisplay, &event, &error );

    // Get the display parameters
    int screen = DefaultScreen( m_pDisplay );
    int depth = DefaultDepth( m_pDisplay, screen );
    int order = ImageByteOrder( m_pDisplay );
75
    Window root = DefaultRootWindow( m_pDisplay );
76 77 78 79 80 81 82 83 84 85 86

    // Template for looking up the XVisualInfo
    XVisualInfo xVInfoTemplate;
    xVInfoTemplate.screen = screen;
    xVInfoTemplate.depth = depth;

    XVisualInfo *pVInfo = NULL;
    int vCount = 0;

    switch( depth )
    {
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
        case 8:
            xVInfoTemplate.c_class = DirectColor;
            // Get the DirectColor visual
            pVInfo = XGetVisualInfo( m_pDisplay, VisualScreenMask |
                                     VisualClassMask, &xVInfoTemplate,
                                     &vCount );
            if( pVInfo == NULL )
            {
                msg_Err( getIntf(), "no DirectColor visual available" );
                m_pDisplay = NULL;
                break;
            }
            m_pVisual = pVInfo->visual;

            // Compute the color shifts
            getShifts( pVInfo->red_mask, m_redLeftShift, m_redRightShift );
            getShifts( pVInfo->green_mask, m_greenLeftShift,
                       m_greenRightShift );
            getShifts( pVInfo->blue_mask, m_blueLeftShift, m_blueRightShift );

            // Create a color map
108
            m_colormap = XCreateColormap( m_pDisplay, root,
109 110 111 112 113 114 115 116 117 118 119
                    DefaultVisual( m_pDisplay, screen ), AllocAll );

            // Create the palette
            XColor pColors[255];
            for( uint16_t i = 0; i < 255; i++ )
            {
                // kludge: colors are indexed reversely because color 255 seems
                // to bereserved for black even if we try to set it to white
                pColors[i].pixel = 254-i;
                pColors[i].pad   = 0;
                pColors[i].flags = DoRed | DoGreen | DoBlue;
120 121 122 123 124 125
                pColors[i].red   =
                    (i >> m_redLeftShift) << (m_redRightShift + 8);
                pColors[i].green =
                    (i >> m_greenLeftShift) << (m_greenRightShift + 8);
                pColors[i].blue  =
                    (i >> m_blueLeftShift) << (m_blueRightShift + 8);
126 127
            }
            XStoreColors( m_pDisplay, m_colormap, pColors, 255 );
128 129
            blendPixelImpl = &X11Display::blendPixel8;
            putPixelImpl = &X11Display::putPixel8;
130 131 132
            m_pixelSize = 1;
            break;

133
        case 15:
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        case 16:
        case 24:
        case 32:
            // Get the TrueColor visual
            xVInfoTemplate.c_class = TrueColor;
            pVInfo = XGetVisualInfo( m_pDisplay, VisualScreenMask |
                                     VisualDepthMask | VisualClassMask,
                                     &xVInfoTemplate, &vCount );
            if( pVInfo == NULL )
            {
                msg_Err( getIntf(), "No TrueColor visual for depth %d",
                         depth );
                m_pDisplay = NULL;
                break;
            }
            m_pVisual = pVInfo->visual;

            // Compute the color shifts
            getShifts( pVInfo->red_mask, m_redLeftShift, m_redRightShift );
            getShifts( pVInfo->green_mask, m_greenLeftShift,
                       m_greenRightShift );
            getShifts( pVInfo->blue_mask, m_blueLeftShift, m_blueRightShift );

157
            if( depth == 15 || depth == 16 )
158 159 160
            {
                if( order == MSBFirst )
                {
161 162
                    blendPixelImpl = &X11Display::blendPixel16MSB;
                    putPixelImpl = &X11Display::putPixel16MSB;
163 164 165
                }
                else
                {
166 167
                    blendPixelImpl = &X11Display::blendPixel16LSB;
                    putPixelImpl = &X11Display::putPixel16LSB;
168 169 170 171 172 173 174
                }
                m_pixelSize = 2;
            }
            else
            {
                if( order == MSBFirst )
                {
175 176
                    blendPixelImpl = &X11Display::blendPixel32MSB;
                    putPixelImpl = &X11Display::putPixel32MSB;
177 178 179
                }
                else
                {
180 181
                    blendPixelImpl = &X11Display::blendPixel32LSB;
                    putPixelImpl = &X11Display::putPixel32LSB;
182 183 184 185 186 187
                }
                m_pixelSize = 4;
            }
            break;

        default:
Clément Stenac's avatar
Clément Stenac committed
188
            msg_Err( getIntf(), "unsupported depth: %d bpp\n", depth );
189 190 191 192 193 194 195 196 197
            m_pDisplay = NULL;
            break;
    }

    // Free the visual info
    if( pVInfo )
    {
        XFree( pVInfo );
    }
198 199 200 201 202 203

    // Create a graphics context that doesn't generate GraphicsExpose events
    if( m_pDisplay )
    {
        XGCValues xgcvalues;
        xgcvalues.graphics_exposures = False;
204
        m_gc = XCreateGC( m_pDisplay, root, GCGraphicsExposures, &xgcvalues );
205

206 207
        // Create a parent window to have a single task in the task bar
        XSetWindowAttributes attr;
208 209
        m_mainWindow = XCreateWindow( m_pDisplay, root, 0, 0, 1, 1, 0, 0,
                                      InputOutput, CopyFromParent, 0, &attr );
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

        // Changing decorations
        struct {
            unsigned long flags;
            unsigned long functions;
            unsigned long decorations;
            long input_mode;
            unsigned long status;
        } motifWmHints;
        Atom hints_atom = XInternAtom( m_pDisplay, "_MOTIF_WM_HINTS", False );
        motifWmHints.flags = 2;    // MWM_HINTS_DECORATIONS;
        motifWmHints.decorations = 0;
        XChangeProperty( m_pDisplay, m_mainWindow, hints_atom, hints_atom, 32,
                         PropModeReplace, (unsigned char *)&motifWmHints,
                         sizeof( motifWmHints ) / sizeof( long ) );

        // Change the window title
        XStoreName( m_pDisplay, m_mainWindow, "VLC Media Player" );

        // Receive map notify events
        XSelectInput( m_pDisplay, m_mainWindow, StructureNotifyMask );

        // Set an empty mask for the window
        Region mask = XCreateRegion();
234 235 236 237
        XShapeCombineRegion( m_pDisplay, m_mainWindow, ShapeBounding, 0, 0,
                             mask, ShapeSet );
        XDestroyRegion( mask );

238 239 240 241 242 243
        // Map the window
        XMapWindow( m_pDisplay, m_mainWindow);

        // Move it outside the screen to avoid seeing it in workspace selector
        XMoveWindow( m_pDisplay, m_mainWindow, -10, -10 );
    }
244 245 246 247 248
}


X11Display::~X11Display()
{
249 250 251 252
    if( m_mainWindow )
    {
        XDestroyWindow( m_pDisplay, m_mainWindow );
    }
253 254 255 256
    if( m_gc )
    {
        XFreeGC( m_pDisplay, m_gc );
    }
257 258 259 260
    if( m_colormap )
    {
        XFreeColormap( m_pDisplay, m_colormap );
    }
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    if( m_pDisplay )
    {
        XCloseDisplay( m_pDisplay );
    }
}


void X11Display::getShifts( uint32_t mask, int &rLeftShift,
                            int &rRightShift ) const
{
    for( rLeftShift = 0; (rLeftShift < 32) && !(mask & 1); rLeftShift++ )
    {
        mask >>= 1;
    }
    for( rRightShift = 8; (mask & 1) ; rRightShift--)
    {
        mask >>= 1;
    }
    if( rRightShift < 0 )
    {
        rLeftShift -= rRightShift;
        rRightShift = 0;
    }
}


287 288
void X11Display::blendPixel8( uint8_t *pPixel, uint8_t r, uint8_t g,
                              uint8_t b, uint8_t a ) const
289 290 291
{
    uint8_t value = 255 - *pPixel;

292
    BLEND_PIXEL(value, r, g, b, a, uint8_t)
293 294 295 296 297

    *pPixel = 255 - value;
}


298 299
void X11Display::blendPixel16MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                  uint8_t b, uint8_t a ) const
300 301 302
{
    uint16_t value = pPixel[1] | pPixel[0] << 8;

303
    BLEND_PIXEL(value, r, g, b, a, uint16_t)
304

305
    pPixel[1] = value; value >>= 8;
306 307 308 309
    pPixel[0] = value;
}


310 311
void X11Display::blendPixel16LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                  uint8_t b, uint8_t a ) const
312 313 314
{
    uint16_t value = pPixel[0] | pPixel[1] << 8;

315
    BLEND_PIXEL(value, r, g, b, a, uint16_t)
316

317
    pPixel[0] = value; value >>= 8;
318 319 320 321
    pPixel[1] = value;
}


322 323
void X11Display::blendPixel32MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                  uint8_t b, uint8_t a ) const
324 325 326 327
{
    uint32_t value = pPixel[3] | pPixel[2] << 8 | pPixel[1] << 16 |
                          pPixel[0] << 24;

328
    BLEND_PIXEL(value, r, g, b, a, uint32_t)
329

330 331 332
    pPixel[3] = value; value >>= 8;
    pPixel[2] = value; value >>= 8;
    pPixel[1] = value; value >>= 8;
333 334 335 336
    pPixel[0] = value;
}


337 338
void X11Display::blendPixel32LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                  uint8_t b, uint8_t a ) const
339 340 341 342
{
    uint32_t value = pPixel[0] | pPixel[1] << 8 | pPixel[2] << 16 |
                          pPixel[3] << 24;

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
    BLEND_PIXEL(value, r, g, b, a, uint32_t)

    pPixel[0] = value; value >>= 8;
    pPixel[1] = value; value >>= 8;
    pPixel[2] = value; value >>= 8;
    pPixel[3] = value;
}


void X11Display::putPixel8( uint8_t *pPixel, uint8_t r, uint8_t g,
                            uint8_t b, uint8_t a ) const
{
    uint8_t value = 255 - *pPixel;

    PUT_PIXEL(value, r, g, b, uint8_t)

    *pPixel = 255 - value;
}


void X11Display::putPixel16MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                uint8_t b, uint8_t a ) const
{
    uint16_t value = pPixel[1] | pPixel[0] << 8;

    PUT_PIXEL(value, r, g, b, uint16_t)
369

370
    pPixel[1] = value; value >>= 8;
371
    pPixel[0] = value;
372 373 374 375 376 377 378 379 380 381 382
}


void X11Display::putPixel16LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                uint8_t b, uint8_t a ) const
{
    uint16_t value = pPixel[0] | pPixel[1] << 8;

    PUT_PIXEL(value, r, g, b, uint16_t)

    pPixel[0] = value; value >>= 8;
383
    pPixel[1] = value;
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
}


void X11Display::putPixel32MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                uint8_t b, uint8_t a ) const
{
    uint32_t value = pPixel[3] | pPixel[2] << 8 | pPixel[1] << 16 |
                          pPixel[0] << 24;

    PUT_PIXEL(value, r, g, b, uint32_t)

    pPixel[3] = value; value >>= 8;
    pPixel[2] = value; value >>= 8;
    pPixel[1] = value; value >>= 8;
    pPixel[0] = value;
}


void X11Display::putPixel32LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
                                uint8_t b, uint8_t a ) const
{
    uint32_t value = pPixel[0] | pPixel[1] << 8 | pPixel[2] << 16 |
                          pPixel[3] << 24;

    PUT_PIXEL(value, r, g, b, uint32_t)

    pPixel[0] = value; value >>= 8;
    pPixel[1] = value; value >>= 8;
    pPixel[2] = value; value >>= 8;
413 414 415 416
    pPixel[3] = value;
}


417 418
unsigned long X11Display::getPixelValue( uint8_t r, uint8_t g, uint8_t b )
    const
419 420
{
    unsigned long value;
421 422 423

    PUT_PIXEL(value, r, g, b, uint32_t)

424 425 426 427 428 429 430 431
    if( m_pixelSize == 1 )
    {
        return 255 - value;
    }
    else
    {
        return value;
    }
432 433 434
}


435
#endif