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