Warning, /include/Geant4/toolx/X11/base_session is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef toolx_X11_base_session
0005 #define toolx_X11_base_session
0006
0007 // pure X11 code, no GL.
0008
0009 #include <ostream>
0010 #include <vector>
0011
0012 #include "dispatcher"
0013 #include <tools/forit>
0014
0015 #include <X11/Xatom.h> //XA_INTEGER
0016
0017 #include <X11/Xutil.h> //XVisualInfo
0018
0019 namespace toolx {
0020 namespace X11 {
0021
0022 class base_session {
0023 public:
0024 base_session(std::ostream& a_out,unsigned int a_monitor = 0)
0025 :m_out(a_out)
0026 ,m_monitor(a_monitor)
0027 ,m_display(0)
0028 ,m_WM_DELETE_WINDOW_atom(None)
0029 ,m_SESSION_EXIT_STEER_atom(None)
0030 {
0031 //NOTE : macOS : XOpenDisplay leaks 128 bytes.
0032 m_display = ::XOpenDisplay(NULL);
0033 if(!m_display) {
0034 m_out << "toolx::X11::base_session::base_session : can't open display." << std::endl;
0035 return;
0036 }
0037
0038 int monitors = ::XScreenCount(m_display);
0039 if(int(m_monitor)>=monitors) {
0040 m_out << "toolx::X11::base_session::base_session : bad monitor index "
0041 << m_monitor << ". (#monitors " << monitors << ")." << std::endl;
0042 ::XCloseDisplay(m_display);
0043 m_display = 0;
0044 return;
0045 }
0046
0047 m_WM_DELETE_WINDOW_atom = ::XInternAtom(m_display,"WM_DELETE_WINDOW",False);
0048 if(m_WM_DELETE_WINDOW_atom==None) {
0049 m_out << "toolx::X11::base_session::base_session : can't create WM_DELETE_WINDOW Atom." << std::endl;
0050 ::XCloseDisplay(m_display);
0051 m_display = 0;
0052 return;
0053 }
0054
0055 m_SESSION_EXIT_STEER_atom = ::XInternAtom(m_display,"TOOLX_X11_SESSION_EXIT_STEER",False);
0056 if(m_SESSION_EXIT_STEER_atom==None) {
0057 m_out << "toolx::X11::base_session::base_session :"
0058 << " can't create TOOLX_X11_SESSION_EXIT_STEER Atom." << std::endl;
0059 ::XCloseDisplay(m_display);
0060 m_display = 0;
0061 return;
0062 }
0063 }
0064 virtual ~base_session() {
0065 clear_dispatchers();
0066 if(m_display) ::XCloseDisplay(m_display);
0067 m_display = 0;
0068 }
0069 protected:
0070 base_session(const base_session& a_from)
0071 :m_out(a_from.m_out)
0072 ,m_monitor(a_from.m_monitor)
0073 ,m_display(0)
0074 ,m_WM_DELETE_WINDOW_atom(None)
0075 ,m_SESSION_EXIT_STEER_atom(None)
0076 {}
0077 base_session& operator=(const base_session& a_from){
0078 if(&a_from==this) return *this;
0079 return *this;
0080 }
0081 public:
0082 std::ostream& out() const {return m_out;}
0083
0084 Atom WM_DELETE_WINDOW_atom() const {return m_WM_DELETE_WINDOW_atom;}
0085 Atom SESSION_EXIT_STEER_atom() const {return m_SESSION_EXIT_STEER_atom;}
0086
0087 bool is_valid() const {return m_display?true:false;}
0088
0089 unsigned int monitor() const {return m_monitor;}
0090 Display* display() const {return m_display;}
0091
0092 bool steer() {
0093 if(!m_display) return false;
0094
0095 while(true) {
0096 XEvent xevent;
0097 ::XNextEvent(m_display,&xevent);
0098 if(xevent.type==ClientMessage) {
0099 if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) break;
0100 }
0101 dispatch(xevent);
0102 }
0103
0104 return true;
0105 }
0106
0107 bool sync() {
0108 if(!m_display) return false;
0109 ::XSync(m_display,False);
0110 while(true) {
0111 XEvent xevent;
0112 if(::XPending(m_display)) {
0113 ::XNextEvent(m_display,&xevent);
0114 if(xevent.type==ClientMessage) {
0115 if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) return false;
0116 }
0117 dispatch(xevent);
0118 } else {
0119 break;
0120 }
0121 }
0122 return true;
0123 }
0124
0125 bool event_pending(bool& a_is) {
0126 if(!m_display) {a_is = false;return false;}
0127 a_is = ::XPending(m_display)?true:false;
0128 return true;
0129 }
0130
0131 bool next_event(bool& a_to_exit) {
0132 if(!m_display) {a_to_exit = false;return false;}
0133 XEvent xevent;
0134 ::XNextEvent(m_display,&xevent);
0135 if(xevent.type==ClientMessage) {
0136 if(xevent.xclient.data.l[0]==(long)m_SESSION_EXIT_STEER_atom) {
0137 a_to_exit = true;
0138 return true;
0139 }
0140 }
0141 dispatch(xevent);
0142 a_to_exit = false;
0143 return true;
0144 }
0145
0146 bool flush() {
0147 if(!m_display) return false;
0148 ::XFlush(m_display);
0149 return true;
0150 }
0151
0152
0153 //////////////////////////////////////////////////
0154 //////////////////////////////////////////////////
0155 //////////////////////////////////////////////////
0156 Window create_window(const char* a_title,int a_x,int a_y,unsigned int a_width,unsigned int a_height) {
0157 if(!m_display) return 0L;
0158
0159 XSetWindowAttributes swa;
0160 swa.event_mask = StructureNotifyMask | ExposureMask
0161 | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
0162 | PointerMotionMask
0163 | KeyPressMask;
0164
0165 swa.background_pixel = ::XWhitePixel(m_display,m_monitor);
0166
0167 Window window = ::XCreateWindow(m_display,
0168 ::XRootWindow(m_display,m_monitor),
0169 a_x,a_y,a_width,a_height,
0170 0,
0171 (int)CopyFromParent,
0172 InputOutput,
0173 (Visual*)CopyFromParent,
0174 CWEventMask|CWBackPixel,&swa);
0175 if(window==0L) {
0176 m_out << "toolx::X11::base_session::create_window : can't create a X11 window." << std::endl;
0177 return 0L;
0178 }
0179
0180 XTextProperty tp;
0181 ::XStringListToTextProperty((char**)&a_title,1,&tp);
0182 XSizeHints sh;
0183 sh.flags = USPosition | USSize;
0184 ::XSetWMProperties(m_display,window,&tp,&tp,0,0,&sh,0,0);
0185 ::XFree(tp.value);
0186
0187 ::XSetWMProtocols(m_display,window,&m_WM_DELETE_WINDOW_atom,1);
0188 return window;
0189 }
0190
0191 void map_raise_window(Window a_window) const {
0192 if(!m_display) return;
0193 ::XMapWindow(m_display,a_window);
0194 ::XRaiseWindow(m_display,a_window);
0195 }
0196
0197 void show_window(Window a_window) const {
0198 if(!m_display) return;
0199
0200 XWindowAttributes watbs;
0201 ::XGetWindowAttributes(m_display,a_window,&watbs);
0202 if(watbs.map_state!=IsUnmapped) return;
0203
0204 ::XMapWindow(m_display,a_window);
0205 ::XRaiseWindow(m_display,a_window);
0206
0207 {XEvent event;
0208 ::XIfEvent(m_display,&event,wait_map_notify,(char*)a_window);}
0209 }
0210
0211 void hide_window(Window a_window) const {
0212 if(!m_display) return;
0213
0214 XWindowAttributes watbs;
0215 ::XGetWindowAttributes(m_display,a_window,&watbs);
0216 if(watbs.map_state==IsUnmapped) return;
0217
0218 ::XUnmapWindow(m_display,a_window);
0219
0220 {XEvent event;
0221 ::XIfEvent(m_display,&event,wait_unmap_notify,(char*)a_window);}
0222 }
0223
0224 void resize_window(Window a_window,unsigned int a_width,unsigned int a_height) const {
0225 if(!m_display) return;
0226 unsigned int mask = CWWidth | CWHeight | CWBorderWidth;
0227 XWindowChanges changes;
0228 changes.border_width = 0;
0229 changes.width = a_width;
0230 changes.height = a_height;
0231 ::XConfigureWindow(m_display,a_window,mask,&changes);
0232 }
0233
0234 bool window_size(Window a_window,int& a_width,int& a_height) const {
0235 if(!m_display) {a_width = 0;a_height = 0;return false;}
0236 XWindowAttributes watbs;
0237 if(!XGetWindowAttributes(m_display,a_window,&watbs)) {a_width = 0;a_height = 0;return false;}
0238 a_width = watbs.width;
0239 a_height = watbs.height;
0240 return true;
0241 }
0242
0243 void delete_window(Window a_window) const {
0244 if(!m_display) return;
0245 ::XDestroyWindow(m_display,a_window);
0246 }
0247
0248 void set_override_redirect(Window a_window) const {
0249 //must be executed before window is mapped.
0250 if(!m_display) return;
0251 XSetWindowAttributes swa;
0252 swa.override_redirect = True;
0253 ::XChangeWindowAttributes(m_display,a_window,CWOverrideRedirect,&swa);
0254 }
0255
0256 void set_wm_no_decorations(Window a_window) const {
0257 //must be executed before window is mapped.
0258 if(!m_display) return;
0259
0260 // struct, mwm_hints_decorations taken from OpenMotif MwmUtils.h.
0261 struct{
0262 unsigned long flags;
0263 unsigned long functions;
0264 unsigned long decorations;
0265 long inputMode;
0266 unsigned long status;
0267 } prop;
0268
0269 unsigned long mwm_hints_decorations = 1L << 1;
0270
0271 Atom atom = ::XInternAtom(m_display,"_MOTIF_WM_HINTS",False);
0272 if(atom==None) {
0273 m_out << "toolx::X11::base_session::set_wm_no_decorations : can't create/get _MOTIF_WM_HINTS Atom." << std::endl;
0274 return;
0275 }
0276 prop.flags = mwm_hints_decorations;
0277 prop.functions = 0;
0278 prop.decorations = 0;
0279
0280 ::XChangeProperty(m_display,a_window,atom,atom,32,PropModeReplace,(unsigned char*)&prop,5);
0281 }
0282
0283 bool post(Window a_win,
0284 long a_0 = 0,long a_1 = 0,
0285 long a_2 = 0,long a_3 = 0,
0286 long a_4 = 0) const {
0287 if(!m_display) return false;
0288 XEvent event;
0289 event.type = ClientMessage;
0290 event.xclient.display = m_display;
0291 event.xclient.window = a_win;
0292 event.xclient.message_type = XA_INTEGER;
0293 event.xclient.format = 8; /* put 8 because bug with 32 on VMCMS */
0294 event.xclient.data.l[0] = a_0;
0295 event.xclient.data.l[1] = a_1;
0296 event.xclient.data.l[2] = a_2;
0297 event.xclient.data.l[3] = a_3;
0298 event.xclient.data.l[4] = a_4;
0299 Status stat = ::XSendEvent(m_display,a_win,False,0L,&event);
0300 ::XFlush(m_display);
0301 return (stat==0?false:true);
0302 }
0303
0304 bool post_EXIT_STEER(Window a_win) {
0305 return post(a_win,SESSION_EXIT_STEER_atom());
0306 }
0307
0308 bool post_expose(Window a_win) const {
0309 int width,height;
0310 if(!window_size(a_win,width,height)) return false;
0311 XEvent event;
0312 event.type = Expose;
0313 event.xexpose.serial = 0;
0314 event.xexpose.send_event = True;
0315 event.xexpose.display = m_display;
0316 event.xexpose.window = a_win;
0317 event.xexpose.x = 0;
0318 event.xexpose.y = 0;
0319 event.xexpose.width = width;
0320 event.xexpose.height = height;
0321 event.xexpose.count = 0;
0322 //locks
0323 Status stat = ::XSendEvent(m_display,a_win,False,0L,&event);
0324 ::XFlush(m_display);
0325 //unlock();
0326 return (stat==0?false:true);
0327 }
0328
0329 //////////////////////////////////////////////////
0330 //////////////////////////////////////////////////
0331 //////////////////////////////////////////////////
0332 void add_dispatcher(dispatcher* a_dispatcher) {
0333 m_dispatchers.push_back(a_dispatcher); //take ownership.
0334 }
0335
0336 void invalidate_dispatchers_with_window(Window a_win){
0337 tools_vforit(dispatcher*,m_dispatchers,it) {
0338 if((*it)->window()==a_win) (*it)->invalidate();
0339 }
0340 }
0341
0342 void remove_dispatchers_with_window(Window a_win){
0343 for(auto it = m_dispatchers.begin(); it != m_dispatchers.end();) {
0344 if((*it)->window()==a_win) {
0345 dispatcher* obj = *it;
0346 it = m_dispatchers.erase(it);
0347 delete obj;
0348 } else {
0349 it++;
0350 }
0351 }
0352 }
0353
0354 bool dispatch(XEvent& a_event) {
0355 {for(auto it = m_dispatchers.begin(); it != m_dispatchers.end();) {
0356 if(!(*it)->is_valid()) {
0357 dispatcher* obj = *it;
0358 it = m_dispatchers.erase(it);
0359 delete obj;
0360 } else {
0361 it++;
0362 }
0363 }}
0364 tools_vforit(dispatcher*,m_dispatchers,it) {
0365 if((*it)->is_valid()) {
0366 if((*it)->dispatch(a_event)) return true;
0367 }
0368 }
0369 return false;
0370 }
0371 protected:
0372 static Bool wait_map_notify(Display*,XEvent* a_event,char* a_arg){
0373 return (a_event->type == MapNotify) && (a_event->xmap.window == (Window)a_arg);
0374 }
0375 static Bool wait_unmap_notify(Display*,XEvent* a_event,char* a_arg){
0376 return (a_event->type == UnmapNotify) && (a_event->xmap.window == (Window)a_arg);
0377 }
0378
0379 void clear_dispatchers() {
0380 for(auto it = m_dispatchers.begin(); it != m_dispatchers.end();) {
0381 dispatcher* obj = *it;
0382 it = m_dispatchers.erase(it);
0383 delete obj;
0384 }
0385 m_dispatchers.clear();
0386 }
0387
0388 protected:
0389 std::ostream& m_out;
0390 unsigned int m_monitor;
0391 Display* m_display;
0392 Atom m_WM_DELETE_WINDOW_atom;
0393 Atom m_SESSION_EXIT_STEER_atom;
0394 std::vector<dispatcher*> m_dispatchers;
0395 };
0396
0397 }}
0398
0399
0400 #endif
0401