00001 /*!@file GUI/AutomateXWin.C Automate X windows by sending keys and getting images */ 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: Lior Elazary 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/GUI/AutomateXWin.C $ 00035 // $Id: AutomateXWin.C 9129 2008-01-14 20:27:55Z lior $ 00036 // 00037 00038 #include "Image/Image.H" 00039 #include "Image/Pixels.H" 00040 #include "GUI/AutomateXWin.H" 00041 00042 00043 // shift x left by i, where i can be positive or negative 00044 #define SHIFTL(x,i) (((i) >= 0) ? ((x) << (i)) : ((x) >> (-i))) 00045 00046 // ###################################################################### 00047 AutomateXWin::AutomateXWin(const char* win_name) : 00048 itsDisplay(NULL), 00049 itsScreen(0), 00050 itsImage(NULL), 00051 itsWidth(0), 00052 itsHeight(0), 00053 itsDepth(0) 00054 00055 { 00056 char *dispName = XDisplayName(NULL); 00057 unsigned num_tries; 00058 int event_base, error_base; 00059 int major_version, minor_version; 00060 00061 itsDisplay = XOpenDisplay(dispName); 00062 if(!itsDisplay) 00063 LFATAL("XOpenDisplay(%s) failed\n", dispName); 00064 00065 if (!XTestQueryExtension (itsDisplay, &event_base, &error_base, &major_version, &minor_version)) { 00066 XCloseDisplay(itsDisplay); 00067 LFATAL("XTest extension not supported on server"); 00068 } 00069 00070 LINFO("XTestQueryExtension passed."); 00071 LINFO("XTest information for server \"%s\":", DisplayString(itsDisplay)); 00072 LINFO(" Major version: %d", major_version); 00073 LINFO(" Minor version: %d", minor_version); 00074 LINFO(" First event number: %d", event_base); 00075 LINFO(" First error number: %d", error_base); 00076 00077 00078 itsScreen = DefaultScreen(itsDisplay); 00079 00080 itsRootWin = RootWindow(itsDisplay, itsScreen); 00081 00082 for(num_tries=0;;) 00083 { 00084 itsWindow = XWindowByName(itsDisplay, itsRootWin, win_name); 00085 if(itsWindow) break; 00086 if(++num_tries == 100) 00087 LFATAL("XWindowByName\n"); 00088 usleep(20000); 00089 } 00090 00091 XFlush(itsDisplay); 00092 XSync(itsDisplay, False); 00093 #ifdef USE_SHM 00094 if(!XShmQueryExtension(itsDisplay)) 00095 LFATAL("XShmQueryExtension"); 00096 #endif 00097 GetWindowGeometry(); 00098 00099 if(!XMatchVisualInfo(itsDisplay, itsScreen, itsDepth, DirectColor, &itsVInfo)) 00100 { 00101 return; 00102 } 00103 00104 } 00105 00106 00107 // ###################################################################### 00108 AutomateXWin::~AutomateXWin() 00109 { 00110 if(!itsImage) return; 00111 00112 #ifdef USE_SHM 00113 XShmDetach(itsDisplay, &itsShminfo); 00114 XDestroyImage(itsImage); 00115 itsImage = NULL; 00116 shmdt(itsShminfo.shmaddr); 00117 #endif 00118 00119 } 00120 00121 // ###################################################################### 00122 void AutomateXWin::setFocus() 00123 { 00124 XSetInputFocus(itsDisplay, itsWindow, RevertToNone, CurrentTime); 00125 } 00126 00127 // ###################################################################### 00128 Image<PixRGB<byte> > AutomateXWin::getImage() 00129 { 00130 00131 00132 DeleteImage(); 00133 #ifdef USE_SHM 00134 if(!itsImage) 00135 { 00136 itsImage = XShmCreateImage(itsDisplay, itsVInfo.visual, 00137 itsDepth, 00138 ZPixmap, 00139 NULL, 00140 &itsShminfo, 00141 itsWidth, 00142 itsHeight); 00143 if(!itsImage) 00144 { 00145 LERROR("XShmCreateImage"); 00146 return Image<PixRGB<byte> >(); 00147 } 00148 00149 itsShminfo.shmid = shmget(IPC_PRIVATE, 00150 itsImage->bytes_per_line * itsImage->height, 00151 IPC_CREAT | 0777); 00152 if(itsShminfo.shmid < 0) 00153 { 00154 LERROR("shmget"); 00155 XDestroyImage(itsImage); 00156 itsImage=NULL; 00157 return Image<PixRGB<byte> >(); 00158 } 00159 itsShminfo.shmaddr = (char *) shmat(itsShminfo.shmid, 0, 0); 00160 if(itsShminfo.shmaddr == (char *)-1) 00161 { 00162 LERROR("shmat"); 00163 XDestroyImage(itsImage); 00164 return Image<PixRGB<byte> >(); 00165 } 00166 shmctl(itsShminfo.shmid, IPC_RMID, 0), 00167 itsImage->data = itsShminfo.shmaddr; 00168 itsShminfo.readOnly = False; 00169 XShmAttach(itsDisplay, &itsShminfo); 00170 00171 XSync(itsDisplay, False); 00172 } 00173 #endif 00174 /* If SHM failed or was disabled, try non-SHM way */ 00175 if(!itsImage) 00176 { 00177 itsImage = XGetImage(itsDisplay, itsWindow, 00178 0, 0, 00179 itsWidth, 00180 itsHeight, 00181 AllPlanes, 00182 XYPixmap); 00183 if(!itsImage) 00184 LERROR("XGetImage\n"); 00185 } 00186 #ifdef USE_SHM 00187 if(!XShmGetImage(itsDisplay, itsWindow, itsImage, 00188 0, 0, 00189 AllPlanes)) 00190 LERROR("XSHMGetImage"); 00191 #endif 00192 00193 Image<PixRGB<byte> > img(itsWidth,itsHeight,NO_INIT); 00194 int rshift = 7 - getHighBitIndex (itsImage->red_mask); 00195 int gshift = 7 - getHighBitIndex (itsImage->green_mask); 00196 int bshift = 7 - getHighBitIndex (itsImage->blue_mask); 00197 00198 for (int y=0; y<itsImage->height; y++) { 00199 for (int x=0; x<itsImage->width; x++) { 00200 unsigned long pixel = XGetPixel (itsImage,x,y); 00201 PixRGB<byte> pixVal( 00202 SHIFTL(pixel & itsImage->red_mask,rshift), 00203 SHIFTL(pixel & itsImage->green_mask,gshift), 00204 SHIFTL(pixel & itsImage->blue_mask,bshift) 00205 ); 00206 img.setVal(x,y, pixVal); 00207 } 00208 } 00209 00210 return img; 00211 00212 } 00213 00214 void AutomateXWin::DeleteImage(void) 00215 { 00216 if(!itsImage) return; 00217 00218 #ifndef USE_SHM 00219 XDestroyImage(itsImage); 00220 itsImage = NULL; 00221 #endif 00222 } 00223 00224 // ###################################################################### 00225 void AutomateXWin::sendKey(const int key) 00226 { 00227 XTestFakeKeyEvent(itsDisplay, key, True, CurrentTime); //key down 00228 XTestFakeKeyEvent(itsDisplay, key, False, CurrentTime); //key up 00229 XSync(itsDisplay, True); 00230 } 00231 00232 00233 // ###################################################################### 00234 // return the index of the highest bit 00235 int AutomateXWin::getHighBitIndex (unsigned int x) 00236 { 00237 int i = 0; 00238 while (x) { 00239 i++; 00240 x >>= 1; 00241 } 00242 return i-1; 00243 } 00244 00245 // ###################################################################### 00246 void AutomateXWin::GetWindowGeometry() 00247 { 00248 unsigned border_width; 00249 int xpos, ypos; 00250 Window root; 00251 00252 if(!XGetGeometry( 00253 itsDisplay, itsWindow, &root, 00254 &xpos, &ypos, 00255 &itsWidth, &itsHeight, 00256 &border_width, 00257 &itsDepth)) 00258 { 00259 LERROR("XGetGeometry\n"); 00260 } 00261 LINFO("width=%u, height=%u, depth=%u\n", itsWidth, itsHeight, itsDepth); 00262 00263 } 00264 00265 // ###################################################################### 00266 Window AutomateXWin::XWindowByName(Display *display, const Window rootwin, const char *name) 00267 { 00268 unsigned int num_children; 00269 Window *children, child, window; 00270 XTextProperty windowname; 00271 00272 if(XGetWMName(display, rootwin, &windowname) != 0) 00273 { 00274 LINFO("Window='%s'\n", (const char *)windowname.value); 00275 if(!strcmp((const char *)windowname.value, name)) 00276 return rootwin; 00277 } 00278 00279 window = (Window) NULL; 00280 00281 if(XQueryTree(display, rootwin, &child, &child, &children, &num_children)) 00282 { 00283 unsigned i; 00284 for(i=0; i < num_children; ++i) 00285 { 00286 /* Search each child and their children. */ 00287 window = XWindowByName(display, children[i], name); 00288 if(window != (Window) NULL) 00289 break; 00290 } 00291 if (children != (Window *)NULL) 00292 XFree((void *)children); 00293 } 00294 return window; 00295 } 00296 00297 // ###################################################################### 00298 void AutomateXWin::XListWindows(Display *display, const Window rootwin) 00299 { 00300 unsigned int num_children; 00301 Window *children, child; 00302 XTextProperty windowname; 00303 00304 if(XGetWMName(display, rootwin, &windowname) != 0) 00305 LINFO(" '%s'\n", (const char *)windowname.value); 00306 00307 if(XQueryTree(display, rootwin, &child, &child, &children, &num_children)) 00308 { 00309 unsigned i; 00310 for(i=0; i < num_children; ++i) 00311 { 00312 /* Search each child and their children. */ 00313 XListWindows(display, children[i]); 00314 } 00315 if (children != (Window *)NULL) 00316 XFree((void *)children); 00317 } 00318 } 00319 00320 00321 00322 // ###################################################################### 00323 /* So things look consistent in everyone's emacs... */ 00324 /* Local Variables: */ 00325 /* indent-tabs-mode: nil */ 00326 /* End: */