XWinManaged.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:04:48 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3