VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gxeventloop.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gxeventloop.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gxdef.h"
23 #include "glog.h"
24 #include "gxeventloop.h"
25 #include "gxdisplay.h"
26 #include "gxerror.h"
27 #include "gassert.h"
28 #include <stdexcept>
29 
30 static Bool fn_always_true( ::Display * , XEvent * , XPointer )
31 {
32  return 1 ;
33 }
34 
35 // ==
36 
38  m_display(display) ,
39  m_timeout(0)
40 {
41 }
42 
43 GX::Display & GX::EventLoop::display()
44 {
45  return m_display ;
46 }
47 
49 {
50  for(;;)
51  {
52  runOnce() ;
53  }
54 }
55 
56 
58 {
59  for(;;)
60  {
61  XEvent event ;
62  Bool rc = XCheckIfEvent( display().x() , &event , &fn_always_true , 0 ) ;
63  if( !rc ) break ;
64  handle( event ) ;
65  }
66 }
67 
69 {
70  for(;;)
71  {
72  // break if timeout time is reached
73  struct Timeval now ;
74  if( m_timeout.is_set() && now > m_timeout )
75  {
76  m_timeout.reset() ;
77  break ;
78  }
79 
80  // prepare an interval for select()
81  Timeval t ;
82  struct timeval * tp = nullptr ;
83  if( m_timeout.is_set() )
84  {
85  t = m_timeout - now ;
86  tp = &t.m_timeval ;
87  }
88 
89  // fdset containing just the x-window display fd
90  fd_set fds ;
91  FD_ZERO( &fds ) ;
92  int fd = ConnectionNumber(display().x()) ;
93  FD_SET( fd , &fds ) ;
94 
95  // wait for an x-window event or timeout
96  int rc = select( fd+1 , &fds , nullptr , &fds , tp ) ;
97  if( rc < 0 )
98  throw Error( "select failed" ) ;
99 
100  // process the event(s)
101  handlePendingEvents() ;
102  }
103 }
104 
106 {
107  XEvent event ;
108  for(;;)
109  {
110  Bool rc = XCheckIfEvent( display().x() , &event , &fn_always_true , 0 ) ;
111  if( !rc ) break ;
112  handle( event ) ;
113  }
114 }
115 
116 void GX::EventLoop::startTimer( unsigned int usec )
117 {
118  m_timeout = Timeval() + usec ;
119 }
120 
122 {
123  XEvent event ;
124  XNextEvent( display().x() , &event ) ;
125  handle( event ) ;
126 }
127 
128 void GX::EventLoop::runUntil( int type )
129 {
130  for(;;)
131  {
132  XEvent event ;
133  XNextEvent( display().x() , &event ) ;
134  handle( event ) ;
135  if( event.type == type ) break ;
136  }
137 }
138 
139 GX::Window & GX::EventLoop::w( ::Window w )
140 {
141  if( WindowMap::instance() == nullptr ) throw Error( "no window map" ) ;
142  return WindowMap::instance()->find(w) ;
143 }
144 
145 void GX::EventLoop::handle( XEvent & e )
146 {
147  try
148  {
149  handleImp( e ) ;
150  }
151  catch( WindowMap::NotFound & )
152  {
153  // ignore it
154  G_WARNING( "warning: event received for unknown window: type " << e.type ) ;
155  }
156 }
157 
158 void GX::EventLoop::handleImp( XEvent & e )
159 {
160  if( e.type == Expose )
161  {
162  w(e.xexpose.window).onExposure( e.xexpose.x , e.xexpose.y , e.xexpose.width , e.xexpose.height ) ;
163  w(e.xexpose.window).onPaint() ;
164  w(e.xexpose.window).onExpose( e.xexpose ) ;
165  }
166  else if( e.type == KeyPress )
167  {
168  w(e.xkey.window).onKeyPress( e.xkey ) ;
169  }
170  else if( e.type == KeyRelease )
171  {
172  w(e.xkey.window).onKeyRelease( e.xkey ) ;
173  }
174  else if( e.type == ButtonPress )
175  {
176  bool shift = e.xbutton.state & ShiftMask ;
177  bool control = e.xbutton.state & ControlMask ;
178  if( e.xbutton.button == Button1 )
179  w(e.xbutton.window).onLeftMouseButtonDown( e.xbutton.x , e.xbutton.y , shift , control ) ;
180  }
181  else if( e.type == ButtonRelease )
182  {
183  bool shift = e.xbutton.state & ShiftMask ;
184  bool control = e.xbutton.state & ControlMask ;
185  if( e.xbutton.button == Button1 )
186  w(e.xbutton.window).onLeftMouseButtonUp( e.xbutton.x , e.xbutton.y , shift , control ) ;
187  }
188  else if( e.type == MapNotify )
189  {
190  if( ! w(e.xmap.window).onCreate() )
191  throw Error( "window not created" ) ; // for now
192  w(e.xmap.window).onShow() ;
193  w(e.xmap.window).onMap( e.xmap ) ;
194  }
195  else if( e.type == ClientMessage )
196  {
197  w(e.xclient.window).onUser() ;
198  }
199  else if( e.type == MotionNotify )
200  {
201  w(e.xmotion.window).onMouseMove( e.xmotion.x , e.xmotion.y ) ;
202  }
203 }
204 
205 /// \file gxeventloop.cpp
A window class that is-a GX::Drawable and a GX::EventHandler.
Definition: gxwindow.h:47
virtual void onLeftMouseButtonUp(int x, int y, bool shift, bool control)
Called for a left-mouse-button-up event.
void handlePendingEvents()
Handles all pending events.
virtual void onPaint()
Called second for a window-expose event.
An Xlib Display wrapper.
Definition: gxdisplay.h:38
void startTimer(unsigned int milliseconds)
Starts a timer for runToTimeout().
void runToEmpty()
Processes all events in the queue and then returns.
Definition: gxeventloop.cpp:57
virtual void onExposure(int x, int y, int dx, int dy)
Called first for a window-expose event.
virtual bool onCreate()
Called first for a window-map event.
An exception class for GX classes.
Definition: gxerror.h:37
virtual void onKeyRelease(::XKeyEvent &)
Called for a key-release event.
virtual void onLeftMouseButtonDown(int x, int y, bool shift, bool control)
Called for a left-mouse-button-down event.
virtual void onKeyPress(::XKeyEvent &) override
An override from EventHandler that calls onKey() doing the translation from opaque keycode to meaning...
Definition: gxwindow.cpp:88
GX::Window & find(::Window w) const
Finds a window. Throws if not found.
Definition: gxwindowmap.cpp:55
virtual void onMouseMove(int x, int y)
Called for a mouse-move event.
virtual void onExpose(::XExposeEvent &)
Called third for a window-expose event.
void runOnce()
Waits for one event and processes it.
void runUntil(int event_type)
Runs the event loop until the given event is received.
void run()
Runs the event loop.
Definition: gxeventloop.cpp:48
virtual void onUser()
Called for a client-message event.
void runToTimeout()
Processes all events until the timer goes off.
Definition: gxeventloop.cpp:68
EventLoop(Display &)
Constructor. The display reference is kept.
Definition: gxeventloop.cpp:37
virtual void onShow()
Called second for a window-map event.
virtual void onMap(::XMapEvent &)
Called third for a window-map event.
static WindowMap * instance()
Singleton access. Returns nullptr if none.
Definition: gxwindowmap.cpp:40
A thin wrapper for 'struct timeval' providing relational operators etc.
Definition: gxeventloop.h:38