00001
00002
00003
00004
00005
00006
00007
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
00046 if ((display = XOpenDisplay(NULL)) == NULL)
00047 {
00048
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
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
00112
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
00155
00156 if ((localDisplay = XOpenDisplay(NULL)) == NULL)
00157 {
00158
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
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
00236 throw ("shmget");
00237 }
00238 if ((shmInfo.shmaddr = (char *) shmat(shmInfo.shmid, 0, 0)) < 0)
00239 {
00240
00241 shmInfo.shmaddr = NULL;
00242 throw ("shmat");
00243 }
00244 xImage->data = shmInfo.shmaddr;
00245 shmInfo.readOnly = False;
00246 if (!XShmAttach(localDisplay, &shmInfo))
00247 {
00248
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 ;
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;
00299
00300 if (isShared)
00301 {
00302 if (shmInfo.shmid >= 0)
00303 {
00304 XShmDetach(localDisplay, &shmInfo);
00305 shmdt(shmInfo.shmaddr);
00306 shmInfo.shmaddr = NULL;
00307 shmctl(shmInfo.shmid, IPC_RMID, 0);
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
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
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
00439
00440 if (windowAttributes.depth == 8)
00441 {
00442 printf("Error : display must be 32bits depth");
00443 exit(1);
00444 }
00445
00446
00447
00448
00449 if (createImage() < 0)
00450 {
00451 printf("Error: image.Create() failed\n");
00452 exit(1);
00453 }
00454
00455 clear();
00456
00457
00458
00459 XMapRaised(localDisplay, window);
00460 XSetWMProtocols(localDisplay, window, &atomWMDeleteWindow, 1);
00461 XSelectInput(localDisplay, window, StructureNotifyMask | ExposureMask);
00462 }
00463
00464 #endif // !WIN32