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