00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "GUI/XWindow.H"
00039
00040 #include "Image/Image.H"
00041 #include "Image/Layout.H"
00042 #include "Image/MathOps.H"
00043 #include "Image/Pixels.H"
00044 #include "Util/Assert.H"
00045 #include "Util/StringConversions.H"
00046 #include "Util/log.H"
00047 #include "Util/sformat.H"
00048 #include "rutz/atomic.h"
00049 #include "rutz/mutex.h"
00050 #include "rutz/pipe.h"
00051
00052 #include <X11/Xutil.h>
00053 #include <cerrno>
00054 #include <iostream>
00055 #include <fstream>
00056 #include <stdlib.h>
00057 #include <sys/shm.h>
00058 #include <sys/stat.h>
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 namespace
00086 {
00087 int fourByteAlign(int v)
00088 {
00089 const int remainder = v % 4;
00090 return (remainder == 0) ? v : v + (4-remainder);
00091 }
00092
00093 int getByteOrder()
00094 {
00095 union
00096 {
00097 int i;
00098 byte b[sizeof(int)];
00099 } u;
00100 memset(&u, 0, sizeof(u));
00101 u.b[0] = 1;
00102 if (u.i == 1)
00103 return LSBFirst;
00104
00105
00106 return MSBFirst;
00107 }
00108
00109 Display* g_display = 0;
00110
00111 #ifdef XWINDOW_PTHREADS_LOCKING
00112 pthread_mutex_t g_display_mutex = PTHREAD_MUTEX_INITIALIZER;
00113 #endif
00114
00115 pthread_once_t display_init_once = PTHREAD_ONCE_INIT;
00116
00117 void display_init()
00118 {
00119 XInitThreads();
00120 #ifdef XWINDOW_PTHREADS_LOCKING
00121 pthread_mutex_init(&g_display_mutex, 0);
00122 #endif
00123 const char* displayname = getenv("DISPLAY");
00124 if (displayname == 0 || displayname[0] == '\0')
00125 {
00126 LINFO("the DISPLAY environment variable is not set; "
00127 "assuming DISPLAY=\":0.0\"");
00128 displayname = ":0.0";
00129 }
00130 g_display = XOpenDisplay(displayname);
00131 }
00132
00133 #ifdef XWINDOW_PTHREADS_LOCKING
00134 # define LOCK_DISPLAY GVX_MUTEX_LOCK(&g_display_mutex)
00135 #else
00136
00137 struct DisplayLock
00138 {
00139 DisplayLock(Display* d) : dd(d) { XLockDisplay(d); }
00140
00141 ~DisplayLock() { XUnlockDisplay(dd); }
00142
00143 private:
00144 DisplayLock(const DisplayLock&);
00145 DisplayLock& operator=(const DisplayLock&);
00146
00147 Display* const dd;
00148 };
00149
00150 # define LOCK_DISPLAY DisplayLock tmplock(g_display)
00151
00152 #endif // !defined(XWINDOW_PTHREADS_LOCKING)
00153 }
00154
00155
00156 struct XWindow::XWinImage
00157 {
00158 XWinImage(Display* dpy, bool attemptShm, const Dims& windims,
00159 const int depth);
00160
00161 ~XWinImage();
00162
00163 void destroy(Display* dpy);
00164
00165 void destroyImage();
00166
00167 void createImage(Display* dpy, Visual* vis, const Dims& dims);
00168
00169 Dims getDims() const { return itsImgDims; }
00170
00171 byte* getBuf() const { return reinterpret_cast<byte*>(itsBuf); }
00172
00173 void copyPixelsFrom(const Image<byte>& img, const Point2D<int>& winpos);
00174
00175 void copyPixelsFrom(const Image<PixRGB<byte> >& img, const Point2D<int>& winpos);
00176
00177 void redraw(Display* dpy, Window win, GC gc, const Point2D<int>& pos);
00178
00179 private:
00180 const int itsBytesPerPixel;
00181
00182 XImage* itsImage;
00183
00184 XShmSegmentInfo itsShmInfo;
00185 char* itsBuf;
00186 bool itsUsingShm;
00187 Dims itsImgDims;
00188 bool itsDestroyed;
00189 };
00190
00191 static size_t get_shmmax()
00192 {
00193 {
00194 std::ifstream f("/proc/sys/kernel/shmmax");
00195 if (f.is_open())
00196 {
00197 size_t shmmax = 0;
00198 f >> shmmax;
00199 return shmmax;
00200 }
00201 }
00202
00203 const char* progs[] = { "/usr/sbin/sysctl", "/sbin/sysctl" };
00204
00205 const char* args[] = { "kern.sysv.shmmax", "kernel.shmmax" };
00206
00207 for (size_t i = 0; i < sizeof(progs) / sizeof(progs[0]); ++i)
00208 {
00209 try
00210 {
00211 rutz::exec_pipe p("r", progs[i], args[i], (const char*) 0);
00212 std::string w;
00213 while (p.stream() >> w)
00214 {
00215 if (w.size() > 0 && isdigit(w[0]))
00216 return fromStr<size_t>(w);
00217 }
00218 }
00219 catch (...) { continue; }
00220 }
00221
00222 return 0;
00223 }
00224
00225
00226 XWindow::XWinImage::XWinImage(Display* dpy, bool attemptShm,
00227 const Dims& windims,
00228 const int depth)
00229 :
00230 itsBytesPerPixel(depth == 16 ? 2 : 4),
00231 itsImage(0),
00232 itsShmInfo(),
00233 itsBuf(0),
00234 itsUsingShm(false),
00235 itsImgDims(),
00236 itsDestroyed(false)
00237 {
00238
00239 const int padded_width = fourByteAlign(windims.w());
00240
00241
00242 const size_t bufsize = padded_width*windims.h()*itsBytesPerPixel;
00243 LDEBUG("bufsize=%"ZU, bufsize);
00244
00245 if (attemptShm)
00246 {
00247 itsShmInfo.shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
00248 LDEBUG("shmid=%d", itsShmInfo.shmid);
00249 if (itsShmInfo.shmid == -1)
00250 {
00251 const int errno_save = errno;
00252
00253 const size_t shmmax = get_shmmax();
00254 const std::string shmmax_info =
00255 shmmax > 0
00256 ? sformat("%"ZU, shmmax)
00257 : "unknown";
00258
00259 errno = errno_save;
00260
00261 const std::string extra_help =
00262 (errno == ENOMEM
00263 || (shmmax != 0 && bufsize > shmmax))
00264 ? ("; try increasing the shmmax value in "
00265 "/proc/sys/kernel/shmmax, or with "
00266 "sysctl kern.sysv.shmmax (BSD) "
00267 "or with sysctl kernel.shmmax (Linux)")
00268 : "";
00269
00270 PLERROR("shmget() failed (requested size=%"ZU", shmmax=%s)%s",
00271 bufsize, shmmax_info.c_str(), extra_help.c_str());
00272
00273 LINFO("switching to slower non-shared memory approach");
00274 }
00275 else
00276 {
00277 itsBuf = (char*)shmat(itsShmInfo.shmid, NULL, 0);
00278 if (itsBuf == 0) LFATAL("Cannot get shared memory");
00279 itsShmInfo.shmaddr = itsBuf;
00280 itsShmInfo.readOnly = False;
00281 XShmAttach(dpy, &itsShmInfo);
00282 itsUsingShm = true;
00283 }
00284 }
00285
00286 if (!itsUsingShm)
00287 {
00288 itsBuf = (char*)malloc(bufsize);
00289 LDEBUG("buffer: %p", itsBuf);
00290 if (itsBuf == NULL) LFATAL("Cannot allocate image buffer");
00291 }
00292 }
00293
00294
00295 XWindow::XWinImage::~XWinImage()
00296 {
00297
00298
00299
00300
00301
00302
00303
00304
00305 ASSERT(itsDestroyed == true);
00306 }
00307
00308
00309 void XWindow::XWinImage::destroy(Display* dpy)
00310 {
00311 if (itsUsingShm)
00312 {
00313 XShmDetach(dpy, &itsShmInfo);
00314 this->destroyImage();
00315 shmdt(itsShmInfo.shmaddr);
00316 shmctl(itsShmInfo.shmid, IPC_RMID, NULL);
00317 }
00318 else
00319 {
00320 this->destroyImage();
00321 free(itsBuf);
00322 }
00323
00324 itsDestroyed = true;
00325 }
00326
00327
00328 void XWindow::XWinImage::destroyImage()
00329 {
00330 if (itsImage)
00331 {
00332
00333
00334
00335
00336
00337 itsImage->data = 0;
00338 XDestroyImage(itsImage);
00339 itsImage = 0;
00340 }
00341 }
00342
00343
00344 void XWindow::XWinImage::createImage(Display* dpy, Visual* vis,
00345 const Dims& dims)
00346 {
00347 this->destroyImage();
00348
00349 uint depth = 0;
00350 int pad = 0;
00351
00352
00353 if (itsBytesPerPixel == 2)
00354 { depth = 16; pad = 16;}
00355 else if (itsBytesPerPixel == 4)
00356 { depth = 24; pad = 32;}
00357 else
00358 LFATAL("bogus bytes-per-pixel value '%d'", itsBytesPerPixel);
00359
00360 if (itsUsingShm)
00361
00362 itsImage = XShmCreateImage(g_display, vis, depth, ZPixmap,
00363 itsBuf, &itsShmInfo, dims.w(), dims.h());
00364 else
00365
00366 itsImage = XCreateImage(g_display, vis, depth, ZPixmap, 0,
00367 itsBuf, dims.w(), dims.h(), pad,
00368 fourByteAlign(itsBytesPerPixel * dims.w()));
00369
00370
00371
00372
00373
00374
00375 LDEBUG("X server byte order is %s (%d)",
00376 itsImage->byte_order == LSBFirst ? "LSBFirst" :
00377 itsImage->byte_order == MSBFirst ? "MSBFirst" : "unknown",
00378 itsImage->byte_order);
00379
00380 itsImage->byte_order = getByteOrder();
00381
00382 LDEBUG("using image byte order %s (%d)",
00383 itsImage->byte_order == LSBFirst ? "LSBFirst" :
00384 itsImage->byte_order == MSBFirst ? "MSBFirst" : "unknown",
00385 itsImage->byte_order);
00386
00387 itsImgDims = dims;
00388 }
00389
00390
00391 void XWindow::XWinImage::copyPixelsFrom(const Image<byte>& img,
00392 const Point2D<int>& winpos)
00393 {
00394 ASSERT(winpos.i >= 0);
00395 ASSERT(winpos.i + img.getWidth() <= itsImgDims.w());
00396 ASSERT(winpos.j >= 0);
00397 ASSERT(winpos.j + img.getHeight() <= itsImgDims.h());
00398
00399 const int w = img.getWidth();
00400 const int h = img.getHeight();
00401
00402 const byte* im = img.getArrayPtr();
00403 byte* bu = reinterpret_cast<byte*>(itsBuf)
00404 + itsBytesPerPixel * (winpos.i + winpos.j * itsImgDims.w());
00405
00406 if (itsBytesPerPixel == 2)
00407 {
00408 const int bytes_per_row = fourByteAlign(itsBytesPerPixel * itsImgDims.w());
00409
00410
00411 for (int j = 0; j < h; ++j)
00412 {
00413 byte* bu_row = bu + j*bytes_per_row;
00414 for (int i = 0; i < w; ++i)
00415 {
00416 *bu_row++ = ((*im & 0x1C)<<3) | ((*im & 0xF8)>>3);
00417 *bu_row++ = ((*im & 0xE0)>>5) | (*im & 0xF8);
00418 im++;
00419 }
00420 }
00421 }
00422 else if (itsBytesPerPixel == 4)
00423 {
00424 const int wskip = itsBytesPerPixel * (itsImgDims.w() - img.getWidth());
00425
00426
00427 switch (getByteOrder())
00428 {
00429 case LSBFirst:
00430 for (int j = 0; j < h; ++j)
00431 {
00432 for (int i = 0; i < w; ++i)
00433 { *bu++ = *im; *bu++ = *im; *bu++ = *im++; *bu++ = 255; }
00434 bu += wskip;
00435 }
00436 break;
00437
00438 case MSBFirst:
00439 for (int j = 0; j < h; ++j)
00440 {
00441 for (int i = 0; i < w; ++i)
00442 { *bu++ = 255; *bu++ = *im; *bu++ = *im; *bu++ = *im++; }
00443 bu += wskip;
00444 }
00445 break;
00446
00447 default:
00448 LFATAL("invalid byte order %d", getByteOrder());
00449 }
00450 }
00451 else
00452 LFATAL("bogus bytes-per-pixel value '%d'", itsBytesPerPixel);
00453 }
00454
00455
00456 void XWindow::XWinImage::copyPixelsFrom(const Image<PixRGB<byte> >& img,
00457 const Point2D<int>& winpos)
00458 {
00459 ASSERT(winpos.i >= 0);
00460 ASSERT(winpos.i + img.getWidth() <= itsImgDims.w());
00461 ASSERT(winpos.j >= 0);
00462 ASSERT(winpos.j + img.getHeight() <= itsImgDims.h());
00463
00464 const int w = img.getWidth();
00465 const int h = img.getHeight();
00466
00467 const byte* im = reinterpret_cast<const byte*>(img.getArrayPtr());
00468 byte* bu = reinterpret_cast<byte*>(itsBuf)
00469 + itsBytesPerPixel * (winpos.i + winpos.j * itsImgDims.w());
00470
00471 if (itsBytesPerPixel == 2)
00472 {
00473 const int bytes_per_row = fourByteAlign(itsBytesPerPixel * itsImgDims.w());
00474
00475
00476 for (int j = 0; j < h; ++j)
00477 {
00478 byte* bu_row = bu + j*bytes_per_row;
00479 for (int i = 0; i < w; ++i)
00480 {
00481 *bu_row++ = ((im[1] & 0x1C)<<3) | ((im[2] & 0xF8)>>3);
00482 *bu_row++ = ((im[1] & 0xE0)>>5) | (im[0] & 0xF8);
00483 im += 3;
00484 }
00485 }
00486 }
00487 else if (itsBytesPerPixel == 4)
00488 {
00489 const int wskip = itsBytesPerPixel * (itsImgDims.w() - img.getWidth());
00490
00491
00492 switch (getByteOrder())
00493 {
00494 case LSBFirst:
00495 for (int j = 0; j < h; ++j)
00496 {
00497 for (int i = 0; i < w; ++i)
00498 { *bu++ = im[2]; *bu++ = im[1]; *bu++ = *im; *bu++ = 255; im += 3; }
00499 bu += wskip;
00500 }
00501 break;
00502
00503 case MSBFirst:
00504 for (int j = 0; j < h; ++j)
00505 {
00506 for (int i = 0; i < w; ++i)
00507 { *bu++ = 255; *bu++ = *im; *bu++ = im[1]; *bu++ = im[2]; im += 3; }
00508 bu += wskip;
00509 }
00510 break;
00511
00512 default:
00513 LFATAL("invalid byte order %d", getByteOrder());
00514 }
00515 }
00516 else
00517 LFATAL("bogus bytes-per-pixel value '%d'", itsBytesPerPixel);
00518 }
00519
00520
00521 void XWindow::XWinImage::redraw(Display* dpy, Window win, GC gc,
00522 const Point2D<int>& pos)
00523 {
00524 if (itsImage)
00525 {
00526 if (itsUsingShm)
00527 XShmPutImage(dpy, win, gc, itsImage, 0, 0,
00528 pos.i, pos.j,
00529 itsImgDims.w(), itsImgDims.h(), 0);
00530 else
00531 XPutImage(dpy, win, gc, itsImage, 0, 0,
00532 pos.i, pos.j,
00533 itsImgDims.w(), itsImgDims.h());
00534 }
00535 else
00536 {
00537 XClearWindow(dpy,win);
00538 }
00539 }
00540
00541
00542 XWindow::XWindow(const Dims& dims, const int x, const int y,
00543 const char* title)
00544 :
00545 itsMapped(false)
00546 {
00547 if (dims.isEmpty())
00548 LFATAL("window dimensions must be non-empty");
00549
00550 itsWinDims = dims;
00551
00552
00553 pthread_once(&display_init_once, &display_init);
00554 if (g_display == 0)
00555 LFATAL("Cannot connect to X server");
00556
00557 LOCK_DISPLAY;
00558
00559
00560 const int screen = DefaultScreen(g_display);
00561 itsVisual = DefaultVisual(g_display, screen);
00562 itsDepth = DefaultDepth(g_display, screen);
00563 LDEBUG("Your screen depth is %d bpp", itsDepth);
00564
00565
00566 int x0 = x;
00567 int y0 = y;
00568 if (x0 == -1 && y0 == -1)
00569 {
00570 x0 = 0;
00571 y0 = 0;
00572 }
00573
00574
00575 itsWindow = XCreateSimpleWindow(g_display,
00576 DefaultRootWindow(g_display),
00577 x0, y0, itsWinDims.w(), itsWinDims.h(), 2,
00578 BlackPixel(g_display, screen),
00579 WhitePixel(g_display, screen));
00580 if (itsWindow <= 0) LFATAL("Cannot open window");
00581
00582
00583 XStoreName(g_display, itsWindow, (char*)title);
00584 itsTitle = title;
00585
00586
00587 XMapRaised(g_display, itsWindow);
00588 itsMapped = true;
00589
00590
00591 if (x != -1 || y != -1)
00592 {
00593 XMoveWindow(g_display, itsWindow, x, y);
00594 }
00595
00596
00597 XSelectInput(g_display, itsWindow, NoEventMask);
00598
00599
00600 XFlush(g_display);
00601
00602
00603 itsGc = XCreateGC(g_display, itsWindow, 0, NULL);
00604
00605 XSetWindowBackground(g_display, itsWindow,
00606 WhitePixel(g_display, DefaultScreen(g_display)));
00607
00608
00609 itsAttemptShm = XShmQueryExtension(g_display);
00610
00611
00612 char* disp = getenv("DISPLAY");
00613 if (disp != NULL && disp[0] != ':')
00614 { itsAttemptShm = 0; LDEBUG("Not using shared memory for remote display"); }
00615
00616 this->setDimsImpl(dims);
00617 }
00618
00619
00620 void XWindow::setVisible(const bool v)
00621 {
00622 if (itsMapped != v)
00623 {
00624 Point2D<int> p1 = this->getPosition();
00625 LDEBUG("old position %d,%d", p1.i, p1.j);
00626
00627 {
00628 LOCK_DISPLAY;
00629
00630 if (v)
00631 {
00632 LDEBUG("mapping window %s", itsTitle.c_str());
00633 XMapWindow(g_display, itsWindow);
00634 }
00635 else
00636 {
00637 LDEBUG("unmapping window %s", itsTitle.c_str());
00638 XUnmapWindow(g_display, itsWindow);
00639 }
00640
00641 itsMapped = v;
00642 }
00643
00644 Point2D<int> p2 = this->getPosition();
00645 LDEBUG("new position %d,%d", p2.i, p2.j);
00646 }
00647 }
00648
00649
00650 const char* XWindow::getTitle() const
00651 {
00652 return itsTitle.c_str();
00653 }
00654
00655
00656 void XWindow::setTitle(const char* title)
00657 {
00658 LOCK_DISPLAY;
00659
00660 XStoreName(g_display, itsWindow, (char*)title);
00661 itsTitle = title;
00662 }
00663
00664
00665 void XWindow::setPosition(const int x, const int y)
00666 {
00667 LOCK_DISPLAY;
00668
00669 XMoveWindow(g_display, itsWindow, x, y);
00670 }
00671
00672
00673 Point2D<int> XWindow::getPosition()
00674 {
00675 LOCK_DISPLAY;
00676
00677 XWindowAttributes xwa;
00678 XGetWindowAttributes(g_display, itsWindow, &xwa);
00679 return Point2D<int>(xwa.x, xwa.y);
00680 }
00681
00682
00683 void XWindow::drawImage(const Image< PixRGB<byte> >& img,
00684 const int x, const int y, const bool resizeWindow)
00685 {
00686 if (resizeWindow)
00687 this->setDims(img.getDims());
00688
00689 ASSERT(x >= 0 && y >= 0 && x < itsWinDims.w() && y < itsWinDims.h());
00690 const int w = img.getWidth();
00691 const int h = img.getHeight();
00692 const Dims d = img.getDims();
00693 ASSERT(x + w <= itsWinDims.w() && y + h <= itsWinDims.h());
00694 if (d != itsXimage->getDims())
00695 {
00696 LOCK_DISPLAY;
00697 itsXimage->createImage(g_display, itsVisual, d);
00698 }
00699
00700 itsXimage->copyPixelsFrom(img, Point2D<int>(0,0));
00701
00702 itsImgPos = Point2D<int>(x, y);
00703
00704 this->redrawImage();
00705 }
00706
00707
00708 void XWindow::drawImage(const Image<byte>& img, const int x, const int y,
00709 const bool resizeWindow)
00710 {
00711 if (resizeWindow)
00712 this->setDims(img.getDims());
00713
00714 ASSERT(x >= 0 && y >= 0 && x < itsWinDims.w() && y < itsWinDims.h());
00715 const int w = img.getWidth();
00716 const int h = img.getHeight();
00717 const Dims d = img.getDims();
00718 ASSERT(x + w <= itsWinDims.w() && y + h <= itsWinDims.h());
00719 if (d != itsXimage->getDims())
00720 {
00721 LOCK_DISPLAY;
00722 itsXimage->createImage(g_display, itsVisual, d);
00723 }
00724
00725 itsXimage->copyPixelsFrom(img, Point2D<int>(0,0));
00726
00727 itsImgPos = Point2D<int>(x, y);
00728
00729 this->redrawImage();
00730 }
00731
00732
00733 void XWindow::drawImage(const Image<float>& img,
00734 const int x, const int y,
00735 bool normalize, const bool resizeWindow)
00736 {
00737 if (resizeWindow)
00738 this->setDims(img.getDims());
00739
00740 Image<float> image(img);
00741
00742 if (normalize)
00743 inplaceNormalize(image, 0.0f, 255.0f);
00744 else
00745 inplaceClamp(image, 0.0f, 255.0f);
00746
00747 this->drawImage(Image<byte>(image), x, y);
00748 }
00749
00750
00751 void XWindow::drawRgbLayout(const Layout<PixRGB<byte> >& layout,
00752 const int x, const int y,
00753 const bool resizeWindow)
00754 {
00755 this->drawLayout<PixRGB<byte> >(layout, x, y, resizeWindow);
00756 }
00757
00758
00759 void XWindow::drawGrayLayout(const Layout<byte>& layout,
00760 const int x, const int y,
00761 const bool resizeWindow)
00762 {
00763 this->drawLayout<byte>(layout, x, y, resizeWindow);
00764 }
00765
00766
00767 XWindow::~XWindow()
00768 {
00769 LOCK_DISPLAY;
00770
00771 LDEBUG("Closing down...");
00772 itsXimage->destroy(g_display);
00773 itsXimage.reset(0);
00774
00775 if (itsGc) XFreeGC(g_display, itsGc);
00776 if (g_display && itsWindow)
00777 {
00778 LDEBUG("XDestroyWindow...");
00779 XDestroyWindow(g_display, itsWindow);
00780 XFlush(g_display);
00781 }
00782
00783
00784
00785
00786
00787 }
00788
00789
00790 void XWindow::redrawImage()
00791 {
00792 LOCK_DISPLAY;
00793
00794 itsXimage->redraw(g_display, itsWindow, itsGc, itsImgPos);
00795 XFlush(g_display);
00796 }
00797
00798
00799 Dims XWindow::getDims() const
00800 {
00801 return itsWinDims;
00802 }
00803
00804
00805 void XWindow::setDims(const Dims& dims)
00806 {
00807 if (dims == itsWinDims)
00808 return;
00809
00810 LOCK_DISPLAY;
00811
00812 this->setDimsImpl(dims);
00813 }
00814
00815
00816 void XWindow::selectInput(long event_mask) const
00817 {
00818 LOCK_DISPLAY;
00819
00820 XSelectInput(g_display, itsWindow, event_mask);
00821 }
00822
00823
00824 Atom XWindow::setWMProtocol(const char* atomname) const
00825 {
00826 LOCK_DISPLAY;
00827
00828 Atom a = XInternAtom(g_display, atomname, false);
00829 if (0 == XSetWMProtocols(g_display, itsWindow, &a, 1))
00830 LFATAL("Error setting the WM protocol");
00831
00832 return a;
00833 }
00834
00835
00836 Bool XWindow::checkMaskEvent(long event_mask, XEvent* event) const
00837 {
00838 LOCK_DISPLAY;
00839 return XCheckWindowEvent(g_display, itsWindow, event_mask, event);
00840 }
00841
00842
00843 Bool XWindow::checkTypedEvent(int event_type, XEvent* event) const
00844 {
00845 LOCK_DISPLAY;
00846 return XCheckTypedWindowEvent(g_display, itsWindow, event_type, event);
00847 }
00848
00849
00850 void XWindow::setDimsImpl(const Dims& dims)
00851 {
00852
00853
00854
00855
00856 XSizeHints hints;
00857 hints.flags = PMinSize | PMaxSize;
00858 hints.min_width = 0; hints.max_width = 60000;
00859 hints.min_height = 0; hints.max_height = 60000;
00860 XSetWMNormalHints(g_display, itsWindow, &hints);
00861
00862 XResizeWindow(g_display, itsWindow, dims.w(), dims.h());
00863 itsWinDims = dims;
00864
00865 if (itsXimage.is_valid())
00866 itsXimage->destroy(g_display);
00867
00868 itsXimage.reset(new XWinImage(g_display, itsAttemptShm, itsWinDims,
00869 itsDepth));
00870
00871
00872
00873 hints.flags = PMinSize | PMaxSize | PBaseSize;
00874 hints.min_width = hints.max_width = hints.base_width = itsWinDims.w();
00875 hints.min_height = hints.max_height = hints.base_height = itsWinDims.h();
00876 XSetWMNormalHints(g_display, itsWindow, &hints);
00877 }
00878
00879
00880 template <class T>
00881 void XWindow::drawLayout(const Layout<T>& layout,
00882 const int x, const int y,
00883 const bool resizeWindow)
00884 {
00885 if (resizeWindow)
00886 this->setDims(layout.getDims());
00887
00888 ASSERT(x >= 0 && y >= 0 && x < itsWinDims.w() && y < itsWinDims.h());
00889 const int w = layout.getDims().w();
00890 const int h = layout.getDims().h();
00891 const Dims d = layout.getDims();
00892 ASSERT(x + w <= itsWinDims.w() && y + h <= itsWinDims.h());
00893 if (d != itsXimage->getDims())
00894 {
00895 LOCK_DISPLAY;
00896 itsXimage->createImage(g_display, itsVisual, d);
00897 }
00898
00899 typedef std::pair<const Layout<T>*, Point2D<int> > tile;
00900
00901 std::vector<tile> q;
00902
00903 q.push_back(std::make_pair(&layout, Point2D<int>(0,0)));
00904
00905 while (!q.empty())
00906 {
00907 tile t = q.back();
00908 q.pop_back();
00909
00910 const Layout<T>* const cur = t.first;
00911 const Point2D<int> p = t.second;
00912
00913 const size_t np = cur->numParts();
00914
00915 if (np == 0)
00916 {
00917 if (cur->leafImage().initialized())
00918 itsXimage->copyPixelsFrom(cur->leafImage(), p);
00919 }
00920 else if (cur->getDir() == Layout<T>::H)
00921 {
00922 Point2D<int> pp = p;
00923 for (size_t i = 0; i < np; ++i)
00924 {
00925 q.push_back(std::make_pair(&cur->part(i), pp));
00926 pp.i += cur->part(i).getDims().w();
00927 }
00928 }
00929 else
00930 {
00931 Point2D<int> pp = p;
00932 for (size_t i = 0; i < np; ++i)
00933 {
00934 q.push_back(std::make_pair(&cur->part(i), pp));
00935 pp.j += cur->part(i).getDims().h();
00936 }
00937 }
00938 }
00939
00940 itsImgPos = Point2D<int>(x, y);
00941
00942 this->redrawImage();
00943 }
00944
00945
00946
00947
00948
00949