00001 /* --------------------------------------------------------------------------- 00002 Phission : 00003 Realtime Vision Processing System 00004 00005 Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu) 00006 University of Massachusetts at Lowell, 00007 Laboratory for Artificial Intelligence and Robotics 00008 00009 This file is part of Phission. 00010 00011 Phission is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU Lesser General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 Phission is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU Lesser General Public License for more details. 00020 00021 You should have received a copy of the GNU Lesser General Public License 00022 along with Phission; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 ---------------------------------------------------------------------------*/ 00026 #ifdef HAVE_CONFIG_H 00027 #include <phissionconfig.h> 00028 #endif 00029 00030 #include <phStandard.h> 00031 00032 #include <phX11ImageWindow.h> 00033 00034 /* ------------------------------------------------------------------------- */ 00035 /* .) GUI TK header files */ 00036 /* ------------------------------------------------------------------------- */ 00037 #include <X11/Xlib.h> 00038 #include <X11/Xutil.h> 00039 #include <X11/keysym.h> 00040 00041 #include <phError.h> 00042 #include <phMemory.h> 00043 #include <phPrint.h> 00044 00045 /* ---------------------------------------------------------------------- */ 00046 phX11ImageWindow::phX11ImageWindow( int32_t x, int32_t y, 00047 uint32_t w, uint32_t h, 00048 char *title, 00049 uint32_t flags ) : 00050 phImageWindow(x,y,w,h,title,flags) 00051 { 00052 phFUNCTION("phX11ImageWindow::phX11ImageWindow") 00053 int locked = 0; 00054 int i = 0; 00055 00056 phTHIS_LOOSE_LOCK(locked); 00057 00058 this->m_border = 1; 00059 this->m_x11window = NULL; 00060 00061 this->setName("phX11ImageWindow"); 00062 00063 if (this->m_title == NULL) 00064 { 00065 this->setTitle("Phission: phX11ImageWindow"); 00066 } 00067 00068 this->m_formats = phX11UtilValidFormats; 00069 00070 for (i = 0; i < phX11Window_USEREVENT_COUNT; i++) 00071 { 00072 this->m_atoms[i] = NULL; 00073 this->m_wait[i] = 0; 00074 } 00075 00076 /* initialize the display */ 00077 /* all size settings (x,y,w,h) will be configured in 00078 * the parent constructor */ 00079 rc = this->initWindow(); 00080 phPRINT_RC(rc,NULL, "initWindow() failed"); 00081 00082 /*error:*/ 00083 phTHIS_LOOSE_UNLOCK(locked); 00084 00085 return; 00086 } 00087 00088 /* ---------------------------------------------------------------------- */ 00089 phX11ImageWindow::~phX11ImageWindow() 00090 { 00091 phFUNCTION("phX11ImageWindow::~phX11ImageWindow") 00092 int i = 0; 00093 int locked = 0; 00094 00095 phTHIS_LOOSE_LOCK(locked); 00096 00097 for (i = 0; i < phX11Window_USEREVENT_COUNT; i++) 00098 { 00099 this->m_atoms[i] = NULL; 00100 this->m_wait[i] = 0; 00101 } 00102 00103 00104 /* Delete the window */ 00105 rc = phX11Image_Delete(this->m_x11window,&this->m_imageBuffer); 00106 rc = phX11Window_Delete(&this->m_x11window); 00107 00108 phTHIS_LOOSE_UNLOCK(locked); 00109 } 00110 00111 /* ---------------------------------------------------------------------- */ 00112 int phX11ImageWindow::initWindow() 00113 { 00114 phFUNCTION("phX11ImageWindow::initWindow") 00115 int locked = 0; 00116 int i = 0; 00117 00118 phX11SizeInfo windowSize = {this->m_w,this->m_h}; 00119 phX11LocationInfo windowLocation = {this->m_x,this->m_y}; 00120 00121 const char *names[phX11Window_USEREVENT_COUNT] = { 00122 phWAKEUP_NAME, 00123 phREDRAW_NAME, 00124 phUPDATE_NAME, 00125 phMOVE_NAME, 00126 phRESIZE_NAME, 00127 phMINSIZE_NAME, 00128 phVISIBLE_NAME 00129 }; 00130 int n_names = sizeof(names) / sizeof(const char *); 00131 00132 phTHIS_LOOSE_LOCK(locked); 00133 00134 DEBUG_PRINT("%u/%u %d/%d\n", 00135 windowSize.w,windowSize.h, 00136 windowLocation.x,windowLocation.y); 00137 00138 /* Create an image window */ 00139 rc = phX11Window_Create(windowSize, 00140 windowLocation, 00141 this->m_border, 00142 this->m_title, 00143 &this->m_x11window); 00144 phCHECK_RC(rc,NULL,"phX11Window_Create"); 00145 00146 rc = phX11Image_Create( this->m_x11window, 00147 &this->m_imageBuffer ); 00148 phCHECK_RC(rc,NULL,"phX11Image_Create"); 00149 00150 for (i = 0; i < phX11Window_USEREVENT_COUNT; i++) 00151 { 00152 if (i < n_names) 00153 { 00154 this->m_atoms[i] = 00155 phX11Window_GetEventAtom(this->m_x11window,names[i]); 00156 } 00157 00158 this->m_wait[i] = 0; 00159 } 00160 00161 /* Set the minimum width that the window can be. Since shrinking the 00162 * window smaller than the input size is inefficient, don't allow 00163 * shrinking smaller than it. */ 00164 /* TODO retreive this from the window */ 00165 this->m_min_width = this->m_w; 00166 this->m_min_height = this->m_h; 00167 00168 phTHIS_LOOSE_UNLOCK(locked); 00169 00170 return phSUCCESS; 00171 error: 00172 phTHIS_ERROR_UNLOCK(locked); 00173 00174 return phFAIL; 00175 } 00176 00177 /* ---------------------------------------------------------------------- */ 00178 int phX11ImageWindow::isOpen() 00179 { 00180 if (this == NULL) 00181 { 00182 return 0; 00183 } 00184 00185 return this->isRunning(); 00186 /* return phX11Window_IsOpen(this->m_x11window); */ 00187 } 00188 00189 /* ---------------------------------------------------------------------- */ 00190 int phX11ImageWindow::setTitle(const char *title) 00191 { 00192 phFUNCTION("phX11ImageWindow::setTitle") 00193 int locked = 0; 00194 00195 phTHIS_LOOSE_LOCK(locked); 00196 00197 rc = this->phImageWindow::setTitle(title); 00198 phPRINT_RC(rc,NULL,"this->phImageWindow::setTitle(title)"); 00199 00200 if (this->m_x11window != NULL) 00201 { 00202 rc = phX11Window_SetTitle(this->m_x11window,this->m_title); 00203 phPRINT_RC(rc,NULL,"phX11Window_SetTitle"); 00204 } 00205 00206 phTHIS_LOOSE_UNLOCK(locked); 00207 00208 return phSUCCESS; 00209 } 00210 00211 /* ---------------------------------------------------------------------- */ 00212 /* We're locked when we enter. */ 00213 int phX11ImageWindow::phX11CheckWaitDone(int index) 00214 { 00215 phFUNCTION("phX11ImageWindow::phX11CheckWaitDone") 00216 int donelocked = 0; 00217 int locked = 1; 00218 00219 if ((this->m_wait[index] == 1) && (this->isRunning())) 00220 { 00221 phMUTEX_LOOSE_LOCK(this->m_done_lock[index],donelocked); 00222 phTHIS_LOOSE_UNLOCK(locked); 00223 00224 /* This is available to the X11Display class to allow the 00225 * thread to be woken up to prevent deadlock while waiting for it 00226 * to close down */ 00227 rc = this->m_done_sems[index].take(); 00228 phPRINT_RC(rc,NULL,"this->m_done_sems[%d].take() failed.",index); 00229 00230 this->m_wait[index] = 0; 00231 00232 phMUTEX_LOOSE_UNLOCK(this->m_done_lock[index],donelocked); 00233 phTHIS_LOOSE_LOCK(locked); 00234 } 00235 00236 return phSUCCESS; 00237 } 00238 00239 /* ---------------------------------------------------------------------- */ 00240 /* we're locked when we enter */ 00241 int phX11ImageWindow::phX11WaitRecv(int index, int recv_wait ) 00242 { 00243 phFUNCTION("phX11ImageWindow::phX11WaitRecv") 00244 int do_recv_take= 0; 00245 int locked = 1; 00246 int recv_locked = 0; 00247 00248 /* signal the gui_* function to post a semaphore when it's done */ 00249 if ((rc == phSUCCESS) && (this->isRunning())) 00250 { 00251 this->m_wait[index] = 1; 00252 do_recv_take = 1; 00253 } 00254 00255 /* Wait for the event loop in phX11ImageWindow::run to recv the event */ 00256 if (( do_recv_take ) && (recv_wait)) 00257 { 00258 phMUTEX_LOOSE_LOCK(this->m_recv_lock[index],recv_locked); 00259 phTHIS_LOOSE_UNLOCK(locked); 00260 00261 rc = this->m_recv_sems[index].take(); 00262 phPRINT_RC(rc,NULL,"this->m_recv_sems[%d].take() failed.",index); 00263 00264 phMUTEX_LOOSE_UNLOCK(this->m_recv_lock[index],recv_locked); 00265 phTHIS_LOOSE_LOCK(locked); 00266 } 00267 00268 return phSUCCESS; 00269 } 00270 00271 /* ---------------------------------------------------------------------- */ 00272 int phX11ImageWindow::private_show() 00273 { 00274 phFUNCTION("phX11ImageWindow::private_show") 00275 /* 00276 * We are locked when we get into a "private" method; Locking is done 00277 * as a policy in any public interface method that calls a private 00278 * (implementation specific) method 00279 */ 00280 int locked = 1; 00281 00282 phX11CheckWaitDone(phVISIBLE_INDEX); 00283 /* If the thread is running, then we don't want to collide with it 00284 * so we'll post an event that it can handle */ 00285 if (this->isRunning()) 00286 { 00287 rc = phX11Window_SendVisible(this->m_x11window,phX11Window_SHOW); 00288 phCHECK_RC(rc,NULL,"phX11Window_SendVisible"); 00289 } 00290 else 00291 { 00292 rc = this->gui_show(); 00293 phCHECK_RC(rc,NULL,"this->gui_show()"); 00294 } 00295 00296 #if 0 00297 phX11WaitRecv(phVISIBLE_INDEX); 00298 #endif 00299 00300 return phSUCCESS; 00301 error: 00302 phTHIS_ERROR_UNLOCK(locked); 00303 00304 return phFAIL; 00305 } 00306 00307 /* ---------------------------------------------------------------------- */ 00308 int phX11ImageWindow::private_hide() 00309 { 00310 phFUNCTION("phX11ImageWindow::private_hide") 00311 /* 00312 * We are locked when we get into a "private" method; Locking is done 00313 * as a policy in any public interface method that calls a private 00314 * (implementation specific) method 00315 */ 00316 int locked = 1; 00317 00318 #if 1 00319 phX11CheckWaitDone(phVISIBLE_INDEX); 00320 #endif 00321 00322 /* If the thread is running, then we don't want to collide with it 00323 * so we'll post an event that it can handle */ 00324 if (this->isRunning()) 00325 { 00326 rc = phX11Window_SendVisible(this->m_x11window,phX11Window_HIDE); 00327 phCHECK_RC(rc,NULL,"phX11Window_SendVisible"); 00328 } 00329 else 00330 { 00331 rc = this->gui_hide(); 00332 phCHECK_RC(rc,NULL,"this->gui_hide()"); 00333 } 00334 00335 #if 0 00336 phX11WaitRecv(phVISIBLE_INDEX); 00337 #endif 00338 00339 return phSUCCESS; 00340 error: 00341 phTHIS_ERROR_UNLOCK(locked); 00342 00343 return phFAIL; 00344 } 00345 00346 /* ---------------------------------------------------------------------- */ 00347 int phX11ImageWindow::private_redraw() 00348 { 00349 phFUNCTION("phX11ImageWindow::private_redraw") 00350 /* 00351 * We are locked when we get into a "private" method; Locking is done 00352 * as a policy in any public interface method that calls a private 00353 * (implementation specific) method 00354 */ 00355 int locked = 1; 00356 00357 #if 0 00358 phX11CheckWaitDone(phREDRAW_INDEX); 00359 #endif 00360 00361 /* If the thread is running, then we don't want to collide with it 00362 * so we'll post an event that it can handle */ 00363 if (this->isRunning()) 00364 { 00365 rc = phX11Window_SendRedraw(this->m_x11window); 00366 phCHECK_RC(rc,NULL,"phX11Window_SendRedraw"); 00367 } 00368 else 00369 { 00370 rc = this->gui_redraw(); 00371 phCHECK_RC(rc,NULL,"this->gui_redraw()"); 00372 } 00373 00374 #if 0 00375 phX11WaitRecv(phREDRAW_INDEX); 00376 #endif 00377 00378 return phSUCCESS; 00379 error: 00380 phTHIS_ERROR_UNLOCK(locked); 00381 00382 return phFAIL; 00383 } 00384 00385 /* ---------------------------------------------------------------------- */ 00386 int phX11ImageWindow::private_update() 00387 { 00388 phFUNCTION("phX11ImageWindow::private_update") 00389 /* 00390 * We are locked when we get into a "private" method; Locking is done 00391 * as a policy in any public interface method that calls a private 00392 * (implementation specific) method 00393 */ 00394 int locked = 1; 00395 00396 phX11CheckWaitDone(phUPDATE_INDEX); 00397 00398 /* If the thread is running, then we don't want to collide with it 00399 * so we'll post an event that it can handle */ 00400 if (this->isRunning()) 00401 { 00402 rc = phX11Window_SendUpdate(this->m_x11window); 00403 phCHECK_RC(rc,NULL,"phX11Window_SendUpdate"); 00404 } 00405 else 00406 { 00407 rc = this->gui_update(); 00408 phCHECK_RC(rc,NULL,"this->gui_update()"); 00409 } 00410 00411 phX11WaitRecv(phUPDATE_INDEX); 00412 00413 return phSUCCESS; 00414 error: 00415 phTHIS_ERROR_UNLOCK(locked); 00416 00417 return phFAIL; 00418 } 00419 00420 /* ---------------------------------------------------------------------- */ 00421 int phX11ImageWindow::private_resize(uint32_t width, uint32_t height) 00422 { 00423 phFUNCTION("phX11ImageWindow::private_resize") 00424 /* 00425 * We are locked when we get into a "private" method; Locking is done 00426 * as a policy in any public interface method that calls a private 00427 * (implementation specific) method 00428 */ 00429 int locked = 1; 00430 00431 #if 1 00432 phX11CheckWaitDone(phRESIZE_INDEX); 00433 #endif 00434 00435 /* If the thread is running, then we don't want to collide with it 00436 * so we'll post an event that it can handle */ 00437 if (this->isRunning()) 00438 { 00439 rc = phX11Window_SendResize(this->m_x11window, width,height); 00440 phCHECK_RC(rc,NULL,"phX11Window_SendResize"); 00441 } 00442 else 00443 { 00444 rc = this->gui_resize(width,height); 00445 phCHECK_RC(rc,NULL,"this->gui_resize(%u,%u)",width,height); 00446 } 00447 00448 #if 0 00449 phX11WaitRecv(phRESIZE_INDEX,0); 00450 #endif 00451 00452 return phSUCCESS; 00453 error: 00454 phTHIS_ERROR_UNLOCK(locked); 00455 00456 return phFAIL; 00457 } 00458 00459 /* ---------------------------------------------------------------------- */ 00460 int phX11ImageWindow::private_move(int32_t x, int32_t y) 00461 { 00462 phFUNCTION("phX11ImageWindow::private_move") 00463 /* 00464 * We are locked when we get into a "private" method; Locking is done 00465 * as a policy in any public interface method that calls a private 00466 * (implementation specific) method 00467 */ 00468 int locked = 1; 00469 00470 #if 1 00471 phX11CheckWaitDone(phMOVE_INDEX); 00472 #endif 00473 00474 /* If the thread is running, then we don't want to collide with it 00475 * so we'll post an event that it can handle */ 00476 if (this->isRunning()) 00477 { 00478 rc = phX11Window_SendMove(this->m_x11window, x,y); 00479 phCHECK_RC(rc,NULL,"phX11Window_SendMove"); 00480 } 00481 else 00482 { 00483 rc = this->gui_move(x,y); 00484 phCHECK_RC(rc,NULL,"this->gui_move(%d,%d)",x,y); 00485 } 00486 00487 #if 0 00488 phX11WaitRecv(phMOVE_INDEX); 00489 #endif 00490 00491 return phSUCCESS; 00492 error: 00493 phTHIS_ERROR_UNLOCK(locked); 00494 00495 return phFAIL; 00496 } 00497 00498 /* ---------------------------------------------------------------------- */ 00499 int phX11ImageWindow::private_minsize(uint32_t min_w, uint32_t min_h) 00500 { 00501 phFUNCTION("phX11ImageWindow::private_minsize") 00502 /* 00503 * We are locked when we get into a "private" method; Locking is done 00504 * as a policy in any public interface method that calls a private 00505 * (implementation specific) method 00506 */ 00507 int locked = 1; 00508 00509 phX11CheckWaitDone(phMINSIZE_INDEX); 00510 00511 /* If the thread is running, then we don't want to collide with it 00512 * so we'll post an event that it can handle */ 00513 if (this->isRunning()) 00514 { 00515 rc = phX11Window_SendMinSize(this->m_x11window, min_w,min_h); 00516 phCHECK_RC(rc,NULL,"phX11Window_SendMinSize"); 00517 } 00518 else 00519 { 00520 rc = this->gui_minsize(min_w,min_h); 00521 phCHECK_RC(rc,NULL,"this->gui_minsize(%u,%u)",min_w,min_h); 00522 } 00523 00524 #if 0 00525 phX11WaitRecv(phMINSIZE_INDEX,0); 00526 #endif 00527 00528 return phSUCCESS; 00529 error: 00530 phTHIS_ERROR_UNLOCK(locked); 00531 00532 return phFAIL; 00533 } 00534 00535 /* ---------------------------------------------------------------------- */ 00536 int phX11ImageWindow::gui_show() 00537 { 00538 phFUNCTION("phX11ImageWindow::gui_show") 00539 int locked = 0; 00540 00541 phTHIS_LOOSE_LOCK(locked); 00542 00543 rc = phX11Window_Show(this->m_x11window); 00544 phPRINT_RC(rc,NULL,"phX11Window_Show"); 00545 00546 if (this->m_wait[phVISIBLE_INDEX]) 00547 { 00548 rc = this->m_done_sems[phVISIBLE_INDEX].post(); 00549 phPRINT_RC(rc,NULL, 00550 "this->m_done_sems[phVISIBLE_INDEX].post() failed"); 00551 } 00552 00553 phTHIS_LOOSE_UNLOCK(locked); 00554 00555 return phSUCCESS; 00556 00557 /* 00558 error: 00559 rc = this->unlock(); 00560 phPRINT_RC(rc,NULL,"this->unlock()"); 00561 00562 return phFAIL; 00563 */ 00564 } 00565 00566 /* ---------------------------------------------------------------------- */ 00567 int phX11ImageWindow::gui_hide() 00568 { 00569 phFUNCTION("phX11ImageWindow::gui_hide") 00570 int locked = 0; 00571 00572 phTHIS_LOOSE_LOCK(locked); 00573 00574 rc = phX11Window_Hide(this->m_x11window); 00575 phPRINT_RC(rc,NULL,"phX11Window_Hide"); 00576 00577 if (this->m_wait[phVISIBLE_INDEX]) 00578 { 00579 rc = this->m_done_sems[phVISIBLE_INDEX].post(); 00580 phPRINT_RC(rc,NULL, 00581 "this->m_done_sems[phVISIBLE_INDEX].post() failed"); 00582 } 00583 00584 phTHIS_LOOSE_UNLOCK(locked); 00585 00586 return phSUCCESS; 00587 /* 00588 error: 00589 rc = this->unlock(); 00590 phPRINT_RC(rc,NULL,"this->unlock()"); 00591 00592 return phFAIL; 00593 */ 00594 } 00595 00596 /* ---------------------------------------------------------------------- */ 00597 int phX11ImageWindow::gui_redraw() 00598 { 00599 phFUNCTION("phX11ImageWindow::gui_redraw") 00600 int img_locked = 0; 00601 int locked = 0; 00602 uint32_t w = 0; 00603 uint32_t h = 0; 00604 00605 DEBUG_PRINT("(thread:%p) Enter\n", (void *)phGetCurrentThreadId()() ); 00606 00607 phTHIS_LOCK(locked); 00608 00609 rc = this->m_image.writeLock(); 00610 phCHECK_RC(rc,NULL,"this->m_image.writeLock()"); 00611 img_locked = 1; 00612 00613 if (!this->m_image.isNull()) 00614 { 00615 rc = phX11Window_GetMinSize(this->m_x11window, &w,&h ); 00616 phCHECK_RC(rc,NULL,"phX11Window_GetMinSize"); 00617 00618 if ((this->m_min_width != w) || (this->m_min_height != h)) 00619 { 00620 rc = phX11Window_SetMinSize(this->m_x11window, w,h); 00621 phCHECK_RC(rc,NULL,"phX11Window_SetMinSize"); 00622 } 00623 00624 /* This resizes the image so it must be after we check 00625 * the incoming image data for it's size */ 00626 /* The image may come out altered */ 00627 phX11Image_Put(this->m_x11window, 00628 this->m_imageBuffer, 00629 &this->m_image ); 00630 00631 /* maintain frames-per-second */ 00632 this->tickFrame(); 00633 } 00634 00635 if (this->m_wait[phREDRAW_INDEX]) 00636 { 00637 rc = this->m_done_sems[phREDRAW_INDEX].post(); 00638 phPRINT_RC(rc,NULL, 00639 "this->m_done_sems[phREDRAW_INDEX].post() failed"); 00640 } 00641 00642 rc = this->m_image.rwUnlock(); 00643 img_locked = 0; 00644 phCHECK_RC(rc,NULL,"this->m_image.rwUnlock()"); 00645 00646 phTHIS_UNLOCK(locked); 00647 00648 DEBUG_PRINT("(thread:%p) Exit\n", (void *)phGetCurrentThreadId()()); 00649 00650 return phSUCCESS; 00651 error: 00652 if (img_locked) 00653 { 00654 rc = this->m_image.rwUnlock(); 00655 phPRINT_RC(rc,NULL,"this->m_image.rwUnlock()"); 00656 img_locked = 1; 00657 } 00658 00659 phTHIS_ERROR_UNLOCK(locked); 00660 00661 DEBUG_PRINT("(thread:%p) Exit\n", (void *)phGetCurrentThreadId()()); 00662 00663 return phFAIL; 00664 } 00665 00666 00667 /* ---------------------------------------------------------------------- */ 00668 int phX11ImageWindow::gui_update() 00669 { 00670 phFUNCTION("phX11ImageWindow::gui_update") 00671 int img_locked = 0; 00672 int locked = 0; 00673 00674 DEBUG_PRINT("(thread:%p) Enter\n", (void *)phGetCurrentThreadId()()); 00675 00676 phTHIS_LOCK(locked); 00677 00678 rc = this->m_image.writeLock(); 00679 phCHECK_RC(rc,NULL,"this->m_image.writeLock()"); 00680 img_locked = 1; 00681 00682 if (!this->m_image.isNull()) 00683 { 00684 rc = this->gui_redraw(); 00685 phPRINT_RC(rc,NULL,"this->gui_redraw() failed."); 00686 } 00687 00688 if (this->m_wait[phUPDATE_INDEX]) 00689 { 00690 rc = this->m_done_sems[phUPDATE_INDEX].post(); 00691 phPRINT_RC(rc,NULL, 00692 "this->m_done_sems[phUPDATE_INDEX].post() failed"); 00693 } 00694 00695 rc = this->m_image.rwUnlock(); 00696 img_locked = 0; 00697 phCHECK_RC(rc,NULL,"this->m_image.rwUnlock()"); 00698 00699 phTHIS_UNLOCK(locked); 00700 00701 DEBUG_PRINT("(thread:%p) Exit\n", (void *)phGetCurrentThreadId()()); 00702 00703 return phSUCCESS; 00704 error: 00705 if (img_locked) 00706 { 00707 rc = this->m_image.rwUnlock(); 00708 phPRINT_RC(rc,NULL,"this->m_image.rwUnlock()"); 00709 img_locked = 0; 00710 } 00711 00712 phTHIS_ERROR_UNLOCK(locked); 00713 00714 return phFAIL; 00715 } 00716 00717 /* ---------------------------------------------------------------------- */ 00718 int phX11ImageWindow::gui_resize(uint32_t width, uint32_t height) 00719 { 00720 phFUNCTION("phX11ImageWindow::gui_resize") 00721 int locked = 0; 00722 int writeLocked = 0; 00723 int retrc = phSUCCESS; 00724 00725 DEBUG_PRINT("(thread:%p) Enter\n", (void *)phGetCurrentThreadId()()); 00726 00727 phTHIS_LOCK(locked); 00728 00729 rc = this->m_image.writeLock(); 00730 phCHECK_RC(rc,NULL,"this->m_image.writeLock()"); 00731 writeLocked = 1; 00732 00733 if (!(this->m_image.isNull())) 00734 { 00735 if (height <= 0) height = this->m_h; 00736 if (width <= 0) width = this->m_w; 00737 00738 rc = phX11Window_Resize(this->m_x11window, 00739 width, height); 00740 phPRINT_RC(rc,NULL,"phX11Window_Resize"); 00741 00742 /* we want to propagate back the return value of 1 which denotes 00743 * that no resize took place. This is needed to identify whether 00744 * a ConfigureNotify is a resize event or a move event */ 00745 if (rc == phX11Window_NORESIZE) 00746 { 00747 retrc = rc; 00748 } 00749 /* Only resize if we have to */ 00750 else 00751 { 00752 rc = phX11Window_GetSize(this->m_x11window, 00753 &(this->m_w), &(this->m_h)); 00754 phPRINT_RC(rc,NULL,"phX11Window_GetSize"); 00755 00756 /* Try resizing the image, it won't resize if it doesn't need to */ 00757 rc = phX11Image_Resize( this->m_imageBuffer, 00758 this->m_w, this->m_h); 00759 rc = this->gui_redraw(); 00760 phCHECK_RC(rc,NULL,"this->gui_redraw() failed."); 00761 } 00762 } 00763 00764 if (this->m_wait[phRESIZE_INDEX]) 00765 { 00766 rc = this->m_done_sems[phRESIZE_INDEX].post(); 00767 phPRINT_RC(rc,NULL, 00768 "this->m_done_sems[phRESIZE_INDEX].post() failed"); 00769 } 00770 00771 rc = this->m_image.rwUnlock(); 00772 writeLocked = 0; 00773 phCHECK_RC(rc,NULL,"this->m_image.rwUnlock()"); 00774 00775 phTHIS_UNLOCK(locked); 00776 00777 DEBUG_PRINT("(thread:%p) Exit\n", (void *)phGetCurrentThreadId()()); 00778 00779 return retrc; 00780 00781 error: 00782 if (writeLocked) 00783 { 00784 rc = this->m_image.rwUnlock(); 00785 phPRINT_RC(rc,NULL,"this->m_image.rwUnlock()"); 00786 writeLocked = 0; 00787 } 00788 phTHIS_ERROR_UNLOCK(locked); 00789 00790 return phFAIL; 00791 } 00792 00793 /* ---------------------------------------------------------------------- */ 00794 int phX11ImageWindow::gui_move(int32_t x, int32_t y) 00795 { 00796 phFUNCTION("phX11ImageWindow::gui_move") 00797 int locked = 0; 00798 00799 phTHIS_LOCK(locked); 00800 00801 rc = phX11Window_Move(this->m_x11window,x,y); 00802 phPRINT_RC(rc,NULL,"phX11Window_Move"); 00803 00804 rc = phX11Window_GetLocation(this->m_x11window,&this->m_x,&this->m_y); 00805 phPRINT_RC(rc,NULL,"phX11Window_GetLocation"); 00806 00807 if (this->m_wait[phMOVE_INDEX]) 00808 { 00809 rc = this->m_done_sems[phMOVE_INDEX].post(); 00810 phPRINT_RC(rc,NULL, 00811 "this->m_done_sems[phMOVE_INDEX].post() failed"); 00812 } 00813 00814 phTHIS_UNLOCK(locked); 00815 00816 return phSUCCESS; 00817 00818 error: 00819 phTHIS_ERROR_UNLOCK(locked); 00820 00821 return phFAIL; 00822 } 00823 00824 /* ---------------------------------------------------------------------- */ 00825 int phX11ImageWindow::gui_minsize(uint32_t min_w, uint32_t min_h ) 00826 { 00827 phFUNCTION("phX11ImageWindow::gui_minsize") 00828 int locked = 0; 00829 uint32_t w = 0; 00830 uint32_t h = 0; 00831 00832 phTHIS_LOCK(locked); 00833 00834 rc = phX11Window_GetMinSize(this->m_x11window, &w,&h ); 00835 phCHECK_RC(rc,NULL,"phX11Window_GetMinSize"); 00836 00837 if ((min_w != w) || (min_h != h)) 00838 { 00839 rc = phX11Window_SetMinSize(this->m_x11window, min_w,min_h); 00840 phCHECK_RC(rc,NULL,"phX11Window_SetMinSize"); 00841 00842 if (this->m_image.isNull() == 0) 00843 { 00844 rc = this->gui_redraw(); 00845 phCHECK_RC(rc,NULL,"this->gui_redraw() failed."); 00846 } 00847 } 00848 00849 if (this->m_wait[phMINSIZE_INDEX]) 00850 { 00851 rc = this->m_done_sems[phMINSIZE_INDEX].post(); 00852 phPRINT_RC(rc,NULL, 00853 "this->m_done_sems[phMINSIZE_INDEX].post() failed"); 00854 } 00855 00856 phTHIS_UNLOCK(locked); 00857 00858 return phSUCCESS; 00859 error: 00860 phTHIS_ERROR_UNLOCK(locked); 00861 00862 return phFAIL; 00863 } 00864 00865 00866 /* ---------------------------------------------------------------------- */ 00867 int phX11ImageWindow::sendWakeup() 00868 { 00869 phFUNCTION("phX11ImageWindow::sendWakeup") 00870 int locked = 0; 00871 00872 phTHIS_LOCK(locked); 00873 00874 rc = phX11Window_SendWakeup( this->m_x11window ); 00875 00876 phTHIS_UNLOCK(locked); 00877 00878 return phSUCCESS; 00879 error: 00880 phTHIS_ERROR_UNLOCK(locked); 00881 00882 return phFAIL; 00883 } 00884 00885 /* ---------------------------------------------------------------------- */ 00886 int phX11ImageWindow::wakeup() 00887 { 00888 phFUNCTION("phX11ImageWindow::wakeup()") 00889 00890 rc = this->m_done_sems[phUPDATE_INDEX].post(2); 00891 phPRINT_RC(rc,NULL, 00892 "this->m_done_sems[phUPDATE_INDEX].post() failed"); 00893 00894 rc = this->m_recv_sems[phUPDATE_INDEX].post(2); 00895 phPRINT_RC(rc,NULL, 00896 "this->m_recv_sems[phUPDATE_INDEX].post() failed."); 00897 00898 rc = this->sendWakeup(); 00899 phPRINT_RC(rc,NULL,"this->sendWakeup()"); 00900 /* 00901 rc = this->phImageWindow::wakeup(); 00902 phPRINT_RC(rc,NULL,"this->phImageWindow::wakeup()"); 00903 */ 00904 return phSUCCESS; 00905 } 00906 00907 /* ---------------------------------------------------------------------- */ 00908 int phX11ImageWindow::cleanup() 00909 { 00910 /*phFUNCTION("phX11ImageWindow::cleanup()")*/ 00911 int i = 0; 00912 phX11EventInfo event = phX11EventInfo_Create(); 00913 00914 for (i = 0; i < phX11Window_USEREVENT_COUNT; i++) 00915 { 00916 this->m_wait[i] = 0; 00917 while (this->m_recv_sems[i].tryTake() == phSUCCESS); 00918 while (this->m_done_sems[i].tryTake() == phSUCCESS); 00919 } 00920 00921 phX11Flush(this->m_x11window); 00922 while (phX11Pending(this->m_x11window)) 00923 { 00924 phX11NextEvent(this->m_x11window,event); 00925 } 00926 00927 phX11EventInfo_Destroy( event ); 00928 00929 return phSUCCESS; 00930 } 00931 00932 /* ---------------------------------------------------------------------- */ 00933 #define X11_THROTTLE() 1 00934 int phX11ImageWindow::run() 00935 { 00936 phFUNCTION("phX11ImageWindow::run") 00937 int i = 0; 00938 int locked = 0; 00939 int xWM_DELETE_WINDOW = phX11Window_GetDeleteCmdID(this->m_x11window); 00940 00941 phX11EventInfo event = phX11EventInfo_Create(); 00942 #if X11_THROTTLE() 00943 uint32_t do_sleep = 1; 00944 uint32_t need_stamp = 1; 00945 /*float wait_time_lapse = 0.0;*/ 00946 const float max_timelapse = 10.0; /* us */ 00947 00948 phTimeInterval wait_time; 00949 phTimeStamp starting_time; 00950 phTimeStamp current_time; 00951 phTimeStamp time_lapse; 00952 #endif 00953 00954 /* .) Set the variables for remote viewing */ 00955 rc = this->gui_show(); 00956 phCHECK_RC(rc,NULL,"this->gui_show()"); 00957 00958 rc = phX11Window_Move(this->m_x11window,this->m_x,this->m_y); 00959 phPRINT_RC(rc,NULL,"phX11Window_Move"); 00960 00961 phX11Flush(this->m_x11window); 00962 00963 rc = this->signal_running(); 00964 phCHECK_RC(rc,NULL,"this->signal_running()"); 00965 00966 /* 00967 i = XEventsQueued(display,QueuedAlready); 00968 phPROGRESS("\nQueuedAlready:%d\n",i); 00969 i = XEventsQueued(display,QueuedAfterFlush); 00970 phPROGRESS("\nQueuedAfterFlush:%d\n",i); 00971 i = XEventsQueued(display,QueuedAfterReading); 00972 phPROGRESS("\nQueuedAfterReading:%d\n",i); 00973 */ 00974 while (this->isRunning()) 00975 { 00976 #if X11_THROTTLE() 00977 wait_time.start(); 00978 #endif 00979 /* Get the next event */ 00980 phX11NextEvent(this->m_x11window,event); 00981 00982 #if X11_THROTTLE() 00983 wait_time.stop(); 00984 #endif 00985 00986 #if X11_THROTTLE() 00987 /* If the wait period went over the time interval, 00988 * * then reset the start time */ 00989 if (wait_time.elapsed().getMicroseconds() > max_timelapse) 00990 { 00991 need_stamp = 1; 00992 } 00993 /* Otherwise, adjust the start time */ 00994 else 00995 { 00996 starting_time += wait_time.elapsed(); 00997 } 00998 00999 /* Get the start time */ 01000 if (need_stamp) 01001 { 01002 starting_time.stamp(); 01003 need_stamp = 0; 01004 } 01005 01006 /* Get the current time */ 01007 current_time.stamp(); 01008 01009 /* Calculate the time lapse between the start stamp and 01010 * the current stamp */ 01011 time_lapse = current_time - starting_time; 01012 /* Need to wait */ 01013 if (do_sleep && (time_lapse.getMicroseconds() > max_timelapse)) 01014 { 01015 /* phUSleep((uint32_t)max_timelapse * 5); */ 01016 phYield(); 01017 need_stamp = 1; 01018 } 01019 #endif 01020 /* phPROGRESS("event.type:%d\n",event.type); */ 01021 switch (phX11Event_GetType(event)) 01022 { 01023 case KeyPress: 01024 { 01025 KeySym val = (KeySym)phX11KeycodeToKeysym(this->m_x11window, 01026 event); 01027 val &= 0xFF; 01028 /* Close down the display */ 01029 if ((val == (XK_q & 0xFF)) || 01030 (val == (XK_Q & 0xFF)) || 01031 (val == (XK_Escape & 0xFF))) 01032 { 01033 this->setRunning(0); 01034 } 01035 } 01036 break; 01037 #if 0 01038 case KeyRelease: 01039 break; 01040 case ButtonPress: 01041 phPROGRESS("ButtonPress\n"); 01042 break; 01043 case ButtonRelease: 01044 phPROGRESS("ButtonRelease\n"); 01045 break; 01046 case MotionNotify: 01047 break; 01048 case EnterNotify: 01049 break; 01050 case LeaveNotify: 01051 break; 01052 case FocusIn: 01053 break; 01054 case FocusOut: 01055 break; 01056 case KeymapNotify: 01057 break; 01058 #endif 01059 case Expose: 01060 /* TODO : Add a feature here to only redraw a 01061 * certain area of the image. The handler 01062 * is currently "dumb" since it redraws everything 01063 * on an expose event */ 01064 /* phPROGRESS("Expose\n"); */ 01065 if (phX11Event_FromImageWindow(this->m_x11window,event)) 01066 { 01067 /* TODO: Implement a proper expose function */ 01068 /* Because this version of the software completely 01069 * redraws the entire screen when an Expose event occurs, 01070 * We can flush all the Expose events and use only the 01071 * most recent one */ 01072 /* The most recent event is returned in the 'event' 01073 * parameter */ 01074 phX11FlushToRecent_ImageWindow( this->m_x11window, 01075 Expose, 01076 event ); 01077 rc = this->gui_redraw(); 01078 phPRINT_RC(rc,NULL,"this->gui_redraw();"); 01079 } 01080 break; 01081 #if 0 01082 case GraphicsExpose: 01083 break; 01084 case NoExpose: 01085 break; 01086 case VisibilityNotify: 01087 break; 01088 case CreateNotify: 01089 break; 01090 case DestroyNotify: 01091 break; 01092 #endif 01093 case UnmapNotify: 01094 /* XPutBackEvent(display,&event); */ 01095 /* phThread::yieldThread()(); */ 01096 break; 01097 case MapNotify: 01098 /* XPutBackEvent(display,&event); */ 01099 /* phThread::yieldThread()(); */ 01100 break; 01101 #if 0 01102 case MapRequest: 01103 break; 01104 case ReparentNotify: 01105 break; 01106 #endif 01107 case ConfigureNotify: 01108 /* phPROGRESS("ConfigureNotify\n"); */ 01109 if (phX11Event_FromBaseWindow(this->m_x11window,event)) 01110 { 01111 uint32_t w = 0; 01112 uint32_t h = 0; 01113 int32_t x = 0; 01114 int32_t y = 0; 01115 int32_t send_event = 0; 01116 int resizerc = 0; 01117 01118 /* Only get the most recent configure notify event */ 01119 phX11FlushToRecent_BaseWindow( this->m_x11window, 01120 ConfigureNotify, 01121 event ); 01122 rc = this->gui_redraw(); 01123 phX11Event_GetXConfigureInfo(event, 01124 &w,&h,&x,&y,&send_event); 01125 01126 phTHIS_LOOSE_LOCK(locked); 01127 01128 resizerc = this->gui_resize(w,h); 01129 phPRINT_RC(resizerc,NULL, 01130 "this->gui_resize(w:%u,h:%u) failed", 01131 w,h); 01132 01133 /* It's not a synthetic move, we need to translate 01134 * the coordinates */ 01135 if (!send_event) 01136 { 01137 rc = phX11Window_TranslateRootCoords(this->m_x11window, 01138 x,y,&x,&y); 01139 phPRINT_RC(rc,NULL,"phX11Window_TranslateRootCoords"); 01140 } 01141 01142 /* if rc == 1, then no resize happened, so we'll assume 01143 * that this is a move event to be processed */ 01144 else if ((resizerc == phX11Window_NORESIZE) && 01145 ((this->m_x != x) || (this->m_y != y))) 01146 { 01147 DEBUG_PRINT("<>(%d,%d)(%d,%d)\n",x,y,this->m_x,this->m_y); 01148 /* Set the location values in the window */ 01149 rc = phX11Window_SetLocation(this->m_x11window, 01150 x,y); 01151 phPRINT_RC(rc,NULL,"phX11Window_SetLocation failed."); 01152 01153 /* Set the local copies of the values here */ 01154 rc = phX11Window_GetLocation(this->m_x11window, 01155 &this->m_x,&this->m_y); 01156 phPRINT_RC(rc,NULL,"phX11Window_GetLocation failed."); 01157 01158 DEBUG_PRINT("->(%u,%u)\n",this->m_x,this->m_y); 01159 } 01160 01161 phTHIS_LOOSE_UNLOCK(locked); 01162 } 01163 break; 01164 #if 0 01165 case ConfigureRequest: 01166 phPROGRESS("ConfigureRequest\n"); 01167 break; 01168 case GravityNotify: 01169 phPROGRESS("GravityNotify\n"); 01170 break; 01171 case ResizeRequest: 01172 phPROGRESS("ResizeRequest\n"); 01173 break; 01174 case CirculateNotify: 01175 phPROGRESS("CirculateNotify\n"); 01176 break; 01177 case CirculateRequest: 01178 phPROGRESS("CirculateRequest\n"); 01179 break; 01180 case PropertyNotify: 01181 phPROGRESS("PropertyNotify\n"); 01182 break; 01183 case SelectionClear: 01184 phPROGRESS("SelectionClear\n"); 01185 break; 01186 case SelectionRequest: 01187 phPROGRESS("SelectionRequest\n"); 01188 break; 01189 case SelectionNotify: 01190 phPROGRESS("SelectionNotify\n"); 01191 break; 01192 case ColormapNotify: 01193 phPROGRESS("ColormapNotify\n"); 01194 break; 01195 #endif 01196 #if 0 01197 case MappingNotify: 01198 break; 01199 #endif 01200 case ClientMessage: 01201 { 01202 int format = 0; 01203 long l_0 = 0; 01204 long l_1 = 0; 01205 long l_2 = 0; 01206 /* phPROGRESS("ClientMessage\n"); */ 01207 01208 phX11Event_GetXClientInfo( event, &format, &l_0, &l_1, &l_2 ); 01209 01210 /* ---------------------------------------------------------- */ 01211 if (((format== 32) && (l_0 == (int)xWM_DELETE_WINDOW)) || 01212 /* Handle user wakeup */ 01213 (phX11EventAtom_Equal(this->m_atoms[phWAKEUP_INDEX], 01214 event))) 01215 { 01216 this->setRunning(0); 01217 } 01218 /* ---------------------------------------------------------- */ 01219 else 01220 { 01221 int img_wlocked = 0; 01222 01223 rc = this->m_image.writeLock(); 01224 phPRINT_RC(rc,NULL,"this->m_image.writeLock()"); 01225 if (rc == phSUCCESS) img_wlocked = 1; 01226 01227 /* Handle user redraw */ 01228 if (phX11EventAtom_Equal(this->m_atoms[phREDRAW_INDEX], 01229 event)) 01230 { 01231 rc = this->m_recv_sems[phREDRAW_INDEX].post(); 01232 phPRINT_RC(rc,NULL,"this->m_recv_sems[phREDRAW_INDEX].post() failed."); 01233 01234 rc = this->gui_redraw(); 01235 phPRINT_RC(rc,NULL,"this->gui_()"); 01236 } 01237 /* Handle user update */ 01238 else if (phX11EventAtom_Equal(this->m_atoms[phUPDATE_INDEX], 01239 event)) 01240 { 01241 rc = this->m_recv_sems[phUPDATE_INDEX].post(); 01242 phPRINT_RC(rc,NULL,"this->m_recv_sems[phUPDATE_INDEX].post() failed."); 01243 01244 rc = this->gui_update(); 01245 phPRINT_RC(rc,NULL,"this->gui_update()"); 01246 } 01247 /* Handle user move event */ 01248 else if (phX11EventAtom_Equal(this->m_atoms[phMOVE_INDEX], 01249 event)) 01250 { 01251 int32_t x = (int32_t)l_1; 01252 int32_t y = (int32_t)l_2; 01253 01254 rc = this->m_recv_sems[phMOVE_INDEX].post(); 01255 phPRINT_RC(rc,NULL,"this->m_recv_sems[phMOVE_INDEX].post() failed."); 01256 01257 rc = this->gui_move(x,y); 01258 phPRINT_RC(rc,NULL,"this->gui_move(%d,%d)",x,y); 01259 } 01260 /* Handle user resize event */ 01261 else if (phX11EventAtom_Equal(this->m_atoms[phRESIZE_INDEX], 01262 event)) 01263 { 01264 uint32_t w = (uint32_t)l_1; 01265 uint32_t h = (uint32_t)l_2; 01266 01267 rc = this->m_recv_sems[phRESIZE_INDEX].post(); 01268 phPRINT_RC(rc,NULL,"this->m_recv_sems[phRESIZE_INDEX].post() failed."); 01269 01270 rc = this->gui_resize(w,h); 01271 phPRINT_RC(rc,NULL,"this->gui_resize(%u,%u)",w,h); 01272 } 01273 /* Handle user minsize event */ 01274 else if (phX11EventAtom_Equal(this->m_atoms[phMINSIZE_INDEX], 01275 event)) 01276 { 01277 uint32_t min_w = (uint32_t)l_1; 01278 uint32_t min_h = (uint32_t)l_2; 01279 01280 rc = this->m_recv_sems[phMINSIZE_INDEX].post(); 01281 phPRINT_RC(rc,NULL,"this->m_recv_sems[phMINSIZE_INDEX].post() failed."); 01282 01283 rc = this->gui_minsize(min_w,min_h); 01284 phPRINT_RC(rc,NULL,"this->gui_minsize(%u,%u)", 01285 min_w, min_h ); 01286 } 01287 /* Handle user visibility event */ 01288 else if (phX11EventAtom_Equal(this->m_atoms[phVISIBLE_INDEX], 01289 event)) 01290 { 01291 int32_t show = (int32_t)l_1; 01292 01293 rc = this->m_recv_sems[phVISIBLE_INDEX].post(); 01294 phPRINT_RC(rc,NULL,"this->m_recv_sems[phVISIBLE_INDEX].post() failed."); 01295 01296 if (show == phX11Window_SHOW) 01297 { 01298 rc = this->gui_show(); 01299 phPRINT_RC(rc,NULL,"this->gui_show()"); 01300 } 01301 else if (show == phX11Window_HIDE) 01302 { 01303 rc = this->gui_hide(); 01304 phPRINT_RC(rc,NULL,"this->gui_hide()"); 01305 } 01306 } 01307 01308 /* Release the locks */ 01309 if (img_wlocked) 01310 { 01311 rc = this->m_image.rwUnlock(); 01312 phPRINT_RC(rc,NULL,"this->m_image.rwUnlock()"); 01313 } 01314 } 01315 } 01316 break; 01317 01318 default: 01319 break; 01320 } 01321 } 01322 01323 rc = this->getImage()->wakeup_self(); 01324 phPRINT_RC(rc,NULL,"this->getImage()->wakeup_self()"); 01325 01326 for (i = 0; i < phX11Window_USEREVENT_COUNT; i++ ) 01327 { 01328 rc = this->m_recv_sems[i].post(); 01329 phPRINT_RC(rc,NULL,"this->m_recv_sems[i:%d].post() failed.",i); 01330 01331 rc = this->m_done_sems[i].post(); 01332 phPRINT_RC(rc,NULL, 01333 "this->m_done_sems[i:%d].post() failed",i); 01334 } 01335 01336 rc = this->gui_hide(); 01337 phCHECK_RC(rc,NULL,"this->gui_hide()"); 01338 01339 if (event != NULL) phX11EventInfo_Destroy( event ); 01340 01341 DEBUG_PRINT("Thread returning cleanly\n"); 01342 01343 return phSUCCESS; 01344 error: 01345 phPROGRESS("Thread returning with error\n"); 01346 01347 rc = this->gui_hide(); 01348 phPRINT_RC(rc,NULL,"this->gui_hide()"); 01349 01350 rc = this->signal_error(); 01351 phPRINT_RC(rc,NULL,"this->signal_error"); 01352 01353 for (i = 0; i < phX11Window_USEREVENT_COUNT; i++ ) 01354 { 01355 rc = this->m_recv_sems[i].post(); 01356 phPRINT_RC(rc,NULL,"this->m_recv_sems[i:%d].post() failed.",i); 01357 01358 rc = this->m_done_sems[i].post(); 01359 phPRINT_RC(rc,NULL, 01360 "this->m_done_sems[i:%d].post() failed",i); 01361 } 01362 01363 if (event != NULL) phX11EventInfo_Destroy( event ); 01364 01365 return phFAIL; 01366 } 01367 01368
Copyright (C) 2002 - 2007 |
Philip D.S. Thoren ( pthoren@users.sourceforge.net ) University Of Massachusetts at Lowell Robotics Lab |