00001 /*!@file GUI/XWinManaged.C A window class with active window management */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/GUI/XWinManaged.C $ 00035 // $Id: XWinManaged.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #include "GUI/XWinManaged.H" 00039 00040 #include "Image/Image.H" 00041 #include "Image/Pixels.H" 00042 #include "Util/log.H" 00043 #include "Util/sformat.H" 00044 #include "rutz/mutex.h" 00045 00046 #include <stdlib.h> 00047 #include <unistd.h> 00048 #include <X11/Xutil.h> 00049 00050 namespace 00051 { 00052 const int SLEEPTIME = 10000; 00053 00054 const long g_event_mask = (ExposureMask | 00055 ButtonPressMask | KeyPressMask); 00056 00057 const unsigned int g_max_queue_len = 32; 00058 } 00059 00060 // ###################################################################### 00061 void XWinManaged::init() 00062 { 00063 this->selectInput(g_event_mask); 00064 00065 deleteAtom = this->setWMProtocol("WM_DELETE_WINDOW"); 00066 00067 windowPresent.atomic_set(1); 00068 itsTraceEvents.atomic_set(0); 00069 00070 if (0 != pthread_mutex_init(&itsEventsMutex, NULL)) 00071 LFATAL("pthread_mutex_init() failed"); 00072 00073 if (0 != pthread_create(&eventLoopThread, NULL, &cEventLoop, this)) 00074 LFATAL("Cannot create thread"); 00075 } 00076 00077 // ###################################################################### 00078 XWinManaged::XWinManaged(const Dims& dims, 00079 const int x, const int y, const char* title) 00080 : 00081 XWindow(dims, x, y, title), 00082 toBeClosed(false) 00083 { 00084 init(); 00085 } 00086 00087 00088 // ###################################################################### 00089 XWinManaged::XWinManaged(const Image< PixRGB<byte> >& img, 00090 const char* title) 00091 : 00092 XWindow(img.getDims(), -1, -1, title), 00093 toBeClosed(false) 00094 { 00095 init(); 00096 XWindow::drawImage(img); 00097 } 00098 00099 00100 // ###################################################################### 00101 XWinManaged::XWinManaged(const Image<byte>& img, const char* title) 00102 : 00103 XWindow(img.getDims(), -1, -1, title), 00104 toBeClosed(false) 00105 { 00106 init(); 00107 XWindow::drawImage(img); 00108 } 00109 00110 // ###################################################################### 00111 XWinManaged::XWinManaged(const Image<float>& img, const char* title, 00112 bool normalize) 00113 : 00114 XWindow(img.getDims(), -1, -1, title), 00115 toBeClosed(false) 00116 { 00117 init(); 00118 drawImage(img,0,0,normalize); 00119 } 00120 00121 00122 // ###################################################################### 00123 XWinManaged::~XWinManaged() 00124 { 00125 windowPresent.atomic_set(0); 00126 00127 if (0 != pthread_join(eventLoopThread, NULL)) 00128 LERROR("Thread is not returning"); 00129 00130 if (0 != pthread_mutex_destroy(&itsEventsMutex)) 00131 LERROR("pthread_mutex_destroy() failed"); 00132 } 00133 00134 // ###################################################################### 00135 void* XWinManaged::cEventLoop(void* xself) 00136 { 00137 XWinManaged* self = static_cast<XWinManaged*>(xself); 00138 00139 while (1) 00140 { 00141 if (!self->windowPresent.atomic_get()) 00142 break; 00143 00144 00145 XEvent event; 00146 const Bool status1 = self->checkMaskEvent(g_event_mask, &event); 00147 00148 if (True == status1) 00149 self->eventHandler(&event); 00150 00151 // NB: XCheckWindowEvent() will NOT return ClientMessage 00152 // events, since those events are "unmaskable", so we need to 00153 // do a separate XCheckTypedWindowEvent() to pull in 00154 // ClientMessage events (ClientMessage events are needed to 00155 // get close-button notification) 00156 const Bool status2 = self->checkTypedEvent(ClientMessage, &event); 00157 00158 if (True == status2) 00159 self->eventHandler(&event); 00160 00161 if (False == status1 && False == status2) 00162 // we didn't get any event this time, so sleep before 00163 // looking for the next event 00164 usleep (SLEEPTIME); 00165 } 00166 pthread_exit(NULL); 00167 return 0; 00168 } 00169 00170 // ###################################################################### 00171 void XWinManaged::eventHandler(XEvent* event) 00172 { 00173 if (itsTraceEvents.atomic_get() > 0 || MYLOGVERB >= LOG_DEBUG) 00174 LINFO("%s in window '%s'...", 00175 describeEvent(event).c_str(), this->getTitle()); 00176 00177 switch(event->type) 00178 { 00179 00180 case ClientMessage: 00181 { 00182 if (event->xclient.data.l[0] == (int)deleteAtom) 00183 { 00184 // user wants to close window - set the flag 00185 toBeClosed = true; 00186 } 00187 } 00188 break; 00189 00190 case Expose: 00191 { 00192 while (this->checkMaskEvent(ExposureMask, event)) 00193 { /* empty loop body */ } 00194 00195 this->redrawImage(); 00196 } 00197 break; 00198 00199 case KeyPress: 00200 { 00201 GVX_MUTEX_LOCK(&itsEventsMutex); 00202 itsKeyEvents.push_back(event->xkey); 00203 if (itsKeyEvents.size() > g_max_queue_len) 00204 itsKeyEvents.pop_front(); 00205 } 00206 break; 00207 00208 case ButtonPress: 00209 { 00210 GVX_MUTEX_LOCK(&itsEventsMutex); 00211 itsButtonEvents.push_back(event->xbutton); 00212 if (itsButtonEvents.size() > g_max_queue_len) 00213 itsButtonEvents.pop_front(); 00214 } 00215 break; 00216 } 00217 } 00218 00219 // ###################################################################### 00220 void XWinManaged::setTraceEvents(bool on) 00221 { 00222 itsTraceEvents.atomic_set(on ? 1 : 0); 00223 } 00224 00225 // ###################################################################### 00226 int XWinManaged::getLastKeyPress() 00227 { 00228 XKeyEvent ev; 00229 if (!this->getLastKeyEvent(&ev)) 00230 return -1; 00231 00232 return ev.keycode; 00233 } 00234 00235 // ###################################################################### 00236 std::string XWinManaged::getLastKeyString() 00237 { 00238 XKeyEvent ev; 00239 if (!this->getLastKeyEvent(&ev)) 00240 return std::string(); 00241 00242 char buf[30]; 00243 const int len = 00244 XLookupString(&ev, &buf[0], sizeof(buf), 0, 0); 00245 (void) len; 00246 buf[sizeof(buf)-1] = '\0'; 00247 00248 return std::string(&buf[0]); 00249 } 00250 00251 // ###################################################################### 00252 KeySym XWinManaged::getLastKeySym(std::string* s) 00253 { 00254 XKeyEvent ev; 00255 if (!this->getLastKeyEvent(&ev)) 00256 return NoSymbol; 00257 00258 char buf[30]; 00259 KeySym keysym; 00260 const int len = 00261 XLookupString(&ev, &buf[0], sizeof(buf), &keysym, 0); 00262 (void) len; 00263 buf[sizeof(buf)-1] = '\0'; 00264 00265 if (s != 0) 00266 *s = buf; 00267 00268 return keysym; 00269 } 00270 00271 // ###################################################################### 00272 bool XWinManaged::getLastKeyEvent(XKeyEvent* ev) 00273 { 00274 GVX_MUTEX_LOCK(&itsEventsMutex); 00275 if (itsKeyEvents.empty()) 00276 return false; 00277 00278 *ev = itsKeyEvents.front(); 00279 itsKeyEvents.pop_front(); 00280 return true; 00281 } 00282 00283 // ###################################################################### 00284 Point2D<int> XWinManaged::getLastMouseClick() 00285 { 00286 XButtonEvent ev; 00287 if (!this->getLastButtonEvent(&ev)) 00288 return Point2D<int>(-1, -1); 00289 00290 return Point2D<int>(ev.x, ev.y); 00291 } 00292 00293 // ###################################################################### 00294 bool XWinManaged::getLastButtonEvent(XButtonEvent* ev) 00295 { 00296 GVX_MUTEX_LOCK(&itsEventsMutex); 00297 if (itsButtonEvents.empty()) 00298 return false; 00299 00300 *ev = itsButtonEvents.front(); 00301 itsButtonEvents.pop_front(); 00302 return true; 00303 } 00304 00305 // ###################################################################### 00306 std::string XWinManaged::describeKeyEvent(const XKeyEvent* ev) const 00307 { 00308 char buf[30]; 00309 KeySym keysym; 00310 XKeyEvent evcopy = *ev; // XLookupString() wants a non-const pointer 00311 const int len = 00312 XLookupString(&evcopy, &buf[0], sizeof(buf), 00313 &keysym, 0); 00314 00315 const char* symname = XKeysymToString(keysym); 00316 if (symname == 0) 00317 symname = "VoidSymbol"; 00318 00319 if (len > 1) 00320 return sformat("KeyPress code=%d sym=XK_%s (\"%s\")", 00321 ev->keycode, symname, &buf[0]); 00322 00323 // else ... 00324 return sformat("KeyPress code=%d sym=XK_%s", 00325 ev->keycode, symname); 00326 } 00327 00328 // ###################################################################### 00329 std::string XWinManaged::describeButtonEvent(const XButtonEvent* ev) const 00330 { 00331 return sformat("ButtonPress button #%u at (%d,%d)", 00332 ev->button, ev->x, ev->y); 00333 } 00334 00335 // ###################################################################### 00336 std::string XWinManaged::describeEvent(const XEvent* ev) const 00337 { 00338 switch (ev->type) 00339 { 00340 case ClientMessage: 00341 if (ev->xclient.data.l[0] == (int)deleteAtom) 00342 return "Close button"; 00343 else 00344 return "ClientMessage"; 00345 break; 00346 00347 case Expose: 00348 return "Expose"; 00349 break; 00350 00351 case KeyPress: 00352 return describeKeyEvent(&ev->xkey); 00353 break; 00354 00355 case ButtonPress: 00356 return describeButtonEvent(&ev->xbutton); 00357 break; 00358 } 00359 00360 // default: 00361 return "other XEvent"; 00362 } 00363 00364 // ###################################################################### 00365 /* So things look consistent in everyone's emacs... */ 00366 /* Local Variables: */ 00367 /* indent-tabs-mode: nil */ 00368 /* End: */