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