diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index 9b8416dca6..adade59536 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -26,7 +26,6 @@ #include "textEncoder.h" #include "throw_event.h" #include "lightReMutexHolder.h" -#include "nativeWindowHandle.h" #include #include @@ -180,105 +179,28 @@ open_window() { } } - XVisualInfo *visual_info = glxgsg->_visual; - if (visual_info == NULL) { + _visual_info = glxgsg->_visual; + if (_visual_info == NULL) { // No X visual for this fbconfig; how can we open the window? glxdisplay_cat.error() << "No X visual: cannot open window.\n"; return false; } - Visual *visual = visual_info->visual; - int depth = visual_info->depth; - - if (!_properties.has_origin()) { - _properties.set_origin(0, 0); - } - if (!_properties.has_size()) { - _properties.set_size(100, 100); - } - - Window parent_window = glx_pipe->get_root(); - WindowHandle *window_handle = _properties.get_parent_window(); - if (window_handle != NULL) { - glxdisplay_cat.info() - << "Got parent_window " << *window_handle << "\n"; - WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); - if (os_handle != NULL) { - glxdisplay_cat.info() - << "os_handle type " << os_handle->get_type() << "\n"; - - if (os_handle->is_of_type(NativeWindowHandle::X11Handle::get_class_type())) { - NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle); - parent_window = x11_handle->get_handle(); - } else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) { - NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle); - parent_window = (Window)int_handle->get_handle(); - } - } - } - _parent_window_handle = window_handle; + Visual *visual = _visual_info->visual; #ifdef HAVE_GLXFBCONFIG if (glxgsg->_fbconfig != None) { setup_colormap(glxgsg->_fbconfig); } else { - setup_colormap(visual_info); + setup_colormap(_visual_info); } #else - setup_colormap(visual_info); + setup_colormap(_visual_info); #endif // HAVE_GLXFBCONFIG - _event_mask = - ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask | - EnterWindowMask | LeaveWindowMask | - PointerMotionMask | - FocusChangeMask | - StructureNotifyMask; - - // Initialize window attributes - XSetWindowAttributes wa; - wa.background_pixel = XBlackPixel(_display, _screen); - wa.border_pixel = 0; - wa.colormap = _colormap; - wa.event_mask = _event_mask; - - unsigned long attrib_mask = - CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; - - _xwindow = XCreateWindow - (_display, parent_window, - _properties.get_x_origin(), _properties.get_y_origin(), - _properties.get_x_size(), _properties.get_y_size(), - 0, depth, InputOutput, visual, attrib_mask, &wa); - - if (_xwindow == (Window)0) { - glxdisplay_cat.error() - << "failed to create X window.\n"; + if (!x11GraphicsWindow::open_window()) { return false; } - set_wm_properties(_properties, false); - - // We don't specify any fancy properties of the XIC. It would be - // nicer if we could support fancy IM's that want preedit callbacks, - // etc., but that can wait until we have an X server that actually - // supports these to test it on. - XIM im = glx_pipe->get_im(); - _ic = NULL; - if (im) { - _ic = XCreateIC - (im, - XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - (void*)NULL); - if (_ic == (XIC)NULL) { - glxdisplay_cat.warning() - << "Couldn't create input context.\n"; - } - } - - if (_properties.get_cursor_hidden()) { - XDefineCursor(_display, _xwindow, glx_pipe->get_hidden_cursor()); - } glXMakeCurrent(_display, _xwindow, glxgsg->_context); glxgsg->reset_if_new(); @@ -292,25 +214,6 @@ open_window() { return false; } _fb_properties = glxgsg->get_fb_properties(); - - XMapWindow(_display, _xwindow); - - if (_properties.get_raw_mice()) { - open_raw_mice(); - } else { - if (glxdisplay_cat.is_debug()) { - glxdisplay_cat.debug() - << "Raw mice not requested.\n"; - } - } - - // Create a WindowHandle for ourselves - _window_handle = NativeWindowHandle::make_x11(_xwindow); - - // And tell our parent window that we're now its child. - if (_parent_window_handle != (WindowHandle *)NULL) { - _parent_window_handle->attach_child(_window_handle); - } return true; } diff --git a/panda/src/tinydisplay/tinyXGraphicsWindow.cxx b/panda/src/tinydisplay/tinyXGraphicsWindow.cxx index 9265b1c0e7..554c25e0f0 100644 --- a/panda/src/tinydisplay/tinyXGraphicsWindow.cxx +++ b/panda/src/tinydisplay/tinyXGraphicsWindow.cxx @@ -468,10 +468,10 @@ open_window() { << "No suitable X Visual available; cannot open window.\n"; return false; } - XVisualInfo *visual_info = &vinfo_array[0]; + _visual_info = &vinfo_array[0]; - _visual = visual_info->visual; - _depth = visual_info->depth; + _visual = _visual_info->visual; + _depth = _visual_info->depth; _bytes_per_pixel = _depth / 8; if (_bytes_per_pixel == 3) { // Seems to be a special case. @@ -479,7 +479,7 @@ open_window() { } tinydisplay_cat.info() << "Got X Visual with depth " << _depth << " (bpp " << _bytes_per_pixel << ") and class "; - switch (visual_info->c_class) { + switch (_visual_info->c_class) { case TrueColor: tinydisplay_cat.info(false) << "TrueColor\n"; break; @@ -505,87 +505,11 @@ open_window() { break; } - if (!_properties.has_origin()) { - _properties.set_origin(0, 0); - } - if (!_properties.has_size()) { - _properties.set_size(100, 100); - } - - Window parent_window = tinyx_pipe->get_root(); - WindowHandle *window_handle = _properties.get_parent_window(); - if (window_handle != NULL) { - tinydisplay_cat.info() - << "Got parent_window " << *window_handle << "\n"; - WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); - if (os_handle != NULL) { - tinydisplay_cat.info() - << "os_handle type " << os_handle->get_type() << "\n"; - - if (os_handle->is_of_type(NativeWindowHandle::X11Handle::get_class_type())) { - NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle); - parent_window = x11_handle->get_handle(); - } else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) { - NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle); - parent_window = (Window)int_handle->get_handle(); - } - } - } - _parent_window_handle = window_handle; + setup_colormap(_visual_info); - setup_colormap(visual_info); - - _event_mask = - ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask | - EnterWindowMask | LeaveWindowMask | - PointerMotionMask | - FocusChangeMask | - StructureNotifyMask; - - // Initialize window attributes - XSetWindowAttributes wa; - wa.background_pixel = XBlackPixel(_display, _screen); - wa.border_pixel = 0; - wa.colormap = _colormap; - wa.event_mask = _event_mask; - - unsigned long attrib_mask = - CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; - - _xwindow = XCreateWindow - (_display, parent_window, - _properties.get_x_origin(), _properties.get_y_origin(), - _properties.get_x_size(), _properties.get_y_size(), - 0, _depth, InputOutput, _visual, attrib_mask, &wa); - - if (_xwindow == (Window)0) { - tinydisplay_cat.error() - << "failed to create X window.\n"; + if (!x11GraphicsWindow::open_window()) { return false; } - set_wm_properties(_properties, false); - - // We don't specify any fancy properties of the XIC. It would be - // nicer if we could support fancy IM's that want preedit callbacks, - // etc., but that can wait until we have an X server that actually - // supports these to test it on. - XIM im = tinyx_pipe->get_im(); - _ic = NULL; - if (im) { - _ic = XCreateIC - (im, - XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - NULL); - if (_ic == (XIC)NULL) { - tinydisplay_cat.warning() - << "Couldn't create input context.\n"; - } - } - - if (_properties.get_cursor_hidden()) { - XDefineCursor(_display, _xwindow, tinyx_pipe->get_hidden_cursor()); - } _gc = XCreateGC(_display, _xwindow, 0, NULL); diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index 951887a398..6acd4dbadb 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -1,5 +1,5 @@ // Filename: x11GraphicsPipe.cxx -// Created by: pro-rsoft (07Jul09) +// Created by: rdb (07Jul09) // //////////////////////////////////////////////////////////////////// // diff --git a/panda/src/x11display/x11GraphicsPipe.h b/panda/src/x11display/x11GraphicsPipe.h index 1774d30a6b..343ab60033 100644 --- a/panda/src/x11display/x11GraphicsPipe.h +++ b/panda/src/x11display/x11GraphicsPipe.h @@ -1,5 +1,5 @@ // Filename: x11GraphicsPipe.h -// Created by: pro-rsoft (07Jul09) +// Created by: rdb (07Jul09) // //////////////////////////////////////////////////////////////////// // diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 9215e1ad16..ba6f317cc9 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -1,5 +1,5 @@ // Filename: x11GraphicsWindow.cxx -// Created by: pro-rsoft (07Jul09) +// Created by: rdb (07Jul09) // //////////////////////////////////////////////////////////////////// // @@ -24,6 +24,7 @@ #include "textEncoder.h" #include "throw_event.h" #include "lightReMutexHolder.h" +#include "nativeWindowHandle.h" #include #include @@ -35,6 +36,16 @@ #include #endif +#ifdef HAVE_XRANDR +// Ugly workaround around the conflicting definition +// of Connection that randr.h provides. +#define _RANDR_H_ +typedef unsigned short Rotation; +typedef unsigned short SizeID; +typedef unsigned short SubpixelOrder; +#include +#endif + #ifdef HAVE_LINUX_INPUT_H #include #endif @@ -64,6 +75,8 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, _screen = x11_pipe->get_screen(); _xwindow = (Window)NULL; _ic = (XIC)NULL; + _visual_info = NULL; + _orig_size_id = -1; _awaiting_configure = false; _dga_mouse_enabled = false; _wm_delete_window = x11_pipe->_wm_delete_window; @@ -456,15 +469,20 @@ set_properties_now(WindowProperties &properties) { } // Fullscreen mode is implemented with a hint to the window manager. - // However, we also implicitly set the origin to (0, 0) and the size - // to the desktop size, and request undecorated mode, in case the - // user has a less-capable window manager (or no window manager at - // all). - if (properties.get_fullscreen()) { - properties.set_undecorated(true); - properties.set_origin(0, 0); - properties.set_size(x11_pipe->get_display_width(), - x11_pipe->get_display_height()); + // However, we also implicitly set the origin to (0, 0) and request + // undecorated mode, in case the user has a less-capable + // window manager (or no window manager at all). + if (properties.has_fullscreen()) { + if (properties.get_fullscreen()) { + properties.set_undecorated(true); + properties.set_origin(0, 0); +#ifndef HAVE_XRANDR + // If we don't have Xrandr support, we fake the fullscreen + // support by setting the window size to the desktop size. + properties.set_size(x11_pipe->get_display_width(), + x11_pipe->get_display_height()); +#endif + } } GraphicsWindow::set_properties_now(properties); @@ -656,6 +674,18 @@ close_window() { XFlush(_display); } +#ifdef HAVE_XRANDR + // Change the resolution back to what it was. + // Don't remove the SizeID typecast! + if (_orig_size_id != (SizeID) -1) { + x11GraphicsPipe *x11_pipe; + DCAST_INTO_V(x11_pipe, _pipe); + XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root()); + XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), _orig_size_id, _orig_rotation, CurrentTime); + _orig_size_id = -1; + } +#endif + GraphicsWindow::close_window(); } @@ -668,8 +698,146 @@ close_window() { //////////////////////////////////////////////////////////////////// bool x11GraphicsWindow:: open_window() { - assert(false); // This shouldn't happen. - return false; + if (_visual_info == NULL) { + // No X visual for this fbconfig; how can we open the window? + x11display_cat.error() + << "No X visual: cannot open window.\n"; + return false; + } + + x11GraphicsPipe *x11_pipe; + DCAST_INTO_R(x11_pipe, _pipe, false); + + if (!_properties.has_origin()) { + _properties.set_origin(0, 0); + } + if (!_properties.has_size()) { + _properties.set_size(100, 100); + } + +#ifdef HAVE_XRANDR + _orig_size_id = -1; + if (_properties.get_fullscreen()) { + XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root()); + _orig_size_id = XRRConfigCurrentConfiguration(conf, &_orig_rotation); + int num_sizes, new_size_id = -1; + XRRScreenSize *xrrs; + xrrs = XRRSizes(_display, 0, &num_sizes); + for (int i = 0; i < num_sizes; ++i) { + if (xrrs[i].width == _properties.get_x_size() && + xrrs[i].height == _properties.get_y_size()) { + new_size_id = i; + } + } + if (new_size_id == -1) { + x11display_cat.error() + << "Videocard has no supported display resolutions at specified res (" + << _properties.get_x_size() << " x " << _properties.get_y_size() <<")\n"; + _orig_size_id = -1; + return false; + } + if (new_size_id != _orig_size_id) { + XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); + } else { + _orig_size_id = -1; + } + _properties.set_origin(0, 0); + } +#endif + + Window parent_window = x11_pipe->get_root(); + WindowHandle *window_handle = _properties.get_parent_window(); + if (window_handle != NULL) { + x11display_cat.info() + << "Got parent_window " << *window_handle << "\n"; + WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); + if (os_handle != NULL) { + x11display_cat.info() + << "os_handle type " << os_handle->get_type() << "\n"; + + if (os_handle->is_of_type(NativeWindowHandle::X11Handle::get_class_type())) { + NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle); + parent_window = x11_handle->get_handle(); + } else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) { + NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle); + parent_window = (Window)int_handle->get_handle(); + } + } + } + _parent_window_handle = window_handle; + + _event_mask = + ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask | + PointerMotionMask | + FocusChangeMask | StructureNotifyMask; + + // Initialize window attributes + XSetWindowAttributes wa; + wa.background_pixel = XBlackPixel(_display, _screen); + wa.border_pixel = 0; + wa.colormap = _colormap; + wa.event_mask = _event_mask; + + unsigned long attrib_mask = + CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + _xwindow = XCreateWindow + (_display, parent_window, + _properties.get_x_origin(), _properties.get_y_origin(), + _properties.get_x_size(), _properties.get_y_size(), + 0, _visual_info->depth, InputOutput, + _visual_info->visual, attrib_mask, &wa); + + if (_xwindow == (Window)0) { + x11display_cat.error() + << "failed to create X window.\n"; + return false; + } + set_wm_properties(_properties, false); + + // We don't specify any fancy properties of the XIC. It would be + // nicer if we could support fancy IM's that want preedit callbacks, + // etc., but that can wait until we have an X server that actually + // supports these to test it on. + XIM im = x11_pipe->get_im(); + _ic = NULL; + if (im) { + _ic = XCreateIC + (im, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + (void*)NULL); + if (_ic == (XIC)NULL) { + x11display_cat.warning() + << "Couldn't create input context.\n"; + } + } + + if (_properties.get_cursor_hidden()) { + XDefineCursor(_display, _xwindow, x11_pipe->get_hidden_cursor()); + } + + XMapWindow(_display, _xwindow); + + if (_properties.get_raw_mice()) { + open_raw_mice(); + } else { + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "Raw mice not requested.\n"; + } + } + + // Create a WindowHandle for ourselves + _window_handle = NativeWindowHandle::make_x11(_xwindow); + + // And tell our parent window that we're now its child. + if (_parent_window_handle != (WindowHandle *)NULL) { + _parent_window_handle->attach_child(_window_handle); + } + + return true; } //////////////////////////////////////////////////////////////////// @@ -898,8 +1066,7 @@ setup_colormap(XVisualInfo *visual) { // Description: Adds raw mice to the _input_devices list. //////////////////////////////////////////////////////////////////// void x11GraphicsWindow:: -open_raw_mice() -{ +open_raw_mice() { #ifdef HAVE_LINUX_INPUT_H bool any_present = false; bool any_mice = false; diff --git a/panda/src/x11display/x11GraphicsWindow.h b/panda/src/x11display/x11GraphicsWindow.h index bcc9bfbf84..122a519246 100644 --- a/panda/src/x11display/x11GraphicsWindow.h +++ b/panda/src/x11display/x11GraphicsWindow.h @@ -1,5 +1,5 @@ // Filename: x11GraphicsWindow.h -// Created by: pro-rsoft (07Jul09) +// Created by: rdb (07Jul09) // //////////////////////////////////////////////////////////////////// // @@ -21,6 +21,11 @@ #include "graphicsWindow.h" #include "buttonHandle.h" +#ifdef HAVE_XRANDR +typedef unsigned short Rotation; +typedef unsigned short SizeID; +#endif + //////////////////////////////////////////////////////////////////// // Class : x11GraphicsWindow // Description : Interfaces to the X11 window system. @@ -75,6 +80,10 @@ protected: Window _xwindow; Colormap _colormap; XIC _ic; + XVisualInfo *_visual_info; + + Rotation _orig_rotation; + SizeID _orig_size_id; long _event_mask; bool _awaiting_configure;