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