mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
978 lines
37 KiB
C++
978 lines
37 KiB
C++
// Filename: graphicsWindow.cxx
|
|
// Created by: mike (09Jan97)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "graphicsWindow.h"
|
|
#include "graphicsPipe.h"
|
|
#include "config_display.h"
|
|
#include "mouseButton.h"
|
|
#include "keyboardButton.h"
|
|
#include "lightMutexHolder.h"
|
|
#include "lightReMutexHolder.h"
|
|
#include "throw_event.h"
|
|
#include "string_utils.h"
|
|
|
|
TypeHandle GraphicsWindow::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::Constructor
|
|
// Access: Protected
|
|
// Description: Normally, the GraphicsWindow constructor is not
|
|
// called directly; these are created instead via the
|
|
// GraphicsEngine::make_window() function.
|
|
////////////////////////////////////////////////////////////////////
|
|
GraphicsWindow::
|
|
GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
|
|
const string &name,
|
|
const FrameBufferProperties &fb_prop,
|
|
const WindowProperties &win_prop,
|
|
int flags,
|
|
GraphicsStateGuardian *gsg,
|
|
GraphicsOutput *host) :
|
|
GraphicsOutput(engine, pipe, name, fb_prop, win_prop, flags, gsg, host, true),
|
|
_input_lock("GraphicsWindow::_input_lock"),
|
|
_properties_lock("GraphicsWindow::_properties_lock")
|
|
{
|
|
#ifdef DO_MEMORY_USAGE
|
|
MemoryUsage::update_type(this, this);
|
|
#endif
|
|
|
|
if (display_cat.is_debug()) {
|
|
display_cat.debug()
|
|
<< "Creating new window " << get_name() << "\n";
|
|
}
|
|
|
|
_properties.set_open(false);
|
|
_properties.set_undecorated(false);
|
|
_properties.set_fullscreen(false);
|
|
_properties.set_minimized(false);
|
|
_properties.set_cursor_hidden(false);
|
|
|
|
request_properties(WindowProperties::get_default());
|
|
request_properties(win_prop);
|
|
|
|
_window_event = "window-event";
|
|
_got_expose_event = false;
|
|
_unexposed_draw = win_unexposed_draw;
|
|
set_pixel_zoom(pixel_zoom);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::Destructor
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
GraphicsWindow::
|
|
~GraphicsWindow() {
|
|
// Clean up python event handlers.
|
|
#ifdef HAVE_PYTHON
|
|
PythonWinProcClasses::iterator iter;
|
|
for (iter = _python_window_proc_classes.begin();
|
|
iter != _python_window_proc_classes.end();
|
|
++iter) {
|
|
delete *iter;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_properties
|
|
// Access: Published
|
|
// Description: Returns the current properties of the window.
|
|
////////////////////////////////////////////////////////////////////
|
|
const WindowProperties GraphicsWindow::
|
|
get_properties() const {
|
|
WindowProperties result;
|
|
{
|
|
LightReMutexHolder holder(_properties_lock);
|
|
result = _properties;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_requested_properties
|
|
// Access: Published
|
|
// Description: Returns the properties of the window that are
|
|
// currently requested. These properties will be
|
|
// applied to the window (if valid) at the next
|
|
// execution of process_events().
|
|
////////////////////////////////////////////////////////////////////
|
|
const WindowProperties GraphicsWindow::
|
|
get_requested_properties() const {
|
|
WindowProperties result;
|
|
{
|
|
LightReMutexHolder holder(_properties_lock);
|
|
result = _requested_properties;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::clear_rejected_properties
|
|
// Access: Published
|
|
// Description: Empties the set of failed properties that will be
|
|
// returned by get_rejected_properties().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
clear_rejected_properties() {
|
|
LightReMutexHolder holder(_properties_lock);
|
|
_rejected_properties.clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_rejected_properties
|
|
// Access: Published
|
|
// Description: Returns the set of properties that have recently been
|
|
// requested, but could not be applied to the window for
|
|
// some reason. This set of properties will remain
|
|
// unchanged until they are changed by a new failed
|
|
// request, or clear_rejected_properties() is called.
|
|
////////////////////////////////////////////////////////////////////
|
|
WindowProperties GraphicsWindow::
|
|
get_rejected_properties() const {
|
|
WindowProperties result;
|
|
{
|
|
LightReMutexHolder holder(_properties_lock);
|
|
result = _rejected_properties;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::request_properties
|
|
// Access: Published
|
|
// Description: Requests a property change on the window. For
|
|
// example, use this method to request a window change
|
|
// size or minimize or something.
|
|
//
|
|
// The change is not made immediately; rather, the
|
|
// request is saved and will be applied the next time
|
|
// the window task is run (probably at the next frame).
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
request_properties(const WindowProperties &requested_properties) {
|
|
LightReMutexHolder holder(_properties_lock);
|
|
_requested_properties.add_properties(requested_properties);
|
|
|
|
if (!_has_size && _requested_properties.has_size()) {
|
|
// If we just requested a particular size, anticipate that it will
|
|
// stick. This is helpful for the MultitexReducer, which needs to
|
|
// know the size of the textures that it will be working with,
|
|
// even if the texture hasn't been fully generated yet.
|
|
_x_size = _requested_properties.get_x_size();
|
|
_y_size = _requested_properties.get_y_size();
|
|
|
|
// Don't set _has_size yet, because we don't really know yet.
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::is_active
|
|
// Access: Published, Virtual
|
|
// Description: Returns true if the window is ready to be rendered
|
|
// into, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
is_active() const {
|
|
// Make this smarter?
|
|
return GraphicsOutput::is_active() && _properties.get_open() && !_properties.get_minimized();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::set_window_event
|
|
// Access: Published
|
|
// Description: Changes the name of the event that is generated when
|
|
// this window is modified externally, e.g. to be
|
|
// resized or closed by the user.
|
|
//
|
|
// By default, all windows have the same window event
|
|
// unless they are explicitly changed. When the event
|
|
// is generated, it includes one parameter: the window
|
|
// itself.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
set_window_event(const string &window_event) {
|
|
LightReMutexHolder holder(_properties_lock);
|
|
_window_event = window_event;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_window_event
|
|
// Access: Published
|
|
// Description: Returns the name of the event that is generated when
|
|
// this window is modified externally, e.g. to be
|
|
// resized or closed by the user. See set_window_event().
|
|
////////////////////////////////////////////////////////////////////
|
|
string GraphicsWindow::
|
|
get_window_event() const {
|
|
string result;
|
|
LightReMutexHolder holder(_properties_lock);
|
|
result = _window_event;
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::set_close_request_event
|
|
// Access: Published
|
|
// Description: Sets the event that is triggered when the user
|
|
// requests to close the window, e.g. via alt-F4, or
|
|
// clicking on the close box.
|
|
//
|
|
// The default for each window is for this event to be
|
|
// the empty string, which means the window-close
|
|
// request is handled immediately by Panda (and the
|
|
// window will be closed without the app getting a
|
|
// chance to intervene). If you set this to a nonempty
|
|
// string, then the window is not closed, but instead
|
|
// the event is thrown. It is then up to the app to
|
|
// respond appropriately, for instance by presenting an
|
|
// "are you sure?" dialog box, and eventually calling
|
|
// close_window() when the user is sure.
|
|
//
|
|
// It is considered poor form to set this string and
|
|
// then not handle the event. This can frustrate the
|
|
// user by making it difficult for him to cleanly shut
|
|
// down the application (and may force the user to
|
|
// hard-kill the app, or reboot the machine).
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
set_close_request_event(const string &close_request_event) {
|
|
LightReMutexHolder holder(_properties_lock);
|
|
_close_request_event = close_request_event;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_close_request_event
|
|
// Access: Published
|
|
// Description: Returns the name of the event set via
|
|
// set_close_request_event(). If this string is
|
|
// nonempty, then when the user requests to close
|
|
// window, this event will be generated instead. See
|
|
// set_close_request_event().
|
|
////////////////////////////////////////////////////////////////////
|
|
string GraphicsWindow::
|
|
get_close_request_event() const {
|
|
string result;
|
|
LightReMutexHolder holder(_properties_lock);
|
|
result = _close_request_event;
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_num_input_devices
|
|
// Access: Published
|
|
// Description: Returns the number of separate input devices
|
|
// associated with the window. Typically, a window will
|
|
// have exactly one input device: the keyboard/mouse
|
|
// pair. However, some windows may have no input
|
|
// devices, and others may add additional devices, for
|
|
// instance for a joystick.
|
|
////////////////////////////////////////////////////////////////////
|
|
int GraphicsWindow::
|
|
get_num_input_devices() const {
|
|
int result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
result = _input_devices.size();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_input_device_name
|
|
// Access: Published
|
|
// Description: Returns the name of the nth input device.
|
|
////////////////////////////////////////////////////////////////////
|
|
string GraphicsWindow::
|
|
get_input_device_name(int device) const {
|
|
string result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), "");
|
|
result = _input_devices[device].get_name();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::has_pointer
|
|
// Access: Published
|
|
// Description: Returns true if the nth input device has a
|
|
// screen-space pointer (for instance, a mouse), false
|
|
// otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
has_pointer(int device) const {
|
|
bool result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), false);
|
|
result = _input_devices[device].has_pointer();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::has_keyboard
|
|
// Access: Published
|
|
// Description: Returns true if the nth input device has a keyboard,
|
|
// false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
has_keyboard(int device) const {
|
|
bool result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), false);
|
|
result = _input_devices[device].has_keyboard();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::enable_pointer_events
|
|
// Access: Published
|
|
// Description: Turn on the generation of pointer events.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
enable_pointer_events(int device) {
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertv(device >= 0 && device < (int)_input_devices.size());
|
|
_input_devices[device].enable_pointer_events();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::disable_pointer_events
|
|
// Access: Published
|
|
// Description: Turn off the generation of pointer events.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
disable_pointer_events(int device) {
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertv(device >= 0 && device < (int)_input_devices.size());
|
|
_input_devices[device].disable_pointer_events();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::enable_pointer_mode
|
|
// Access: Published
|
|
// Description: See GraphicsWindowInputDevice::enable_pointer_mode
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
enable_pointer_mode(int device, double speed) {
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertv(device >= 0 && device < (int)_input_devices.size());
|
|
_input_devices[device].enable_pointer_mode(speed);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::disable_pointer_events
|
|
// Access: Published
|
|
// Description: See GraphicsWindowInputDevice::disable_pointer_mode
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
disable_pointer_mode(int device) {
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertv(device >= 0 && device < (int)_input_devices.size());
|
|
_input_devices[device].disable_pointer_mode();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_pointer
|
|
// Access: Published
|
|
// Description: Returns the MouseData associated with the nth input
|
|
// device's pointer.
|
|
////////////////////////////////////////////////////////////////////
|
|
MouseData GraphicsWindow::
|
|
get_pointer(int device) const {
|
|
MouseData result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData());
|
|
result = _input_devices[device].get_pointer();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::move_pointer
|
|
// Access: Published, Virtual
|
|
// Description: Forces the pointer to the indicated position within
|
|
// the window, if possible.
|
|
//
|
|
// Returns true if successful, false on failure. This
|
|
// may fail if the mouse is not currently within the
|
|
// window, or if the API doesn't support this operation.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
move_pointer(int, int, int) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::close_ime
|
|
// Access: Published, Virtual
|
|
// Description: Forces the ime window to close if any
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
close_ime() {
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::has_button_event
|
|
// Access: Public
|
|
// Description: Returns true if the indicated device has a pending
|
|
// button event (a mouse button or keyboard button
|
|
// down/up), false otherwise. If this returns true, the
|
|
// particular event may be extracted via
|
|
// get_button_event().
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
has_button_event(int device) const {
|
|
bool result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), false);
|
|
result = _input_devices[device].has_button_event();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_button_event
|
|
// Access: Public
|
|
// Description: Assuming a previous call to has_button_event()
|
|
// returned true, this returns the pending button event.
|
|
////////////////////////////////////////////////////////////////////
|
|
ButtonEvent GraphicsWindow::
|
|
get_button_event(int device) {
|
|
ButtonEvent result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), ButtonEvent());
|
|
nassertr(_input_devices[device].has_button_event(), ButtonEvent());
|
|
result = _input_devices[device].get_button_event();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::has_pointer_event
|
|
// Access: Public
|
|
// Description: Returns true if the indicated device has a pending
|
|
// pointer event (a mouse movement). If this returns
|
|
// true, the particular event may be extracted via
|
|
// get_pointer_events().
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
has_pointer_event(int device) const {
|
|
bool result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), false);
|
|
result = _input_devices[device].has_pointer_event();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_pointer_events
|
|
// Access: Public
|
|
// Description: Assuming a previous call to has_pointer_event()
|
|
// returned true, this returns the pending pointer event list.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(PointerEventList) GraphicsWindow::
|
|
get_pointer_events(int device) {
|
|
PT(PointerEventList) result;
|
|
{
|
|
LightMutexHolder holder(_input_lock);
|
|
nassertr(device >= 0 && device < (int)_input_devices.size(), NULL);
|
|
nassertr(_input_devices[device].has_pointer_event(), NULL);
|
|
result = _input_devices[device].get_pointer_events();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::verify_window_sizes
|
|
// Access: Public, Virtual
|
|
// Description: Determines which of the indicated window sizes are
|
|
// supported by available hardware (e.g. in fullscreen
|
|
// mode).
|
|
//
|
|
// On entry, dimen is an array containing contiguous x,y
|
|
// pairs specifying possible display sizes; it is
|
|
// numsizes*2 words long. The function will zero out
|
|
// any invalid x,y size pairs. The return value is the
|
|
// number of valid sizes that were found.
|
|
//
|
|
// Note this doesn't guarantee a resize attempt will
|
|
// work; you still need to check the return value.
|
|
//
|
|
// (It might be better to implement some sort of query
|
|
// interface that returns an array of supported sizes,
|
|
// but this way is somewhat simpler and will do the job
|
|
// on most cards, assuming they handle the std sizes the
|
|
// app knows about.)
|
|
////////////////////////////////////////////////////////////////////
|
|
int GraphicsWindow::
|
|
verify_window_sizes(int numsizes, int *dimen) {
|
|
return numsizes;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::request_open
|
|
// Access: Public, Virtual
|
|
// Description: This is called by the GraphicsEngine to request that
|
|
// the window (or whatever) open itself or, in general,
|
|
// make itself valid, at the next call to
|
|
// process_events().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
request_open() {
|
|
WindowProperties open_properties;
|
|
open_properties.set_open(true);
|
|
request_properties(open_properties);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::request_close
|
|
// Access: Public, Virtual
|
|
// Description: This is called by the GraphicsEngine to request that
|
|
// the window (or whatever) close itself or, in general,
|
|
// make itself invalid, at the next call to
|
|
// process_events(). By that time we promise the gsg
|
|
// pointer will be cleared.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
request_close() {
|
|
WindowProperties close_properties;
|
|
close_properties.set_open(false);
|
|
request_properties(close_properties);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::set_close_now
|
|
// Access: Public, Virtual
|
|
// Description: This is called by the GraphicsEngine to insist that
|
|
// the window be closed immediately. This is only
|
|
// called from the window thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
set_close_now() {
|
|
WindowProperties close_properties;
|
|
close_properties.set_open(false);
|
|
set_properties_now(close_properties);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::process_events
|
|
// Access: Public, Virtual
|
|
// Description: Do whatever processing is necessary to ensure that
|
|
// the window responds to user events. Also, honor any
|
|
// requests recently made via request_properties().
|
|
//
|
|
// This function is called only within the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
process_events() {
|
|
if (_requested_properties.is_any_specified()) {
|
|
// We don't bother to grab the mutex until after we have already
|
|
// checked whether any properties have been specified. This is
|
|
// technically sloppy, but it ought to be o.k. since it's just a
|
|
// bitmask after all.
|
|
WindowProperties properties;
|
|
{
|
|
LightReMutexHolder holder(_properties_lock);
|
|
properties = _requested_properties;
|
|
_requested_properties.clear();
|
|
|
|
set_properties_now(properties);
|
|
if (properties.is_any_specified()) {
|
|
display_cat.info()
|
|
<< "Unable to set window properties: " << properties << "\n";
|
|
_rejected_properties.add_properties(properties);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::set_properties_now
|
|
// Access: Public, Virtual
|
|
// Description: Applies the requested set of properties to the
|
|
// window, if possible, for instance to request a change
|
|
// in size or minimization status.
|
|
//
|
|
// The window properties are applied immediately, rather
|
|
// than waiting until the next frame. This implies that
|
|
// this method may *only* be called from within the
|
|
// window thread.
|
|
//
|
|
// The properties that have been applied are cleared
|
|
// from the structure by this function; so on return,
|
|
// whatever remains in the properties structure are
|
|
// those that were unchanged for some reason (probably
|
|
// because the underlying interface does not support
|
|
// changing that property on an open window).
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
set_properties_now(WindowProperties &properties) {
|
|
if (properties.has_open() &&
|
|
properties.get_open() != _properties.get_open()) {
|
|
// Open or close a new window. In this case we can get all of the
|
|
// properties at once.
|
|
|
|
_properties.add_properties(properties);
|
|
properties.clear();
|
|
|
|
if (_properties.get_open()) {
|
|
if (open_window()) {
|
|
// When the window is first opened, force its size to be
|
|
// broadcast to its display regions.
|
|
_is_valid = true;
|
|
set_size_and_recalc(_properties.get_x_size(),
|
|
_properties.get_y_size());
|
|
} else {
|
|
// Since we can't even open the window, tag the
|
|
// _rejected_properties with all of the window properties that
|
|
// failed.
|
|
_rejected_properties.add_properties(_properties);
|
|
|
|
// And mark the window closed.
|
|
_properties.set_open(false);
|
|
_is_valid = false;
|
|
}
|
|
|
|
} else {
|
|
// We used to resist closing a window before its GSG has been
|
|
// released. Now it seems we never release a GSG, so go ahead
|
|
// and close the window.
|
|
close_window();
|
|
_is_valid = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!_properties.get_open()) {
|
|
// The window is not currently open; we can set properties at
|
|
// will.
|
|
_properties.add_properties(properties);
|
|
properties.clear();
|
|
return;
|
|
}
|
|
|
|
properties.clear_open();
|
|
|
|
// The window is already open; we are limited to what we can change
|
|
// on the fly.
|
|
|
|
if (properties.has_size() || properties.has_origin()) {
|
|
// Consider changing the window's size and/or position.
|
|
WindowProperties reshape_props;
|
|
if (properties.has_size()) {
|
|
reshape_props.set_size(properties.get_x_size(), properties.get_y_size());
|
|
} else {
|
|
reshape_props.set_size(_properties.get_x_size(), _properties.get_y_size());
|
|
}
|
|
|
|
if (properties.has_origin() && !is_fullscreen()) {
|
|
reshape_props.set_origin(properties.get_x_origin(), properties.get_y_origin());
|
|
} else if (_properties.has_origin()) {
|
|
reshape_props.set_origin(_properties.get_x_origin(), _properties.get_y_origin());
|
|
}
|
|
|
|
bool has_origin = reshape_props.has_origin();
|
|
int x_origin = 0, y_origin = 0;
|
|
if (has_origin) {
|
|
x_origin = reshape_props.get_x_origin();
|
|
y_origin = reshape_props.get_y_origin();
|
|
}
|
|
|
|
if (reshape_props.get_x_size() != _properties.get_x_size() ||
|
|
reshape_props.get_y_size() != _properties.get_y_size() ||
|
|
(has_origin && (x_origin != _properties.get_x_origin() ||
|
|
y_origin != _properties.get_y_origin()))) {
|
|
if (do_reshape_request(x_origin, y_origin, has_origin,
|
|
reshape_props.get_x_size(),
|
|
reshape_props.get_y_size())) {
|
|
properties.clear_size();
|
|
properties.clear_origin();
|
|
}
|
|
} else {
|
|
properties.clear_size();
|
|
properties.clear_origin();
|
|
}
|
|
}
|
|
|
|
if (properties.has_fullscreen() &&
|
|
properties.get_fullscreen() == _properties.get_fullscreen()) {
|
|
// Fullscreen property specified, but unchanged.
|
|
properties.clear_fullscreen();
|
|
}
|
|
if (properties.has_mouse_mode() ) {
|
|
|
|
if (properties.get_mouse_mode() == _properties.get_mouse_mode()) {
|
|
properties.clear_mouse_mode();
|
|
}
|
|
else {
|
|
if(properties.get_mouse_mode() == WindowProperties::M_absolute) {
|
|
_properties.set_mouse_mode(WindowProperties::M_absolute);
|
|
mouse_mode_absolute();
|
|
properties.clear_mouse_mode();
|
|
}
|
|
else
|
|
{
|
|
_properties.set_mouse_mode(WindowProperties::M_relative);
|
|
mouse_mode_relative();
|
|
properties.clear_mouse_mode();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::close_window
|
|
// Access: Protected, Virtual
|
|
// Description: Closes the window right now. Called from the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
close_window() {
|
|
display_cat.info()
|
|
<< "Closing " << get_type() << "\n";
|
|
|
|
// Tell our parent window (if any) that we're no longer its child.
|
|
if (_window_handle != (WindowHandle *)NULL &&
|
|
_parent_window_handle != (WindowHandle *)NULL) {
|
|
_parent_window_handle->detach_child(_window_handle);
|
|
}
|
|
|
|
_window_handle = NULL;
|
|
_parent_window_handle = NULL;
|
|
_is_valid = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::open_window
|
|
// Access: Protected, Virtual
|
|
// Description: Opens the window right now. Called from the window
|
|
// thread. Returns true if the window is successfully
|
|
// opened, or false if there was a problem.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
open_window() {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::reset_window
|
|
// Access: Protected, Virtual
|
|
// Description: resets the window framebuffer from its derived
|
|
// children. Does nothing here.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
reset_window(bool swapchain) {
|
|
display_cat.info()
|
|
<< "Resetting " << get_type() << "\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::do_reshape_request
|
|
// Access: Protected, Virtual
|
|
// Description: Called from the window thread in response to a request
|
|
// from within the code (via request_properties()) to
|
|
// change the size and/or position of the window.
|
|
// Returns true if the window is successfully changed,
|
|
// or false if there was a problem.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
do_reshape_request(int x_origin, int y_origin, bool has_origin,
|
|
int x_size, int y_size) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::system_changed_properties
|
|
// Access: Protected
|
|
// Description: Should be called (from within the window thread) when
|
|
// process_events() detects an external change in some
|
|
// important window property; for instance, when the
|
|
// user resizes the window.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
system_changed_properties(const WindowProperties &properties) {
|
|
if (display_cat.is_debug()) {
|
|
display_cat.debug()
|
|
<< "system_changed_properties(" << properties << ")\n";
|
|
}
|
|
|
|
LightReMutexHolder holder(_properties_lock);
|
|
|
|
if (properties.has_size()) {
|
|
system_changed_size(properties.get_x_size(), properties.get_y_size());
|
|
}
|
|
|
|
WindowProperties old_properties = _properties;
|
|
_properties.add_properties(properties);
|
|
if (_properties != old_properties) {
|
|
throw_event(_window_event, this);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::system_changed_size
|
|
// Access: Protected
|
|
// Description: An internal function to update all the DisplayRegions
|
|
// with the new size of the window. This should always
|
|
// be called before changing the _size members of the
|
|
// _properties structure.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
system_changed_size(int x_size, int y_size) {
|
|
if (display_cat.is_debug()) {
|
|
display_cat.debug()
|
|
<< "system_changed_size(" << x_size << ", " << y_size << ")\n";
|
|
}
|
|
|
|
if (!_properties.has_size() || (x_size != _properties.get_x_size() ||
|
|
y_size != _properties.get_y_size())) {
|
|
set_size_and_recalc(x_size, y_size);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::add_input_device
|
|
// Access: Protected
|
|
// Description: Adds a GraphicsWindowInputDevice to the vector.
|
|
// Returns the index of the new device.
|
|
////////////////////////////////////////////////////////////////////
|
|
int GraphicsWindow::
|
|
add_input_device(const GraphicsWindowInputDevice &device) {
|
|
LightMutexHolder holder(_input_lock);
|
|
int index = (int)_input_devices.size();
|
|
_input_devices.push_back(device);
|
|
_input_devices.back().set_device_index(index);
|
|
return index;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::mouse_mode_relative
|
|
// Access: Protected, Virtual
|
|
// Description: detaches mouse. Only mouse delta from now on.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
mouse_mode_relative() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::mouse_mode_absolute
|
|
// Access: Protected, Virtual
|
|
// Description: reattaches mouse to location
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
mouse_mode_absolute() {
|
|
|
|
}
|
|
|
|
#ifdef HAVE_PYTHON
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::add_custom_event_handler
|
|
// Access: Published
|
|
// Description: Adds a python event handler to be called
|
|
// when a window event occurs.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
add_python_event_handler(PyObject* handler, PyObject* name){
|
|
PythonGraphicsWindowProc* pgwp = new PythonGraphicsWindowProc(handler, name);
|
|
_python_window_proc_classes.insert(pgwp);
|
|
add_window_proc(pgwp);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::remove_custom_event_handler
|
|
// Access: Published
|
|
// Description: Removes the specified python event handler.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsWindow::
|
|
remove_python_event_handler(PyObject* name){
|
|
list<PythonGraphicsWindowProc*> toRemove;
|
|
PythonWinProcClasses::iterator iter;
|
|
for(iter = _python_window_proc_classes.begin(); iter != _python_window_proc_classes.end(); ++iter){
|
|
PythonGraphicsWindowProc* pgwp = *iter;
|
|
if(PyObject_Compare(pgwp->get_name(), name) == 0)
|
|
toRemove.push_back(pgwp);
|
|
}
|
|
list<PythonGraphicsWindowProc*>::iterator iter2;
|
|
for(iter2 = toRemove.begin(); iter2 != toRemove.end(); ++iter2){
|
|
PythonGraphicsWindowProc* pgwp = *iter2;
|
|
remove_window_proc(pgwp);
|
|
_python_window_proc_classes.erase(pgwp);
|
|
delete pgwp;
|
|
}
|
|
}
|
|
|
|
#endif // HAVE_PYTHON
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::is_touch_event
|
|
// Access: Published, Virtual
|
|
// Description: Returns whether the specified event msg is a touch message.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::
|
|
is_touch_event(GraphicsWindowProcCallbackData* callbackData){
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_num_touches
|
|
// Access: Published, Virtual
|
|
// Description: Returns the current number of touches on this window.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
int GraphicsWindow::
|
|
get_num_touches(){
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::get_touch_info
|
|
// Access: Published, Virtual
|
|
// Description: Returns the TouchInfo object describing the specified touch.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
TouchInfo GraphicsWindow::
|
|
get_touch_info(int index){
|
|
return TouchInfo();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsWindow::supports_window_procs
|
|
// Access: Published, Virtual
|
|
// Description: Returns whether this window supports adding of Windows proc handlers.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsWindow::supports_window_procs() const{
|
|
return false;
|
|
}
|