00001 // Filename: graphicsWindow.cxx 00002 // Created by: mike (09Jan97) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "graphicsWindow.h" 00016 #include "graphicsPipe.h" 00017 #include "config_display.h" 00018 #include "mouseButton.h" 00019 #include "keyboardButton.h" 00020 #include "lightMutexHolder.h" 00021 #include "lightReMutexHolder.h" 00022 #include "throw_event.h" 00023 #include "string_utils.h" 00024 00025 TypeHandle GraphicsWindow::_type_handle; 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: GraphicsWindow::Constructor 00029 // Access: Protected 00030 // Description: Normally, the GraphicsWindow constructor is not 00031 // called directly; these are created instead via the 00032 // GraphicsEngine::make_window() function. 00033 //////////////////////////////////////////////////////////////////// 00034 GraphicsWindow:: 00035 GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, 00036 const string &name, 00037 const FrameBufferProperties &fb_prop, 00038 const WindowProperties &win_prop, 00039 int flags, 00040 GraphicsStateGuardian *gsg, 00041 GraphicsOutput *host) : 00042 GraphicsOutput(engine, pipe, name, fb_prop, win_prop, flags, gsg, host, true), 00043 _input_lock("GraphicsWindow::_input_lock"), 00044 _properties_lock("GraphicsWindow::_properties_lock") 00045 { 00046 #ifdef DO_MEMORY_USAGE 00047 MemoryUsage::update_type(this, this); 00048 #endif 00049 00050 if (display_cat.is_debug()) { 00051 display_cat.debug() 00052 << "Creating new window " << get_name() << "\n"; 00053 } 00054 00055 _properties.set_open(false); 00056 _properties.set_undecorated(false); 00057 _properties.set_fullscreen(false); 00058 _properties.set_minimized(false); 00059 _properties.set_cursor_hidden(false); 00060 00061 request_properties(WindowProperties::get_default()); 00062 request_properties(win_prop); 00063 00064 _window_event = "window-event"; 00065 _got_expose_event = false; 00066 _unexposed_draw = win_unexposed_draw; 00067 set_pixel_zoom(pixel_zoom); 00068 } 00069 00070 //////////////////////////////////////////////////////////////////// 00071 // Function: GraphicsWindow::Destructor 00072 // Access: Published, Virtual 00073 // Description: 00074 //////////////////////////////////////////////////////////////////// 00075 GraphicsWindow:: 00076 ~GraphicsWindow() { 00077 // Clean up python event handlers. 00078 #ifdef HAVE_PYTHON 00079 PythonWinProcClasses::iterator iter; 00080 for (iter = _python_window_proc_classes.begin(); 00081 iter != _python_window_proc_classes.end(); 00082 ++iter) { 00083 delete *iter; 00084 } 00085 #endif 00086 } 00087 00088 //////////////////////////////////////////////////////////////////// 00089 // Function: GraphicsWindow::get_properties 00090 // Access: Published 00091 // Description: Returns the current properties of the window. 00092 //////////////////////////////////////////////////////////////////// 00093 const WindowProperties GraphicsWindow:: 00094 get_properties() const { 00095 WindowProperties result; 00096 { 00097 LightReMutexHolder holder(_properties_lock); 00098 result = _properties; 00099 } 00100 return result; 00101 } 00102 00103 //////////////////////////////////////////////////////////////////// 00104 // Function: GraphicsWindow::get_requested_properties 00105 // Access: Published 00106 // Description: Returns the properties of the window that are 00107 // currently requested. These properties will be 00108 // applied to the window (if valid) at the next 00109 // execution of process_events(). 00110 //////////////////////////////////////////////////////////////////// 00111 const WindowProperties GraphicsWindow:: 00112 get_requested_properties() const { 00113 WindowProperties result; 00114 { 00115 LightReMutexHolder holder(_properties_lock); 00116 result = _requested_properties; 00117 } 00118 return result; 00119 } 00120 00121 //////////////////////////////////////////////////////////////////// 00122 // Function: GraphicsWindow::clear_rejected_properties 00123 // Access: Published 00124 // Description: Empties the set of failed properties that will be 00125 // returned by get_rejected_properties(). 00126 //////////////////////////////////////////////////////////////////// 00127 void GraphicsWindow:: 00128 clear_rejected_properties() { 00129 LightReMutexHolder holder(_properties_lock); 00130 _rejected_properties.clear(); 00131 } 00132 00133 //////////////////////////////////////////////////////////////////// 00134 // Function: GraphicsWindow::get_rejected_properties 00135 // Access: Published 00136 // Description: Returns the set of properties that have recently been 00137 // requested, but could not be applied to the window for 00138 // some reason. This set of properties will remain 00139 // unchanged until they are changed by a new failed 00140 // request, or clear_rejected_properties() is called. 00141 //////////////////////////////////////////////////////////////////// 00142 WindowProperties GraphicsWindow:: 00143 get_rejected_properties() const { 00144 WindowProperties result; 00145 { 00146 LightReMutexHolder holder(_properties_lock); 00147 result = _rejected_properties; 00148 } 00149 return result; 00150 } 00151 00152 //////////////////////////////////////////////////////////////////// 00153 // Function: GraphicsWindow::request_properties 00154 // Access: Published 00155 // Description: Requests a property change on the window. For 00156 // example, use this method to request a window change 00157 // size or minimize or something. 00158 // 00159 // The change is not made immediately; rather, the 00160 // request is saved and will be applied the next time 00161 // the window task is run (probably at the next frame). 00162 //////////////////////////////////////////////////////////////////// 00163 void GraphicsWindow:: 00164 request_properties(const WindowProperties &requested_properties) { 00165 LightReMutexHolder holder(_properties_lock); 00166 _requested_properties.add_properties(requested_properties); 00167 00168 if (!_has_size && _requested_properties.has_size()) { 00169 // If we just requested a particular size, anticipate that it will 00170 // stick. This is helpful for the MultitexReducer, which needs to 00171 // know the size of the textures that it will be working with, 00172 // even if the texture hasn't been fully generated yet. 00173 _x_size = _requested_properties.get_x_size(); 00174 _y_size = _requested_properties.get_y_size(); 00175 00176 // Don't set _has_size yet, because we don't really know yet. 00177 } 00178 } 00179 00180 //////////////////////////////////////////////////////////////////// 00181 // Function: GraphicsWindow::is_active 00182 // Access: Published, Virtual 00183 // Description: Returns true if the window is ready to be rendered 00184 // into, false otherwise. 00185 //////////////////////////////////////////////////////////////////// 00186 bool GraphicsWindow:: 00187 is_active() const { 00188 // Make this smarter? 00189 return GraphicsOutput::is_active() && _properties.get_open() && !_properties.get_minimized(); 00190 } 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: GraphicsWindow::set_window_event 00194 // Access: Published 00195 // Description: Changes the name of the event that is generated when 00196 // this window is modified externally, e.g. to be 00197 // resized or closed by the user. 00198 // 00199 // By default, all windows have the same window event 00200 // unless they are explicitly changed. When the event 00201 // is generated, it includes one parameter: the window 00202 // itself. 00203 //////////////////////////////////////////////////////////////////// 00204 void GraphicsWindow:: 00205 set_window_event(const string &window_event) { 00206 LightReMutexHolder holder(_properties_lock); 00207 _window_event = window_event; 00208 } 00209 00210 //////////////////////////////////////////////////////////////////// 00211 // Function: GraphicsWindow::get_window_event 00212 // Access: Published 00213 // Description: Returns the name of the event that is generated when 00214 // this window is modified externally, e.g. to be 00215 // resized or closed by the user. See set_window_event(). 00216 //////////////////////////////////////////////////////////////////// 00217 string GraphicsWindow:: 00218 get_window_event() const { 00219 string result; 00220 LightReMutexHolder holder(_properties_lock); 00221 result = _window_event; 00222 return result; 00223 } 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: GraphicsWindow::set_close_request_event 00227 // Access: Published 00228 // Description: Sets the event that is triggered when the user 00229 // requests to close the window, e.g. via alt-F4, or 00230 // clicking on the close box. 00231 // 00232 // The default for each window is for this event to be 00233 // the empty string, which means the window-close 00234 // request is handled immediately by Panda (and the 00235 // window will be closed without the app getting a 00236 // chance to intervene). If you set this to a nonempty 00237 // string, then the window is not closed, but instead 00238 // the event is thrown. It is then up to the app to 00239 // respond appropriately, for instance by presenting an 00240 // "are you sure?" dialog box, and eventually calling 00241 // close_window() when the user is sure. 00242 // 00243 // It is considered poor form to set this string and 00244 // then not handle the event. This can frustrate the 00245 // user by making it difficult for him to cleanly shut 00246 // down the application (and may force the user to 00247 // hard-kill the app, or reboot the machine). 00248 //////////////////////////////////////////////////////////////////// 00249 void GraphicsWindow:: 00250 set_close_request_event(const string &close_request_event) { 00251 LightReMutexHolder holder(_properties_lock); 00252 _close_request_event = close_request_event; 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: GraphicsWindow::get_close_request_event 00257 // Access: Published 00258 // Description: Returns the name of the event set via 00259 // set_close_request_event(). If this string is 00260 // nonempty, then when the user requests to close 00261 // window, this event will be generated instead. See 00262 // set_close_request_event(). 00263 //////////////////////////////////////////////////////////////////// 00264 string GraphicsWindow:: 00265 get_close_request_event() const { 00266 string result; 00267 LightReMutexHolder holder(_properties_lock); 00268 result = _close_request_event; 00269 return result; 00270 } 00271 00272 //////////////////////////////////////////////////////////////////// 00273 // Function: GraphicsWindow::get_num_input_devices 00274 // Access: Published 00275 // Description: Returns the number of separate input devices 00276 // associated with the window. Typically, a window will 00277 // have exactly one input device: the keyboard/mouse 00278 // pair. However, some windows may have no input 00279 // devices, and others may add additional devices, for 00280 // instance for a joystick. 00281 //////////////////////////////////////////////////////////////////// 00282 int GraphicsWindow:: 00283 get_num_input_devices() const { 00284 int result; 00285 { 00286 LightMutexHolder holder(_input_lock); 00287 result = _input_devices.size(); 00288 } 00289 return result; 00290 } 00291 00292 //////////////////////////////////////////////////////////////////// 00293 // Function: GraphicsWindow::get_input_device_name 00294 // Access: Published 00295 // Description: Returns the name of the nth input device. 00296 //////////////////////////////////////////////////////////////////// 00297 string GraphicsWindow:: 00298 get_input_device_name(int device) const { 00299 string result; 00300 { 00301 LightMutexHolder holder(_input_lock); 00302 nassertr(device >= 0 && device < (int)_input_devices.size(), ""); 00303 result = _input_devices[device].get_name(); 00304 } 00305 return result; 00306 } 00307 00308 //////////////////////////////////////////////////////////////////// 00309 // Function: GraphicsWindow::has_pointer 00310 // Access: Published 00311 // Description: Returns true if the nth input device has a 00312 // screen-space pointer (for instance, a mouse), false 00313 // otherwise. 00314 //////////////////////////////////////////////////////////////////// 00315 bool GraphicsWindow:: 00316 has_pointer(int device) const { 00317 bool result; 00318 { 00319 LightMutexHolder holder(_input_lock); 00320 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00321 result = _input_devices[device].has_pointer(); 00322 } 00323 return result; 00324 } 00325 00326 //////////////////////////////////////////////////////////////////// 00327 // Function: GraphicsWindow::has_keyboard 00328 // Access: Published 00329 // Description: Returns true if the nth input device has a keyboard, 00330 // false otherwise. 00331 //////////////////////////////////////////////////////////////////// 00332 bool GraphicsWindow:: 00333 has_keyboard(int device) const { 00334 bool result; 00335 { 00336 LightMutexHolder holder(_input_lock); 00337 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00338 result = _input_devices[device].has_keyboard(); 00339 } 00340 return result; 00341 } 00342 00343 //////////////////////////////////////////////////////////////////// 00344 // Function: GraphicsWindow::enable_pointer_events 00345 // Access: Published 00346 // Description: Turn on the generation of pointer events. 00347 //////////////////////////////////////////////////////////////////// 00348 void GraphicsWindow:: 00349 enable_pointer_events(int device) { 00350 LightMutexHolder holder(_input_lock); 00351 nassertv(device >= 0 && device < (int)_input_devices.size()); 00352 _input_devices[device].enable_pointer_events(); 00353 } 00354 00355 //////////////////////////////////////////////////////////////////// 00356 // Function: GraphicsWindow::disable_pointer_events 00357 // Access: Published 00358 // Description: Turn off the generation of pointer events. 00359 //////////////////////////////////////////////////////////////////// 00360 void GraphicsWindow:: 00361 disable_pointer_events(int device) { 00362 LightMutexHolder holder(_input_lock); 00363 nassertv(device >= 0 && device < (int)_input_devices.size()); 00364 _input_devices[device].disable_pointer_events(); 00365 } 00366 00367 //////////////////////////////////////////////////////////////////// 00368 // Function: GraphicsWindow::enable_pointer_mode 00369 // Access: Published 00370 // Description: See GraphicsWindowInputDevice::enable_pointer_mode 00371 //////////////////////////////////////////////////////////////////// 00372 void GraphicsWindow:: 00373 enable_pointer_mode(int device, double speed) { 00374 LightMutexHolder holder(_input_lock); 00375 nassertv(device >= 0 && device < (int)_input_devices.size()); 00376 _input_devices[device].enable_pointer_mode(speed); 00377 } 00378 00379 //////////////////////////////////////////////////////////////////// 00380 // Function: GraphicsWindow::disable_pointer_events 00381 // Access: Published 00382 // Description: See GraphicsWindowInputDevice::disable_pointer_mode 00383 //////////////////////////////////////////////////////////////////// 00384 void GraphicsWindow:: 00385 disable_pointer_mode(int device) { 00386 LightMutexHolder holder(_input_lock); 00387 nassertv(device >= 0 && device < (int)_input_devices.size()); 00388 _input_devices[device].disable_pointer_mode(); 00389 } 00390 00391 //////////////////////////////////////////////////////////////////// 00392 // Function: GraphicsWindow::get_pointer 00393 // Access: Published 00394 // Description: Returns the MouseData associated with the nth input 00395 // device's pointer. 00396 //////////////////////////////////////////////////////////////////// 00397 MouseData GraphicsWindow:: 00398 get_pointer(int device) const { 00399 MouseData result; 00400 { 00401 LightMutexHolder holder(_input_lock); 00402 nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData()); 00403 result = _input_devices[device].get_pointer(); 00404 } 00405 return result; 00406 } 00407 00408 //////////////////////////////////////////////////////////////////// 00409 // Function: GraphicsWindow::move_pointer 00410 // Access: Published, Virtual 00411 // Description: Forces the pointer to the indicated position within 00412 // the window, if possible. 00413 // 00414 // Returns true if successful, false on failure. This 00415 // may fail if the mouse is not currently within the 00416 // window, or if the API doesn't support this operation. 00417 //////////////////////////////////////////////////////////////////// 00418 bool GraphicsWindow:: 00419 move_pointer(int, int, int) { 00420 return false; 00421 } 00422 00423 //////////////////////////////////////////////////////////////////// 00424 // Function: GraphicsWindow::close_ime 00425 // Access: Published, Virtual 00426 // Description: Forces the ime window to close if any 00427 // 00428 //////////////////////////////////////////////////////////////////// 00429 void GraphicsWindow:: 00430 close_ime() { 00431 return; 00432 } 00433 00434 //////////////////////////////////////////////////////////////////// 00435 // Function: GraphicsWindow::has_button_event 00436 // Access: Public 00437 // Description: Returns true if the indicated device has a pending 00438 // button event (a mouse button or keyboard button 00439 // down/up), false otherwise. If this returns true, the 00440 // particular event may be extracted via 00441 // get_button_event(). 00442 //////////////////////////////////////////////////////////////////// 00443 bool GraphicsWindow:: 00444 has_button_event(int device) const { 00445 bool result; 00446 { 00447 LightMutexHolder holder(_input_lock); 00448 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00449 result = _input_devices[device].has_button_event(); 00450 } 00451 return result; 00452 } 00453 00454 //////////////////////////////////////////////////////////////////// 00455 // Function: GraphicsWindow::get_button_event 00456 // Access: Public 00457 // Description: Assuming a previous call to has_button_event() 00458 // returned true, this returns the pending button event. 00459 //////////////////////////////////////////////////////////////////// 00460 ButtonEvent GraphicsWindow:: 00461 get_button_event(int device) { 00462 ButtonEvent result; 00463 { 00464 LightMutexHolder holder(_input_lock); 00465 nassertr(device >= 0 && device < (int)_input_devices.size(), ButtonEvent()); 00466 nassertr(_input_devices[device].has_button_event(), ButtonEvent()); 00467 result = _input_devices[device].get_button_event(); 00468 } 00469 return result; 00470 } 00471 00472 //////////////////////////////////////////////////////////////////// 00473 // Function: GraphicsWindow::has_pointer_event 00474 // Access: Public 00475 // Description: Returns true if the indicated device has a pending 00476 // pointer event (a mouse movement). If this returns 00477 // true, the particular event may be extracted via 00478 // get_pointer_events(). 00479 //////////////////////////////////////////////////////////////////// 00480 bool GraphicsWindow:: 00481 has_pointer_event(int device) const { 00482 bool result; 00483 { 00484 LightMutexHolder holder(_input_lock); 00485 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00486 result = _input_devices[device].has_pointer_event(); 00487 } 00488 return result; 00489 } 00490 00491 //////////////////////////////////////////////////////////////////// 00492 // Function: GraphicsWindow::get_pointer_events 00493 // Access: Public 00494 // Description: Assuming a previous call to has_pointer_event() 00495 // returned true, this returns the pending pointer event list. 00496 //////////////////////////////////////////////////////////////////// 00497 PT(PointerEventList) GraphicsWindow:: 00498 get_pointer_events(int device) { 00499 PT(PointerEventList) result; 00500 { 00501 LightMutexHolder holder(_input_lock); 00502 nassertr(device >= 0 && device < (int)_input_devices.size(), NULL); 00503 nassertr(_input_devices[device].has_pointer_event(), NULL); 00504 result = _input_devices[device].get_pointer_events(); 00505 } 00506 return result; 00507 } 00508 00509 //////////////////////////////////////////////////////////////////// 00510 // Function: GraphicsWindow::verify_window_sizes 00511 // Access: Public, Virtual 00512 // Description: Determines which of the indicated window sizes are 00513 // supported by available hardware (e.g. in fullscreen 00514 // mode). 00515 // 00516 // On entry, dimen is an array containing contiguous x,y 00517 // pairs specifying possible display sizes; it is 00518 // numsizes*2 words long. The function will zero out 00519 // any invalid x,y size pairs. The return value is the 00520 // number of valid sizes that were found. 00521 // 00522 // Note this doesn't guarantee a resize attempt will 00523 // work; you still need to check the return value. 00524 // 00525 // (It might be better to implement some sort of query 00526 // interface that returns an array of supported sizes, 00527 // but this way is somewhat simpler and will do the job 00528 // on most cards, assuming they handle the std sizes the 00529 // app knows about.) 00530 //////////////////////////////////////////////////////////////////// 00531 int GraphicsWindow:: 00532 verify_window_sizes(int numsizes, int *dimen) { 00533 return numsizes; 00534 } 00535 00536 //////////////////////////////////////////////////////////////////// 00537 // Function: GraphicsWindow::request_open 00538 // Access: Public, Virtual 00539 // Description: This is called by the GraphicsEngine to request that 00540 // the window (or whatever) open itself or, in general, 00541 // make itself valid, at the next call to 00542 // process_events(). 00543 //////////////////////////////////////////////////////////////////// 00544 void GraphicsWindow:: 00545 request_open() { 00546 WindowProperties open_properties; 00547 open_properties.set_open(true); 00548 request_properties(open_properties); 00549 } 00550 00551 //////////////////////////////////////////////////////////////////// 00552 // Function: GraphicsWindow::request_close 00553 // Access: Public, Virtual 00554 // Description: This is called by the GraphicsEngine to request that 00555 // the window (or whatever) close itself or, in general, 00556 // make itself invalid, at the next call to 00557 // process_events(). By that time we promise the gsg 00558 // pointer will be cleared. 00559 //////////////////////////////////////////////////////////////////// 00560 void GraphicsWindow:: 00561 request_close() { 00562 WindowProperties close_properties; 00563 close_properties.set_open(false); 00564 request_properties(close_properties); 00565 } 00566 00567 //////////////////////////////////////////////////////////////////// 00568 // Function: GraphicsWindow::set_close_now 00569 // Access: Public, Virtual 00570 // Description: This is called by the GraphicsEngine to insist that 00571 // the window be closed immediately. This is only 00572 // called from the window thread. 00573 //////////////////////////////////////////////////////////////////// 00574 void GraphicsWindow:: 00575 set_close_now() { 00576 WindowProperties close_properties; 00577 close_properties.set_open(false); 00578 set_properties_now(close_properties); 00579 } 00580 00581 //////////////////////////////////////////////////////////////////// 00582 // Function: GraphicsWindow::process_events 00583 // Access: Public, Virtual 00584 // Description: Do whatever processing is necessary to ensure that 00585 // the window responds to user events. Also, honor any 00586 // requests recently made via request_properties(). 00587 // 00588 // This function is called only within the window 00589 // thread. 00590 //////////////////////////////////////////////////////////////////// 00591 void GraphicsWindow:: 00592 process_events() { 00593 if (_requested_properties.is_any_specified()) { 00594 // We don't bother to grab the mutex until after we have already 00595 // checked whether any properties have been specified. This is 00596 // technically sloppy, but it ought to be o.k. since it's just a 00597 // bitmask after all. 00598 WindowProperties properties; 00599 { 00600 LightReMutexHolder holder(_properties_lock); 00601 properties = _requested_properties; 00602 _requested_properties.clear(); 00603 00604 set_properties_now(properties); 00605 if (properties.is_any_specified()) { 00606 display_cat.info() 00607 << "Unable to set window properties: " << properties << "\n"; 00608 _rejected_properties.add_properties(properties); 00609 } 00610 } 00611 } 00612 } 00613 00614 //////////////////////////////////////////////////////////////////// 00615 // Function: GraphicsWindow::set_properties_now 00616 // Access: Public, Virtual 00617 // Description: Applies the requested set of properties to the 00618 // window, if possible, for instance to request a change 00619 // in size or minimization status. 00620 // 00621 // The window properties are applied immediately, rather 00622 // than waiting until the next frame. This implies that 00623 // this method may *only* be called from within the 00624 // window thread. 00625 // 00626 // The properties that have been applied are cleared 00627 // from the structure by this function; so on return, 00628 // whatever remains in the properties structure are 00629 // those that were unchanged for some reason (probably 00630 // because the underlying interface does not support 00631 // changing that property on an open window). 00632 //////////////////////////////////////////////////////////////////// 00633 void GraphicsWindow:: 00634 set_properties_now(WindowProperties &properties) { 00635 if (properties.has_open() && 00636 properties.get_open() != _properties.get_open()) { 00637 // Open or close a new window. In this case we can get all of the 00638 // properties at once. 00639 00640 _properties.add_properties(properties); 00641 properties.clear(); 00642 00643 if (_properties.get_open()) { 00644 if (open_window()) { 00645 // When the window is first opened, force its size to be 00646 // broadcast to its display regions. 00647 _is_valid = true; 00648 set_size_and_recalc(_properties.get_x_size(), 00649 _properties.get_y_size()); 00650 } else { 00651 // Since we can't even open the window, tag the 00652 // _rejected_properties with all of the window properties that 00653 // failed. 00654 _rejected_properties.add_properties(_properties); 00655 00656 // And mark the window closed. 00657 _properties.set_open(false); 00658 _is_valid = false; 00659 } 00660 00661 } else { 00662 // We used to resist closing a window before its GSG has been 00663 // released. Now it seems we never release a GSG, so go ahead 00664 // and close the window. 00665 close_window(); 00666 _is_valid = false; 00667 } 00668 return; 00669 } 00670 00671 if (!_properties.get_open()) { 00672 // The window is not currently open; we can set properties at 00673 // will. 00674 _properties.add_properties(properties); 00675 properties.clear(); 00676 return; 00677 } 00678 00679 properties.clear_open(); 00680 00681 // The window is already open; we are limited to what we can change 00682 // on the fly. 00683 00684 if (properties.has_size() || properties.has_origin()) { 00685 // Consider changing the window's size and/or position. 00686 WindowProperties reshape_props; 00687 if (properties.has_size()) { 00688 reshape_props.set_size(properties.get_x_size(), properties.get_y_size()); 00689 } else { 00690 reshape_props.set_size(_properties.get_x_size(), _properties.get_y_size()); 00691 } 00692 00693 if (properties.has_origin() && !is_fullscreen()) { 00694 reshape_props.set_origin(properties.get_x_origin(), properties.get_y_origin()); 00695 } else if (_properties.has_origin()) { 00696 reshape_props.set_origin(_properties.get_x_origin(), _properties.get_y_origin()); 00697 } 00698 00699 bool has_origin = reshape_props.has_origin(); 00700 int x_origin = 0, y_origin = 0; 00701 if (has_origin) { 00702 x_origin = reshape_props.get_x_origin(); 00703 y_origin = reshape_props.get_y_origin(); 00704 } 00705 00706 if (reshape_props.get_x_size() != _properties.get_x_size() || 00707 reshape_props.get_y_size() != _properties.get_y_size() || 00708 (has_origin && (x_origin != _properties.get_x_origin() || 00709 y_origin != _properties.get_y_origin()))) { 00710 if (do_reshape_request(x_origin, y_origin, has_origin, 00711 reshape_props.get_x_size(), 00712 reshape_props.get_y_size())) { 00713 properties.clear_size(); 00714 properties.clear_origin(); 00715 } 00716 } else { 00717 properties.clear_size(); 00718 properties.clear_origin(); 00719 } 00720 } 00721 00722 if (properties.has_fullscreen() && 00723 properties.get_fullscreen() == _properties.get_fullscreen()) { 00724 // Fullscreen property specified, but unchanged. 00725 properties.clear_fullscreen(); 00726 } 00727 if (properties.has_mouse_mode() ) { 00728 00729 if (properties.get_mouse_mode() == _properties.get_mouse_mode()) { 00730 properties.clear_mouse_mode(); 00731 } 00732 else { 00733 if(properties.get_mouse_mode() == WindowProperties::M_absolute) { 00734 _properties.set_mouse_mode(WindowProperties::M_absolute); 00735 mouse_mode_absolute(); 00736 properties.clear_mouse_mode(); 00737 } 00738 else 00739 { 00740 _properties.set_mouse_mode(WindowProperties::M_relative); 00741 mouse_mode_relative(); 00742 properties.clear_mouse_mode(); 00743 } 00744 } 00745 } 00746 } 00747 00748 //////////////////////////////////////////////////////////////////// 00749 // Function: GraphicsWindow::close_window 00750 // Access: Protected, Virtual 00751 // Description: Closes the window right now. Called from the window 00752 // thread. 00753 //////////////////////////////////////////////////////////////////// 00754 void GraphicsWindow:: 00755 close_window() { 00756 display_cat.info() 00757 << "Closing " << get_type() << "\n"; 00758 00759 // Tell our parent window (if any) that we're no longer its child. 00760 if (_window_handle != (WindowHandle *)NULL && 00761 _parent_window_handle != (WindowHandle *)NULL) { 00762 _parent_window_handle->detach_child(_window_handle); 00763 } 00764 00765 _window_handle = NULL; 00766 _parent_window_handle = NULL; 00767 _is_valid = false; 00768 } 00769 00770 //////////////////////////////////////////////////////////////////// 00771 // Function: GraphicsWindow::open_window 00772 // Access: Protected, Virtual 00773 // Description: Opens the window right now. Called from the window 00774 // thread. Returns true if the window is successfully 00775 // opened, or false if there was a problem. 00776 //////////////////////////////////////////////////////////////////// 00777 bool GraphicsWindow:: 00778 open_window() { 00779 return false; 00780 } 00781 00782 //////////////////////////////////////////////////////////////////// 00783 // Function: GraphicsWindow::reset_window 00784 // Access: Protected, Virtual 00785 // Description: resets the window framebuffer from its derived 00786 // children. Does nothing here. 00787 //////////////////////////////////////////////////////////////////// 00788 void GraphicsWindow:: 00789 reset_window(bool swapchain) { 00790 display_cat.info() 00791 << "Resetting " << get_type() << "\n"; 00792 } 00793 00794 //////////////////////////////////////////////////////////////////// 00795 // Function: GraphicsWindow::do_reshape_request 00796 // Access: Protected, Virtual 00797 // Description: Called from the window thread in response to a request 00798 // from within the code (via request_properties()) to 00799 // change the size and/or position of the window. 00800 // Returns true if the window is successfully changed, 00801 // or false if there was a problem. 00802 //////////////////////////////////////////////////////////////////// 00803 bool GraphicsWindow:: 00804 do_reshape_request(int x_origin, int y_origin, bool has_origin, 00805 int x_size, int y_size) { 00806 return false; 00807 } 00808 00809 //////////////////////////////////////////////////////////////////// 00810 // Function: GraphicsWindow::system_changed_properties 00811 // Access: Protected 00812 // Description: Should be called (from within the window thread) when 00813 // process_events() detects an external change in some 00814 // important window property; for instance, when the 00815 // user resizes the window. 00816 //////////////////////////////////////////////////////////////////// 00817 void GraphicsWindow:: 00818 system_changed_properties(const WindowProperties &properties) { 00819 if (display_cat.is_debug()) { 00820 display_cat.debug() 00821 << "system_changed_properties(" << properties << ")\n"; 00822 } 00823 00824 LightReMutexHolder holder(_properties_lock); 00825 00826 if (properties.has_size()) { 00827 system_changed_size(properties.get_x_size(), properties.get_y_size()); 00828 } 00829 00830 WindowProperties old_properties = _properties; 00831 _properties.add_properties(properties); 00832 if (_properties != old_properties) { 00833 throw_event(_window_event, this); 00834 } 00835 } 00836 00837 //////////////////////////////////////////////////////////////////// 00838 // Function: GraphicsWindow::system_changed_size 00839 // Access: Protected 00840 // Description: An internal function to update all the DisplayRegions 00841 // with the new size of the window. This should always 00842 // be called before changing the _size members of the 00843 // _properties structure. 00844 //////////////////////////////////////////////////////////////////// 00845 void GraphicsWindow:: 00846 system_changed_size(int x_size, int y_size) { 00847 if (display_cat.is_debug()) { 00848 display_cat.debug() 00849 << "system_changed_size(" << x_size << ", " << y_size << ")\n"; 00850 } 00851 00852 if (!_properties.has_size() || (x_size != _properties.get_x_size() || 00853 y_size != _properties.get_y_size())) { 00854 set_size_and_recalc(x_size, y_size); 00855 } 00856 } 00857 00858 //////////////////////////////////////////////////////////////////// 00859 // Function: GraphicsWindow::add_input_device 00860 // Access: Protected 00861 // Description: Adds a GraphicsWindowInputDevice to the vector. 00862 // Returns the index of the new device. 00863 //////////////////////////////////////////////////////////////////// 00864 int GraphicsWindow:: 00865 add_input_device(const GraphicsWindowInputDevice &device) { 00866 LightMutexHolder holder(_input_lock); 00867 int index = (int)_input_devices.size(); 00868 _input_devices.push_back(device); 00869 _input_devices.back().set_device_index(index); 00870 return index; 00871 } 00872 00873 //////////////////////////////////////////////////////////////////// 00874 // Function: GraphicsWindow::mouse_mode_relative 00875 // Access: Protected, Virtual 00876 // Description: detaches mouse. Only mouse delta from now on. 00877 // 00878 //////////////////////////////////////////////////////////////////// 00879 void GraphicsWindow:: 00880 mouse_mode_relative() { 00881 } 00882 00883 //////////////////////////////////////////////////////////////////// 00884 // Function: GraphicsWindow::mouse_mode_absolute 00885 // Access: Protected, Virtual 00886 // Description: reattaches mouse to location 00887 // 00888 //////////////////////////////////////////////////////////////////// 00889 void GraphicsWindow:: 00890 mouse_mode_absolute() { 00891 00892 } 00893 00894 #ifdef HAVE_PYTHON 00895 00896 //////////////////////////////////////////////////////////////////// 00897 // Function: GraphicsWindow::add_custom_event_handler 00898 // Access: Published 00899 // Description: Adds a python event handler to be called 00900 // when a window event occurs. 00901 // 00902 //////////////////////////////////////////////////////////////////// 00903 void GraphicsWindow:: 00904 add_python_event_handler(PyObject* handler, PyObject* name){ 00905 PythonGraphicsWindowProc* pgwp = new PythonGraphicsWindowProc(handler, name); 00906 _python_window_proc_classes.insert(pgwp); 00907 add_window_proc(pgwp); 00908 } 00909 00910 //////////////////////////////////////////////////////////////////// 00911 // Function: GraphicsWindow::remove_custom_event_handler 00912 // Access: Published 00913 // Description: Removes the specified python event handler. 00914 // 00915 //////////////////////////////////////////////////////////////////// 00916 void GraphicsWindow:: 00917 remove_python_event_handler(PyObject* name){ 00918 list<PythonGraphicsWindowProc*> toRemove; 00919 PythonWinProcClasses::iterator iter; 00920 for(iter = _python_window_proc_classes.begin(); iter != _python_window_proc_classes.end(); ++iter){ 00921 PythonGraphicsWindowProc* pgwp = *iter; 00922 if(PyObject_Compare(pgwp->get_name(), name) == 0) 00923 toRemove.push_back(pgwp); 00924 } 00925 list<PythonGraphicsWindowProc*>::iterator iter2; 00926 for(iter2 = toRemove.begin(); iter2 != toRemove.end(); ++iter2){ 00927 PythonGraphicsWindowProc* pgwp = *iter2; 00928 remove_window_proc(pgwp); 00929 _python_window_proc_classes.erase(pgwp); 00930 delete pgwp; 00931 } 00932 } 00933 00934 #endif // HAVE_PYTHON 00935 00936 //////////////////////////////////////////////////////////////////// 00937 // Function: GraphicsWindow::is_touch_event 00938 // Access: Published, Virtual 00939 // Description: Returns whether the specified event msg is a touch message. 00940 // 00941 //////////////////////////////////////////////////////////////////// 00942 bool GraphicsWindow:: 00943 is_touch_event(GraphicsWindowProcCallbackData* callbackData){ 00944 return false; 00945 } 00946 00947 //////////////////////////////////////////////////////////////////// 00948 // Function: GraphicsWindow::get_num_touches 00949 // Access: Published, Virtual 00950 // Description: Returns the current number of touches on this window. 00951 // 00952 //////////////////////////////////////////////////////////////////// 00953 int GraphicsWindow:: 00954 get_num_touches(){ 00955 return 0; 00956 } 00957 00958 //////////////////////////////////////////////////////////////////// 00959 // Function: GraphicsWindow::get_touch_info 00960 // Access: Published, Virtual 00961 // Description: Returns the TouchInfo object describing the specified touch. 00962 // 00963 //////////////////////////////////////////////////////////////////// 00964 TouchInfo GraphicsWindow:: 00965 get_touch_info(int index){ 00966 return TouchInfo(); 00967 } 00968 00969 //////////////////////////////////////////////////////////////////// 00970 // Function: GraphicsWindow::supports_window_procs 00971 // Access: Published, Virtual 00972 // Description: Returns whether this window supports adding of Windows proc handlers. 00973 // 00974 //////////////////////////////////////////////////////////////////// 00975 bool GraphicsWindow::supports_window_procs() const{ 00976 return false; 00977 }