64fa4aed54d1130f1facb2d47c4118ea7c6f56d3
[vlc/vlc-austin.git] / modules / gui / skins2 / x11 / x11_window.cpp
1 /*****************************************************************************
2  * x11_window.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/Xatom.h>
28
29 #include "../src/generic_window.hpp"
30 #include "../src/vlcproc.hpp"
31 #include "x11_window.hpp"
32 #include "x11_display.hpp"
33 #include "x11_graphics.hpp"
34 #include "x11_dragdrop.hpp"
35 #include "x11_factory.hpp"
36
37 #include <assert.h>
38
39 X11Window::X11Window( intf_thread_t *pIntf, GenericWindow &rWindow,
40                       X11Display &rDisplay, bool dragDrop, bool playOnDrop,
41                       X11Window *pParentWindow, GenericWindow::WindowType_t type ):
42     OSWindow( pIntf ), m_rDisplay( rDisplay ), m_pParent( pParentWindow ),
43     m_dragDrop( dragDrop ), m_type ( type )
44 {
45     XSetWindowAttributes attr;
46     unsigned long valuemask;
47     string name_type;
48
49     if( type == GenericWindow::FullscreenWindow )
50     {
51         m_wnd_parent = DefaultRootWindow( XDISPLAY );
52
53         int i_screen = DefaultScreen( XDISPLAY );
54
55         attr.event_mask = ExposureMask | StructureNotifyMask;
56         attr.background_pixel = BlackPixel( XDISPLAY, i_screen );
57         attr.backing_store = Always;
58         valuemask = CWBackingStore | CWBackPixel | CWEventMask;
59
60         if( NET_WM_STATE_FULLSCREEN == None )
61         {
62             attr.override_redirect = True;
63             valuemask = valuemask | CWOverrideRedirect;
64         }
65
66         name_type = "Fullscreen";
67     }
68     else if( type == GenericWindow::VoutWindow )
69     {
70         m_wnd_parent = pParentWindow->m_wnd;
71
72         int i_screen = DefaultScreen( XDISPLAY );
73
74         attr.event_mask = ExposureMask | StructureNotifyMask;
75         attr.backing_store = Always;
76         attr.background_pixel = BlackPixel( XDISPLAY, i_screen );
77         valuemask = CWBackingStore | CWBackPixel | CWEventMask;
78
79         name_type = "VoutWindow";
80     }
81     else
82     {
83         m_wnd_parent = DefaultRootWindow( XDISPLAY );
84
85         attr.event_mask = ExposureMask | StructureNotifyMask;
86         valuemask = CWEventMask;
87
88         name_type = "TopWindow";
89     }
90
91     // Create the window
92     m_wnd = XCreateWindow( XDISPLAY, m_wnd_parent, -10, 0, 10, 10, 0, 0,
93                            InputOutput, CopyFromParent, valuemask, &attr );
94
95     // wait for X server to process the previous commands
96     XSync( XDISPLAY, false );
97
98     // Set the colormap for 8bpp mode
99     if( XPIXELSIZE == 1 )
100     {
101         XSetWindowColormap( XDISPLAY, m_wnd, m_rDisplay.getColormap() );
102     }
103
104     // Select events received by the window
105     long event_mask;
106     if( type == GenericWindow::VoutWindow )
107     {
108         event_mask =  ExposureMask|KeyPressMask|
109                       LeaveWindowMask|FocusChangeMask;
110     }
111     else
112     {
113         event_mask =  ExposureMask|KeyPressMask|
114                       PointerMotionMask|ButtonPressMask|ButtonReleaseMask|
115                       LeaveWindowMask|FocusChangeMask;
116     }
117     XSelectInput( XDISPLAY, m_wnd, event_mask );
118
119     // Store a pointer on the generic window in a map
120     X11Factory *pFactory = (X11Factory*)X11Factory::instance( getIntf() );
121     pFactory->m_windowMap[m_wnd] = &rWindow;
122
123     // Changing decorations
124     struct {
125         unsigned long flags;
126         unsigned long functions;
127         unsigned long decorations;
128         signed   long input_mode;
129         unsigned long status;
130     } motifWmHints;
131     Atom hints_atom = XInternAtom( XDISPLAY, "_MOTIF_WM_HINTS", False );
132     motifWmHints.flags = 2;    // MWM_HINTS_DECORATIONS;
133     motifWmHints.decorations = 0;
134     XChangeProperty( XDISPLAY, m_wnd, hints_atom, hints_atom, 32,
135                      PropModeReplace, (unsigned char *)&motifWmHints,
136                      sizeof( motifWmHints ) / sizeof( uint32_t ) );
137
138     // Drag & drop
139     if( m_dragDrop )
140     {
141         // Create a Dnd object for this window
142         m_pDropTarget = new X11DragDrop( getIntf(), m_rDisplay, m_wnd,
143                                          playOnDrop );
144
145         // Register the window as a drop target
146         Atom xdndAtom = XInternAtom( XDISPLAY, "XdndAware", False );
147         char xdndVersion = 4;
148         XChangeProperty( XDISPLAY, m_wnd, xdndAtom, XA_ATOM, 32,
149                          PropModeReplace, (unsigned char *)&xdndVersion, 1 );
150
151         // Store a pointer to be used in X11Loop
152         pFactory->m_dndMap[m_wnd] = m_pDropTarget;
153     }
154
155     // Change the window title
156     string name_window = "VLC (" + name_type + ")";
157     XStoreName( XDISPLAY, m_wnd, name_window.c_str() );
158
159     // Associate the window to the main "parent" window
160     XSetTransientForHint( XDISPLAY, m_wnd, m_rDisplay.getMainWindow() );
161
162     // initialize Class Hint
163     XClassHint classhint;
164     classhint.res_name = (char*) "vlc";
165     classhint.res_class = (char*) "Vlc";
166     XSetClassHint( XDISPLAY, m_wnd, &classhint );
167
168     // initialize WM_CLIENT_MACHINE
169     char* hostname = NULL;
170     long host_name_max = sysconf( _SC_HOST_NAME_MAX );
171     if( host_name_max <= 0 )
172         host_name_max = _POSIX_HOST_NAME_MAX;
173     hostname = new char[host_name_max];
174     if( hostname && gethostname( hostname, host_name_max ) == 0 )
175     {
176         hostname[host_name_max - 1] = '\0';
177
178         XTextProperty textprop;
179         textprop.value = (unsigned char *) hostname;
180         textprop.encoding = XA_STRING;
181         textprop.format = 8;
182         textprop.nitems = strlen( hostname );
183         XSetWMClientMachine( XDISPLAY, m_wnd, &textprop);
184     }
185     delete[] hostname;
186
187     // initialize EWMH pid
188     pid_t pid = getpid();
189     assert(  NET_WM_PID != None );
190     XChangeProperty( XDISPLAY, m_wnd, NET_WM_PID, XA_CARDINAL, 32,
191                      PropModeReplace, (unsigned char *)&pid, 1 );
192
193 }
194
195
196 X11Window::~X11Window()
197 {
198     X11Factory *pFactory = (X11Factory*)X11Factory::instance( getIntf() );
199     pFactory->m_windowMap[m_wnd] = NULL;
200     pFactory->m_dndMap[m_wnd] = NULL;
201
202     if( m_dragDrop )
203     {
204         delete m_pDropTarget;
205     }
206     XDestroyWindow( XDISPLAY, m_wnd );
207     XSync( XDISPLAY, False );
208 }
209
210 void X11Window::reparent( void* OSHandle, int x, int y, int w, int h )
211 {
212     // Reparent the window
213     Window new_parent =
214            OSHandle ? (Window) OSHandle : DefaultRootWindow( XDISPLAY );
215
216     XReparentWindow( XDISPLAY, m_wnd, new_parent, x, y);
217     if( w && h )
218         XResizeWindow( XDISPLAY, m_wnd, w, h );
219
220     m_wnd_parent = new_parent;
221 }
222
223
224 void X11Window::show() const
225 {
226     // Map the window
227     if( m_type == GenericWindow::VoutWindow )
228     {
229        XLowerWindow( XDISPLAY, m_wnd );
230        XMapWindow( XDISPLAY, m_wnd );
231     }
232     else if( m_type == GenericWindow::FullscreenWindow )
233     {
234         XMapRaised( XDISPLAY, m_wnd );
235         setFullscreen();
236         // toggleOnTop( true );
237     }
238     else
239     {
240         XMapRaised( XDISPLAY, m_wnd );
241     }
242 }
243
244
245 void X11Window::hide() const
246 {
247     // Unmap the window
248     XUnmapWindow( XDISPLAY, m_wnd );
249 }
250
251 void X11Window::moveResize( int left, int top, int width, int height ) const
252 {
253     if( width && height )
254         XMoveResizeWindow( XDISPLAY, m_wnd, left, top, width, height );
255     else
256         XMoveWindow( XDISPLAY, m_wnd, left, top );
257 }
258
259
260 void X11Window::raise() const
261 {
262     XRaiseWindow( XDISPLAY, m_wnd );
263 }
264
265
266 void X11Window::setOpacity( uint8_t value ) const
267 {
268     if( NET_WM_WINDOW_OPACITY == None )
269         return;
270
271     if( 255==value )
272         XDeleteProperty(XDISPLAY, m_wnd, NET_WM_WINDOW_OPACITY);
273     else
274     {
275         uint32_t opacity = value * ((uint32_t)-1/255);
276         XChangeProperty(XDISPLAY, m_wnd, NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
277                         PropModeReplace, (unsigned char *) &opacity, 1L);
278     }
279     XSync( XDISPLAY, False );
280 }
281
282
283 void X11Window::setFullscreen( ) const
284 {
285     if( NET_WM_STATE_FULLSCREEN != None )
286     {
287         XClientMessageEvent event;
288         memset( &event, 0, sizeof( XClientMessageEvent ) );
289
290         event.type = ClientMessage;
291         event.message_type = NET_WM_STATE;
292         event.display = XDISPLAY;
293         event.window = m_wnd;
294         event.format = 32;
295         event.data.l[ 0 ] = 1;
296         event.data.l[ 1 ] = NET_WM_STATE_FULLSCREEN;
297  
298         XSendEvent( XDISPLAY,
299                     DefaultRootWindow( XDISPLAY ),
300                     False, SubstructureNotifyMask|SubstructureRedirectMask,
301                     (XEvent*)&event );
302     }
303 }
304
305
306 void X11Window::toggleOnTop( bool onTop ) const
307 {
308     if( NET_WM_STAYS_ON_TOP != None )
309     {
310         /* Switch "on top" status */
311         XClientMessageEvent event;
312         memset( &event, 0, sizeof( XClientMessageEvent ) );
313
314         event.type = ClientMessage;
315         event.message_type = NET_WM_STATE;
316         event.display = XDISPLAY;
317         event.window = m_wnd;
318         event.format = 32;
319         event.data.l[ 0 ] = onTop; /* set property */
320         event.data.l[ 1 ] = NET_WM_STAYS_ON_TOP;
321
322         XSendEvent( XDISPLAY, DefaultRootWindow( XDISPLAY ),
323                     False, SubstructureNotifyMask|SubstructureRedirectMask, (XEvent*)&event );
324     }
325     else if( NET_WM_STATE_ABOVE != None )
326     {
327         /* Switch "above" state */
328         XClientMessageEvent event;
329         memset( &event, 0, sizeof( XClientMessageEvent ) );
330
331         event.type = ClientMessage;
332         event.message_type = NET_WM_STATE;
333         event.display = XDISPLAY;
334         event.window = m_wnd;
335         event.format = 32;
336         event.data.l[ 0 ] = onTop; /* set property */
337         event.data.l[ 1 ] = NET_WM_STATE_ABOVE;
338
339         XSendEvent( XDISPLAY, DefaultRootWindow( XDISPLAY ),
340                     False, SubstructureNotifyMask|SubstructureRedirectMask, (XEvent*)&event );
341     }
342 }
343
344 #endif