]> git.sesse.net Git - vlc/blob - modules/gui/skins2/x11/x11_display.cpp
27adb1e722f688ed84e1e0fefce8ec2195dfa2e3
[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         // Receive WM_DELETE_WINDOW
213         Atom wm_delete = XInternAtom( m_pDisplay, "WM_DELETE_WINDOW", False);
214         XSetWMProtocols( m_pDisplay, m_mainWindow, &wm_delete, 1);
215
216         // Changing decorations
217         struct {
218             unsigned long flags;
219             unsigned long functions;
220             unsigned long decorations;
221             long input_mode;
222             unsigned long status;
223         } motifWmHints;
224         Atom hints_atom = XInternAtom( m_pDisplay, "_MOTIF_WM_HINTS", False );
225         motifWmHints.flags = 2;    // MWM_HINTS_DECORATIONS;
226         motifWmHints.decorations = 0;
227         XChangeProperty( m_pDisplay, m_mainWindow, hints_atom, hints_atom, 32,
228                          PropModeReplace, (unsigned char *)&motifWmHints,
229                          sizeof( motifWmHints ) / sizeof( long ) );
230
231         // Change the window title
232         XStoreName( m_pDisplay, m_mainWindow, "VLC Media Player" );
233
234         // Receive map notify events
235         XSelectInput( m_pDisplay, m_mainWindow, StructureNotifyMask );
236
237         // Set an empty mask for the window
238         Region mask = XCreateRegion();
239         XShapeCombineRegion( m_pDisplay, m_mainWindow, ShapeBounding, 0, 0,
240                              mask, ShapeSet );
241         XDestroyRegion( mask );
242
243         XMapWindow( m_pDisplay, m_mainWindow);
244
245         // Move it outside the screen to avoid seeing it in workspace selector
246         XMoveWindow( m_pDisplay, m_mainWindow, -10, -10 );
247
248         // test EWMH capabilities
249         testEWMH();
250     }
251 }
252
253
254 X11Display::~X11Display()
255 {
256     if( m_mainWindow ) XDestroyWindow( m_pDisplay, m_mainWindow );
257     if( m_gc )         XFreeGC( m_pDisplay, m_gc );
258     if( m_colormap )   XFreeColormap( m_pDisplay, m_colormap );
259     if( m_pDisplay )   XCloseDisplay( m_pDisplay );
260 }
261
262
263 void X11Display::testEWMH()
264 {
265     int i_ret, i_format;
266     unsigned long i_items, i_bytesafter;
267     union { Atom *p_atom; unsigned char *p_char; } p_args;
268     p_args.p_atom = NULL;
269
270     m_net_wm_supported = XInternAtom( m_pDisplay, "_NET_SUPPORTED", False );
271     msg_Dbg( getIntf(), "EWMH: supported %d", m_net_wm_supported != None ? 1 : 0 );
272     if( m_net_wm_supported == None )
273         return;
274
275     i_ret = XGetWindowProperty( m_pDisplay, DefaultRootWindow( m_pDisplay ),
276                                 m_net_wm_supported,
277                                 0, 16384, False, AnyPropertyType,
278                                 &m_net_wm_supported,
279                                 &i_format, &i_items, &i_bytesafter,
280                                 (unsigned char **)&p_args );
281
282     if( i_ret != Success || i_items == 0 )
283         return; /* Not supported */
284
285 #define TEST_EWMH( name, value ) \
286 {\
287     name = XInternAtom( m_pDisplay, value, False );\
288     int i;\
289     for( i = 0; i < i_items; i++ )\
290     {\
291         if( p_args.p_atom[i] == name ) break;\
292     }\
293     if( i == i_items )\
294     {\
295         msg_Dbg( getIntf(), "%s support: no", value );\
296         name = None;\
297     }\
298     else\
299         msg_Dbg( getIntf(), "%s support: yes", value );\
300 }
301
302     TEST_EWMH( m_net_wm_state, "_NET_WM_STATE" )
303     TEST_EWMH( m_net_wm_state_fullscreen, "_NET_WM_STATE_FULLSCREEN" )
304     TEST_EWMH( m_net_wm_stays_on_top, "_NET_WM_STATE_STAYS_ON_TOP" )
305     TEST_EWMH( m_net_wm_state_above, "_NET_WM_STATE_ABOVE" )
306
307     TEST_EWMH( m_net_wm_window_opacity, "_NET_WM_WINDOW_OPACITY" )
308
309 #undef TEST_EWMH
310
311     XFree( p_args.p_atom );
312
313 }
314
315
316 void X11Display::getShifts( uint32_t mask, int &rLeftShift, int &rRightShift )
317 {
318     for( rLeftShift = 0; (rLeftShift < 32) && !(mask & 1); rLeftShift++ )
319     {
320         mask >>= 1;
321     }
322     for( rRightShift = 8; (mask & 1) ; rRightShift--)
323     {
324         mask >>= 1;
325     }
326     if( rRightShift < 0 )
327     {
328         rLeftShift -= rRightShift;
329         rRightShift = 0;
330     }
331 }
332
333
334 void X11Display::blendPixel8( uint8_t *pPixel, uint8_t r, uint8_t g,
335                               uint8_t b, uint8_t a ) const
336 {
337     *pPixel = 255 - blendPixel<uint8_t>(255 - *pPixel,r,g,b,a);
338 }
339
340
341 void X11Display::blendPixel16MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
342                                   uint8_t b, uint8_t a ) const
343 {
344     uint16_t value = pPixel[1] | pPixel[0] << 8;
345
346     value = blendPixel<uint16_t>(value,r,g,b,a);
347
348     pPixel[1] = value; value >>= 8;
349     pPixel[0] = value;
350 }
351
352
353 void X11Display::blendPixel16LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
354                                   uint8_t b, uint8_t a ) const
355 {
356     uint16_t value = pPixel[0] | pPixel[1] << 8;
357
358     value = blendPixel<uint16_t>(value,r,g,b,a);
359
360     pPixel[0] = value; value >>= 8;
361     pPixel[1] = value;
362 }
363
364
365 void X11Display::blendPixel32MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
366                                   uint8_t b, uint8_t a ) const
367 {
368     uint32_t value = pPixel[3] | pPixel[2] << 8 |
369                      pPixel[1] << 16 | pPixel[0] << 24;
370
371     value = blendPixel<uint32_t>(value,r,g,b,a);
372
373     pPixel[3] = value; value >>= 8;
374     pPixel[2] = value; value >>= 8;
375     pPixel[1] = value; value >>= 8;
376     pPixel[0] = value;
377 }
378
379
380 void X11Display::blendPixel32LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
381                                   uint8_t b, uint8_t a ) const
382 {
383     uint32_t value = pPixel[0] | pPixel[1] << 8 |
384                      pPixel[2] << 16 | pPixel[3] << 24;
385
386     value = blendPixel<uint32_t>(value,r,g,b,a);
387
388     pPixel[0] = value; value >>= 8;
389     pPixel[1] = value; value >>= 8;
390     pPixel[2] = value; value >>= 8;
391     pPixel[3] = value;
392 }
393
394
395 void X11Display::putPixel8( uint8_t *pPixel, uint8_t r, uint8_t g,
396                             uint8_t b, uint8_t a ) const
397 {
398     *pPixel = 255 - putPixel<uint8_t>(r,g,b);
399 }
400
401
402 void X11Display::putPixel16MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
403                                 uint8_t b, uint8_t a ) const
404 {
405     uint16_t value = putPixel<uint16_t>(r, g, b);
406
407     pPixel[1] = value; value >>= 8;
408     pPixel[0] = value;
409 }
410
411
412 void X11Display::putPixel16LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
413                                 uint8_t b, uint8_t a ) const
414 {
415     uint16_t value = putPixel<uint16_t>(r,g,b);
416     pPixel[0] = value; value >>= 8;
417     pPixel[1] = value;
418 }
419
420
421 void X11Display::putPixel32MSB( uint8_t *pPixel, uint8_t r, uint8_t g,
422                                 uint8_t b, uint8_t a ) const
423 {
424     uint32_t value = putPixel<uint32_t>(r,g,b);
425
426     pPixel[3] = value; value >>= 8;
427     pPixel[2] = value; value >>= 8;
428     pPixel[1] = value; value >>= 8;
429     pPixel[0] = value;
430 }
431
432
433 void X11Display::putPixel32LSB( uint8_t *pPixel, uint8_t r, uint8_t g,
434                                 uint8_t b, uint8_t a ) const
435 {
436     uint32_t value = putPixel<uint32_t>(r,g,b);
437
438     pPixel[0] = value; value >>= 8;
439     pPixel[1] = value; value >>= 8;
440     pPixel[2] = value; value >>= 8;
441     pPixel[3] = value;
442 }
443
444
445 unsigned long X11Display::getPixelValue( uint8_t r, uint8_t g, uint8_t b )
446     const
447 {
448     unsigned long value = putPixel<unsigned long>(r,g,b);
449
450     return m_pixelSize==1 ? 255 - value : value;
451 }
452
453
454 #endif