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