1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA 02111, 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;
88 OSLoop *X11Loop::instance( intf_thread_t *pIntf, X11Display &rDisplay )
90 if( pIntf->p_sys->p_osLoop == NULL )
92 OSLoop *pOsLoop = new X11Loop( pIntf, rDisplay );
93 pIntf->p_sys->p_osLoop = pOsLoop;
95 return pIntf->p_sys->p_osLoop;
99 void X11Loop::destroy( intf_thread_t *pIntf )
101 if( pIntf->p_sys->p_osLoop )
103 delete pIntf->p_sys->p_osLoop;
104 pIntf->p_sys->p_osLoop = NULL;
111 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
112 X11TimerLoop *pTimerLoop = ((X11Factory*)pOsFactory)->getTimerLoop();
119 // Number of pending events in the queue
120 nPending = XPending( XDISPLAY );
122 while( ! m_exit && nPending > 0 )
124 // Handle the next X11 event
127 // Number of pending events in the queue
128 nPending = XPending( XDISPLAY );
131 // Wait for the next timer and execute it
132 // The sleep is interrupted if an X11 event is received
133 pTimerLoop->waitNextTimer();
144 void X11Loop::flush()
150 void X11Loop::handleX11Event()
153 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
155 // Look for the next event in the queue
156 XNextEvent( XDISPLAY, &event );
158 // If the "parent" window is mapped, show all the windows
159 if( event.xany.window == m_rDisplay.getMainWindow()
160 && event.type == MapNotify )
162 getIntf()->p_sys->p_theme->getWindowManager().showAll();
165 // Find the window to which the event is sent
166 X11Factory *pFactory = (X11Factory*)X11Factory::instance( getIntf() );
167 GenericWindow *pWin = pFactory->m_windowMap[event.xany.window];
171 msg_Dbg( getIntf(), "No associated generic window !!" );
175 // Send the right event object to the window
180 EvtRefresh evt( getIntf(), event.xexpose.x,
181 event.xexpose.y, event.xexpose.width,
182 event.xexpose.height );
183 pWin->processEvent( evt );
188 EvtFocus evt( getIntf(), true );
189 pWin->processEvent( evt );
194 EvtFocus evt( getIntf(), false );
195 pWin->processEvent( evt );
201 // Don't trust the position in the event, it is
202 // out of date. Get the actual current position instead
204 pOsFactory->getMousePos( x, y );
205 EvtMotion evt( getIntf(), x, y );
206 pWin->processEvent( evt );
211 EvtLeave evt( getIntf() );
212 pWin->processEvent( evt );
218 EvtMouse::ActionType_t action = EvtMouse::kDown;
222 action = EvtMouse::kDown;
225 action = EvtMouse::kUp;
230 int mod = EvtInput::kModNone;
231 if( event.xbutton.state & Mod1Mask )
233 mod |= EvtInput::kModAlt;
235 if( event.xbutton.state & ControlMask )
237 mod |= EvtInput::kModCtrl;
239 if( event.xbutton.state & ShiftMask )
241 mod |= EvtInput::kModShift;
244 // Check for double clicks
245 if( event.type == ButtonPress &&
246 event.xbutton.button == 1 )
248 mtime_t time = mdate();
250 pOsFactory->getMousePos( x, y );
251 if( time - m_lastClickTime < m_dblClickDelay &&
252 x == m_lastClickPosX && y == m_lastClickPosY )
255 action = EvtMouse::kDblClick;
259 m_lastClickTime = time;
265 switch( event.xbutton.button )
269 EvtMouse evt( getIntf(), event.xbutton.x,
270 event.xbutton.y, EvtMouse::kLeft,
272 pWin->processEvent( evt );
277 EvtMouse evt( getIntf(), event.xbutton.x,
278 event.xbutton.y, EvtMouse::kMiddle,
280 pWin->processEvent( evt );
285 EvtMouse evt( getIntf(), event.xbutton.x,
286 event.xbutton.y, EvtMouse::kRight,
288 pWin->processEvent( evt );
294 EvtScroll evt( getIntf(), event.xbutton.x,
295 event.xbutton.y, EvtScroll::kUp,
297 pWin->processEvent( evt );
303 EvtScroll evt( getIntf(), event.xbutton.x,
304 event.xbutton.y, EvtScroll::kDown,
306 pWin->processEvent( evt );
315 EvtKey::ActionType_t action = EvtKey::kDown;
316 int mod = EvtInput::kModNone;
318 if( event.xkey.state & Mod1Mask )
320 mod |= EvtInput::kModAlt;
322 if( event.xkey.state & ControlMask )
324 mod |= EvtInput::kModCtrl;
326 if( event.xkey.state & ShiftMask )
328 mod |= EvtInput::kModShift;
331 // Take the first keysym = lower case character
332 KeySym keysym = XLookupKeysym( &event.xkey, 0 );
334 // Get VLC key code from the keysym
335 int key = keysymToVlcKey[keysym];
345 action = EvtKey::kDown;
348 action = EvtKey::kUp;
351 EvtKey evt( getIntf(), key, action, mod );
352 pWin->processEvent( evt );
358 // Get the message type
359 string type = XGetAtomName( XDISPLAY, event.xclient.message_type );
361 // Find the DnD object for this window
362 X11DragDrop *pDnd = pFactory->m_dndMap[event.xany.window];
365 msg_Err( getIntf(), "No associated D&D object !!" );
369 if( type == "XdndEnter" )
371 pDnd->dndEnter( event.xclient.data.l );
373 else if( type == "XdndPosition" )
375 pDnd->dndPosition( event.xclient.data.l );
377 else if( type == "XdndLeave" )
379 pDnd->dndLeave( event.xclient.data.l );
381 else if( type == "XdndDrop" )
383 pDnd->dndDrop( event.xclient.data.l );
389 // Hack to update the visibility variable if the window
390 // is unmapped by the window manager
391 ((VarBoolImpl&)pWin->getVisibleVar()).set( false, false );