monitor.cc

00001 /*******************************************************************************
00002 
00003            filename             : monitor.cpp
00004            description          : Class implementation
00005 
00006            copyright            : (C) 2004, 2006 by Jean-Christophe Baillie
00007            email                : jean-christophe.baillie@m4x.org
00008 
00009 ********************************************************************************/
00010 
00011 #include "libport/cstdio"
00012 #include <cstdlib>
00013 #include <pthread.h>
00014 #include "libport/windows.hh"
00015 
00016 #include "monitor.h"
00017 
00018 #ifdef WIN32
00019 # include "monitor-win.cpp"
00020 #else
00021 
00022 
00023 static char *AtomWMDeleteWindowName = (char *) "WM_DELETE_WINDOW";
00024 
00025 
00026 Display    *Monitor::display;
00027 std::list<Monitor*> Monitor::monitorList;
00028 pthread_mutex_t      Monitor::lock=PTHREAD_MUTEX_INITIALIZER;
00029 
00030 static void *
00031 wrapper(void *)
00032 {
00033   Monitor::processMessages();
00034   return 0;
00035 }
00036 
00037 void
00038 Monitor::addList(Monitor *mon)
00039 {
00040   if (monitorList.empty())
00041     {
00042       display = NULL;
00043       mon->gc = 0;
00044 
00045       // Open display
00046       if ((display = XOpenDisplay(NULL)) == NULL)
00047         {
00048           // NULL for DISPLAY
00049           printf("Error: XOpenDisplay() failed\n");
00050           exit(1);
00051         }
00052 
00053       mon->gc = DefaultGC(display, DefaultScreen(display));
00054       XSetForeground(display, mon->gc, 255 + 256 * 255 + 256 * 256 * 255);
00055       pthread_t *pt=new pthread_t;
00056       monitorList.push_back(mon);
00057 
00058       pthread_create(pt, 0, &wrapper, 0);
00059     }
00060   else
00061     monitorList.push_back(mon);
00062 }
00063 
00064 
00065 void
00066 Monitor::removeList(Monitor * mon)
00067 {
00068   monitorList.remove(mon);
00069   XFreeGC(display, mon->gc);
00070   if (monitorList.empty() && display != NULL)
00071     {
00072       XCloseDisplay(display);
00073       display = NULL;
00074     }
00075 }
00076 
00077 
00078 void
00079 Monitor::processMessages()
00080 {
00081   XEvent event;
00082   //plan b
00083   printf("Processmessages spawned\n");
00084   while (!monitorList.empty())
00085     {
00086       pthread_mutex_lock(&lock);
00087       while (XPending(display) > 0)
00088         XNextEvent(display, &event);
00089       for (std::list<Monitor *>::iterator it=monitorList.begin();
00090            it != monitorList.end(); ++it)
00091         (*it)->put();
00092       pthread_mutex_unlock(&lock);
00093       usleep(300000);
00094     }
00095   return;
00096 
00097   while (!monitorList.empty())
00098     {
00099       bool found = false;
00100       XNextEvent(display, &event);
00101       switch (event.type)
00102         {
00103         case Expose:
00104           if (event.xexpose.count == 0)
00105             {
00106               for (std::list<Monitor *>::iterator it=monitorList.begin();
00107                    it != monitorList.end(); ++it)
00108                 if ((*it)->window == event.xexpose.window)
00109                   {
00110                     (*it)->put();
00111                     // FIXME: What can be done here instead of these
00112                     // two casts?
00113                     printf("repainting %d\n",
00114                            static_cast<int>(event.xexpose.window));
00115                     found = true;
00116                     break;
00117                   }
00118               if (!found)
00119                 printf("error: expose event for unknown window %d\n",
00120                        static_cast<int>(event.xexpose.window));
00121             }
00122         }
00123     }
00124 }
00125 
00126 /*-----------------------------------------------------------------------------*/
00127 
00128 inline void
00129 setimageat(bits8 ** point, bits8 a, bits8 b, bits8 c)
00130 {
00131   (*point)[0] = a;
00132   (*point)[1] = b;
00133   (*point)[2] = c;
00134   (*point)[3] = c;
00135 
00136   *point = *point + 4;
00137 }
00138 
00139 Monitor::Monitor(int _w, int _h, const char * name, bool _fastMode)
00140   : sharedPixmap(None)
00141 {
00142   isShared = False;
00143   xImage = NULL;
00144 
00145   w = _w;
00146   h = _h;
00147   if (! _fastMode)
00148     {
00149       addList(this);
00150       localDisplay = display;
00151     }
00152   else
00153     {
00154       // Open display
00155 
00156       if ((localDisplay = XOpenDisplay(NULL)) == NULL)
00157         {
00158           // NULL for DISPLAY
00159           printf("Error: XOpenDisplay() failed\n");
00160           exit(1);
00161         }
00162       gc = DefaultGC(localDisplay, DefaultScreen(localDisplay));
00163       XSetForeground(localDisplay, gc, 255 + 256 * 255 + 256 * 256 * 255);
00164     }
00165 
00166   // Obtain WM protocols atom for ClientMessage exit event
00167   pthread_mutex_lock(&lock);
00168   atomWMDeleteWindow = XInternAtom(localDisplay, AtomWMDeleteWindowName, True);
00169   if (atomWMDeleteWindow == None)
00170     {
00171       printf("Error: %s atom does not exist\n", AtomWMDeleteWindowName);
00172       exit(1);
00173     }
00174 
00175   createWindow(name ? name : "XImage - XShm optimized");
00176   pthread_mutex_unlock(&lock);
00177   printf("Monitor created window %d\n", static_cast<int>(window));
00178 }
00179 
00180 Monitor::~Monitor()
00181 {
00182   removeList(this);
00183   XFreeGC(localDisplay, gc);
00184   if (display != localDisplay)
00185     XCloseDisplay(localDisplay);
00186 
00187   destroyImage();
00188 }
00189 
00190 int Monitor::createImage()
00191 {
00192   XGCValues gcValues;
00193   unsigned long gcValuesMask;
00194   XWindowAttributes windowAttributes;
00195 
00196 
00197   gcValues.function = GXcopy;
00198   gcValuesMask = GCFunction;
00199   gc = XCreateGC(localDisplay, window, gcValuesMask, &gcValues);
00200 
00201   XGetWindowAttributes(localDisplay, window, &windowAttributes);
00202 
00203   visual = windowAttributes.visual;
00204   depth = windowAttributes.depth;
00205   isShared = XShmQueryExtension(localDisplay);
00206   char * D = getenv("DISPLAY");
00207   if (D)
00208     {
00209       D=strdup(D);
00210       char * delim=strstr(D, ":");
00211       if (delim)
00212         *delim=0;
00213       if (D[0]!=0 && strcmp(D, "localhost") && strcmp(D, "127.0.0.1"))
00214         isShared = false;
00215       free(D);
00216     }
00217   if (getenv("DISABLE_SHM") != 0)
00218     isShared = false;
00219   try {
00220     errno = 0;
00221     xImage = NULL;
00222     sharedPixmap = None;
00223     if (isShared)
00224     {
00225       shmInfo.shmid = -1;
00226       shmInfo.shmaddr = NULL;
00227       if ((xImage = XShmCreateImage(localDisplay, visual, depth, ZPixmap,
00228                                     NULL, &shmInfo, w, h)) == NULL)
00229       {
00230         throw ("XShmCreateImage");
00231       }
00232       if ((shmInfo.shmid = shmget(IPC_PRIVATE, xImage->bytes_per_line *
00233                                   xImage->height, IPC_CREAT | 0777)) < 0)
00234       {
00235         // Create segment
00236         throw ("shmget");
00237       }
00238       if ((shmInfo.shmaddr = (char *) shmat(shmInfo.shmid, 0, 0)) < 0)
00239       {
00240         // We attach
00241         shmInfo.shmaddr = NULL;
00242         throw ("shmat");
00243       }
00244       xImage->data = shmInfo.shmaddr;
00245       shmInfo.readOnly = False;
00246       if (!XShmAttach(localDisplay, &shmInfo))
00247       {
00248         // X attaches
00249         throw ("XShmAttach");
00250       }
00251 
00252 
00253       XSync(localDisplay, False);
00254 
00255 
00256       if (XShmPixmapFormat(localDisplay) == ZPixmap)
00257       {
00258         if ((sharedPixmap = XShmCreatePixmap(localDisplay, window,
00259                                              shmInfo.shmaddr, &shmInfo, w, h,
00260                                              depth)) == None)
00261         {
00262           ;     // HasSharedPixmap() will return false.
00263         }
00264       }
00265     }
00266     else
00267     {
00268       if ((xImage = XCreateImage(localDisplay, visual, depth, ZPixmap, 0,
00269                                  NULL, w, h, 16, 0)) == NULL)
00270       {
00271         throw ("XCreateImage");
00272       }
00273       if ((xImage->data = static_cast<char *> (malloc (xImage->bytes_per_line
00274                                                        * xImage->height)))
00275            == NULL)
00276       {
00277         throw ("malloc");
00278       }
00279     }
00280     return 0;
00281   }
00282   catch(char *function)
00283   {
00284     printf("%s%s:%s\n", "Error: Image::Create failed in ",
00285            function, ((errno == 0) ? "No further info" : strerror(errno)));
00286 
00287     destroyImage();
00288     return -1;
00289   }
00290 
00291 }
00292 
00293 /*------------------------------------------------------------------------*/
00294 
00295 int Monitor::destroyImage()
00296 {
00297   if (xImage == NULL)
00298     return 0;   // Nothing to do
00299 
00300   if (isShared)
00301     {
00302       if (shmInfo.shmid >= 0)
00303         {
00304           XShmDetach(localDisplay, &shmInfo);   // X detaches
00305           shmdt(shmInfo.shmaddr);       // We detach
00306           shmInfo.shmaddr = NULL;
00307           shmctl(shmInfo.shmid, IPC_RMID, 0);   // Destroy segment
00308           shmInfo.shmid = -1;
00309         }
00310     }
00311   else if (xImage->data != NULL)
00312     free(xImage->data);
00313 
00314   xImage->data = NULL;
00315 
00316   XDestroyImage(xImage);
00317 
00318   xImage = NULL;
00319 
00320   if (sharedPixmap != None)
00321     {
00322       XFreePixmap(localDisplay, sharedPixmap);
00323       sharedPixmap = None;
00324     }
00325 
00326   return 0;
00327 }
00328 
00329 
00330 void
00331 Monitor::clear()
00332 {
00333   if (xImage == NULL)
00334     return;
00335 
00336   memset(xImage->data, 0, xImage->height * xImage->bytes_per_line);
00337 }
00338 
00339 
00340 int
00341 Monitor::put()
00342 {
00343   if (xImage == NULL)
00344     return -1;
00345 
00346   int width = Width();
00347   int height = Height();
00348 
00349   if (isShared)
00350     XShmPutImage(localDisplay, window, gc, xImage,
00351                  0, 0, 0, 0, width, height, False);
00352   else
00353     XPutImage(localDisplay, window, gc, xImage,
00354               0, 0, 0, 0, width, height);
00355 
00356   return 0;
00357 }
00358 
00359 int
00360 Monitor::setImage(bits8* buffer, int bufferlen)
00361 {
00362   if (xImage == NULL)
00363     return -1;
00364   //XImage *xImage;
00365   bits8* imageLine;
00366   int i = 0;
00367 
00368   if (localDisplay != display)
00369   {
00370     if (XPending(localDisplay) > 0)
00371     {
00372       XNextEvent(localDisplay, &event);
00373       switch (event.type)
00374       {
00375         case ClientMessage:
00376           if ((int) event.xclient.data.l[0] == (int) atomWMDeleteWindow)
00377             return -1;
00378           break;
00379 
00380         case Expose:
00381           if (event.xexpose.count == 0)
00382             put();
00383 
00384           break;
00385       }
00386     }
00387     else
00388     {
00389       //xImage = X();
00390       imageLine = (bits8 *) xImage->data;
00391       for (i = 0; i < bufferlen / 3; ++i)
00392         setimageat(&imageLine,
00393                    *(buffer + i * 3 + 2),
00394                    *(buffer + i * 3 + 1),
00395                    *(buffer + i * 3 + 0));
00396       put();
00397     }
00398   }
00399   else
00400   {
00401     imageLine = (bits8 *) xImage->data;
00402     for (i = 0; i < bufferlen / 3; ++i)
00403       setimageat(&imageLine,
00404                  *(buffer + i * 3 + 2),
00405                  *(buffer + i * 3 + 1),
00406                  *(buffer + i * 3 + 0));
00407   }
00408   return 1; // ?
00409 }
00410 
00411 /**************************************************************************/
00412 
00413 void
00414 Monitor::createWindow(const char *name)
00415 {
00416   screenNumber = DefaultScreen(localDisplay);
00417   screen = XScreenOfDisplay(localDisplay, screenNumber);
00418   windowsHeight = h;
00419   windowsWidth = w;
00420 
00421   window = XCreateSimpleWindow(localDisplay, RootWindowOfScreen(screen),
00422                                100, 100, w, h, 0,
00423                                BlackPixelOfScreen(screen),
00424                                BlackPixelOfScreen(screen));
00425 
00426   XStoreName(localDisplay, window, name);
00427   XGetWindowAttributes(localDisplay, window, &windowAttributes);
00428 
00429   if (((windowAttributes.depth == 8)
00430        && (windowAttributes.visual->c_class != PseudoColor))
00431       || ((windowAttributes.depth > 8)
00432           && (windowAttributes.visual->c_class != TrueColor)))
00433     {
00434       printf("Error: Visual not supported\n");
00435       exit(1);
00436     }
00437 
00438   // Create PseudoColor HI240 colormap, if needed
00439 
00440   if (windowAttributes.depth == 8)
00441     {
00442       printf("Error : display must be 32bits depth");
00443       exit(1);
00444     }
00445 
00446 
00447   // Create image
00448 
00449   if (createImage() < 0)
00450     {
00451       printf("Error: image.Create() failed\n");
00452       exit(1);
00453     }
00454 
00455   clear();
00456 
00457   // Ready to start: Display window, select events, and initiate
00458   // capture sequence
00459   XMapRaised(localDisplay, window);
00460   XSetWMProtocols(localDisplay, window, &atomWMDeleteWindow, 1);
00461   XSelectInput(localDisplay, window, StructureNotifyMask | ExposureMask);
00462 }
00463 
00464 #endif // !WIN32

Generated on Tue Apr 10 17:45:44 2007 for URBISDK by  doxygen 1.5.1