Panda3D
|
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 }