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 // Commented out as it really doesn't seem useful
164 // but rather brings visible problems
165 // pTheme->getWindowManager().synchVisibility();
171 // Find the window to which the event is sent
172 GenericWindow *pWin =
173 ((X11Factory*)pOsFactory)->m_windowMap[event.xany.window];
180 // Send the right event object to the window
185 EvtRefresh evt( getIntf(), event.xexpose.x,
186 event.xexpose.y, event.xexpose.width,
187 event.xexpose.height );
188 pWin->processEvent( evt );
193 EvtFocus evt( getIntf(), true );
194 pWin->processEvent( evt );
199 EvtFocus evt( getIntf(), false );
200 pWin->processEvent( evt );
206 // Don't trust the position in the event, it is
207 // out of date. Get the actual current position instead
209 pOsFactory->getMousePos( x, y );
210 EvtMotion evt( getIntf(), x, y );
211 pWin->processEvent( evt );
216 EvtLeave evt( getIntf() );
217 pWin->processEvent( evt );
223 EvtMouse::ActionType_t action = EvtMouse::kDown;
227 action = EvtMouse::kDown;
230 action = EvtMouse::kUp;
235 int mod = EvtInput::kModNone;
236 if( event.xbutton.state & Mod1Mask )
238 mod |= EvtInput::kModAlt;
240 if( event.xbutton.state & ControlMask )
242 mod |= EvtInput::kModCtrl;
244 if( event.xbutton.state & ShiftMask )
246 mod |= EvtInput::kModShift;
249 // Check for double clicks
250 if( event.type == ButtonPress &&
251 event.xbutton.button == 1 )
253 mtime_t time = mdate();
255 pOsFactory->getMousePos( x, y );
256 if( time - m_lastClickTime < m_dblClickDelay &&
257 x == m_lastClickPosX && y == m_lastClickPosY )
260 action = EvtMouse::kDblClick;
264 m_lastClickTime = time;
270 switch( event.xbutton.button )
274 EvtMouse evt( getIntf(), event.xbutton.x,
275 event.xbutton.y, EvtMouse::kLeft,
277 pWin->processEvent( evt );
282 EvtMouse evt( getIntf(), event.xbutton.x,
283 event.xbutton.y, EvtMouse::kMiddle,
285 pWin->processEvent( evt );
290 EvtMouse evt( getIntf(), event.xbutton.x,
291 event.xbutton.y, EvtMouse::kRight,
293 pWin->processEvent( evt );
299 EvtScroll evt( getIntf(), event.xbutton.x,
300 event.xbutton.y, EvtScroll::kUp,
302 pWin->processEvent( evt );
308 EvtScroll evt( getIntf(), event.xbutton.x,
309 event.xbutton.y, EvtScroll::kDown,
311 pWin->processEvent( evt );
320 EvtKey::ActionType_t action = EvtKey::kDown;
321 int mod = EvtInput::kModNone;
323 if( event.xkey.state & Mod1Mask )
325 mod |= EvtInput::kModAlt;
327 if( event.xkey.state & ControlMask )
329 mod |= EvtInput::kModCtrl;
331 if( event.xkey.state & ShiftMask )
333 mod |= EvtInput::kModShift;
336 // Take the first keysym = lower case character
337 KeySym keysym = XLookupKeysym( &event.xkey, 0 );
339 // Get VLC key code from the keysym
340 int key = keysymToVlcKey[keysym];
350 action = EvtKey::kDown;
353 action = EvtKey::kUp;
356 EvtKey evt( getIntf(), key, action, mod );
357 pWin->processEvent( evt );
363 // Get the message type
364 string type = XGetAtomName( XDISPLAY, event.xclient.message_type );
366 // Find the DnD object for this window
368 ((X11Factory*)pOsFactory)->m_dndMap[event.xany.window];
371 msg_Err( getIntf(), "no associated D&D object" );
375 if( type == "XdndEnter" )
377 pDnd->dndEnter( event.xclient.data.l );
379 else if( type == "XdndPosition" )
381 pDnd->dndPosition( event.xclient.data.l );
383 else if( type == "XdndLeave" )
385 pDnd->dndLeave( event.xclient.data.l );
387 else if( type == "XdndDrop" )
389 pDnd->dndDrop( event.xclient.data.l );