Panda3D

x11GraphicsPipe.cxx

00001 // Filename: x11GraphicsPipe.cxx
00002 // Created by:  rdb (07Jul09)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "x11GraphicsPipe.h"
00016 #include "x11GraphicsWindow.h"
00017 #include "config_x11display.h"
00018 #include "frameBufferProperties.h"
00019 
00020 #ifdef HAVE_XRANDR
00021 // Ugly workaround around the conflicting definition
00022 // of Connection that randr.h provides.
00023 #define Connection XConnection
00024 #include <X11/extensions/Xrandr.h>
00025 #undef Connection
00026 #endif
00027 
00028 TypeHandle x11GraphicsPipe::_type_handle;
00029 
00030 bool x11GraphicsPipe::_error_handlers_installed = false;
00031 x11GraphicsPipe::ErrorHandlerFunc *x11GraphicsPipe::_prev_error_handler;
00032 x11GraphicsPipe::IOErrorHandlerFunc *x11GraphicsPipe::_prev_io_error_handler;
00033 bool x11GraphicsPipe::_x_error_messages_enabled = true;
00034 int x11GraphicsPipe::_x_error_count = 0;
00035 
00036 LightReMutex x11GraphicsPipe::_x_mutex;
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: x11GraphicsPipe::Constructor
00040 //       Access: Public
00041 //  Description: 
00042 ////////////////////////////////////////////////////////////////////
00043 x11GraphicsPipe::
00044 x11GraphicsPipe(const string &display) {
00045   string display_spec = display;
00046   if (display_spec.empty()) {
00047     display_spec = display_cfg;
00048   }
00049   if (display_spec.empty()) {
00050     display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY");
00051   }
00052   if (display_spec.empty()) {
00053     display_spec = ":0.0";
00054   }
00055 
00056   // The X docs say we should do this to get international character
00057   // support from the keyboard.
00058   setlocale(LC_ALL, "");
00059 
00060   // But it's important that we use the "C" locale for numeric
00061   // formatting, since all of the internal Panda code assumes this--we
00062   // need a decimal point to mean a decimal point.
00063   setlocale(LC_NUMERIC, "C");
00064 
00065   _is_valid = false;
00066   _supported_types = OT_window | OT_buffer | OT_texture_buffer;
00067   _display = NULL;
00068   _screen = 0;
00069   _root = (Window)NULL;
00070   _im = (XIM)NULL;
00071   _hidden_cursor = None;
00072 
00073   install_error_handlers();
00074 
00075   _display = XOpenDisplay(display_spec.c_str());
00076   if (!_display) {
00077     x11display_cat.error()
00078       << "Could not open display \"" << display_spec << "\".\n";
00079     return;
00080   }
00081 
00082   if (!XSupportsLocale()) {
00083     x11display_cat.warning()
00084       << "X does not support locale " << setlocale(LC_ALL, NULL) << "\n";
00085   }
00086   XSetLocaleModifiers("");
00087 
00088   _screen = DefaultScreen(_display);
00089   _root = RootWindow(_display, _screen);
00090   _display_width = DisplayWidth(_display, _screen);
00091   _display_height = DisplayHeight(_display, _screen);
00092   _is_valid = true;
00093 
00094 #ifdef HAVE_XRANDR
00095   // Use Xrandr to fill in the supported resolution list.
00096   int num_sizes, num_rates;
00097   XRRScreenSize *xrrs;
00098   xrrs = XRRSizes(_display, 0, &num_sizes);
00099   _display_information->_total_display_modes = 0;
00100   for (int i = 0; i < num_sizes; ++i) {
00101     XRRRates(_display, 0, i, &num_rates);
00102     _display_information->_total_display_modes += num_rates;
00103   }
00104   
00105   short *rates;
00106   short counter = 0;
00107   _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes];
00108   for (int i = 0; i < num_sizes; ++i) {
00109     int num_rates;
00110     rates = XRRRates(_display, 0, i, &num_rates);
00111     for (int j = 0; j < num_rates; ++j) {
00112       DisplayMode* dm = _display_information->_display_mode_array + counter;
00113       dm->width = xrrs[i].width;
00114       dm->height = xrrs[i].height;
00115       dm->refresh_rate = rates[j];
00116       ++counter;
00117     }
00118   }
00119 #endif
00120 
00121   // Connect to an input method for supporting international text
00122   // entry.
00123   _im = XOpenIM(_display, NULL, NULL, NULL);
00124   if (_im == (XIM)NULL) {
00125     x11display_cat.warning()
00126       << "Couldn't open input method.\n";
00127   }
00128 
00129   // What styles does the current input method support?
00130   /*
00131   XIMStyles *im_supported_styles;
00132   XGetIMValues(_im, XNQueryInputStyle, &im_supported_styles, NULL);
00133 
00134   for (int i = 0; i < im_supported_styles->count_styles; i++) {
00135     XIMStyle style = im_supported_styles->supported_styles[i];
00136     cerr << "style " << i << ". " << hex << style << dec << "\n";
00137   }
00138 
00139   XFree(im_supported_styles);
00140   */
00141 
00142   // Get some X atom numbers.
00143   _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false);
00144   _net_wm_window_type = XInternAtom(_display, "_NET_WM_WINDOW_TYPE", false);
00145   _net_wm_window_type_splash = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_SPLASH", false);
00146   _net_wm_window_type_fullscreen = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_FULLSCREEN", false);
00147   _net_wm_state = XInternAtom(_display, "_NET_WM_STATE", false);
00148   _net_wm_state_fullscreen = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", false);
00149   _net_wm_state_above = XInternAtom(_display, "_NET_WM_STATE_ABOVE", false);
00150   _net_wm_state_below = XInternAtom(_display, "_NET_WM_STATE_BELOW", false);
00151   _net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false);
00152   _net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false);
00153 }
00154 
00155 ////////////////////////////////////////////////////////////////////
00156 //     Function: x11GraphicsPipe::Destructor
00157 //       Access: Public, Virtual
00158 //  Description: 
00159 ////////////////////////////////////////////////////////////////////
00160 x11GraphicsPipe::
00161 ~x11GraphicsPipe() {
00162   release_hidden_cursor();
00163   if (_im) {
00164     XCloseIM(_im);
00165   }
00166   if (_display) {
00167     XCloseDisplay(_display);
00168   }
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: x11GraphicsPipe::get_preferred_window_thread
00173 //       Access: Public, Virtual
00174 //  Description: Returns an indication of the thread in which this
00175 //               GraphicsPipe requires its window processing to be
00176 //               performed: typically either the app thread (e.g. X)
00177 //               or the draw thread (Windows).
00178 ////////////////////////////////////////////////////////////////////
00179 GraphicsPipe::PreferredWindowThread 
00180 x11GraphicsPipe::get_preferred_window_thread() const {
00181   // Actually, since we're creating the graphics context in
00182   // open_window() now, it appears we need to ensure the open_window()
00183   // call is performed in the draw thread for now, even though X wants
00184   // all of its calls to be single-threaded.
00185 
00186   // This means that all X windows may have to be handled by the same
00187   // draw thread, which we didn't intend (though the global _x_mutex
00188   // may allow them to be technically served by different threads,
00189   // even though the actual X calls will be serialized).  There might
00190   // be a better way.
00191 
00192   return PWT_draw;
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: x11GraphicsPipe::make_hidden_cursor
00197 //       Access: Private
00198 //  Description: Called once to make an invisible Cursor for return
00199 //               from get_hidden_cursor().
00200 ////////////////////////////////////////////////////////////////////
00201 void x11GraphicsPipe::
00202 make_hidden_cursor() {
00203   nassertv(_hidden_cursor == None);
00204 
00205   unsigned int x_size, y_size;
00206   XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size);
00207 
00208   Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1);
00209 
00210   XColor black;
00211   memset(&black, 0, sizeof(black));
00212 
00213   _hidden_cursor = XCreatePixmapCursor(_display, empty, empty, 
00214                                        &black, &black, x_size, y_size);
00215   XFreePixmap(_display, empty);
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: x11GraphicsPipe::release_hidden_cursor
00220 //       Access: Private
00221 //  Description: Called once to release the invisible cursor created
00222 //               by make_hidden_cursor().
00223 ////////////////////////////////////////////////////////////////////
00224 void x11GraphicsPipe::
00225 release_hidden_cursor() {
00226   if (_hidden_cursor != None) {
00227     XFreeCursor(_display, _hidden_cursor);
00228     _hidden_cursor = None;
00229   }
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: x11GraphicsPipe::install_error_handlers
00234 //       Access: Private, Static
00235 //  Description: Installs new Xlib error handler functions if this is
00236 //               the first time this function has been called.  These
00237 //               error handler functions will attempt to reduce Xlib's
00238 //               annoying tendency to shut down the client at the
00239 //               first error.  Unfortunately, it is difficult to play
00240 //               nice with the client if it has already installed its
00241 //               own error handlers.
00242 ////////////////////////////////////////////////////////////////////
00243 void x11GraphicsPipe::
00244 install_error_handlers() {
00245   if (_error_handlers_installed) {
00246     return;
00247   }
00248 
00249   _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
00250   _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
00251   _error_handlers_installed = true;
00252 }
00253 
00254 ////////////////////////////////////////////////////////////////////
00255 //     Function: x11GraphicsPipe::error_handler
00256 //       Access: Private, Static
00257 //  Description: This function is installed as the error handler for a
00258 //               non-fatal Xlib error.
00259 ////////////////////////////////////////////////////////////////////
00260 int x11GraphicsPipe::
00261 error_handler(Display *display, XErrorEvent *error) {
00262   ++_x_error_count;
00263 
00264   static const int msg_len = 80;
00265   char msg[msg_len];
00266   XGetErrorText(display, error->error_code, msg, msg_len);
00267 
00268   if (!_x_error_messages_enabled) {
00269     if (x11display_cat.is_debug()) {
00270       x11display_cat.debug()
00271         << msg << "\n";
00272     }
00273     return 0;
00274   }
00275 
00276   x11display_cat.error()
00277     << msg << "\n";
00278 
00279   if (x_error_abort) {
00280     abort();
00281   }
00282 
00283   // We return to allow the application to continue running, unlike
00284   // the default X error handler which exits.
00285   return 0;
00286 }
00287 
00288 ////////////////////////////////////////////////////////////////////
00289 //     Function: x11GraphicsPipe::io_error_handler
00290 //       Access: Private, Static
00291 //  Description: This function is installed as the error handler for a
00292 //               fatal Xlib error.
00293 ////////////////////////////////////////////////////////////////////
00294 int x11GraphicsPipe::
00295 io_error_handler(Display *display) {
00296   x11display_cat.fatal()
00297     << "X fatal error on display " << (void *)display << "\n";
00298 
00299   // Unfortunately, we can't continue from this function, even if we
00300   // promise never to use X again.  We're supposed to terminate
00301   // without returning, and if we do return, the caller will exit
00302   // anyway.  Sigh.  Very poor design on X's part.
00303   return 0;
00304 }
 All Classes Functions Variables Enumerations