diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 11868cf829..575058e5ae 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -4539,8 +4539,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0 and not RUNTI TargetAdd('pandagles_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx') OPTS=['DIR:panda/metalibs/pandagles', 'BUILDING:PANDAGLES', 'GLES', 'EGL'] TargetAdd('pandagles_pandagles.obj', opts=OPTS, input='pandagles.cxx') - # Uncomment this as soon as x11-specific stuff is removed from p3egldisplay - #TargetAdd('libpandagles.dll', input='p3x11display_composite1.obj') + TargetAdd('libpandagles.dll', input='p3x11display_composite1.obj') TargetAdd('libpandagles.dll', input='pandagles_pandagles.obj') TargetAdd('libpandagles.dll', input='p3glesgsg_config_glesgsg.obj') TargetAdd('libpandagles.dll', input='p3glesgsg_glesgsg.obj') @@ -4558,8 +4557,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0 and not RUNT TargetAdd('pandagles2_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx') OPTS=['DIR:panda/metalibs/pandagles2', 'BUILDING:PANDAGLES2', 'GLES2', 'EGL'] TargetAdd('pandagles2_pandagles2.obj', opts=OPTS, input='pandagles2.cxx') - # Uncomment this as soon as x11-specific stuff is removed from p3egldisplay - #TargetAdd('libpandagles2.dll', input='p3x11display_composite1.obj') + TargetAdd('libpandagles2.dll', input='p3x11display_composite1.obj') TargetAdd('libpandagles2.dll', input='pandagles2_pandagles2.obj') TargetAdd('libpandagles2.dll', input='p3gles2gsg_config_gles2gsg.obj') TargetAdd('libpandagles2.dll', input='p3gles2gsg_gles2gsg.obj') diff --git a/panda/src/egldisplay/config_egldisplay.cxx b/panda/src/egldisplay/config_egldisplay.cxx index 7277e517f8..809e73916c 100644 --- a/panda/src/egldisplay/config_egldisplay.cxx +++ b/panda/src/egldisplay/config_egldisplay.cxx @@ -26,41 +26,6 @@ ConfigureFn(config_egldisplay) { init_libegldisplay(); } -ConfigVariableString display_cfg -("display", "", - PRC_DESC("Specify the X display string for the default display. If this " - "is not specified, $DISPLAY is used.")); - -ConfigVariableBool x_error_abort -("x-error-abort", false, - PRC_DESC("Set this true to trigger and abort (and a stack trace) on receipt " - "of an error from the X window system. This can make it easier " - "to discover where these errors are generated.")); - -ConfigVariableInt x_wheel_up_button -("x-wheel-up-button", 4, - PRC_DESC("This is the mouse button index of the wheel_up event: which " - "mouse button number does the system report when the mouse wheel " - "is rolled one notch up?")); - -ConfigVariableInt x_wheel_down_button -("x-wheel-down-button", 5, - PRC_DESC("This is the mouse button index of the wheel_down event: which " - "mouse button number does the system report when the mouse wheel " - "is rolled one notch down?")); - -ConfigVariableInt x_wheel_left_button -("x-wheel-left-button", 6, - PRC_DESC("This is the mouse button index of the wheel_left event: which " - "mouse button number does the system report when one scrolls " - "to the left?")); - -ConfigVariableInt x_wheel_right_button -("x-wheel-right-button", 7, - PRC_DESC("This is the mouse button index of the wheel_right event: which " - "mouse button number does the system report when one scrolls " - "to the right?")); - /** * Initializes the library. This must be called at least once before any of * the functions or classes in this library can be used. Normally it will be diff --git a/panda/src/egldisplay/config_egldisplay.h b/panda/src/egldisplay/config_egldisplay.h index 1c403ec513..2df5bcc1f4 100644 --- a/panda/src/egldisplay/config_egldisplay.h +++ b/panda/src/egldisplay/config_egldisplay.h @@ -39,12 +39,4 @@ extern EXPCL_PANDAGLES const string get_egl_error_string(int error); #endif -extern ConfigVariableString display_cfg; -extern ConfigVariableBool x_error_abort; - -extern ConfigVariableInt x_wheel_up_button; -extern ConfigVariableInt x_wheel_down_button; -extern ConfigVariableInt x_wheel_left_button; -extern ConfigVariableInt x_wheel_right_button; - #endif diff --git a/panda/src/egldisplay/eglGraphicsPipe.I b/panda/src/egldisplay/eglGraphicsPipe.I index bec9e98a34..53d9c311af 100644 --- a/panda/src/egldisplay/eglGraphicsPipe.I +++ b/panda/src/egldisplay/eglGraphicsPipe.I @@ -10,49 +10,3 @@ * @author rdb * @date 2009-05-21 */ - -/** - * Returns a pointer to the X display associated with the pipe: the display on - * which to create the windows. - */ -INLINE X11_Display *eglGraphicsPipe:: -get_display() const { - return _display; -} - -/** - * Returns the X screen number associated with the pipe. - */ -INLINE int eglGraphicsPipe:: -get_screen() const { - return _screen; -} - -/** - * Returns the handle to the root window on the pipe's display. - */ -INLINE X11_Window eglGraphicsPipe:: -get_root() const { - return _root; -} - -/** - * Returns the input method opened for the pipe, or NULL if the input method - * could not be opened for some reason. - */ -INLINE XIM eglGraphicsPipe:: -get_im() const { - return _im; -} - -/** - * Returns an invisible Cursor suitable for assigning to windows that have the - * cursor_hidden property set. - */ -INLINE X11_Cursor eglGraphicsPipe:: -get_hidden_cursor() { - if (_hidden_cursor == None) { - make_hidden_cursor(); - } - return _hidden_cursor; -} diff --git a/panda/src/egldisplay/eglGraphicsPipe.cxx b/panda/src/egldisplay/eglGraphicsPipe.cxx index 0280b2bd7d..441fc10512 100644 --- a/panda/src/egldisplay/eglGraphicsPipe.cxx +++ b/panda/src/egldisplay/eglGraphicsPipe.cxx @@ -21,67 +21,11 @@ TypeHandle eglGraphicsPipe::_type_handle; -bool eglGraphicsPipe::_error_handlers_installed = false; -eglGraphicsPipe::ErrorHandlerFunc *eglGraphicsPipe::_prev_error_handler; -eglGraphicsPipe::IOErrorHandlerFunc *eglGraphicsPipe::_prev_io_error_handler; - -LightReMutex eglGraphicsPipe::_x_mutex; - /** * */ eglGraphicsPipe:: -eglGraphicsPipe(const string &display) { - string display_spec = display; - if (display_spec.empty()) { - display_spec = display_cfg; - } - if (display_spec.empty()) { - display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY"); - } - if (display_spec.empty()) { - display_spec = ":0.0"; - } - - // The X docs say we should do this to get international character support - // from the keyboard. - setlocale(LC_ALL, ""); - - // But it's important that we use the "C" locale for numeric formatting, - // since all of the internal Panda code assumes this--we need a decimal - // point to mean a decimal point. - setlocale(LC_NUMERIC, "C"); - - _is_valid = false; - _supported_types = OT_window | OT_buffer | OT_texture_buffer; - _display = NULL; - _screen = 0; - _root = (X11_Window)NULL; - _im = (XIM)NULL; - _hidden_cursor = None; - _egl_display = NULL; - - install_error_handlers(); - - _display = XOpenDisplay(display_spec.c_str()); - if (!_display) { - egldisplay_cat.error() - << "Could not open display \"" << display_spec << "\".\n"; - return; - } - - if (!XSupportsLocale()) { - egldisplay_cat.warning() - << "X does not support locale " << setlocale(LC_ALL, NULL) << "\n"; - } - XSetLocaleModifiers(""); - - _screen = DefaultScreen(_display); - _root = RootWindow(_display, _screen); - _display_width = DisplayWidth(_display, _screen); - _display_height = DisplayHeight(_display, _screen); - _is_valid = true; - +eglGraphicsPipe(const string &display) : x11GraphicsPipe(display) { _egl_display = eglGetDisplay((NativeDisplayType) _display); if (!eglInitialize(_egl_display, NULL, NULL)) { egldisplay_cat.error() @@ -94,38 +38,6 @@ eglGraphicsPipe(const string &display) { << "Couldn't bind EGL to the OpenGL ES API: " << get_egl_error_string(eglGetError()) << "\n"; } - - // Connect to an input method for supporting international text entry. - _im = XOpenIM(_display, NULL, NULL, NULL); - if (_im == (XIM)NULL) { - egldisplay_cat.warning() - << "Couldn't open input method.\n"; - } - - // What styles does the current input method support? - /* - XIMStyles *im_supported_styles; - XGetIMValues(_im, XNQueryInputStyle, &im_supported_styles, NULL); - - for (int i = 0; i < im_supported_styles->count_styles; i++) { - XIMStyle style = im_supported_styles->supported_styles[i]; - cerr << "style " << i << ". " << hex << style << dec << "\n"; - } - - XFree(im_supported_styles); - */ - - // Get some X atom numbers. - _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false); - _net_wm_window_type = XInternAtom(_display, "_NET_WM_WINDOW_TYPE", false); - _net_wm_window_type_splash = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_SPLASH", false); - _net_wm_window_type_fullscreen = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_FULLSCREEN", false); - _net_wm_state = XInternAtom(_display, "_NET_WM_STATE", false); - _net_wm_state_fullscreen = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", false); - _net_wm_state_above = XInternAtom(_display, "_NET_WM_STATE_ABOVE", false); - _net_wm_state_below = XInternAtom(_display, "_NET_WM_STATE_BELOW", false); - _net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false); - _net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false); } /** @@ -133,13 +45,6 @@ eglGraphicsPipe(const string &display) { */ eglGraphicsPipe:: ~eglGraphicsPipe() { - release_hidden_cursor(); - if (_im) { - XCloseIM(_im); - } - if (_display) { - XCloseDisplay(_display); - } if (_egl_display) { if (!eglTerminate(_egl_display)) { egldisplay_cat.error() << "Failed to terminate EGL display: " @@ -168,26 +73,6 @@ pipe_constructor() { return new eglGraphicsPipe; } -/** - * Returns an indication of the thread in which this GraphicsPipe requires its - * window processing to be performed: typically either the app thread (e.g. - * X) or the draw thread (Windows). - */ -GraphicsPipe::PreferredWindowThread -eglGraphicsPipe::get_preferred_window_thread() const { - // Actually, since we're creating the graphics context in open_window() now, - // it appears we need to ensure the open_window() call is performed in the - // draw thread for now, even though X wants all of its calls to be single- - // threaded. - - // This means that all X windows may have to be handled by the same draw - // thread, which we didn't intend (though the global _x_mutex may allow them - // to be technically served by different threads, even though the actual X - // calls will be serialized). There might be a better way. - - return PWT_draw; -} - /** * Creates a new window on the pipe, if possible. */ @@ -318,89 +203,3 @@ make_output(const string &name, // Nothing else left to try. return NULL; } - -/** - * Called once to make an invisible Cursor for return from - * get_hidden_cursor(). - */ -void eglGraphicsPipe:: -make_hidden_cursor() { - nassertv(_hidden_cursor == None); - - unsigned int x_size, y_size; - XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size); - - Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1); - - XColor black; - memset(&black, 0, sizeof(black)); - - _hidden_cursor = XCreatePixmapCursor(_display, empty, empty, - &black, &black, x_size, y_size); - XFreePixmap(_display, empty); -} - -/** - * Called once to release the invisible cursor created by - * make_hidden_cursor(). - */ -void eglGraphicsPipe:: -release_hidden_cursor() { - if (_hidden_cursor != None) { - XFreeCursor(_display, _hidden_cursor); - _hidden_cursor = None; - } -} - -/** - * Installs new Xlib error handler functions if this is the first time this - * function has been called. These error handler functions will attempt to - * reduce Xlib's annoying tendency to shut down the client at the first error. - * Unfortunately, it is difficult to play nice with the client if it has - * already installed its own error handlers. - */ -void eglGraphicsPipe:: -install_error_handlers() { - if (_error_handlers_installed) { - return; - } - - _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler); - _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler); - _error_handlers_installed = true; -} - -/** - * This function is installed as the error handler for a non-fatal Xlib error. - */ -int eglGraphicsPipe:: -error_handler(X11_Display *display, XErrorEvent *error) { - static const int msg_len = 80; - char msg[msg_len]; - XGetErrorText(display, error->error_code, msg, msg_len); - egldisplay_cat.error() - << msg << "\n"; - - if (x_error_abort) { - abort(); - } - - // We return to allow the application to continue running, unlike the - // default X error handler which exits. - return 0; -} - -/** - * This function is installed as the error handler for a fatal Xlib error. - */ -int eglGraphicsPipe:: -io_error_handler(X11_Display *display) { - egldisplay_cat.fatal() - << "X fatal error on display " << (void *)display << "\n"; - - // Unfortunately, we can't continue from this function, even if we promise - // never to use X again. We're supposed to terminate without returning, and - // if we do return, the caller will exit anyway. Sigh. Very poor design on - // X's part. - return 0; -} diff --git a/panda/src/egldisplay/eglGraphicsPipe.h b/panda/src/egldisplay/eglGraphicsPipe.h index 3cd9682350..aea34925e6 100644 --- a/panda/src/egldisplay/eglGraphicsPipe.h +++ b/panda/src/egldisplay/eglGraphicsPipe.h @@ -15,11 +15,7 @@ #define EGLGRAPHICSPIPE_H #include "pandabase.h" -#include "graphicsWindow.h" -#include "graphicsPipe.h" -#include "lightMutex.h" -#include "lightReMutex.h" -#include "get_x11.h" +#include "x11GraphicsPipe.h" #ifdef OPENGLES_2 #include "gles2gsg.h" @@ -46,7 +42,7 @@ class eglGraphicsWindow; * This graphics pipe represents the interface for creating OpenGL ES graphics * windows on an X-based (e.g. Unix) client. */ -class eglGraphicsPipe : public GraphicsPipe { +class eglGraphicsPipe : public x11GraphicsPipe { public: eglGraphicsPipe(const string &display = string()); virtual ~eglGraphicsPipe(); @@ -54,29 +50,6 @@ public: virtual string get_interface_name() const; static PT(GraphicsPipe) pipe_constructor(); - INLINE X11_Display *get_display() const; - INLINE int get_screen() const; - INLINE X11_Window get_root() const; - INLINE XIM get_im() const; - - INLINE X11_Cursor get_hidden_cursor(); - -public: - virtual PreferredWindowThread get_preferred_window_thread() const; - -public: - // Atom specifications. - Atom _wm_delete_window; - Atom _net_wm_window_type; - Atom _net_wm_window_type_splash; - Atom _net_wm_window_type_fullscreen; - Atom _net_wm_state; - Atom _net_wm_state_fullscreen; - Atom _net_wm_state_above; - Atom _net_wm_state_below; - Atom _net_wm_state_add; - Atom _net_wm_state_remove; - protected: virtual PT(GraphicsOutput) make_output(const string &name, const FrameBufferProperties &fb_prop, @@ -89,40 +62,16 @@ protected: bool &precertify); private: - void make_hidden_cursor(); - void release_hidden_cursor(); - - static void install_error_handlers(); - static int error_handler(X11_Display *display, XErrorEvent *error); - static int io_error_handler(X11_Display *display); - - X11_Display *_display; - int _screen; - X11_Window _root; - XIM _im; EGLDisplay _egl_display; - X11_Cursor _hidden_cursor; - - typedef int ErrorHandlerFunc(X11_Display *, XErrorEvent *); - typedef int IOErrorHandlerFunc(X11_Display *); - static bool _error_handlers_installed; - static ErrorHandlerFunc *_prev_error_handler; - static IOErrorHandlerFunc *_prev_io_error_handler; - -public: - // This Mutex protects any X library calls, which all have to be single- - // threaded. In particular, it protects eglMakeCurrent(). - static LightReMutex _x_mutex; - public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - GraphicsPipe::init_type(); + x11GraphicsPipe::init_type(); register_type(_type_handle, "eglGraphicsPipe", - GraphicsPipe::get_class_type()); + x11GraphicsPipe::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/egldisplay/eglGraphicsStateGuardian.cxx b/panda/src/egldisplay/eglGraphicsStateGuardian.cxx index 5168bd575e..84fc303efb 100644 --- a/panda/src/egldisplay/eglGraphicsStateGuardian.cxx +++ b/panda/src/egldisplay/eglGraphicsStateGuardian.cxx @@ -257,8 +257,9 @@ reset() { // If "Mesa" is present, assume software. However, if "Mesa DRI" is found, // it's actually a Mesa-based OpenGL layer running over a hardware driver. - if (_gl_renderer.find("Mesa") != string::npos && - _gl_renderer.find("Mesa DRI") == string::npos) { + if (_gl_renderer == "Software Rasterizer" || + (_gl_renderer.find("Mesa") != string::npos && + _gl_renderer.find("Mesa DRI") == string::npos)) { // It's Mesa, therefore probably a software context. _fbprops.set_force_software(1); _fbprops.set_force_hardware(0); diff --git a/panda/src/egldisplay/eglGraphicsWindow.I b/panda/src/egldisplay/eglGraphicsWindow.I index 0f3a6bb472..54fa89ab46 100644 --- a/panda/src/egldisplay/eglGraphicsWindow.I +++ b/panda/src/egldisplay/eglGraphicsWindow.I @@ -10,11 +10,3 @@ * @author rdb * @date 2009-05-21 */ - -/** - * Returns the X11 Window handle. - */ -INLINE X11_Window eglGraphicsWindow:: -get_xwindow() const { - return _xwindow; -} diff --git a/panda/src/egldisplay/eglGraphicsWindow.cxx b/panda/src/egldisplay/eglGraphicsWindow.cxx index 7299815739..b7e7d5dccf 100644 --- a/panda/src/egldisplay/eglGraphicsWindow.cxx +++ b/panda/src/egldisplay/eglGraphicsWindow.cxx @@ -27,17 +27,8 @@ #include "nativeWindowHandle.h" #include "get_x11.h" -#include -#include - -#ifdef HAVE_LINUX_INPUT_H -#include -#endif - TypeHandle eglGraphicsWindow::_type_handle; -#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7))) - /** * */ @@ -49,31 +40,12 @@ eglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, int flags, GraphicsStateGuardian *gsg, GraphicsOutput *host) : - GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host) + x11GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host) { eglGraphicsPipe *egl_pipe; DCAST_INTO_V(egl_pipe, _pipe); - _display = egl_pipe->get_display(); - _screen = egl_pipe->get_screen(); - _xwindow = (X11_Window)NULL; - _ic = (XIC)NULL; _egl_display = egl_pipe->_egl_display; _egl_surface = 0; - _awaiting_configure = false; - _wm_delete_window = egl_pipe->_wm_delete_window; - _net_wm_window_type = egl_pipe->_net_wm_window_type; - _net_wm_window_type_splash = egl_pipe->_net_wm_window_type_splash; - _net_wm_window_type_fullscreen = egl_pipe->_net_wm_window_type_fullscreen; - _net_wm_state = egl_pipe->_net_wm_state; - _net_wm_state_fullscreen = egl_pipe->_net_wm_state_fullscreen; - _net_wm_state_above = egl_pipe->_net_wm_state_above; - _net_wm_state_below = egl_pipe->_net_wm_state_below; - _net_wm_state_add = egl_pipe->_net_wm_state_add; - _net_wm_state_remove = egl_pipe->_net_wm_state_remove; - - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse"); - add_input_device(device); } /** @@ -222,327 +194,6 @@ end_flip() { GraphicsWindow::end_flip(); } -/** - * Do whatever processing is necessary to ensure that the window responds to - * user events. Also, honor any requests recently made via - * request_properties() - * - * This function is called only within the window thread. - */ -void eglGraphicsWindow:: -process_events() { - LightReMutexHolder holder(eglGraphicsPipe::_x_mutex); - - GraphicsWindow::process_events(); - - if (_xwindow == (X11_Window)0) { - return; - } - - poll_raw_mice(); - - XEvent event; - XKeyEvent keyrelease_event; - bool got_keyrelease_event = false; - - while (XCheckIfEvent(_display, &event, check_event, (char *)this)) { - if (XFilterEvent(&event, None)) { - continue; - } - - if (got_keyrelease_event) { - // If a keyrelease event is immediately followed by a matching keypress - // event, that's just key repeat and we should treat the two events - // accordingly. It would be nice if X provided a way to differentiate - // between keyrepeat and explicit keypresses more generally. - got_keyrelease_event = false; - - if (event.type == KeyPress && - event.xkey.keycode == keyrelease_event.keycode && - (event.xkey.time - keyrelease_event.time <= 1)) { - // In particular, we only generate down messages for the repeated - // keys, not down-and-up messages. - handle_keystroke(event.xkey); - - // We thought about not generating the keypress event, but we need - // that repeat for backspace. Rethink later. - handle_keypress(event.xkey); - continue; - - } else { - // This keyrelease event is not immediately followed by a matching - // keypress event, so it's a genuine release. - handle_keyrelease(keyrelease_event); - } - } - - WindowProperties properties; - ButtonHandle button; - - switch (event.type) { - case ReparentNotify: - break; - - case ConfigureNotify: - _awaiting_configure = false; - if (_properties.get_fixed_size()) { - // If the window properties indicate a fixed size only, undo any - // attempt by the user to change them. In X, there doesn't appear to - // be a way to universally disallow this directly (although we do set - // the min_size and max_size to the same value, which seems to work - // for most window managers.) - WindowProperties current_props = get_properties(); - if (event.xconfigure.width != current_props.get_x_size() || - event.xconfigure.height != current_props.get_y_size()) { - XWindowChanges changes; - changes.width = current_props.get_x_size(); - changes.height = current_props.get_y_size(); - int value_mask = (CWWidth | CWHeight); - XConfigureWindow(_display, _xwindow, value_mask, &changes); - } - - } else { - // A normal window may be resized by the user at will. - properties.set_size(event.xconfigure.width, event.xconfigure.height); - system_changed_properties(properties); - } - break; - - case ButtonPress: - // This refers to the mouse buttons. - button = get_mouse_button(event.xbutton); - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); - _input_devices[0].button_down(button); - break; - - case ButtonRelease: - button = get_mouse_button(event.xbutton); - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); - _input_devices[0].button_up(button); - break; - - case MotionNotify: - _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y); - break; - - case KeyPress: - handle_keystroke(event.xkey); - handle_keypress(event.xkey); - break; - - case KeyRelease: - // The KeyRelease can't be processed immediately, because we have to - // check first if it's immediately followed by a matching KeyPress - // event. - keyrelease_event = event.xkey; - got_keyrelease_event = true; - break; - - case EnterNotify: - _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y); - break; - - case LeaveNotify: - _input_devices[0].set_pointer_out_of_window(); - break; - - case FocusIn: - properties.set_foreground(true); - system_changed_properties(properties); - break; - - case FocusOut: - properties.set_foreground(false); - system_changed_properties(properties); - break; - - case UnmapNotify: - properties.set_minimized(true); - system_changed_properties(properties); - break; - - case MapNotify: - properties.set_minimized(false); - system_changed_properties(properties); - - // Auto-focus the window when it is mapped. - XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime); - break; - - case ClientMessage: - if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) { - // This is a message from the window manager indicating that the user - // has requested to close the window. - string close_request_event = get_close_request_event(); - if (!close_request_event.empty()) { - // In this case, the app has indicated a desire to intercept the - // request and process it directly. - throw_event(close_request_event); - - } else { - // In this case, the default case, the app does not intend to - // service the request, so we do by closing the window. - - // TODO: don't release the gsg in the window thread. - close_window(); - properties.set_open(false); - system_changed_properties(properties); - } - } - break; - - case DestroyNotify: - // Apparently, we never get a DestroyNotify on a toplevel window. - // Instead, we rely on hints from the window manager (see above). - egldisplay_cat.info() - << "DestroyNotify\n"; - break; - - default: - egldisplay_cat.error() - << "unhandled X event type " << event.type << "\n"; - } - } - - if (got_keyrelease_event) { - // This keyrelease event is not immediately followed by a matching - // keypress event, so it's a genuine release. - handle_keyrelease(keyrelease_event); - } -} - -/** - * Applies the requested set of properties to the window, if possible, for - * instance to request a change in size or minimization status. - * - * The window properties are applied immediately, rather than waiting until - * the next frame. This implies that this method may *only* be called from - * within the window thread. - * - * The return value is true if the properties are set, false if they are - * ignored. This is mainly useful for derived classes to implement extensions - * to this function. - */ -void eglGraphicsWindow:: -set_properties_now(WindowProperties &properties) { - if (_pipe == (GraphicsPipe *)NULL) { - // If the pipe is null, we're probably closing down. - GraphicsWindow::set_properties_now(properties); - return; - } - - eglGraphicsPipe *egl_pipe; - DCAST_INTO_V(egl_pipe, _pipe); - - // Fullscreen mode is implemented with a hint to the window manager. - // However, we also implicitly set the origin to (0, 0) and the size to the - // desktop size, and request undecorated mode, in case the user has a less- - // capable window manager (or no window manager at all). - if (properties.get_fullscreen()) { - properties.set_undecorated(true); - properties.set_origin(0, 0); - properties.set_size(egl_pipe->get_display_width(), - egl_pipe->get_display_height()); - } - - GraphicsWindow::set_properties_now(properties); - if (!properties.is_any_specified()) { - // The base class has already handled this case. - return; - } - - // The window is already open; we are limited to what we can change on the - // fly. - - // We'll pass some property requests on as a window manager hint. - WindowProperties wm_properties = _properties; - wm_properties.add_properties(properties); - - // The window title may be changed by issuing another hint request. Assume - // this will be honored. - if (properties.has_title()) { - _properties.set_title(properties.get_title()); - properties.clear_title(); - } - - // Ditto for fullscreen mode. - if (properties.has_fullscreen()) { - _properties.set_fullscreen(properties.get_fullscreen()); - properties.clear_fullscreen(); - } - - // The size and position of an already-open window are changed via explicit - // X calls. These may still get intercepted by the window manager. Rather - // than changing _properties immediately, we'll wait for the ConfigureNotify - // message to come back. - XWindowChanges changes; - int value_mask = 0; - - if (properties.has_origin()) { - changes.x = properties.get_x_origin(); - changes.y = properties.get_y_origin(); - value_mask |= (CWX | CWY); - properties.clear_origin(); - } - if (properties.has_size()) { - changes.width = properties.get_x_size(); - changes.height = properties.get_y_size(); - value_mask |= (CWWidth | CWHeight); - properties.clear_size(); - } - if (properties.has_z_order()) { - // We'll send the classic stacking request through the standard interface, - // for users of primitive window managers; but we'll also send it as a - // window manager hint, for users of modern window managers. - _properties.set_z_order(properties.get_z_order()); - switch (properties.get_z_order()) { - case WindowProperties::Z_bottom: - changes.stack_mode = Below; - break; - - case WindowProperties::Z_normal: - changes.stack_mode = TopIf; - break; - - case WindowProperties::Z_top: - changes.stack_mode = Above; - break; - } - - value_mask |= (CWStackMode); - properties.clear_z_order(); - } - - if (value_mask != 0) { - XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes); - - // Don't draw anything until this is done reconfiguring. - _awaiting_configure = true; - } - - // We hide the cursor by setting it to an invisible pixmap. - if (properties.has_cursor_hidden()) { - _properties.set_cursor_hidden(properties.get_cursor_hidden()); - if (properties.get_cursor_hidden()) { - XDefineCursor(_display, _xwindow, egl_pipe->get_hidden_cursor()); - } else { - XDefineCursor(_display, _xwindow, None); - } - properties.clear_cursor_hidden(); - } - - if (properties.has_foreground()) { - if (properties.get_foreground()) { - XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime); - } else { - XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime); - } - properties.clear_foreground(); - } - - set_wm_properties(wm_properties, true); -} - /** * Closes the window right now. Called from the window thread. */ @@ -606,97 +257,19 @@ open_window() { } } - XVisualInfo *visual_info = eglgsg->_visual; - if (visual_info == NULL) { + _visual_info = eglgsg->_visual; + if (_visual_info == NULL) { // No X visual for this fbconfig; how can we open the window? egldisplay_cat.error() << "No X visual: cannot open window.\n"; return false; } - Visual *visual = visual_info->visual; - int depth = visual_info->depth; - if (!_properties.has_origin()) { - _properties.set_origin(0, 0); - } - if (!_properties.has_size()) { - _properties.set_size(100, 100); - } + setup_colormap(_visual_info); - X11_Window parent_window = egl_pipe->get_root(); - WindowHandle *window_handle = _properties.get_parent_window(); - if (window_handle != NULL) { - egldisplay_cat.info() - << "Got parent_window " << *window_handle << "\n"; - WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); - if (os_handle != NULL) { - egldisplay_cat.info() - << "os_handle type " << os_handle->get_type() << "\n"; - - if (os_handle->is_of_type(NativeWindowHandle::X11Handle::get_class_type())) { - NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle); - parent_window = x11_handle->get_handle(); - } else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) { - NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle); - parent_window = (X11_Window)int_handle->get_handle(); - } - } - } - _parent_window_handle = window_handle; - - setup_colormap(visual_info); - - _event_mask = - ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask | - EnterWindowMask | LeaveWindowMask | - PointerMotionMask | - FocusChangeMask | - StructureNotifyMask; - - // Initialize window attributes - XSetWindowAttributes wa; - wa.background_pixel = XBlackPixel(_display, _screen); - wa.border_pixel = 0; - wa.colormap = _colormap; - wa.event_mask = _event_mask; - - unsigned long attrib_mask = - CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; - - _xwindow = XCreateWindow - (_display, parent_window, - _properties.get_x_origin(), _properties.get_y_origin(), - _properties.get_x_size(), _properties.get_y_size(), - 0, depth, InputOutput, visual, attrib_mask, &wa); - - if (_xwindow == (X11_Window)0) { - egldisplay_cat.error() - << "failed to create X window.\n"; + if (!x11GraphicsWindow::open_window()) { return false; } - set_wm_properties(_properties, false); - - // We don't specify any fancy properties of the XIC. It would be nicer if - // we could support fancy IM's that want preedit callbacks, etc., but that - // can wait until we have an X server that actually supports these to test - // it on. - XIM im = egl_pipe->get_im(); - _ic = NULL; - if (im) { - _ic = XCreateIC - (im, - XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - (void*)NULL); - if (_ic == (XIC)NULL) { - egldisplay_cat.warning() - << "Couldn't create input context.\n"; - } - } - - if (_properties.get_cursor_hidden()) { - XDefineCursor(_display, _xwindow, egl_pipe->get_hidden_cursor()); - } _egl_surface = eglCreateWindowSurface(_egl_display, eglgsg->_fbconfig, (NativeWindowType) _xwindow, NULL); if (eglGetError() != EGL_SUCCESS) { @@ -721,923 +294,5 @@ open_window() { } _fb_properties = eglgsg->get_fb_properties(); - XMapWindow(_display, _xwindow); - - if (_properties.get_raw_mice()) { - open_raw_mice(); - } else { - if (egldisplay_cat.is_debug()) { - egldisplay_cat.debug() - << "Raw mice not requested.\n"; - } - } - - // Create a WindowHandle for ourselves - _window_handle = NativeWindowHandle::make_x11(_xwindow); - - // And tell our parent window that we're now its child. - if (_parent_window_handle != (WindowHandle *)NULL) { - _parent_window_handle->attach_child(_window_handle); - } - return true; } - -/** - * Asks the window manager to set the appropriate properties. In X, these - * properties cannot be specified directly by the application; they must be - * requested via the window manager, which may or may not choose to honor the - * request. - * - * If already_mapped is true, the window has already been mapped (manifested) - * on the display. This means we may need to use a different action in some - * cases. - */ -void eglGraphicsWindow:: -set_wm_properties(const WindowProperties &properties, bool already_mapped) { - // Name the window if there is a name - XTextProperty window_name; - XTextProperty *window_name_p = (XTextProperty *)NULL; - if (properties.has_title()) { - char *name = (char *)properties.get_title().c_str(); - if (XStringListToTextProperty(&name, 1, &window_name) != 0) { - window_name_p = &window_name; - } - } - - // The size hints request a window of a particular size andor a particular - // placement onscreen. - XSizeHints *size_hints_p = NULL; - if (properties.has_origin() || properties.has_size()) { - size_hints_p = XAllocSizeHints(); - if (size_hints_p != (XSizeHints *)NULL) { - if (properties.has_origin()) { - size_hints_p->x = properties.get_x_origin(); - size_hints_p->y = properties.get_y_origin(); - size_hints_p->flags |= USPosition; - } - if (properties.has_size()) { - size_hints_p->width = properties.get_x_size(); - size_hints_p->height = properties.get_y_size(); - size_hints_p->flags |= USSize; - - if (properties.get_fixed_size()) { - size_hints_p->min_width = properties.get_x_size(); - size_hints_p->min_height = properties.get_y_size(); - size_hints_p->max_width = properties.get_x_size(); - size_hints_p->max_height = properties.get_y_size(); - size_hints_p->flags |= (PMinSize | PMaxSize); - } - } - } - } - - // The window manager hints include requests to the window manager other - // than those specific to window geometry. - XWMHints *wm_hints_p = NULL; - wm_hints_p = XAllocWMHints(); - if (wm_hints_p != (XWMHints *)NULL) { - if (properties.has_minimized() && properties.get_minimized()) { - wm_hints_p->initial_state = IconicState; - } else { - wm_hints_p->initial_state = NormalState; - } - wm_hints_p->flags = StateHint; - } - - // Two competing window manager interfaces have evolved. One of them allows - // to set certain properties as a "type"; the other one as a "state". We'll - // try to honor both. - static const int max_type_data = 32; - PN_int32 type_data[max_type_data]; - int next_type_data = 0; - - static const int max_state_data = 32; - PN_int32 state_data[max_state_data]; - int next_state_data = 0; - - static const int max_set_data = 32; - class SetAction { - public: - inline SetAction() { } - inline SetAction(Atom state, Atom action) : _state(state), _action(action) { } - Atom _state; - Atom _action; - }; - SetAction set_data[max_set_data]; - int next_set_data = 0; - - if (properties.get_fullscreen()) { - // For a "fullscreen" request, we pass this through, hoping the window - // manager will support EWMH. - type_data[next_type_data++] = _net_wm_window_type_fullscreen; - - // We also request it as a state. - state_data[next_state_data++] = _net_wm_state_fullscreen; - set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, _net_wm_state_add); - } else { - set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, _net_wm_state_remove); - } - - // If we asked for a window without a border, there's no excellent way to - // arrange that. For users whose window managers follow the EWMH - // specification, we can ask for a "splash" screen, which is usually - // undecorated. It's not exactly right, but the spec doesn't give us an - // exactly-right option. - - // For other users, we'll totally punt and just set the window's Class to - // "Undecorated", and let the user configure hisher window manager not to - // put a border around windows of this class. - XClassHint *class_hints_p = NULL; - if (properties.get_undecorated()) { - class_hints_p = XAllocClassHint(); - class_hints_p->res_class = (char*) "Undecorated"; - - if (!properties.get_fullscreen()) { - type_data[next_type_data++] = _net_wm_window_type_splash; - } - } - - if (properties.has_z_order()) { - switch (properties.get_z_order()) { - case WindowProperties::Z_bottom: - state_data[next_state_data++] = _net_wm_state_below; - set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_add); - set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove); - break; - - case WindowProperties::Z_normal: - set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove); - set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove); - break; - - case WindowProperties::Z_top: - state_data[next_state_data++] = _net_wm_state_above; - set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove); - set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_add); - break; - } - } - - nassertv(next_type_data < max_type_data); - nassertv(next_state_data < max_state_data); - nassertv(next_set_data < max_set_data); - - XChangeProperty(_display, _xwindow, _net_wm_window_type, - XA_ATOM, 32, PropModeReplace, - (unsigned char *)type_data, next_type_data); - - // Request the state properties all at once. - XChangeProperty(_display, _xwindow, _net_wm_state, - XA_ATOM, 32, PropModeReplace, - (unsigned char *)state_data, next_state_data); - - if (already_mapped) { - // We have to request state changes differently when the window has been - // mapped. To do this, we need to send a client message to the root - // window for each change. - - eglGraphicsPipe *egl_pipe; - DCAST_INTO_V(egl_pipe, _pipe); - - for (int i = 0; i < next_set_data; ++i) { - XClientMessageEvent event; - memset(&event, 0, sizeof(event)); - - event.type = ClientMessage; - event.send_event = True; - event.display = _display; - event.window = _xwindow; - event.message_type = _net_wm_state; - event.format = 32; - event.data.l[0] = set_data[i]._action; - event.data.l[1] = set_data[i]._state; - event.data.l[2] = 0; - event.data.l[3] = 1; - - XSendEvent(_display, egl_pipe->get_root(), True, 0, (XEvent *)&event); - } - } - - XSetWMProperties(_display, _xwindow, window_name_p, window_name_p, - NULL, 0, size_hints_p, wm_hints_p, class_hints_p); - - if (size_hints_p != (XSizeHints *)NULL) { - XFree(size_hints_p); - } - if (wm_hints_p != (XWMHints *)NULL) { - XFree(wm_hints_p); - } - if (class_hints_p != (XClassHint *)NULL) { - XFree(class_hints_p); - } - - // Also, indicate to the window manager that we'd like to get a chance to - // close our windows cleanly, rather than being rudely disconnected from the - // X server if the user requests a window close. - Atom protocols[] = { - _wm_delete_window, - }; - - XSetWMProtocols(_display, _xwindow, protocols, - sizeof(protocols) / sizeof(Atom)); -} - -/** - * Allocates a colormap appropriate to the visual and stores in in the - * _colormap method. - */ -void eglGraphicsWindow:: -setup_colormap(XVisualInfo *visual) { - eglGraphicsPipe *egl_pipe; - DCAST_INTO_V(egl_pipe, _pipe); - X11_Window root_window = egl_pipe->get_root(); - - int visual_class = visual->c_class; - int rc, is_rgb; - - switch (visual_class) { - case PseudoColor: - _colormap = XCreateColormap(_display, root_window, - visual->visual, AllocAll); - break; - case TrueColor: - case DirectColor: - _colormap = XCreateColormap(_display, root_window, - visual->visual, AllocNone); - break; - case StaticColor: - case StaticGray: - case GrayScale: - _colormap = XCreateColormap(_display, root_window, - visual->visual, AllocNone); - break; - default: - egldisplay_cat.error() - << "Could not allocate a colormap for visual class " - << visual_class << ".\n"; - break; - } -} - -/** - * Adds raw mice to the _input_devices list. - */ -void eglGraphicsWindow:: -open_raw_mice() -{ -#ifdef HAVE_LINUX_INPUT_H - bool any_present = false; - bool any_mice = false; - - for (int i=0; i<64; i++) { - uint8_t evtypes[EV_MAX/8 + 1]; - ostringstream fnb; - fnb << "/dev/input/event" << i; - string fn = fnb.str(); - int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0); - if (fd >= 0) { - any_present = true; - char name[256]; - char phys[256]; - char uniq[256]; - if ((ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)|| - (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)|| - (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)|| - (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) { - close(fd); - egldisplay_cat.error() << - "Opening raw mice: ioctl failed on " << fn << "\n"; - } else { - if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) { - for (char *p=name; *p; p++) { - if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) { - *p = '_'; - } - } - for (char *p=uniq; *p; p++) { - if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) { - *p = '_'; - } - } - string full_id = ((string)name) + "." + uniq; - MouseDeviceInfo inf; - inf._fd = fd; - inf._input_device_index = _input_devices.size(); - inf._io_buffer = ""; - _mouse_device_info.push_back(inf); - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_only(this, full_id); - add_input_device(device); - egldisplay_cat.info() << "Raw mouse " << - inf._input_device_index << " detected: " << full_id << "\n"; - any_mice = true; - } else { - close(fd); - } - } - } else { - if ((errno == ENOENT)||(errno == ENOTDIR)) { - break; - } else { - any_present = true; - egldisplay_cat.error() << - "Opening raw mice: " << strerror(errno) << " " << fn << "\n"; - } - } - } - - if (!any_present) { - egldisplay_cat.error() << - "Opening raw mice: files not found: /dev/input/event*\n"; - } else if (!any_mice) { - egldisplay_cat.error() << - "Opening raw mice: no mouse devices detected in /dev/input/event*\n"; - } -#else - egldisplay_cat.error() << - "Opening raw mice: panda not compiled with raw mouse support.\n"; -#endif -} - -/** - * Reads events from the raw mouse device files. - */ -void eglGraphicsWindow:: -poll_raw_mice() -{ -#ifdef HAVE_LINUX_INPUT_H - for (int dev=0; dev<_mouse_device_info.size(); dev++) { - MouseDeviceInfo &inf = _mouse_device_info[dev]; - - // Read all bytes into buffer. - if (inf._fd >= 0) { - while (1) { - char tbuf[1024]; - int nread = read(inf._fd, tbuf, sizeof(tbuf)); - if (nread > 0) { - inf._io_buffer += string(tbuf, nread); - } else { - if ((nread < 0)&&((errno == EWOULDBLOCK) || (errno==EAGAIN))) { - break; - } - close(inf._fd); - inf._fd = -1; - break; - } - } - } - - // Process events. - int nevents = inf._io_buffer.size() / sizeof(struct input_event); - if (nevents == 0) { - continue; - } - const input_event *events = (const input_event *)(inf._io_buffer.c_str()); - GraphicsWindowInputDevice &dev = _input_devices[inf._input_device_index]; - int x = dev.get_raw_pointer().get_x(); - int y = dev.get_raw_pointer().get_y(); - for (int i=0; i= BTN_MOUSE)&&(events[i].code < BTN_MOUSE+8)) { - int btn = events[i].code - BTN_MOUSE; - dev.set_pointer_in_window(x,y); - if (events[i].value) { - dev.button_down(MouseButton::button(btn)); - } else { - dev.button_up(MouseButton::button(btn)); - } - } - } - } - inf._io_buffer.erase(0,nevents*sizeof(struct input_event)); - dev.set_pointer_in_window(x,y); - } -#endif -} - -/** - * Generates a keystroke corresponding to the indicated X KeyPress event. - */ -void eglGraphicsWindow:: -handle_keystroke(XKeyEvent &event) { - _input_devices[0].set_pointer_in_window(event.x, event.y); - - if (_ic) { - // First, get the keystroke as a wide-character sequence. - static const int buffer_size = 256; - wchar_t buffer[buffer_size]; - Status status; - int len = XwcLookupString(_ic, &event, buffer, buffer_size, NULL, - &status); - if (status == XBufferOverflow) { - egldisplay_cat.error() - << "Overflowed input buffer.\n"; - } - - // Now each of the returned wide characters represents a keystroke. - for (int i = 0; i < len; i++) { - _input_devices[0].keystroke(buffer[i]); - } - - } else { - // Without an input context, just get the ascii keypress. - ButtonHandle button = get_button(event, true); - if (button.has_ascii_equivalent()) { - _input_devices[0].keystroke(button.get_ascii_equivalent()); - } - } -} - -/** - * Generates a keypress corresponding to the indicated X KeyPress event. - */ -void eglGraphicsWindow:: -handle_keypress(XKeyEvent &event) { - _input_devices[0].set_pointer_in_window(event.x, event.y); - - // Now get the raw unshifted button. - ButtonHandle button = get_button(event, false); - if (button != ButtonHandle::none()) { - if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) { - _input_devices[0].button_down(KeyboardButton::control()); - } - if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) { - _input_devices[0].button_down(KeyboardButton::shift()); - } - if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) { - _input_devices[0].button_down(KeyboardButton::alt()); - } - if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) { - _input_devices[0].button_down(KeyboardButton::meta()); - } - _input_devices[0].button_down(button); - } -} - -/** - * Generates a keyrelease corresponding to the indicated X KeyRelease event. - */ -void eglGraphicsWindow:: -handle_keyrelease(XKeyEvent &event) { - _input_devices[0].set_pointer_in_window(event.x, event.y); - - // Now get the raw unshifted button. - ButtonHandle button = get_button(event, false); - if (button != ButtonHandle::none()) { - if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) { - _input_devices[0].button_up(KeyboardButton::control()); - } - if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) { - _input_devices[0].button_up(KeyboardButton::shift()); - } - if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) { - _input_devices[0].button_up(KeyboardButton::alt()); - } - if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) { - _input_devices[0].button_up(KeyboardButton::meta()); - } - _input_devices[0].button_up(button); - } -} - -/** - * Returns the Panda ButtonHandle corresponding to the keyboard button - * indicated by the given key event. - */ -ButtonHandle eglGraphicsWindow:: -get_button(XKeyEvent &key_event, bool allow_shift) { - KeySym key = XLookupKeysym(&key_event, 0); - - if ((key_event.state & Mod2Mask) != 0) { - // Mod2Mask corresponds to NumLock being in effect. In this case, we want - // to get the alternate keysym associated with any keypad keys. Weird - // system. - KeySym k2; - ButtonHandle button; - switch (key) { - case XK_KP_Space: - case XK_KP_Tab: - case XK_KP_Enter: - case XK_KP_F1: - case XK_KP_F2: - case XK_KP_F3: - case XK_KP_F4: - case XK_KP_Equal: - case XK_KP_Multiply: - case XK_KP_Add: - case XK_KP_Separator: - case XK_KP_Subtract: - case XK_KP_Divide: - case XK_KP_Left: - case XK_KP_Up: - case XK_KP_Right: - case XK_KP_Down: - case XK_KP_Begin: - case XK_KP_Prior: - case XK_KP_Next: - case XK_KP_Home: - case XK_KP_End: - case XK_KP_Insert: - case XK_KP_Delete: - case XK_KP_0: - case XK_KP_1: - case XK_KP_2: - case XK_KP_3: - case XK_KP_4: - case XK_KP_5: - case XK_KP_6: - case XK_KP_7: - case XK_KP_8: - case XK_KP_9: - k2 = XLookupKeysym(&key_event, 1); - button = map_button(k2); - if (button != ButtonHandle::none()) { - return button; - } - // If that didn't produce a button we know, just fall through and handle - // the normal, un-numlocked key. - break; - - default: - break; - } - } - - if (allow_shift) { - // If shift is held down, get the shifted keysym. - if ((key_event.state & ShiftMask) != 0) { - KeySym k2 = XLookupKeysym(&key_event, 1); - ButtonHandle button = map_button(k2); - if (button != ButtonHandle::none()) { - return button; - } - } - - // If caps lock is down, shift lowercase letters to uppercase. We can do - // this in just the ASCII set, because we handle international keyboards - // elsewhere (via an input context). - if ((key_event.state & (ShiftMask | LockMask)) != 0) { - if (key >= XK_a and key <= XK_z) { - key += (XK_A - XK_a); - } - } - } - - return map_button(key); -} - -/** - * Maps from a single X keysym to Panda's ButtonHandle. Called by - * get_button(), above. - */ -ButtonHandle eglGraphicsWindow:: -map_button(KeySym key) { - switch (key) { - case XK_BackSpace: - return KeyboardButton::backspace(); - case XK_Tab: - case XK_KP_Tab: - return KeyboardButton::tab(); - case XK_Return: - case XK_KP_Enter: - return KeyboardButton::enter(); - case XK_Escape: - return KeyboardButton::escape(); - case XK_KP_Space: - case XK_space: - return KeyboardButton::space(); - case XK_exclam: - return KeyboardButton::ascii_key('!'); - case XK_quotedbl: - return KeyboardButton::ascii_key('"'); - case XK_numbersign: - return KeyboardButton::ascii_key('#'); - case XK_dollar: - return KeyboardButton::ascii_key('$'); - case XK_percent: - return KeyboardButton::ascii_key('%'); - case XK_ampersand: - return KeyboardButton::ascii_key('&'); - case XK_apostrophe: // == XK_quoteright - return KeyboardButton::ascii_key('\''); - case XK_parenleft: - return KeyboardButton::ascii_key('('); - case XK_parenright: - return KeyboardButton::ascii_key(')'); - case XK_asterisk: - case XK_KP_Multiply: - return KeyboardButton::ascii_key('*'); - case XK_plus: - case XK_KP_Add: - return KeyboardButton::ascii_key('+'); - case XK_comma: - case XK_KP_Separator: - return KeyboardButton::ascii_key(','); - case XK_minus: - case XK_KP_Subtract: - return KeyboardButton::ascii_key('-'); - case XK_period: - case XK_KP_Decimal: - return KeyboardButton::ascii_key('.'); - case XK_slash: - case XK_KP_Divide: - return KeyboardButton::ascii_key('/'); - case XK_0: - case XK_KP_0: - return KeyboardButton::ascii_key('0'); - case XK_1: - case XK_KP_1: - return KeyboardButton::ascii_key('1'); - case XK_2: - case XK_KP_2: - return KeyboardButton::ascii_key('2'); - case XK_3: - case XK_KP_3: - return KeyboardButton::ascii_key('3'); - case XK_4: - case XK_KP_4: - return KeyboardButton::ascii_key('4'); - case XK_5: - case XK_KP_5: - return KeyboardButton::ascii_key('5'); - case XK_6: - case XK_KP_6: - return KeyboardButton::ascii_key('6'); - case XK_7: - case XK_KP_7: - return KeyboardButton::ascii_key('7'); - case XK_8: - case XK_KP_8: - return KeyboardButton::ascii_key('8'); - case XK_9: - case XK_KP_9: - return KeyboardButton::ascii_key('9'); - case XK_colon: - return KeyboardButton::ascii_key(':'); - case XK_semicolon: - return KeyboardButton::ascii_key(';'); - case XK_less: - return KeyboardButton::ascii_key('<'); - case XK_equal: - case XK_KP_Equal: - return KeyboardButton::ascii_key('='); - case XK_greater: - return KeyboardButton::ascii_key('>'); - case XK_question: - return KeyboardButton::ascii_key('?'); - case XK_at: - return KeyboardButton::ascii_key('@'); - case XK_A: - return KeyboardButton::ascii_key('A'); - case XK_B: - return KeyboardButton::ascii_key('B'); - case XK_C: - return KeyboardButton::ascii_key('C'); - case XK_D: - return KeyboardButton::ascii_key('D'); - case XK_E: - return KeyboardButton::ascii_key('E'); - case XK_F: - return KeyboardButton::ascii_key('F'); - case XK_G: - return KeyboardButton::ascii_key('G'); - case XK_H: - return KeyboardButton::ascii_key('H'); - case XK_I: - return KeyboardButton::ascii_key('I'); - case XK_J: - return KeyboardButton::ascii_key('J'); - case XK_K: - return KeyboardButton::ascii_key('K'); - case XK_L: - return KeyboardButton::ascii_key('L'); - case XK_M: - return KeyboardButton::ascii_key('M'); - case XK_N: - return KeyboardButton::ascii_key('N'); - case XK_O: - return KeyboardButton::ascii_key('O'); - case XK_P: - return KeyboardButton::ascii_key('P'); - case XK_Q: - return KeyboardButton::ascii_key('Q'); - case XK_R: - return KeyboardButton::ascii_key('R'); - case XK_S: - return KeyboardButton::ascii_key('S'); - case XK_T: - return KeyboardButton::ascii_key('T'); - case XK_U: - return KeyboardButton::ascii_key('U'); - case XK_V: - return KeyboardButton::ascii_key('V'); - case XK_W: - return KeyboardButton::ascii_key('W'); - case XK_X: - return KeyboardButton::ascii_key('X'); - case XK_Y: - return KeyboardButton::ascii_key('Y'); - case XK_Z: - return KeyboardButton::ascii_key('Z'); - case XK_bracketleft: - return KeyboardButton::ascii_key('['); - case XK_backslash: - return KeyboardButton::ascii_key('\\'); - case XK_bracketright: - return KeyboardButton::ascii_key(']'); - case XK_asciicircum: - return KeyboardButton::ascii_key('^'); - case XK_underscore: - return KeyboardButton::ascii_key('_'); - case XK_grave: // == XK_quoteleft - return KeyboardButton::ascii_key('`'); - case XK_a: - return KeyboardButton::ascii_key('a'); - case XK_b: - return KeyboardButton::ascii_key('b'); - case XK_c: - return KeyboardButton::ascii_key('c'); - case XK_d: - return KeyboardButton::ascii_key('d'); - case XK_e: - return KeyboardButton::ascii_key('e'); - case XK_f: - return KeyboardButton::ascii_key('f'); - case XK_g: - return KeyboardButton::ascii_key('g'); - case XK_h: - return KeyboardButton::ascii_key('h'); - case XK_i: - return KeyboardButton::ascii_key('i'); - case XK_j: - return KeyboardButton::ascii_key('j'); - case XK_k: - return KeyboardButton::ascii_key('k'); - case XK_l: - return KeyboardButton::ascii_key('l'); - case XK_m: - return KeyboardButton::ascii_key('m'); - case XK_n: - return KeyboardButton::ascii_key('n'); - case XK_o: - return KeyboardButton::ascii_key('o'); - case XK_p: - return KeyboardButton::ascii_key('p'); - case XK_q: - return KeyboardButton::ascii_key('q'); - case XK_r: - return KeyboardButton::ascii_key('r'); - case XK_s: - return KeyboardButton::ascii_key('s'); - case XK_t: - return KeyboardButton::ascii_key('t'); - case XK_u: - return KeyboardButton::ascii_key('u'); - case XK_v: - return KeyboardButton::ascii_key('v'); - case XK_w: - return KeyboardButton::ascii_key('w'); - case XK_x: - return KeyboardButton::ascii_key('x'); - case XK_y: - return KeyboardButton::ascii_key('y'); - case XK_z: - return KeyboardButton::ascii_key('z'); - case XK_braceleft: - return KeyboardButton::ascii_key('{'); - case XK_bar: - return KeyboardButton::ascii_key('|'); - case XK_braceright: - return KeyboardButton::ascii_key('}'); - case XK_asciitilde: - return KeyboardButton::ascii_key('~'); - case XK_F1: - case XK_KP_F1: - return KeyboardButton::f1(); - case XK_F2: - case XK_KP_F2: - return KeyboardButton::f2(); - case XK_F3: - case XK_KP_F3: - return KeyboardButton::f3(); - case XK_F4: - case XK_KP_F4: - return KeyboardButton::f4(); - case XK_F5: - return KeyboardButton::f5(); - case XK_F6: - return KeyboardButton::f6(); - case XK_F7: - return KeyboardButton::f7(); - case XK_F8: - return KeyboardButton::f8(); - case XK_F9: - return KeyboardButton::f9(); - case XK_F10: - return KeyboardButton::f10(); - case XK_F11: - return KeyboardButton::f11(); - case XK_F12: - return KeyboardButton::f12(); - case XK_KP_Left: - case XK_Left: - return KeyboardButton::left(); - case XK_KP_Up: - case XK_Up: - return KeyboardButton::up(); - case XK_KP_Right: - case XK_Right: - return KeyboardButton::right(); - case XK_KP_Down: - case XK_Down: - return KeyboardButton::down(); - case XK_KP_Prior: - case XK_Prior: - return KeyboardButton::page_up(); - case XK_KP_Next: - case XK_Next: - return KeyboardButton::page_down(); - case XK_KP_Home: - case XK_Home: - return KeyboardButton::home(); - case XK_KP_End: - case XK_End: - return KeyboardButton::end(); - case XK_KP_Insert: - case XK_Insert: - return KeyboardButton::insert(); - case XK_KP_Delete: - case XK_Delete: - return KeyboardButton::del(); - case XK_Num_Lock: - return KeyboardButton::num_lock(); - case XK_Scroll_Lock: - return KeyboardButton::scroll_lock(); - case XK_Print: - return KeyboardButton::print_screen(); - case XK_Pause: - return KeyboardButton::pause(); - case XK_Menu: - return KeyboardButton::menu(); - case XK_Shift_L: - return KeyboardButton::lshift(); - case XK_Shift_R: - return KeyboardButton::rshift(); - case XK_Control_L: - return KeyboardButton::lcontrol(); - case XK_Control_R: - return KeyboardButton::rcontrol(); - case XK_Alt_L: - return KeyboardButton::lalt(); - case XK_Alt_R: - return KeyboardButton::ralt(); - case XK_Meta_L: - return KeyboardButton::lmeta(); - case XK_Meta_R: - return KeyboardButton::rmeta(); - case XK_Caps_Lock: - return KeyboardButton::caps_lock(); - case XK_Shift_Lock: - return KeyboardButton::shift_lock(); - } - - return ButtonHandle::none(); -} - -/** - * Returns the Panda ButtonHandle corresponding to the mouse button indicated - * by the given button event. - */ -ButtonHandle eglGraphicsWindow:: -get_mouse_button(XButtonEvent &button_event) { - int index = button_event.button; - if (index == x_wheel_up_button) { - return MouseButton::wheel_up(); - } else if (index == x_wheel_down_button) { - return MouseButton::wheel_down(); - } else if (index == x_wheel_left_button) { - return MouseButton::wheel_left(); - } else if (index == x_wheel_right_button) { - return MouseButton::wheel_right(); - } else { - return MouseButton::button(index - 1); - } -} -/** - * This function is used as a predicate to XCheckIfEvent() to determine if the - * indicated queued X event is relevant and should be returned to this window. - */ -Bool eglGraphicsWindow:: -check_event(X11_Display *display, XEvent *event, char *arg) { - const eglGraphicsWindow *self = (eglGraphicsWindow *)arg; - - // We accept any event that is sent to our window. - return (event->xany.window == self->_xwindow); -} diff --git a/panda/src/egldisplay/eglGraphicsWindow.h b/panda/src/egldisplay/eglGraphicsWindow.h index 4a17920791..508365cc65 100644 --- a/panda/src/egldisplay/eglGraphicsWindow.h +++ b/panda/src/egldisplay/eglGraphicsWindow.h @@ -17,14 +17,12 @@ #include "pandabase.h" #include "eglGraphicsPipe.h" -#include "graphicsWindow.h" -#include "buttonHandle.h" -#include "get_x11.h" +#include "x11GraphicsWindow.h" /** * An interface to the egl system for managing GLES windows under X. */ -class eglGraphicsWindow : public GraphicsWindow { +class eglGraphicsWindow : public x11GraphicsWindow { public: eglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, const string &name, @@ -40,70 +38,22 @@ public: virtual void end_frame(FrameMode mode, Thread *current_thread); virtual void end_flip(); - virtual void process_events(); - virtual void set_properties_now(WindowProperties &properties); - - INLINE X11_Window get_xwindow() const; - protected: virtual void close_window(); virtual bool open_window(); private: - void set_wm_properties(const WindowProperties &properties, - bool already_mapped); - - void setup_colormap(XVisualInfo *visual); - void handle_keystroke(XKeyEvent &event); - void handle_keypress(XKeyEvent &event); - void handle_keyrelease(XKeyEvent &event); - - ButtonHandle get_button(XKeyEvent &key_event, bool allow_shift); - ButtonHandle map_button(KeySym key); - ButtonHandle get_mouse_button(XButtonEvent &button_event); - - static Bool check_event(X11_Display *display, XEvent *event, char *arg); - - void open_raw_mice(); - void poll_raw_mice(); - -private: - X11_Display *_display; - int _screen; - X11_Window _xwindow; - Colormap _colormap; - XIC _ic; EGLDisplay _egl_display; EGLSurface _egl_surface; - long _event_mask; - bool _awaiting_configure; - Atom _wm_delete_window; - Atom _net_wm_window_type; - Atom _net_wm_window_type_splash; - Atom _net_wm_window_type_fullscreen; - Atom _net_wm_state; - Atom _net_wm_state_fullscreen; - Atom _net_wm_state_above; - Atom _net_wm_state_below; - Atom _net_wm_state_add; - Atom _net_wm_state_remove; - - struct MouseDeviceInfo { - int _fd; - int _input_device_index; - string _io_buffer; - }; - pvector _mouse_device_info; - public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - GraphicsWindow::init_type(); + x11GraphicsWindow::init_type(); register_type(_type_handle, "eglGraphicsWindow", - GraphicsWindow::get_class_type()); + x11GraphicsWindow::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type();