1 /*****************************************************************************
2 * x11_window.cpp: X11 implementation of the Window class
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: x11_window.cpp,v 1.30 2003/10/22 19:12:56 ipkiss Exp $
7 * Authors: Cyril Deguet <asmax@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111,
23 *****************************************************************************/
27 //--- GENERAL ---------------------------------------------------------------
30 //--- VLC -------------------------------------------------------------------
33 //--- X11 -------------------------------------------------------------------
35 #include <X11/Xatom.h>
36 #include <X11/extensions/shape.h>
38 //--- SKIN ------------------------------------------------------------------
39 #include "../os_api.h"
40 #include "../src/anchor.h"
41 #include "../controls/generic.h"
42 #include "../src/window.h"
43 #include "../os_window.h"
44 #include "../src/event.h"
45 #include "../os_event.h"
46 #include "../src/graphics.h"
47 #include "../os_graphics.h"
48 #include "../src/skin_common.h"
49 #include "../src/theme.h"
50 #include "../os_theme.h"
51 #include "x11_timer.h"
54 static bool ToolTipCallback( void *data );
55 static void DrawToolTipText( tooltip_t *tooltip );
58 //---------------------------------------------------------------------------
60 //---------------------------------------------------------------------------
61 X11Window::X11Window( intf_thread_t *p_intf, Window wnd, int x, int y,
62 bool visible, int transition, int normalalpha, int movealpha,
63 bool dragdrop, bool playondrop, string name )
64 : SkinWindow( p_intf, x, y, visible, transition, normalalpha, movealpha,
69 display = p_intf->p_sys->display;
70 int screen = DefaultScreen( display );
75 // Creation of a graphic context that doesn't generate a GraphicsExpose
76 // event when using functions like XCopyArea
78 gcVal.graphics_exposures = False;
80 Gc = XCreateGC( display, wnd, GCGraphicsExposures, &gcVal );
83 // Removing fading effect
88 // register the listview as a drop target
89 DropObject = new X11DropObject( p_intf, Wnd, playondrop );
91 Atom xdndAtom = XInternAtom( display, "XdndAware", False );
94 XChangeProperty( display, wnd, xdndAtom, XA_ATOM, 32,
95 PropModeReplace, (unsigned char *)&xdndVersion, 1);
99 // Associate vlc icon to the window
101 XWMHints *hints = XGetWMHints( display, Wnd );
104 hints = XAllocWMHints();
106 if( p_intf->p_sys->iconPixmap != None )
108 hints->icon_pixmap = p_intf->p_sys->iconPixmap;
109 hints->flags |= IconPixmapHint;
111 if( p_intf->p_sys->iconMask != None )
113 hints->icon_mask = p_intf->p_sys->iconMask;
114 hints->flags |= IconMaskHint;
116 XSetWMHints( display, Wnd, hints );
120 // Create Tool Tip window
123 color.green = 0xffff;
125 Colormap cm = DefaultColormap( display, screen );
126 Window root = DefaultRootWindow( display );
129 XAllocColor( display, cm, &color );
130 XSetWindowAttributes attr;
131 attr.background_pixel = color.pixel;
132 attr.override_redirect = True;
133 ToolTip.window = XCreateWindow( display, root, 0, 0, 1, 1, 1, 0,
134 InputOutput, CopyFromParent,
135 CWBackPixel|CWOverrideRedirect, &attr );
136 ToolTip.font = XLoadFont( display,
137 "-*-helvetica-bold-r-*-*-*-80-*-*-*-*-*-*" );
138 gcVal.font = ToolTip.font;
139 gcVal.foreground = 0;
140 gcVal.background = color.pixel;
141 ToolTip.gc = XCreateGC( display, ToolTip.window,
142 GCBackground|GCForeground|GCFont, &gcVal );
145 ToolTip.display = display;
146 X11Timer *timer = new X11Timer( p_intf, 500000, ToolTipCallback, &ToolTip );
147 ToolTip.p_intf = p_intf;
148 ToolTip.timer = timer;
149 ToolTip.active = False;
151 // Double-click handling
155 // TODO: can be retrieved somewhere ?
158 //---------------------------------------------------------------------------
159 X11Window::~X11Window()
165 delete ToolTip.timer;
167 XFreeGC( display, ToolTip.gc );
168 XFreeGC( display, Gc );
169 XDestroyWindow( display, ToolTip.window );
170 XDestroyWindow( display, Wnd );
173 //---------------------------------------------------------------------------
174 void X11Window::ToggleOnTop()
177 ev.type = ClientMessage;
178 ev.xclient.display = display;
179 ev.xclient.window = Wnd;
180 ev.xclient.serial = 0;
181 ev.xclient.send_event = True;
182 ev.xclient.message_type = XInternAtom( display, "_NET_WM_STATE", True );
183 ev.xclient.format = 32;
184 ev.xclient.data.l[1] = XInternAtom( display, "_NET_WM_STATE_ABOVE", False);
185 ev.xclient.data.l[2] = 0;
186 ev.xclient.data.l[3] = 0;
187 ev.xclient.data.l[4] = 0;
189 if( !p_intf->p_sys->b_on_top )
191 // Set the window on top
192 ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD
196 // Set the window not on top
197 ev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE
201 XSendEvent( display, DefaultRootWindow( display ), False,
202 SubstructureRedirectMask | SubstructureNotifyMask, &ev );
206 ev.xclient.data.l[1] = XInternAtom( display, "_NET_WM_STATE_STAYS_ON_TOP",
209 XSendEvent( display, DefaultRootWindow( display ), False,
210 SubstructureRedirectMask | SubstructureNotifyMask, &ev );
213 //---------------------------------------------------------------------------
214 void X11Window::OSShow( bool show )
217 XResizeWindow( display, Wnd, 1, 1 ); // Avoid flicker
222 // We do the call to XShapeCombineRegion() here because the window
223 // must be unmapped for this to work.
224 Drawable drawable = (( X11Graphics* )Image )->GetImage();
227 XImage *image = XGetImage( display, drawable, 0, 0, Width, Height,
228 AllPlanes, ZPixmap );
231 // Mask for transparency
232 Region region = XCreateRegion();
233 for( int line = 0; line < Height; line++ )
235 int start = 0, end = 0;
236 while( start < Width )
238 while( start < Width && XGetPixel( image, start, line )
244 while( end < Width && XGetPixel( image, end, line ) != 0)
251 rect.width = end - start + 1;
253 Region newRegion = XCreateRegion();
254 XUnionRectWithRegion( &rect, region, newRegion );
255 XDestroyRegion( region );
260 XDestroyImage( image );
262 XShapeCombineRegion( display, Wnd, ShapeBounding, 0, 0, region,
264 XDestroyRegion( region );
269 msg_Err( p_intf, "X11Window::OSShow XShapeCombineRegion() failed");
272 XMapWindow( display, Wnd );
273 XMoveResizeWindow( display, Wnd, Left, Top, Width, Height );
279 XUnmapWindow( display, Wnd );
283 //---------------------------------------------------------------------------
284 bool X11Window::ProcessOSEvent( Event *evt )
286 unsigned int msg = evt->GetMessage();
287 //unsigned int p1 = evt->GetParam1();
288 int p2 = evt->GetParam2();
297 RefreshFromImage( 0, 0, Width, Height );
302 MouseMove( (int)( (XMotionEvent *)p2 )->x,
303 (int)( (XMotionEvent *)p2 )->y, 1 );
304 else if( RButtonDown )
305 MouseMove( (int)( (XMotionEvent *)p2 )->x,
306 (int)( (XMotionEvent *)p2 )->y, 2 );
308 MouseMove( (int)( (XMotionEvent *)p2 )->x,
309 (int)( (XMotionEvent *)p2 )->y, 0 );
314 // Raise all the windows
315 for( list<SkinWindow *>::const_iterator win =
316 p_intf->p_sys->p_theme->WindowList.begin();
317 win != p_intf->p_sys->p_theme->WindowList.end(); win++ )
319 Window id = ( (X11Window *)(*win) )->GetHandle();
320 // the current window is raised last
324 XRaiseWindow( display, id );
329 XRaiseWindow( display, Wnd );
333 if( ((XButtonEvent *)p2 )->state & ControlMask )
337 if( ((XButtonEvent *)p2 )->state & ShiftMask )
342 switch( ( (XButtonEvent *)p2 )->button )
346 button |= MOUSE_LEFT;
347 time = OSAPI_GetTime();
348 OSAPI_GetMousePos( posX, posY );
349 if( time - ClickedTime < DblClickDelay &&
350 posX == ClickedX && posY == ClickedY )
354 MouseDblClick( (int)( (XButtonEvent *)p2 )->x,
355 (int)( (XButtonEvent *)p2 )->y, button );
363 MouseDown( (int)( (XButtonEvent *)p2 )->x,
364 (int)( (XButtonEvent *)p2 )->y, button );
370 button |= MOUSE_RIGHT;
372 MouseDown( (int)( (XButtonEvent *)p2 )->x,
373 (int)( (XButtonEvent *)p2 )->y, button );
383 if( ((XButtonEvent *)p2 )->state & ControlMask )
387 if( ((XButtonEvent *)p2 )->state & ShiftMask )
392 switch( ( (XButtonEvent *)p2 )->button )
396 button |= MOUSE_LEFT;
398 MouseUp( (int)( (XButtonEvent *)p2 )->x,
399 (int)( (XButtonEvent *)p2 )->y, button );
403 button |= MOUSE_RIGHT;
406 MouseUp( (int)( (XButtonEvent *)p2 )->x,
407 (int)( (XButtonEvent *)p2 )->y, button );
412 MouseScroll( (int)( (XButtonEvent *)p2 )->x,
413 (int)( (XButtonEvent *)p2 )->y,
419 MouseScroll( (int)( (XButtonEvent *)p2 )->x,
420 (int)( (XButtonEvent *)p2 )->y,
430 OSAPI_PostMessage( this, WINDOW_LEAVE, 0, 0 );
435 type = XGetAtomName( display, ( (XClientMessageEvent*)
436 p2 )->message_type );
438 if( type == "XdndEnter" )
440 DropObject->DndEnter( ((XClientMessageEvent*)p2)->data.l );
443 else if( type == "XdndPosition" )
445 DropObject->DndPosition( ((XClientMessageEvent*)p2)->data.l );
448 else if( type == "XdndLeave" )
450 DropObject->DndLeave( ((XClientMessageEvent*)p2)->data.l );
453 else if( type == "XdndDrop" )
455 DropObject->DndDrop( ((XClientMessageEvent*)p2)->data.l );
464 //---------------------------------------------------------------------------
465 void X11Window::SetTransparency( int Value )
469 SetLayeredWindowAttributes( hWnd, 0, Alpha, LWA_ALPHA | LWA_COLORKEY );
470 UpdateWindow( hWnd );*/
472 //---------------------------------------------------------------------------
473 void X11Window::RefreshFromImage( int x, int y, int w, int h )
475 Drawable drawable = (( X11Graphics* )Image )->GetImage();
478 XCopyArea( display, drawable, Wnd, Gc, x, y, w, h, x, y );
482 //---------------------------------------------------------------------------
483 void X11Window::WindowManualMove()
485 // Get mouse cursor position
487 OSAPI_GetMousePos( x, y );
489 // Move window and chek for magnetism
490 p_intf->p_sys->p_theme->MoveSkinMagnet( this,
491 WindowX + x - CursorX, WindowY + y - CursorY );
494 //---------------------------------------------------------------------------
495 void X11Window::WindowManualMoveInit()
497 OSAPI_GetMousePos( CursorX, CursorY );
501 //---------------------------------------------------------------------------
502 void X11Window::Move( int left, int top )
506 XMoveWindow( display, Wnd, left, top );
508 //---------------------------------------------------------------------------
509 void X11Window::Size( int width, int height )
513 XResizeWindow( display, Wnd, width, height );
515 //---------------------------------------------------------------------------
518 bool ToolTipCallback( void *data )
520 int direction, fontAscent, fontDescent;
522 Display *disp = ((tooltip_t*)data)->display;
523 Window win = ((tooltip_t*)data)->window;
524 Font font = ((tooltip_t*)data)->font;
525 GC gc = ((tooltip_t*)data)->gc;
526 string text = ((tooltip_t*)data)->text;
527 int curX = ((tooltip_t*)data)->curX;
528 int curY = ((tooltip_t*)data)->curY;
531 XClearWindow( disp, win );
533 XQueryTextExtents( disp, font, text.c_str(), text.size(), &direction,
534 &fontAscent, &fontDescent, &overall );
535 int w = overall.rbearing - overall.lbearing;
536 int h = overall.ascent + overall.descent;
537 XMapRaised( disp, win );
538 XMoveWindow( disp, win, curX - w/4, curY + 20 );
539 XResizeWindow( disp, win, w+8, h+8 );
540 XDrawString( disp, win, gc, 4, overall.ascent+4, text.c_str(),
543 ((tooltip_t*)data)->active = True;
551 void DrawToolTipText( tooltip_t *tooltip )
553 int direction, fontAscent, fontDescent;
555 Display *disp = tooltip->display;
556 Window win = tooltip->window;
557 Font font = tooltip->font;
559 string text = tooltip->text;
560 int curX = tooltip->curX;
561 int curY = tooltip->curY;
564 XClearWindow( disp, win );
566 XQueryTextExtents( disp, font, text.c_str(), text.size(), &direction,
567 &fontAscent, &fontDescent, &overall );
568 int w = overall.rbearing - overall.lbearing;
569 int h = overall.ascent + overall.descent;
570 XMoveWindow( disp, win, curX - w/4, curY + 20 );
571 XResizeWindow( disp, win, w+8, h+8 );
572 XDrawString( disp, win, gc, 4, overall.ascent+4, text.c_str(),
579 void X11Window::ChangeToolTipText( string text )
583 if( ToolTipText != "none" )
585 ToolTipText = "none";
587 // Hide the tooltip window
588 X11TimerManager *timerManager = X11TimerManager::Instance( p_intf );
589 timerManager->removeTimer( ToolTip.timer );
590 XUnmapWindow( display, ToolTip.window );
591 XResizeWindow( display, ToolTip.window, 1, 1 );
593 ToolTip.active = False;
599 if( text != ToolTipText )
603 if( !ToolTip.active )
605 // Create the tooltip
606 OSAPI_GetMousePos( ToolTip.curX, ToolTip.curY );
607 X11TimerManager *timerManager = X11TimerManager::Instance( p_intf );
608 timerManager->addTimer( ToolTip.timer );
612 // Refresh the tooltip
613 DrawToolTipText( &ToolTip );
618 //---------------------------------------------------------------------------