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