5cb0bf130460e988930c4b54f5b902b4c05c8a76
[vlc.git] / modules / gui / skins2 / x11 / x11_display.cpp
1 /*****************************************************************************
2  * x11_display.cpp
3  *****************************************************************************
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  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef X11_SKINS
26
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/extensions/shape.h>
30
31 #include "x11_display.hpp"
32 #include "../src/logger.hpp"
33
34 // Macro to compute a pixel value
35 #define PUT_PIXEL(value, r, g, b, type) \
36     value = \
37         ( ((type)r >> m_redRightShift) << m_redLeftShift ) | \
38         ( ((type)g >> m_greenRightShift) << m_greenLeftShift ) | \
39         ( ((type)b >> m_blueRightShift) << m_blueLeftShift );
40
41 // Macro to blend a pixel with another color
42 #define BLEND_PIXEL(value, r, g, b, a, type) \
43     uint16_t temp; \
44     temp = ((uint8_t)((value >> m_redLeftShift) << m_redRightShift)); \
45     uint8_t red = r + ( temp * (255 - a) ) / 255; \
46     temp = ((uint8_t)((value >> m_greenLeftShift) << m_greenRightShift)); \
47     uint8_t green = g + ( temp * (255 - a) ) / 255; \
48     temp = ((uint8_t)((value >> m_blueLeftShift) << m_blueRightShift)); \
49     uint8_t blue = b + ( temp * (255 - a) ) / 255; \
50     PUT_PIXEL(value, red, green, blue, type)
51
52
53 X11Display::X11Display( intf_thread_t *pIntf ): SkinObject( pIntf ),
54     m_mainWindow( 0 ), m_gc( NULL ), m_colormap( 0 )
55 {
56     // Open a connection to the X Server
57     m_pDisplay = XOpenDisplay( NULL );
58
59     if( m_pDisplay == NULL )
60     {
61         MSG_ERR( "Cannot open display" );
62         return;
63     }
64
65     // Load the XShape extension
66     int event, error;
67     XShapeQueryExtension( m_pDisplay, &event, &error );
68
69     // Get the display parameters
70     int screen = DefaultScreen( m_pDisplay );
71     int depth = DefaultDepth( m_pDisplay, screen );
72     int order = ImageByteOrder( m_pDisplay );
73     Window root = DefaultRootWindow( m_pDisplay );
74
75     // Template for looking up the XVisualInfo
76     XVisualInfo xVInfoTemplate;
77     xVInfoTemplate.screen = screen;
78     xVInfoTemplate.depth = depth;
79
80     XVisualInfo *pVInfo = NULL;
81     int vCount = 0;
82
83     switch( depth )
84     {
85         case 8:
86             xVInfoTemplate.c_class = DirectColor;
87             // Get the DirectColor visual
88             pVInfo = XGetVisualInfo( m_pDisplay, VisualScreenMask |
89                                      VisualClassMask, &xVInfoTemplate,
90                                      &vCount );
91             if( pVInfo == NULL )
92             {
93                 msg_Err( getIntf(), "no DirectColor visual available" );
94                 m_pDisplay = NULL;
95                 break;
96             }
97             m_pVisual = pVInfo->visual;
98
99             // Compute the color shifts
100             getShifts( pVInfo->red_mask, m_redLeftShift, m_redRightShift );
101             getShifts( pVInfo->green_mask, m_greenLeftShift,
102                        m_greenRightShift );
103             getShifts( pVInfo->blue_mask, m_blueLeftShift, m_blueRightShift );
104
105             // Create a color map
106             m_colormap = XCreateColormap( m_pDisplay, root,
107                     DefaultVisual( m_pDisplay, screen ), AllocAll );
108
109             // Create the palette
110             XColor pColors[255];
111             for( uint16_t i = 0; i < 255; i++ )
112             {
113                 // kludge: colors are indexed reversely because color 255 seems
114                 // to bereserved for black even if we try to set it to white
115                 pColors[i].pixel = 254-i;
116                 pColors[i].pad   = 0;
117                 pColors[i].flags = DoRed | DoGreen | DoBlue;
118                 pColors[i].red   =
119                     (i >> m_redLeftShift) << (m_redRightShift + 8);
120                 pColors[i].green =
121                     (i >> m_greenLeftShift) << (m_greenRightShift + 8);
122                 pColors[i].blue  =
123                     (i >> m_blueLeftShift) << (m_blueRightShift + 8);
124             }
125             XStoreColors( m_pDisplay, m_colormap, pColors, 255 );
126             blendPixelImpl = &X11Display::blendPixel8;
127             putPixelImpl = &X11Display::putPixel8;
128             m_pixelSize = 1;
129             break;
130
131         case 15:
132         case 16:
133         case 24:
134         case 32:
135             // Get the TrueColor visual
136             xVInfoTemplate.c_class = TrueColor;
137             pVInfo = XGetVisualInfo( m_pDisplay, VisualScreenMask |
138                                      VisualDepthMask | VisualClassMask,
139                                      &xVInfoTemplate, &vCount );
140             if( pVInfo == NULL )
141             {
142                 msg_Err( getIntf(), "No TrueColor visual for depth %d",
143                          depth );
144                 m_pDisplay = NULL;
145                 break;
146             }
147             m_pVisual = pVInfo->visual;
148
149             // Compute the color shifts
150             getShifts( pVInfo->red_mask, m_redLeftShift, m_redRightShift );
151             getShifts( pVInfo->green_mask, m_greenLeftShift,
152                        m_greenRightShift );
153             getShifts( pVInfo->blue_mask, m_blueLeftShift, m_blueRightShift );
154
155             if( depth == 15 || depth == 16 )
156             {
157                 if( order == MSBFirst )
158                 {
159                     blendPixelImpl = &X11Display::blendPixel16MSB;
160                     putPixelImpl = &X11Display::putPixel16MSB;
161                 }
162                 else
163                 {
164                     blendPixelImpl = &X11Display::blendPixel16LSB;
165                     putPixelImpl = &X11Display::putPixel16LSB;
166                 }
167                 m_pixelSize = 2;
168             }
169             else
170             {
171                 if( order == MSBFirst )
172                 {
173                     blendPixelImpl = &X11Display::blendPixel32MSB;
174                     putPixelImpl = &X11Display::putPixel32MSB;
175                 }
176                 else
177                 {
178                     blendPixelImpl = &X11Display::blendPixel32LSB;
179                     putPixelImpl = &X11Display::putPixel32LSB;
180                 }
181                 m_pixelSize = 4;
182             }
183             break;
184
185         default:
186             msg_Err( getIntf(), "unsupported depth: %d bpp\n", depth );
187             m_pDisplay = NULL;
188             break;
189     }
190
191     // Free the visual info
192     if( pVInfo )
193     {
194         XFree( pVInfo );
195     }
196
197     // Create a graphics context that doesn't generate GraphicsExpose events
198     if( m_pDisplay )
199     {
200         XGCValues xgcvalues;
201         xgcvalues.graphics_exposures = False;
202         m_gc = XCreateGC( m_pDisplay, root, GCGraphicsExposures, &xgcvalues );
203
204         // Create a parent window to have a single task in the task bar
205         XSetWindowAttributes attr;
206         m_mainWindow = XCreateWindow( m_pDisplay, root, 0, 0, 1, 1, 0, 0,
207                                       InputOutput, CopyFromParent, 0, &attr );
208
209         // Changing decorations
210         struct {
211             unsigned long flags;
212             unsigned long functions;
213             unsigned long decorations;
214             long input_mode;
215             unsigned long status;
216         } motifWmHints;
217         Atom hints_atom = XInternAtom( m_pDisplay, "_MOTIF_WM_HINTS", False );
218         motifWmHints.flags = 2;    // MWM_HINTS_DECORATIONS;
219         motifWmHints.decorations = 0;
220         XChangeProperty( m_pDisplay, m_mainWindow, hints_atom, hints_atom, 32,
221                          PropModeReplace, (unsigned char *)&motifWmHints,
222                          sizeof( motifWmHints ) / sizeof( long ) );
223
224         // Change the window title
225         XStoreName( m_pDisplay, m_mainWindow, "VLC Media Player" );
226
227         // Receive map notify events
228         XSelectInput( m_pDisplay, m_mainWindow, StructureNotifyMask );
229
230         // Set an empty mask for the window
231         Region mask = XCreateRegion();
232         XShapeCombineRegion( m_pDisplay, m_mainWindow, ShapeBounding, 0, 0,
233                              mask, ShapeSet );
234         XDestroyRegion( mask );
235
236         // Map the window
237         XMapWindow( m_pDisplay, m_mainWindow);
238
239         // Move it outside the screen to avoid seeing it in workspace selector
240         XMoveWindow( m_pDisplay, m_mainWindow, -10, -10 );
241     }
242 }
243
244
245 X11Display::~X11Display()
246 {
247     if( m_mainWindow )
248     {
249         XDestroyWindow( m_pDisplay, m_mainWindow );
250     }
251     if( m_gc )
252     {
253         XFreeGC( m_pDisplay, m_gc );
254     }
255     if( m_colormap )
256     {
257         XFreeColormap( m_pDisplay, m_colormap );
258     }
259     if( m_pDisplay )
260     {
261         XCloseDisplay( m_pDisplay );
262     }
263 }
264
265
266 void X11Display::getShifts( uint32_t mask, int &rLeftShift,
267                             int &rRightShift ) const
268 {
269     for( rLeftShift = 0; (rLeftShift < 32) && !(mask & 1); rLeftShift++ )
270     {
271         mask >>= 1;
272     }
273     for( rRightShift = 8; (mask & 1) ; rRightShift--)
274     {
275         mask >>= 1;
276     }
277     if( rRightShift < 0 )
278     {
279         rLeftShift -= rRightShift;
280         rRightShift = 0;
281     }
282 }
283
284
285 void X11Display::blendPixel8( uint8_t *pPixel, uint8_t r, uint8_t g,
286                               uint8_t b, uint8_t a ) const
287 {
288     uint8_t value = 255 - *pPixel;
289
290     BLEND_PIXEL(value, r, g, b, a, uint8_t)
291
292     *pPixel = 255 - value;
293 }
294
295
296 void X11Display::blendPixel16MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
297                                   uint8_t b, uint8_t a ) const
298 {
299     uint16_t value = pPixel[1] | pPixel[0] << 8;
300
301     BLEND_PIXEL(value, r, g, b, a, uint16_t)
302
303     pPixel[1] = value; value >>= 8;
304     pPixel[0] = value;
305 }
306
307
308 void X11Display::blendPixel16LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
309                                   uint8_t b, uint8_t a ) const
310 {
311     uint16_t value = pPixel[0] | pPixel[1] << 8;
312
313     BLEND_PIXEL(value, r, g, b, a, uint16_t)
314
315     pPixel[0] = value; value >>= 8;
316     pPixel[1] = value;
317 }
318
319
320 void X11Display::blendPixel32MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
321                                   uint8_t b, uint8_t a ) const
322 {
323     uint32_t value = pPixel[3] | pPixel[2] << 8 | pPixel[1] << 16 |
324                           pPixel[0] << 24;
325
326     BLEND_PIXEL(value, r, g, b, a, uint32_t)
327
328     pPixel[3] = value; value >>= 8;
329     pPixel[2] = value; value >>= 8;
330     pPixel[1] = value; value >>= 8;
331     pPixel[0] = value;
332 }
333
334
335 void X11Display::blendPixel32LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
336                                   uint8_t b, uint8_t a ) const
337 {
338     uint32_t value = pPixel[0] | pPixel[1] << 8 | pPixel[2] << 16 |
339                           pPixel[3] << 24;
340
341     BLEND_PIXEL(value, r, g, b, a, uint32_t)
342
343     pPixel[0] = value; value >>= 8;
344     pPixel[1] = value; value >>= 8;
345     pPixel[2] = value; value >>= 8;
346     pPixel[3] = value;
347 }
348
349
350 void X11Display::putPixel8( uint8_t *pPixel, uint8_t r, uint8_t g,
351                             uint8_t b, uint8_t a ) const
352 {
353     uint8_t value = 255 - *pPixel;
354
355     PUT_PIXEL(value, r, g, b, uint8_t)
356
357     *pPixel = 255 - value;
358 }
359
360
361 void X11Display::putPixel16MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
362                                 uint8_t b, uint8_t a ) const
363 {
364     uint16_t value = pPixel[1] | pPixel[0] << 8;
365
366     PUT_PIXEL(value, r, g, b, uint16_t)
367
368     pPixel[1] = value; value >>= 8;
369     pPixel[0] = value;
370 }
371
372
373 void X11Display::putPixel16LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
374                                 uint8_t b, uint8_t a ) const
375 {
376     uint16_t value = pPixel[0] | pPixel[1] << 8;
377
378     PUT_PIXEL(value, r, g, b, uint16_t)
379
380     pPixel[0] = value; value >>= 8;
381     pPixel[1] = value;
382 }
383
384
385 void X11Display::putPixel32MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
386                                 uint8_t b, uint8_t a ) const
387 {
388     uint32_t value = pPixel[3] | pPixel[2] << 8 | pPixel[1] << 16 |
389                           pPixel[0] << 24;
390
391     PUT_PIXEL(value, r, g, b, uint32_t)
392
393     pPixel[3] = value; value >>= 8;
394     pPixel[2] = value; value >>= 8;
395     pPixel[1] = value; value >>= 8;
396     pPixel[0] = value;
397 }
398
399
400 void X11Display::putPixel32LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
401                                 uint8_t b, uint8_t a ) const
402 {
403     uint32_t value = pPixel[0] | pPixel[1] << 8 | pPixel[2] << 16 |
404                           pPixel[3] << 24;
405
406     PUT_PIXEL(value, r, g, b, uint32_t)
407
408     pPixel[0] = value; value >>= 8;
409     pPixel[1] = value; value >>= 8;
410     pPixel[2] = value; value >>= 8;
411     pPixel[3] = value;
412 }
413
414
415 unsigned long X11Display::getPixelValue( uint8_t r, uint8_t g, uint8_t b )
416     const
417 {
418     unsigned long value;
419
420     PUT_PIXEL(value, r, g, b, uint32_t)
421
422     if( m_pixelSize == 1 )
423     {
424         return 255 - value;
425     }
426     else
427     {
428         return value;
429     }
430 }
431
432
433 #endif