1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
27 #include <X11/keysym.h>
28 #include "x11_loop.hpp"
29 #include "x11_display.hpp"
30 #include "x11_dragdrop.hpp"
31 #include "x11_factory.hpp"
32 #include "x11_timer.hpp"
33 #include "../src/generic_window.hpp"
34 #include "../src/theme.hpp"
35 #include "../src/window_manager.hpp"
36 #include "../events/evt_focus.hpp"
37 #include "../events/evt_key.hpp"
38 #include "../events/evt_mouse.hpp"
39 #include "../events/evt_motion.hpp"
40 #include "../events/evt_leave.hpp"
41 #include "../events/evt_refresh.hpp"
42 #include "../events/evt_scroll.hpp"
43 #include "../commands/async_queue.hpp"
44 #include "../utils/var_bool.hpp"
48 // Maximum interval between clicks for a double-click (in microsec)
49 int X11Loop::m_dblClickDelay = 400000;
52 X11Loop::X11Loop( intf_thread_t *pIntf, X11Display &rDisplay ):
53 OSLoop( pIntf ), m_rDisplay( rDisplay ), m_exit( false ),
54 m_lastClickTime( 0 ), m_lastClickPosX( 0 ), m_lastClickPosY( 0 )
56 // Initialize the key map
57 keysymToVlcKey[XK_F1] = KEY_F1;
58 keysymToVlcKey[XK_F2] = KEY_F2;
59 keysymToVlcKey[XK_F3] = KEY_F3;
60 keysymToVlcKey[XK_F4] = KEY_F4;
61 keysymToVlcKey[XK_F5] = KEY_F5;
62 keysymToVlcKey[XK_F6] = KEY_F6;
63 keysymToVlcKey[XK_F7] = KEY_F7;
64 keysymToVlcKey[XK_F8] = KEY_F8;
65 keysymToVlcKey[XK_F9] = KEY_F9;
66 keysymToVlcKey[XK_F10] = KEY_F10;
67 keysymToVlcKey[XK_F11] = KEY_F11;
68 keysymToVlcKey[XK_F12] = KEY_F12;
69 keysymToVlcKey[XK_Return] = KEY_ENTER;
70 keysymToVlcKey[XK_space] = KEY_SPACE;
71 keysymToVlcKey[XK_Escape] = KEY_ESC;
72 keysymToVlcKey[XK_Left] = KEY_LEFT;
73 keysymToVlcKey[XK_Right] = KEY_RIGHT;
74 keysymToVlcKey[XK_Up] = KEY_UP;
75 keysymToVlcKey[XK_Down] = KEY_DOWN;
76 keysymToVlcKey[XK_Home] = KEY_HOME;
77 keysymToVlcKey[XK_End] = KEY_END;
78 keysymToVlcKey[XK_Prior] = KEY_PAGEUP;
79 keysymToVlcKey[XK_Next] = KEY_PAGEDOWN;
80 keysymToVlcKey[XK_Delete] = KEY_DELETE;
81 keysymToVlcKey[XK_Insert] = KEY_INSERT;
90 OSLoop *X11Loop::instance( intf_thread_t *pIntf, X11Display &rDisplay )
92 if( pIntf->p_sys->p_osLoop == NULL )
94 OSLoop *pOsLoop = new X11Loop( pIntf, rDisplay );
95 pIntf->p_sys->p_osLoop = pOsLoop;
97 return pIntf->p_sys->p_osLoop;
101 void X11Loop::destroy( intf_thread_t *pIntf )
103 delete pIntf->p_sys->p_osLoop;
104 pIntf->p_sys->p_osLoop = NULL;
110 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
111 X11TimerLoop *pTimerLoop = ((X11Factory*)pOsFactory)->getTimerLoop();
118 // Number of pending events in the queue
119 nPending = XPending( XDISPLAY );
121 while( ! m_exit && nPending > 0 )
123 // Handle the next X11 event
126 // Number of pending events in the queue
127 nPending = XPending( XDISPLAY );
130 // Wait for the next timer and execute it
131 // The sleep is interrupted if an X11 event is received
134 pTimerLoop->waitNextTimer();
146 void X11Loop::handleX11Event()
149 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
151 // Look for the next event in the queue
152 XNextEvent( XDISPLAY, &event );
154 if( event.xany.window == m_rDisplay.getMainWindow() )
156 if( event.type == MapNotify )
158 // When the "parent" window is mapped, show all the visible
159 // windows, as it is not automatic, unfortunately
160 Theme *pTheme = getIntf()->p_sys->p_theme;
163 pTheme->getWindowManager().synchVisibility();
169 // Find the window to which the event is sent
170 GenericWindow *pWin =
171 ((X11Factory*)pOsFactory)->m_windowMap[event.xany.window];
178 // Send the right event object to the window
183 EvtRefresh evt( getIntf(), event.xexpose.x,
184 event.xexpose.y, event.xexpose.width,
185 event.xexpose.height );
186 pWin->processEvent( evt );
191 EvtFocus evt( getIntf(), true );
192 pWin->processEvent( evt );
197 EvtFocus evt( getIntf(), false );
198 pWin->processEvent( evt );
204 // Don't trust the position in the event, it is
205 // out of date. Get the actual current position instead
207 pOsFactory->getMousePos( x, y );
208 EvtMotion evt( getIntf(), x, y );
209 pWin->processEvent( evt );
214 EvtLeave evt( getIntf() );
215 pWin->processEvent( evt );
221 EvtMouse::ActionType_t action = EvtMouse::kDown;
225 action = EvtMouse::kDown;
228 action = EvtMouse::kUp;
233 int mod = EvtInput::kModNone;
234 if( event.xbutton.state & Mod1Mask )
236 mod |= EvtInput::kModAlt;
238 if( event.xbutton.state & ControlMask )
240 mod |= EvtInput::kModCtrl;
242 if( event.xbutton.state & ShiftMask )
244 mod |= EvtInput::kModShift;
247 // Check for double clicks
248 if( event.type == ButtonPress &&
249 event.xbutton.button == 1 )
251 mtime_t time = mdate();
253 pOsFactory->getMousePos( x, y );
254 if( time - m_lastClickTime < m_dblClickDelay &&
255 x == m_lastClickPosX && y == m_lastClickPosY )
258 action = EvtMouse::kDblClick;
262 m_lastClickTime = time;
268 switch( event.xbutton.button )
272 EvtMouse evt( getIntf(), event.xbutton.x,
273 event.xbutton.y, EvtMouse::kLeft,
275 pWin->processEvent( evt );
280 EvtMouse evt( getIntf(), event.xbutton.x,
281 event.xbutton.y, EvtMouse::kMiddle,
283 pWin->processEvent( evt );
288 EvtMouse evt( getIntf(), event.xbutton.x,
289 event.xbutton.y, EvtMouse::kRight,
291 pWin->processEvent( evt );
297 EvtScroll evt( getIntf(), event.xbutton.x,
298 event.xbutton.y, EvtScroll::kUp,
300 pWin->processEvent( evt );
306 EvtScroll evt( getIntf(), event.xbutton.x,
307 event.xbutton.y, EvtScroll::kDown,
309 pWin->processEvent( evt );
318 EvtKey::ActionType_t action = EvtKey::kDown;
319 int mod = EvtInput::kModNone;
321 if( event.xkey.state & Mod1Mask )
323 mod |= EvtInput::kModAlt;
325 if( event.xkey.state & ControlMask )
327 mod |= EvtInput::kModCtrl;
329 if( event.xkey.state & ShiftMask )
331 mod |= EvtInput::kModShift;
334 // Take the first keysym = lower case character
335 KeySym keysym = XLookupKeysym( &event.xkey, 0 );
337 // Get VLC key code from the keysym
338 int key = keysymToVlcKey[keysym];
348 action = EvtKey::kDown;
351 action = EvtKey::kUp;
354 EvtKey evt( getIntf(), key, action, mod );
355 pWin->processEvent( evt );
361 // Get the message type
362 string type = XGetAtomName( XDISPLAY, event.xclient.message_type );
364 // Find the DnD object for this window
366 ((X11Factory*)pOsFactory)->m_dndMap[event.xany.window];
369 msg_Err( getIntf(), "no associated D&D object" );
373 if( type == "XdndEnter" )
375 pDnd->dndEnter( event.xclient.data.l );
377 else if( type == "XdndPosition" )
379 pDnd->dndPosition( event.xclient.data.l );
381 else if( type == "XdndLeave" )
383 pDnd->dndLeave( event.xclient.data.l );
385 else if( type == "XdndDrop" )
387 pDnd->dndDrop( event.xclient.data.l );