00001 // Filename: graphicsWindow.cxx 00002 // Created by: mike (09Jan97) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "graphicsWindow.h" 00020 #include "graphicsPipe.h" 00021 #include "config_display.h" 00022 #include "mouseButton.h" 00023 #include "keyboardButton.h" 00024 #include "mutexHolder.h" 00025 #include "hardwareChannel.h" 00026 #include "throw_event.h" 00027 00028 #include "pmap.h" 00029 00030 TypeHandle GraphicsWindow::_type_handle; 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Function: GraphicsWindow::Constructor 00034 // Access: Protected 00035 // Description: Normally, the GraphicsWindow constructor is not 00036 // called directly; these are created instead via the 00037 // GraphicsEngine::make_window() function. 00038 //////////////////////////////////////////////////////////////////// 00039 GraphicsWindow:: 00040 GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) { 00041 #ifdef DO_MEMORY_USAGE 00042 MemoryUsage::update_type(this, this); 00043 #endif 00044 _pipe = pipe; 00045 _gsg = gsg; 00046 00047 // Some default properties for windows unless specified otherwise. 00048 // Other properties (size, title, etc.) must be explicitly 00049 // specified. 00050 _properties.set_open(false); 00051 _properties.set_undecorated(false); 00052 _properties.set_fullscreen(false); 00053 _properties.set_minimized(false); 00054 _properties.set_cursor_hidden(false); 00055 00056 _display_regions_stale = false; 00057 _window_event = "window-event"; 00058 00059 // By default, windows are set up to clear color and depth. 00060 set_clear_color_active(true); 00061 set_clear_depth_active(true); 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: GraphicsWindow::Copy Constructor 00066 // Access: Private 00067 // Description: 00068 //////////////////////////////////////////////////////////////////// 00069 GraphicsWindow:: 00070 GraphicsWindow(const GraphicsWindow &) { 00071 nassertv(false); 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: GraphicsWindow::Copy Assignment Operator 00076 // Access: Private 00077 // Description: 00078 //////////////////////////////////////////////////////////////////// 00079 void GraphicsWindow:: 00080 operator = (const GraphicsWindow &) { 00081 nassertv(false); 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: GraphicsWindow::Destructor 00086 // Access: Published, Virtual 00087 // Description: 00088 //////////////////////////////////////////////////////////////////// 00089 GraphicsWindow:: 00090 ~GraphicsWindow() { 00091 // The window should be closed by the time we destruct. 00092 nassertv(!_properties.get_open()); 00093 00094 // And we shouldn't have a GraphicsPipe pointer anymore. 00095 nassertv(_pipe == (GraphicsPipe *)NULL); 00096 00097 // We don't have to destruct our child channels explicitly, since 00098 // they are all reference-counted and will go away when their 00099 // pointers do. However, we do need to zero out their pointers to 00100 // us. 00101 Channels::iterator ci; 00102 for (ci = _channels.begin(); ci != _channels.end(); ++ci) { 00103 (*ci)->_window = NULL; 00104 } 00105 } 00106 00107 //////////////////////////////////////////////////////////////////// 00108 // Function: GraphicsWindow::get_properties 00109 // Access: Published 00110 // Description: Returns the current properties of the window. 00111 //////////////////////////////////////////////////////////////////// 00112 WindowProperties GraphicsWindow:: 00113 get_properties() const { 00114 WindowProperties result; 00115 { 00116 MutexHolder holder(_lock); 00117 result = _properties; 00118 } 00119 return result; 00120 } 00121 00122 //////////////////////////////////////////////////////////////////// 00123 // Function: GraphicsWindow::get_requested_properties 00124 // Access: Published 00125 // Description: Returns the properties of the window that are 00126 // currently requested. These properties will be 00127 // applied to the window (if valid) at the next 00128 // execution of process_events(). 00129 //////////////////////////////////////////////////////////////////// 00130 WindowProperties GraphicsWindow:: 00131 get_requested_properties() const { 00132 WindowProperties result; 00133 { 00134 MutexHolder holder(_lock); 00135 result = _requested_properties; 00136 } 00137 return result; 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: GraphicsWindow::clear_rejected_properties 00142 // Access: Published 00143 // Description: Empties the set of failed properties that will be 00144 // returned by get_rejected_properties(). 00145 //////////////////////////////////////////////////////////////////// 00146 void GraphicsWindow:: 00147 clear_rejected_properties() { 00148 MutexHolder holder(_lock); 00149 _rejected_properties.clear(); 00150 } 00151 00152 //////////////////////////////////////////////////////////////////// 00153 // Function: GraphicsWindow::get_rejected_properties 00154 // Access: Published 00155 // Description: Returns the set of properties that have recently been 00156 // requested, but could not be applied to the window for 00157 // some reason. This set of properties will remain 00158 // unchanged until they are changed by a new failed 00159 // request, or clear_rejected_properties() is called. 00160 //////////////////////////////////////////////////////////////////// 00161 WindowProperties GraphicsWindow:: 00162 get_rejected_properties() const { 00163 WindowProperties result; 00164 { 00165 MutexHolder holder(_lock); 00166 result = _rejected_properties; 00167 } 00168 return result; 00169 } 00170 00171 //////////////////////////////////////////////////////////////////// 00172 // Function: GraphicsWindow::request_properties 00173 // Access: Published 00174 // Description: Requests a property change on the window. For 00175 // example, use this method to request a window change 00176 // size or minimize or something. 00177 // 00178 // The change is not made immediately; rather, the 00179 // request is saved and will be applied the next time 00180 // the window task is run (probably at the next frame). 00181 //////////////////////////////////////////////////////////////////// 00182 void GraphicsWindow:: 00183 request_properties(const WindowProperties &requested_properties) { 00184 MutexHolder holder(_lock); 00185 _requested_properties.add_properties(requested_properties); 00186 } 00187 00188 //////////////////////////////////////////////////////////////////// 00189 // Function: GraphicsWindow::set_window_event 00190 // Access: Published 00191 // Description: Changes the name of the event that is generated when 00192 // this window is modified externally, e.g. to be 00193 // resized or closed by the user. 00194 // 00195 // By default, all windows have the same window event 00196 // unless they are explicitly changed. When the event 00197 // is generated, it includes one parameter: the window 00198 // itself. 00199 //////////////////////////////////////////////////////////////////// 00200 void GraphicsWindow:: 00201 set_window_event(const string &window_event) { 00202 MutexHolder holder(_lock); 00203 _window_event = window_event; 00204 } 00205 00206 //////////////////////////////////////////////////////////////////// 00207 // Function: GraphicsWindow::get_window_event 00208 // Access: Published 00209 // Description: Returns the name of the event that is generated when 00210 // this window is modified externally, e.g. to be 00211 // resized or closed by the user. See set_window_event(). 00212 //////////////////////////////////////////////////////////////////// 00213 string GraphicsWindow:: 00214 get_window_event() const { 00215 string result; 00216 MutexHolder holder(_lock); 00217 result = _window_event; 00218 return result; 00219 } 00220 00221 00222 //////////////////////////////////////////////////////////////////// 00223 // Function: GraphicsWindow::get_channel 00224 // Access: Public 00225 // Description: Returns a GraphicsChannel pointer that can be used to 00226 // access the indicated channel number. All windows 00227 // have at least one channel, channel 0, which 00228 // corresponds to the entire window. If the hardware 00229 // supports it, some kinds of windows may also have a 00230 // number of hardware channels available at indices 00231 // 1..n, which will correspond to a subregion of the 00232 // window. 00233 // 00234 // This function returns a GraphicsChannel pointer if a 00235 // channel is available, or NULL if it is not. If 00236 // called twice with the same index number, it will 00237 // return the same pointer. 00238 //////////////////////////////////////////////////////////////////// 00239 GraphicsChannel *GraphicsWindow:: 00240 get_channel(int index) { 00241 MutexHolder holder(_lock); 00242 nassertr(index >= 0, NULL); 00243 00244 if (index < (int)_channels.size()) { 00245 if (_channels[index] != (GraphicsChannel *)NULL) { 00246 return _channels[index]; 00247 } 00248 } 00249 00250 // This channel has never been requested before; define it. 00251 00252 PT(GraphicsChannel) chan; 00253 if (index == 0) { 00254 // Channel 0 is the default channel: the entire screen. 00255 chan = new GraphicsChannel(this); 00256 } else { 00257 // Any other channel is some hardware-specific channel. 00258 GraphicsPipe *pipe = _pipe; 00259 if (pipe != (GraphicsPipe *)NULL) { 00260 chan = _pipe->get_hw_channel(this, index); 00261 if (chan == (GraphicsChannel *)NULL) { 00262 display_cat.error() 00263 << "GraphicsWindow::get_channel() - got a NULL channel" << endl; 00264 } else { 00265 if (chan->get_window() != this) { 00266 chan = NULL; 00267 } 00268 } 00269 } 00270 } 00271 00272 if (chan != (GraphicsChannel *)NULL) { 00273 declare_channel(index, chan); 00274 } 00275 00276 return chan; 00277 } 00278 00279 //////////////////////////////////////////////////////////////////// 00280 // Function: GraphicsWindow::remove_channel 00281 // Access: Public 00282 // Description: Deletes a GraphicsChannel that was previously created 00283 // via a call to get_channel(). Note that the channel 00284 // is not actually deleted until all pointers to it are 00285 // cleared. 00286 //////////////////////////////////////////////////////////////////// 00287 void GraphicsWindow:: 00288 remove_channel(int index) { 00289 MutexHolder holder(_lock); 00290 if (index >= 0 && index < (int)_channels.size()) { 00291 _channels[index].clear(); 00292 } 00293 } 00294 00295 //////////////////////////////////////////////////////////////////// 00296 // Function: GraphicsWindow::get_max_channel_index 00297 // Access: Public 00298 // Description: Returns the largest channel index number yet created, 00299 // plus 1. All channels associated with this window 00300 // will have an index number in the range [0, 00301 // get_max_channel_index()). This function, in 00302 // conjunction with is_channel_defined(), below, may be 00303 // used to determine the complete set of channels 00304 // associated with the window. 00305 //////////////////////////////////////////////////////////////////// 00306 int GraphicsWindow:: 00307 get_max_channel_index() const { 00308 int result; 00309 { 00310 MutexHolder holder(_lock); 00311 result = _channels.size(); 00312 } 00313 return result; 00314 } 00315 00316 //////////////////////////////////////////////////////////////////// 00317 // Function: GraphicsWindow::is_channel_defined 00318 // Access: Public 00319 // Description: Returns true if the channel with the given index 00320 // number has already been defined, false if it hasn't. 00321 // If this returns true, calling get_channel() on the 00322 // given index number will return the channel pointer. 00323 // If it returns false, calling get_channel() will 00324 // create and return a new channel pointer. 00325 //////////////////////////////////////////////////////////////////// 00326 bool GraphicsWindow:: 00327 is_channel_defined(int index) const { 00328 bool result; 00329 { 00330 MutexHolder holder(_lock); 00331 if (index < 0 || index >= (int)_channels.size()) { 00332 result = false; 00333 } else { 00334 result = (_channels[index] != (GraphicsChannel *)NULL); 00335 } 00336 } 00337 return result; 00338 } 00339 00340 //////////////////////////////////////////////////////////////////// 00341 // Function: GraphicsWindow::get_num_display_regions 00342 // Access: Published 00343 // Description: Returns the number of active DisplayRegions that have 00344 // been created within the various layers and channels 00345 // of the window. 00346 //////////////////////////////////////////////////////////////////// 00347 int GraphicsWindow:: 00348 get_num_display_regions() const { 00349 determine_display_regions(); 00350 int result; 00351 { 00352 MutexHolder holder(_lock); 00353 result = _display_regions.size(); 00354 } 00355 return result; 00356 } 00357 00358 //////////////////////////////////////////////////////////////////// 00359 // Function: GraphicsWindow::get_display_region 00360 // Access: Published 00361 // Description: Returns the nth active DisplayRegion of those that 00362 // have been created within the various layers and 00363 // channels of the window. This may return NULL if n is 00364 // out of bounds; particularly likely if the number of 00365 // display regions has changed since the last call to 00366 // get_num_display_regions(). 00367 //////////////////////////////////////////////////////////////////// 00368 DisplayRegion *GraphicsWindow:: 00369 get_display_region(int n) const { 00370 determine_display_regions(); 00371 DisplayRegion *result; 00372 { 00373 MutexHolder holder(_lock); 00374 if (n >= 0 && n < (int)_display_regions.size()) { 00375 result = _display_regions[n]; 00376 } else { 00377 result = NULL; 00378 } 00379 } 00380 return result; 00381 } 00382 00383 //////////////////////////////////////////////////////////////////// 00384 // Function: GraphicsWindow::get_num_input_devices 00385 // Access: Published 00386 // Description: Returns the number of separate input devices 00387 // associated with the window. Typically, a window will 00388 // have exactly one input device: the keyboard/mouse 00389 // pair. However, some windows may have no input 00390 // devices, and others may add additional devices, for 00391 // instance for a joystick. 00392 //////////////////////////////////////////////////////////////////// 00393 int GraphicsWindow:: 00394 get_num_input_devices() const { 00395 int result; 00396 { 00397 MutexHolder holder(_input_lock); 00398 result = _input_devices.size(); 00399 } 00400 return result; 00401 } 00402 00403 //////////////////////////////////////////////////////////////////// 00404 // Function: GraphicsWindow::get_input_device_name 00405 // Access: Published 00406 // Description: Returns the name of the nth input device. 00407 //////////////////////////////////////////////////////////////////// 00408 string GraphicsWindow:: 00409 get_input_device_name(int device) const { 00410 string result; 00411 { 00412 MutexHolder holder(_input_lock); 00413 nassertr(device >= 0 && device < (int)_input_devices.size(), ""); 00414 result = _input_devices[device].get_name(); 00415 } 00416 return result; 00417 } 00418 00419 //////////////////////////////////////////////////////////////////// 00420 // Function: GraphicsWindow::has_pointer 00421 // Access: Published 00422 // Description: Returns true if the nth input device has a 00423 // screen-space pointer (for instance, a mouse), false 00424 // otherwise. 00425 //////////////////////////////////////////////////////////////////// 00426 bool GraphicsWindow:: 00427 has_pointer(int device) const { 00428 bool result; 00429 { 00430 MutexHolder holder(_input_lock); 00431 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00432 result = _input_devices[device].has_pointer(); 00433 } 00434 return result; 00435 } 00436 00437 //////////////////////////////////////////////////////////////////// 00438 // Function: GraphicsWindow::has_keyboard 00439 // Access: Published 00440 // Description: Returns true if the nth input device has a keyboard, 00441 // false otherwise. 00442 //////////////////////////////////////////////////////////////////// 00443 bool GraphicsWindow:: 00444 has_keyboard(int device) const { 00445 bool result; 00446 { 00447 MutexHolder holder(_input_lock); 00448 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00449 result = _input_devices[device].has_keyboard(); 00450 } 00451 return result; 00452 } 00453 00454 //////////////////////////////////////////////////////////////////// 00455 // Function: GraphicsWindow::get_mouse_data 00456 // Access: Public 00457 // Description: Returns the MouseData associated with the nth input 00458 // device. 00459 //////////////////////////////////////////////////////////////////// 00460 MouseData GraphicsWindow:: 00461 get_mouse_data(int device) const { 00462 MouseData result; 00463 { 00464 MutexHolder holder(_input_lock); 00465 nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData()); 00466 result = _input_devices[device].get_mouse_data(); 00467 } 00468 return result; 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: GraphicsWindow::has_button_event 00473 // Access: Public 00474 // Description: Returns true if the indicated device has a pending 00475 // button event (a mouse button or keyboard button 00476 // down/up), false otherwise. If this returns true, the 00477 // particular event may be extracted via 00478 // get_button_event(). 00479 //////////////////////////////////////////////////////////////////// 00480 bool GraphicsWindow:: 00481 has_button_event(int device) const { 00482 bool result; 00483 { 00484 MutexHolder holder(_input_lock); 00485 nassertr(device >= 0 && device < (int)_input_devices.size(), false); 00486 result = _input_devices[device].has_button_event(); 00487 } 00488 return result; 00489 } 00490 00491 //////////////////////////////////////////////////////////////////// 00492 // Function: GraphicsWindow::get_button_event 00493 // Access: Public 00494 // Description: Assuming a previous call to has_button_event() 00495 // returned true, this returns the pending button event. 00496 //////////////////////////////////////////////////////////////////// 00497 ButtonEvent GraphicsWindow:: 00498 get_button_event(int device) { 00499 ButtonEvent result; 00500 { 00501 MutexHolder holder(_input_lock); 00502 nassertr(device >= 0 && device < (int)_input_devices.size(), ButtonEvent()); 00503 nassertr(_input_devices[device].has_button_event(), ButtonEvent()); 00504 result = _input_devices[device].get_button_event(); 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::make_scratch_display_region 00538 // Access: Public 00539 // Description: Allocates and returns a temporary DisplayRegion that 00540 // may be used to render offscreen into. This 00541 // DisplayRegion is not associated with any layer. 00542 // 00543 // To allocate a normal DisplayRegion for rendering, use 00544 // the interface provided in GraphicsLayer. 00545 //////////////////////////////////////////////////////////////////// 00546 PT(DisplayRegion) GraphicsWindow:: 00547 make_scratch_display_region(int x_size, int y_size) const { 00548 #ifndef NDEBUG 00549 { 00550 MutexHolder holder(_lock); 00551 if (x_size > _properties.get_x_size() || 00552 y_size > _properties.get_y_size()) { 00553 display_cat.error() 00554 << "make_scratch_display_region(): requested region of size " 00555 << x_size << ", " << y_size << " is larger than window of size " 00556 << _properties.get_x_size() << ", " << _properties.get_y_size() 00557 << ".\n"; 00558 x_size = min(x_size, _properties.get_x_size()); 00559 y_size = min(y_size, _properties.get_y_size()); 00560 } 00561 } 00562 #endif 00563 00564 PT(DisplayRegion) region = new DisplayRegion(x_size, y_size); 00565 region->copy_clear_settings(*this); 00566 return region; 00567 } 00568 00569 //////////////////////////////////////////////////////////////////// 00570 // Function: GraphicsWindow::begin_frame 00571 // Access: Public, Virtual 00572 // Description: This function will be called within the draw thread 00573 // before beginning rendering for a given frame. It 00574 // should do whatever setup is required, and return true 00575 // if the frame should be rendered, or false if it 00576 // should be skipped. 00577 //////////////////////////////////////////////////////////////////// 00578 bool GraphicsWindow:: 00579 begin_frame() { 00580 if (_gsg == (GraphicsStateGuardian *)NULL) { 00581 return false; 00582 } 00583 00584 // Okay, we already have a GSG, so activate it. 00585 make_current(); 00586 return _gsg->begin_frame(); 00587 } 00588 00589 //////////////////////////////////////////////////////////////////// 00590 // Function: GraphicsWindow::clear 00591 // Access: Public 00592 // Description: Clears the entire framebuffer before rendering, 00593 // according to the settings of get_color_clear_active() 00594 // and get_depth_clear_active() (inherited from 00595 // ClearableRegion). 00596 // 00597 // This function is called only within the draw thread. 00598 //////////////////////////////////////////////////////////////////// 00599 void GraphicsWindow:: 00600 clear() { 00601 if (is_any_clear_active()) { 00602 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 00603 00604 int x_size, y_size; 00605 { 00606 MutexHolder holder(_lock); 00607 x_size = _properties.get_x_size(); 00608 y_size = _properties.get_y_size(); 00609 } 00610 PT(DisplayRegion) win_dr = 00611 make_scratch_display_region(x_size, y_size); 00612 DisplayRegionStack old_dr = _gsg->push_display_region(win_dr); 00613 _gsg->clear(this); 00614 _gsg->pop_display_region(old_dr); 00615 } 00616 } 00617 00618 //////////////////////////////////////////////////////////////////// 00619 // Function: GraphicsWindow::end_frame 00620 // Access: Public, Virtual 00621 // Description: This function will be called within the draw thread 00622 // after rendering is completed for a given frame. It 00623 // should do whatever finalization is required. 00624 //////////////////////////////////////////////////////////////////// 00625 void GraphicsWindow:: 00626 end_frame() { 00627 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 00628 _gsg->end_frame(); 00629 } 00630 00631 //////////////////////////////////////////////////////////////////// 00632 // Function: GraphicsWindow::make_current 00633 // Access: Public, Virtual 00634 // Description: This function will be called within the draw thread 00635 // during begin_frame() to ensure the graphics context 00636 // is ready for drawing. 00637 //////////////////////////////////////////////////////////////////// 00638 void GraphicsWindow:: 00639 make_current() { 00640 } 00641 00642 //////////////////////////////////////////////////////////////////// 00643 // Function: GraphicsWindow::release_gsg 00644 // Access: Public 00645 // Description: Releases the current GSG pointer, if it is currently 00646 // held, and resets the GSG to NULL. The window will be 00647 // permanently unable to render; this is normally called 00648 // only just before destroying the window. This should 00649 // only be called from within the draw thread. 00650 //////////////////////////////////////////////////////////////////// 00651 void GraphicsWindow:: 00652 release_gsg() { 00653 _gsg.clear(); 00654 } 00655 00656 //////////////////////////////////////////////////////////////////// 00657 // Function: GraphicsWindow::begin_flip 00658 // Access: Public, Virtual 00659 // Description: This function will be called within the draw thread 00660 // after end_frame() has been called on all windows, to 00661 // initiate the exchange of the front and back buffers. 00662 // 00663 // This should instruct the window to prepare for the 00664 // flip at the next video sync, but it should not wait. 00665 // 00666 // We have the two separate functions, begin_flip() and 00667 // end_flip(), to make it easier to flip all of the 00668 // windows at the same time. 00669 //////////////////////////////////////////////////////////////////// 00670 void GraphicsWindow:: 00671 begin_flip() { 00672 } 00673 00674 //////////////////////////////////////////////////////////////////// 00675 // Function: GraphicsWindow::end_flip 00676 // Access: Public, Virtual 00677 // Description: This function will be called within the draw thread 00678 // after begin_flip() has been called on all windows, to 00679 // finish the exchange of the front and back buffers. 00680 // 00681 // This should cause the window to wait for the flip, if 00682 // necessary. 00683 //////////////////////////////////////////////////////////////////// 00684 void GraphicsWindow:: 00685 end_flip() { 00686 } 00687 00688 //////////////////////////////////////////////////////////////////// 00689 // Function: GraphicsWindow::process_events 00690 // Access: Public, Virtual 00691 // Description: Do whatever processing is necessary to ensure that 00692 // the window responds to user events. Also, honor any 00693 // requests recently made via request_properties(). 00694 // 00695 // This function is called only within the window 00696 // thread. 00697 //////////////////////////////////////////////////////////////////// 00698 void GraphicsWindow:: 00699 process_events() { 00700 if (_requested_properties.is_any_specified()) { 00701 // We don't bother to grab the mutex until after we have already 00702 // checked whether any properties have been specified. This is 00703 // technically sloppy, but it ought to be o.k. since it's just a 00704 // bitmask after all. 00705 WindowProperties properties; 00706 { 00707 MutexHolder holder(_lock); 00708 properties = _requested_properties; 00709 _requested_properties.clear(); 00710 00711 set_properties_now(properties); 00712 if (properties.is_any_specified()) { 00713 display_cat.info() 00714 << "Unable to set window properties: " << properties << "\n"; 00715 _rejected_properties.add_properties(properties); 00716 } 00717 } 00718 } 00719 } 00720 00721 //////////////////////////////////////////////////////////////////// 00722 // Function: GraphicsWindow::set_properties_now 00723 // Access: Public, Virtual 00724 // Description: Applies the requested set of properties to the 00725 // window, if possible, for instance to request a change 00726 // in size or minimization status. 00727 // 00728 // The window properties are applied immediately, rather 00729 // than waiting until the next frame. This implies that 00730 // this method may *only* be called from within the 00731 // window thread. 00732 // 00733 // The properties that have been applied are cleared 00734 // from the structure by this function; so on return, 00735 // whatever remains in the properties structure are 00736 // those that were unchanged for some reason (probably 00737 // because the underlying interface does not support 00738 // changing that property on an open window). 00739 //////////////////////////////////////////////////////////////////// 00740 void GraphicsWindow:: 00741 set_properties_now(WindowProperties &properties) { 00742 if (properties.has_open() && 00743 properties.get_open() != _properties.get_open()) { 00744 // Open or close a new window. In this case we can get all of the 00745 // properties at once. 00746 _properties.add_properties(properties); 00747 properties.clear(); 00748 00749 if (_properties.get_open()) { 00750 if (open_window()) { 00751 // When the window is first opened, force its size to be 00752 // broadcast to its display regions. 00753 Channels::iterator ci; 00754 for (ci = _channels.begin(); ci != _channels.end(); ++ci) { 00755 GraphicsChannel *chan = (*ci); 00756 chan->window_resized(_properties.get_x_size(), 00757 _properties.get_y_size()); 00758 } 00759 00760 } else { 00761 // Since we can't even open the window, tag the 00762 // _rejected_properties with all of the window properties that 00763 // failed. 00764 _rejected_properties.add_properties(_properties); 00765 00766 // And mark the window closed. 00767 _properties.set_open(false); 00768 } 00769 00770 } else { 00771 // We can't close the window if its GSG hasn't been released 00772 // yet. 00773 nassertv(_gsg == (GraphicsStateGuardian *)NULL); 00774 close_window(); 00775 } 00776 return; 00777 } 00778 00779 if (!_properties.get_open()) { 00780 // The window is not currently open; we can set properties at 00781 // will. 00782 _properties.add_properties(properties); 00783 properties.clear(); 00784 return; 00785 } 00786 00787 // The window is already open; we are limited to what we can change 00788 // on the fly. 00789 00790 if (properties.has_size() || properties.has_origin()) { 00791 // Consider changing the window's size and/or position. 00792 WindowProperties reshape_props; 00793 if (properties.has_size()) { 00794 reshape_props.set_size(properties.get_x_size(), properties.get_y_size()); 00795 } else { 00796 reshape_props.set_size(_properties.get_x_size(), _properties.get_y_size()); 00797 } 00798 if (properties.has_origin() && !is_fullscreen()) { 00799 reshape_props.set_origin(properties.get_x_origin(), properties.get_y_origin()); 00800 } else { 00801 reshape_props.set_origin(_properties.get_x_origin(), _properties.get_y_origin()); 00802 } 00803 00804 if (reshape_props.get_x_size() != _properties.get_x_size() || 00805 reshape_props.get_y_size() != _properties.get_y_size() || 00806 reshape_props.get_x_origin() != _properties.get_x_origin() || 00807 reshape_props.get_y_origin() != _properties.get_y_origin()) { 00808 if (do_reshape_request(reshape_props.get_x_origin(), 00809 reshape_props.get_y_origin(), 00810 reshape_props.get_x_size(), 00811 reshape_props.get_y_size())) { 00812 system_changed_size(reshape_props.get_x_size(), 00813 reshape_props.get_y_size()); 00814 _properties.add_properties(reshape_props); 00815 properties.clear_size(); 00816 properties.clear_origin(); 00817 } 00818 } 00819 } 00820 00821 if (properties.has_fullscreen() && 00822 properties.get_fullscreen() == _properties.get_fullscreen()) { 00823 // Fullscreen property specified, but unchanged. 00824 properties.clear_fullscreen(); 00825 } 00826 } 00827 00828 //////////////////////////////////////////////////////////////////// 00829 // Function: GraphicsWindow::close_window 00830 // Access: Protected, Virtual 00831 // Description: Closes the window right now. Called from the window 00832 // thread. 00833 //////////////////////////////////////////////////////////////////// 00834 void GraphicsWindow:: 00835 close_window() { 00836 } 00837 00838 //////////////////////////////////////////////////////////////////// 00839 // Function: GraphicsWindow::open_window 00840 // Access: Protected, Virtual 00841 // Description: Opens the window right now. Called from the window 00842 // thread. Returns true if the window is successfully 00843 // opened, or false if there was a problem. 00844 //////////////////////////////////////////////////////////////////// 00845 bool GraphicsWindow:: 00846 open_window() { 00847 return false; 00848 } 00849 00850 //////////////////////////////////////////////////////////////////// 00851 // Function: GraphicsWindow::open_window 00852 // Access: Protected, Virtual 00853 // Description: Called from the window thread in response to a request 00854 // from within the code (via request_properties()) to 00855 // change the size and/or position of the window. 00856 // Returns true if the window is successfully changed, 00857 // or false if there was a problem. 00858 //////////////////////////////////////////////////////////////////// 00859 bool GraphicsWindow:: 00860 do_reshape_request(int x_origin, int y_origin, int x_size, int y_size) { 00861 return false; 00862 } 00863 00864 //////////////////////////////////////////////////////////////////// 00865 // Function: GraphicsWindow::system_changed_properties 00866 // Access: Protected 00867 // Description: Should be called (from within the window thread) when 00868 // process_events() detects an external change in some 00869 // important window property; for instance, when the 00870 // user resizes the window. 00871 //////////////////////////////////////////////////////////////////// 00872 void GraphicsWindow:: 00873 system_changed_properties(const WindowProperties &properties) { 00874 MutexHolder holder(_lock); 00875 00876 if (properties.has_size()) { 00877 system_changed_size(properties.get_x_size(), properties.get_y_size()); 00878 } 00879 00880 WindowProperties old_properties = _properties; 00881 _properties.add_properties(properties); 00882 if (_properties != old_properties) { 00883 throw_event(_window_event, this); 00884 } 00885 } 00886 00887 //////////////////////////////////////////////////////////////////// 00888 // Function: GraphicsWindow::system_changed_size 00889 // Access: Protected 00890 // Description: An internal function to update all the channels with 00891 // the new size of the window. This should always be 00892 // called before changing the _size members of the 00893 // _properties structure. 00894 //////////////////////////////////////////////////////////////////// 00895 void GraphicsWindow:: 00896 system_changed_size(int x_size, int y_size) { 00897 if (x_size != _properties.get_x_size() || 00898 y_size != _properties.get_y_size()) { 00899 Channels::iterator ci; 00900 for (ci = _channels.begin(); ci != _channels.end(); ++ci) { 00901 GraphicsChannel *chan = (*ci); 00902 chan->window_resized(x_size, y_size); 00903 } 00904 } 00905 } 00906 00907 //////////////////////////////////////////////////////////////////// 00908 // Function: GraphicsWindow::declare_channel 00909 // Access: Protected 00910 // Description: An internal function to add the indicated 00911 // newly-created channel to the list at the indicated 00912 // channel number. 00913 // 00914 // The caller must grab and hold _lock before making 00915 // this call. 00916 //////////////////////////////////////////////////////////////////// 00917 void GraphicsWindow:: 00918 declare_channel(int index, GraphicsChannel *chan) { 00919 nassertv(index >= 0); 00920 if (index >= (int)_channels.size()) { 00921 _channels.reserve(index); 00922 while (index >= (int)_channels.size()) { 00923 _channels.push_back(NULL); 00924 } 00925 } 00926 00927 nassertv(index < (int)_channels.size()); 00928 _channels[index] = chan; 00929 } 00930 00931 //////////////////////////////////////////////////////////////////// 00932 // Function: GraphicsWindow::do_determine_display_regions 00933 // Access: Private 00934 // Description: Recomputes the list of active DisplayRegions within 00935 // the window. 00936 //////////////////////////////////////////////////////////////////// 00937 void GraphicsWindow:: 00938 do_determine_display_regions() { 00939 MutexHolder holder(_lock); 00940 _display_regions_stale = false; 00941 _display_regions.clear(); 00942 Channels::const_iterator ci; 00943 for (ci = _channels.begin(); ci != _channels.end(); ++ci) { 00944 GraphicsChannel *chan = (*ci); 00945 if (chan->is_active()) { 00946 GraphicsChannel::GraphicsLayers::const_iterator li; 00947 for (li = chan->_layers.begin(); li != chan->_layers.end(); ++li) { 00948 GraphicsLayer *layer = (*li); 00949 if (layer->is_active()) { 00950 GraphicsLayer::DisplayRegions::const_iterator dri; 00951 for (dri = layer->_display_regions.begin(); 00952 dri != layer->_display_regions.end(); 00953 ++dri) { 00954 DisplayRegion *dr = (*dri); 00955 if (dr->is_active()) { 00956 _display_regions.push_back(dr); 00957 } 00958 } 00959 } 00960 } 00961 } 00962 } 00963 }