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