g4tools  5.4.0
base_session
Go to the documentation of this file.
1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
2 // See the file tools.license for terms.
3 
4 #ifndef tools_X11_base_session
5 #define tools_X11_base_session
6 
7 // pure X11 code, no GL.
8 
9 #include <ostream>
10 #include <vector>
11 
12 #include "dispatcher"
13 #include <tools/forit>
14 
15 #include <X11/Xatom.h> //XA_INTEGER
16 
17 #include <X11/Xutil.h> //XVisualInfo
18 
19 namespace tools {
20 namespace X11 {
21 
22 class base_session {
23 public:
24  //virtual bool make_current(Window) const {
25  // if(!m_display) return false;
26  // return true;
27  //}
28  //virtual bool swap_buffers(Window) const {
29  // if(!m_display) return false;
30  // return true;
31  //}
32 public:
33  base_session(std::ostream& a_out,unsigned int a_monitor = 0)
34  :m_out(a_out)
35  ,m_monitor(a_monitor)
36  ,m_display(0)
39  {
40  //NOTE : macOS : XOpenDisplay leaks 128 bytes.
41  m_display = ::XOpenDisplay(NULL);
42  if(!m_display) {
43  m_out << "tools::X11::base_session::base_session : can't open display." << std::endl;
44  return;
45  }
46 
47  int monitors = ::XScreenCount(m_display);
48  if(int(m_monitor)>=monitors) {
49  m_out << "tools::X11::base_session::base_session : bad monitor index "
50  << m_monitor << ". (#monitors " << monitors << ")." << std::endl;
51  ::XCloseDisplay(m_display);
52  m_display = 0;
53  return;
54  }
55 
56  m_WM_DELETE_WINDOW_atom = ::XInternAtom(m_display,"WM_DELETE_WINDOW",False);
57  if(m_WM_DELETE_WINDOW_atom==None) {
58  m_out << "tools::X11::base_session::base_session : can't create WM_DELETE_WINDOW Atom." << std::endl;
59  ::XCloseDisplay(m_display);
60  m_display = 0;
61  return;
62  }
63 
64  m_SESSION_EXIT_STEER_atom = ::XInternAtom(m_display,"TOOLS_X11_SESSION_EXIT_STEER",False);
65  if(m_SESSION_EXIT_STEER_atom==None) {
66  m_out << "tools::X11::base_session::base_session :"
67  << " can't create TOOLS_X11_SESSION_EXIT_STEER Atom." << std::endl;
68  ::XCloseDisplay(m_display);
69  m_display = 0;
70  return;
71  }
72  }
73  virtual ~base_session() {
75  if(m_display) ::XCloseDisplay(m_display);
76  m_display = 0;
77  //std::cout << "debug : ~base_session" << std::endl;
78  }
79 protected:
80  base_session(const base_session& a_from)
81  :m_out(a_from.m_out)
82  ,m_monitor(a_from.m_monitor)
83  ,m_display(0)
86  {}
88  if(&a_from==this) return *this;
89  return *this;
90  }
91 public:
92  std::ostream& out() const {return m_out;}
93 
96 
97  bool is_valid() const {return m_display?true:false;}
98 
99  Display* display() const {return m_display;}
100 
101  bool steer() {
102  if(!m_display) return false;
103 
104  while(true) {
105  XEvent xevent;
106  ::XNextEvent(m_display,&xevent);
107  if(xevent.type==ClientMessage) {
108  if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) break;
109  }
110  dispatch(xevent);
111  }
112 
113  return true;
114  }
115 
116  bool sync() {
117  if(!m_display) return false;
118  //::glXWaitX();
119  ::XSync(m_display,False);
120  while(true) {
121  XEvent xevent;
122  if(::XPending(m_display)) {
123  ::XNextEvent(m_display,&xevent);
124  if(xevent.type==ClientMessage) {
125  if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) return false;
126  }
127  dispatch(xevent);
128  } else {
129  break;
130  }
131  }
132  return true;
133  }
134 
135  bool event_pending(bool& a_is) {
136  if(!m_display) {a_is = false;return false;}
137  a_is = ::XPending(m_display)?true:false;
138  return true;
139  }
140 
141  bool next_event(bool& a_to_exit) {
142  if(!m_display) {a_to_exit = false;return false;}
143  XEvent xevent;
144  ::XNextEvent(m_display,&xevent);
145  if(xevent.type==ClientMessage) {
146  if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) {
147  a_to_exit = true;
148  return true;
149  }
150  }
151  dispatch(xevent);
152  a_to_exit = false;
153  return true;
154  }
155 
156  bool flush() {
157  if(!m_display) return false;
158  ::XFlush(m_display);
159  return true;
160  }
161 
162 
166  Window create_window(const char* a_title,int a_x,int a_y,unsigned int a_width,unsigned int a_height) {
167  if(!m_display) return 0L;
168 
169  XSetWindowAttributes swa;
170  swa.event_mask = StructureNotifyMask | ExposureMask
171  | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
172  | PointerMotionMask
173  | KeyPressMask;
174 
175  swa.background_pixel = ::XWhitePixel(m_display,m_monitor);
176 
177  Window window = ::XCreateWindow(m_display,
178  ::XRootWindow(m_display,m_monitor),
179  a_x,a_y,a_width,a_height,
180  0,
181  (int)CopyFromParent,
182  InputOutput,
183  (Visual*)CopyFromParent,
184  CWEventMask|CWBackPixel,&swa);
185  if(window==0L) {
186  m_out << "tools::X11::base_session::create_window : can't create a X11 window." << std::endl;
187  return 0L;
188  }
189 
190  XTextProperty tp;
191  ::XStringListToTextProperty((char**)&a_title,1,&tp);
192  XSizeHints sh;
193  sh.flags = USPosition | USSize;
194  ::XSetWMProperties(m_display,window,&tp,&tp,0,0,&sh,0,0);
195  ::XFree(tp.value);
196 
197  ::XSetWMProtocols(m_display,window,&m_WM_DELETE_WINDOW_atom,1);
198  return window;
199  }
200 
201  void map_raise_window(Window a_window) const {
202  if(!m_display) return;
203  ::XMapWindow(m_display,a_window);
204  ::XRaiseWindow(m_display,a_window);
205  }
206 
207  void show_window(Window a_window) const {
208  if(!m_display) return;
209  // we should test if already mapped ! Else we are going to forever wait in the below XIfEvent.
210  ::XMapWindow(m_display,a_window);
211  ::XRaiseWindow(m_display,a_window);
212  {XEvent event;
213  ::XIfEvent(m_display,&event,wait_map_notify,(char*)a_window);}
214  }
215 
216  void hide_window(Window a_window) const {
217  if(!m_display) return;
218  ::XUnmapWindow(m_display,a_window);
219  {XEvent event;
220  ::XIfEvent(m_display,&event,wait_unmap_notify,(char*)a_window);}
221  }
222 
223  void resize_window(Window a_window,unsigned int a_width,unsigned int a_height) const {
224  if(!m_display) return;
225  unsigned int mask = CWWidth | CWHeight | CWBorderWidth;
226  XWindowChanges changes;
227  changes.border_width = 0;
228  changes.width = a_width;
229  changes.height = a_height;
230  ::XConfigureWindow(m_display,a_window,mask,&changes);
231  }
232 
233  bool window_size(Window a_window,int& a_width,int& a_height) const {
234  if(!m_display) {a_width = 0;a_height = 0;return false;}
235  XWindowAttributes watbs;
236  if(!XGetWindowAttributes(m_display,a_window,&watbs)) {a_width = 0;a_height = 0;return false;}
237  a_width = watbs.width;
238  a_height = watbs.height;
239  return true;
240  }
241 
242  void delete_window(Window a_window) const {
243  if(!m_display) return;
244  ::XDestroyWindow(m_display,a_window);
245  }
246 
247  void set_override_redirect(Window a_window) const {
248  //must be executed before window is mapped.
249  if(!m_display) return;
250  XSetWindowAttributes swa;
251  swa.override_redirect = True;
252  ::XChangeWindowAttributes(m_display,a_window,CWOverrideRedirect,&swa);
253  }
254 
255  void set_wm_no_decorations(Window a_window) const {
256  //must be executed before window is mapped.
257  if(!m_display) return;
258 
259  // struct, mwm_hints_decorations taken from OpenMotif MwmUtils.h.
260  struct{
261  unsigned long flags;
262  unsigned long functions;
263  unsigned long decorations;
264  long inputMode;
265  unsigned long status;
266  } prop;
267 
268  //unsigned long mwm_hints_functions = 1L << 0;
269  unsigned long mwm_hints_decorations = 1L << 1;
270 
271  Atom atom = ::XInternAtom(m_display,"_MOTIF_WM_HINTS",False);
272  if(atom==None) {
273  m_out << "tools::X11::base_session::set_wm_no_decorations : can't create/get _MOTIF_WM_HINTS Atom." << std::endl;
274  return;
275  }
276  prop.flags = mwm_hints_decorations;
277  prop.functions = 0;
278  prop.decorations = 0;
279 
280  ::XChangeProperty(m_display,a_window,atom,atom,32,PropModeReplace,(unsigned char*)&prop,5);
281  }
282 
283  bool post(Window a_win,
284  long a_0 = 0,long a_1 = 0,
285  long a_2 = 0,long a_3 = 0,
286  long a_4 = 0) const {
287  if(!m_display) return false;
288  XEvent event;
289  event.type = ClientMessage;
290  event.xclient.display = m_display;
291  event.xclient.window = a_win;
292  event.xclient.message_type = XA_INTEGER;
293  event.xclient.format = 8; /* put 8 because bug with 32 on VMCMS */
294  event.xclient.data.l[0] = a_0;
295  event.xclient.data.l[1] = a_1;
296  event.xclient.data.l[2] = a_2;
297  event.xclient.data.l[3] = a_3;
298  event.xclient.data.l[4] = a_4;
299  //lock();
300  Status stat = ::XSendEvent(m_display,a_win,False,0L,&event);
301  ::XFlush(m_display);
302  //unlock();
303  return (stat==0?false:true);
304  }
305 
306  bool post_EXIT_STEER(Window a_win) {
307  return post(a_win,SESSION_EXIT_STEER_atom());
308  }
309 
313  void add_dispatcher(dispatcher* a_dispatcher) {
314  m_dispatchers.push_back(a_dispatcher); //take ownership.
315  }
316 
319  if((*it)->window()==a_win) (*it)->invalidate();
320  }
321  }
322 
323  void remove_dispatchers_with_window(Window a_win){
325  if((*it)->window()==a_win) {
326  dispatcher* obj = *it;
327  it = m_dispatchers.erase(it);
328  delete obj;
329  } else {
330  it++;
331  }
332  }
333  }
334 
335  bool dispatch(XEvent& a_event) {
337  if(!(*it)->is_valid()) {
338  dispatcher* obj = *it;
339  it = m_dispatchers.erase(it);
340  delete obj;
341  } else {
342  it++;
343  }
344  }}
346  if((*it)->is_valid()) {
347  if((*it)->dispatch(a_event)) return true;
348  }
349  }
350  return false;
351  }
352 protected:
353  static Bool wait_map_notify(Display*,XEvent* a_event,char* a_arg){
354  return (a_event->type == MapNotify) && (a_event->xmap.window == (Window)a_arg);
355  }
356  static Bool wait_unmap_notify(Display*,XEvent* a_event,char* a_arg){
357  return (a_event->type == UnmapNotify) && (a_event->xmap.window == (Window)a_arg);
358  }
359 
360 /*
361  void wait_xxx(Window a_window) {
362  if(!m_display) return;
363  {wait_what arg;
364  arg.m_event_type = ConfigureNotify;
365  arg.m_window = a_window;
366  XEvent event;
367  ::XIfEvent(m_display,&event,wait_for,(char*)&arg);
368  dispatch(event);}
369  }
370 
371  struct wait_what {
372  int m_event_type;
373  Window m_window;
374  };
375  static Bool wait_for(Display*,XEvent* a_event,char* a_arg){
376  wait_what* arg = (wait_what*)a_arg;
377  return (a_event->type == arg->m_event_type) &&
378  (a_event->xmap.window == arg->m_window);
379  }
380 */
381 
384  dispatcher* obj = *it;
385  it = m_dispatchers.erase(it);
386  delete obj;
387  }
388  m_dispatchers.clear();
389  }
390 
391 protected:
392  std::ostream& m_out;
393  unsigned int m_monitor;
394  Display* m_display;
397  std::vector<dispatcher*> m_dispatchers;
398 };
399 
400 }}
401 
402 #endif
403 
tools::X11::base_session::is_valid
bool is_valid() const
Definition: base_session:97
tools::X11::base_session::map_raise_window
void map_raise_window(Window a_window) const
Definition: base_session:201
tools::X11::base_session::set_override_redirect
void set_override_redirect(Window a_window) const
Definition: base_session:247
tools::X11::base_session::out
std::ostream & out() const
Definition: base_session:92
tools::X11::base_session::invalidate_dispatchers_with_window
void invalidate_dispatchers_with_window(Window a_win)
Definition: base_session:317
tools::X11::base_session::post
bool post(Window a_win, long a_0=0, long a_1=0, long a_2=0, long a_3=0, long a_4=0) const
Definition: base_session:283
tools::X11::base_session::SESSION_EXIT_STEER_atom
Atom SESSION_EXIT_STEER_atom() const
Definition: base_session:95
tools::X11::base_session::delete_window
void delete_window(Window a_window) const
Definition: base_session:242
tools::X11::base_session::m_out
std::ostream & m_out
Definition: base_session:392
tools::X11::base_session::base_session
base_session(const base_session &a_from)
Definition: base_session:80
tools::X11::base_session::event_pending
bool event_pending(bool &a_is)
Definition: base_session:135
tools::X11::base_session::~base_session
virtual ~base_session()
Definition: base_session:73
tools::X11::base_session::flush
bool flush()
Definition: base_session:156
tools::X11::base_session::resize_window
void resize_window(Window a_window, unsigned int a_width, unsigned int a_height) const
Definition: base_session:223
tools::X11::base_session::wait_unmap_notify
static Bool wait_unmap_notify(Display *, XEvent *a_event, char *a_arg)
Definition: base_session:356
tools::X11::base_session::post_EXIT_STEER
bool post_EXIT_STEER(Window a_win)
Definition: base_session:306
tools::X11::base_session::WM_DELETE_WINDOW_atom
Atom WM_DELETE_WINDOW_atom() const
Definition: base_session:94
tools::X11::base_session::base_session
base_session(std::ostream &a_out, unsigned int a_monitor=0)
Definition: base_session:33
tools::X11::base_session::steer
bool steer()
Definition: base_session:101
tools::X11::base_session::create_window
Window create_window(const char *a_title, int a_x, int a_y, unsigned int a_width, unsigned int a_height)
Definition: base_session:166
tools::X11::base_session::m_WM_DELETE_WINDOW_atom
Atom m_WM_DELETE_WINDOW_atom
Definition: base_session:395
tools::X11::base_session::remove_dispatchers_with_window
void remove_dispatchers_with_window(Window a_win)
Definition: base_session:323
tools::X11::base_session::show_window
void show_window(Window a_window) const
Definition: base_session:207
tools_vforit
#define tools_vforit(a__T, a__v, a__it)
Definition: forit:13
tools::X11::base_session::hide_window
void hide_window(Window a_window) const
Definition: base_session:216
tools_vforit_npp
#define tools_vforit_npp(a__T, a__v, a__it)
Definition: forit:25
tools::X11::base_session::next_event
bool next_event(bool &a_to_exit)
Definition: base_session:141
tools
inlined C code : ///////////////////////////////////
Definition: aida_ntuple:26
tools::X11::base_session::sync
bool sync()
Definition: base_session:116
tools::X11::base_session::window_size
bool window_size(Window a_window, int &a_width, int &a_height) const
Definition: base_session:233
tools::X11::base_session::operator=
base_session & operator=(const base_session &a_from)
Definition: base_session:87
tools::X11::base_session::m_monitor
unsigned int m_monitor
Definition: base_session:393
tools::X11::base_session::display
Display * display() const
Definition: base_session:99
tools::X11::base_session::add_dispatcher
void add_dispatcher(dispatcher *a_dispatcher)
Definition: base_session:313
tools::X11::base_session::m_dispatchers
std::vector< dispatcher * > m_dispatchers
Definition: base_session:397
tools::X11::base_session::m_display
Display * m_display
Definition: base_session:394
tools::X11::base_session
Definition: base_session:22
tools::X11::base_session::clear_dispatchers
void clear_dispatchers()
Definition: base_session:382
forit
tools::X11::base_session::set_wm_no_decorations
void set_wm_no_decorations(Window a_window) const
Definition: base_session:255
tools::X11::base_session::m_SESSION_EXIT_STEER_atom
Atom m_SESSION_EXIT_STEER_atom
Definition: base_session:396
tools::X11::base_session::dispatch
bool dispatch(XEvent &a_event)
Definition: base_session:335
dispatcher
tools::X11::dispatcher
Definition: dispatcher:16
tools::X11::base_session::wait_map_notify
static Bool wait_map_notify(Display *, XEvent *a_event, char *a_arg)
Definition: base_session:353