diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/ThirdParty/ANGLE/util/x11/X11Window.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/ThirdParty/ANGLE/util/x11/X11Window.cpp')
-rw-r--r-- | Source/ThirdParty/ANGLE/util/x11/X11Window.cpp | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/Source/ThirdParty/ANGLE/util/x11/X11Window.cpp b/Source/ThirdParty/ANGLE/util/x11/X11Window.cpp new file mode 100644 index 000000000..869e32c3c --- /dev/null +++ b/Source/ThirdParty/ANGLE/util/x11/X11Window.cpp @@ -0,0 +1,611 @@ +// +// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// X11Window.cpp: Implementation of OSWindow for X11 + +#include "x11/X11Window.h" + +#include "common/debug.h" +#include "system_utils.h" +#include "Timer.h" + +namespace { + +Bool WaitForMapNotify(Display *dpy, XEvent *event, XPointer window) +{ + return event->type == MapNotify && event->xmap.window == reinterpret_cast<Window>(window); +} + +static Key X11CodeToKey(Display *display, unsigned int scancode) +{ + int temp; + KeySym *keySymbols; + keySymbols = XGetKeyboardMapping(display, scancode, 1, &temp); + + unsigned int keySymbol = keySymbols[0]; + XFree(keySymbols); + + switch (keySymbol) + { + case XK_Shift_L: return KEY_LSHIFT; + case XK_Shift_R: return KEY_RSHIFT; + case XK_Alt_L: return KEY_LALT; + case XK_Alt_R: return KEY_RALT; + case XK_Control_L: return KEY_LCONTROL; + case XK_Control_R: return KEY_RCONTROL; + case XK_Super_L: return KEY_LSYSTEM; + case XK_Super_R: return KEY_RSYSTEM; + case XK_Menu: return KEY_MENU; + + case XK_semicolon: return KEY_SEMICOLON; + case XK_slash: return KEY_SLASH; + case XK_equal: return KEY_EQUAL; + case XK_minus: return KEY_DASH; + case XK_bracketleft: return KEY_LBRACKET; + case XK_bracketright:return KEY_RBRACKET; + case XK_comma: return KEY_COMMA; + case XK_period: return KEY_PERIOD; + case XK_backslash: return KEY_BACKSLASH; + case XK_asciitilde: return KEY_TILDE; + case XK_Escape: return KEY_ESCAPE; + case XK_space: return KEY_SPACE; + case XK_Return: return KEY_RETURN; + case XK_BackSpace: return KEY_BACK; + case XK_Tab: return KEY_TAB; + case XK_Page_Up: return KEY_PAGEUP; + case XK_Page_Down: return KEY_PAGEDOWN; + case XK_End: return KEY_END; + case XK_Home: return KEY_HOME; + case XK_Insert: return KEY_INSERT; + case XK_Delete: return KEY_DELETE; + case XK_KP_Add: return KEY_ADD; + case XK_KP_Subtract: return KEY_SUBTRACT; + case XK_KP_Multiply: return KEY_MULTIPLY; + case XK_KP_Divide: return KEY_DIVIDE; + case XK_Pause: return KEY_PAUSE; + + case XK_F1: return KEY_F1; + case XK_F2: return KEY_F2; + case XK_F3: return KEY_F3; + case XK_F4: return KEY_F4; + case XK_F5: return KEY_F5; + case XK_F6: return KEY_F6; + case XK_F7: return KEY_F7; + case XK_F8: return KEY_F8; + case XK_F9: return KEY_F9; + case XK_F10: return KEY_F10; + case XK_F11: return KEY_F11; + case XK_F12: return KEY_F12; + case XK_F13: return KEY_F13; + case XK_F14: return KEY_F14; + case XK_F15: return KEY_F15; + + case XK_Left: return KEY_LEFT; + case XK_Right: return KEY_RIGHT; + case XK_Down: return KEY_DOWN; + case XK_Up: return KEY_UP; + + case XK_KP_Insert: return KEY_NUMPAD0; + case XK_KP_End: return KEY_NUMPAD1; + case XK_KP_Down: return KEY_NUMPAD2; + case XK_KP_Page_Down:return KEY_NUMPAD3; + case XK_KP_Left: return KEY_NUMPAD4; + case XK_KP_5: return KEY_NUMPAD5; + case XK_KP_Right: return KEY_NUMPAD6; + case XK_KP_Home: return KEY_NUMPAD7; + case XK_KP_Up: return KEY_NUMPAD8; + case XK_KP_Page_Up: return KEY_NUMPAD9; + + case XK_a: return KEY_A; + case XK_b: return KEY_B; + case XK_c: return KEY_C; + case XK_d: return KEY_D; + case XK_e: return KEY_E; + case XK_f: return KEY_F; + case XK_g: return KEY_G; + case XK_h: return KEY_H; + case XK_i: return KEY_I; + case XK_j: return KEY_J; + case XK_k: return KEY_K; + case XK_l: return KEY_L; + case XK_m: return KEY_M; + case XK_n: return KEY_N; + case XK_o: return KEY_O; + case XK_p: return KEY_P; + case XK_q: return KEY_Q; + case XK_r: return KEY_R; + case XK_s: return KEY_S; + case XK_t: return KEY_T; + case XK_u: return KEY_U; + case XK_v: return KEY_V; + case XK_w: return KEY_W; + case XK_x: return KEY_X; + case XK_y: return KEY_Y; + case XK_z: return KEY_Z; + + case XK_1: return KEY_NUM1; + case XK_2: return KEY_NUM2; + case XK_3: return KEY_NUM3; + case XK_4: return KEY_NUM4; + case XK_5: return KEY_NUM5; + case XK_6: return KEY_NUM6; + case XK_7: return KEY_NUM7; + case XK_8: return KEY_NUM8; + case XK_9: return KEY_NUM9; + case XK_0: return KEY_NUM0; + } + + return Key(0); +} + +static void AddX11KeyStateToEvent(Event *event, unsigned int state) +{ + event->Key.Shift = state & ShiftMask; + event->Key.Control = state & ControlMask; + event->Key.Alt = state & Mod1Mask; + event->Key.System = state & Mod4Mask; +} + +} + +X11Window::X11Window() + : WM_DELETE_WINDOW(None), + WM_PROTOCOLS(None), + TEST_EVENT(None), + mDisplay(nullptr), + mWindow(0), + mRequestedVisualId(-1), + mVisible(false) +{ +} + +X11Window::X11Window(int visualId) + : WM_DELETE_WINDOW(None), + WM_PROTOCOLS(None), + TEST_EVENT(None), + mDisplay(nullptr), + mWindow(0), + mRequestedVisualId(visualId), + mVisible(false) +{ +} + +X11Window::~X11Window() +{ + destroy(); +} + +bool X11Window::initialize(const std::string &name, size_t width, size_t height) +{ + destroy(); + + mDisplay = XOpenDisplay(NULL); + if (!mDisplay) + { + return false; + } + + { + int screen = DefaultScreen(mDisplay); + Window root = RootWindow(mDisplay, screen); + + Visual *visual; + if (mRequestedVisualId == -1) + { + visual = DefaultVisual(mDisplay, screen); + } + else + { + XVisualInfo visualTemplate; + visualTemplate.visualid = mRequestedVisualId; + + int numVisuals = 0; + XVisualInfo *visuals = XGetVisualInfo(mDisplay, VisualIDMask, &visualTemplate, &numVisuals); + if (numVisuals <= 0) + { + return false; + } + ASSERT(numVisuals == 1); + + visual = visuals[0].visual; + XFree(visuals); + } + + int depth = DefaultDepth(mDisplay, screen); + Colormap colormap = XCreateColormap(mDisplay, root, visual, AllocNone); + + XSetWindowAttributes attributes; + unsigned long attributeMask = CWBorderPixel | CWColormap | CWEventMask; + + attributes.event_mask = StructureNotifyMask | PointerMotionMask | ButtonPressMask | + ButtonReleaseMask | FocusChangeMask | EnterWindowMask | + LeaveWindowMask | KeyPressMask | KeyReleaseMask; + attributes.border_pixel = 0; + attributes.colormap = colormap; + + mWindow = XCreateWindow(mDisplay, root, 0, 0, width, height, 0, depth, InputOutput, + visual, attributeMask, &attributes); + XFreeColormap(mDisplay, colormap); + } + + if (!mWindow) + { + destroy(); + return false; + } + + // Tell the window manager to notify us when the user wants to close the + // window so we can do it ourselves. + WM_DELETE_WINDOW = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False); + WM_PROTOCOLS = XInternAtom(mDisplay, "WM_PROTOCOLS", False); + if (WM_DELETE_WINDOW == None || WM_PROTOCOLS == None) + { + destroy(); + return false; + } + + if(XSetWMProtocols(mDisplay, mWindow, &WM_DELETE_WINDOW, 1) == 0) + { + destroy(); + return false; + } + + // Create an atom to identify our test event + TEST_EVENT = XInternAtom(mDisplay, "ANGLE_TEST_EVENT", False); + if (TEST_EVENT == None) + { + destroy(); + return false; + } + + XFlush(mDisplay); + + mX = 0; + mY = 0; + mWidth = width; + mHeight = height; + + return true; +} + +void X11Window::destroy() +{ + if (mWindow) + { + XDestroyWindow(mDisplay, mWindow); + mWindow = 0; + } + if (mDisplay) + { + XCloseDisplay(mDisplay); + mDisplay = nullptr; + } + WM_DELETE_WINDOW = None; + WM_PROTOCOLS = None; +} + +EGLNativeWindowType X11Window::getNativeWindow() const +{ + return mWindow; +} + +EGLNativeDisplayType X11Window::getNativeDisplay() const +{ + return mDisplay; +} + +void X11Window::messageLoop() +{ + int eventCount = XPending(mDisplay); + while (eventCount--) + { + XEvent event; + XNextEvent(mDisplay, &event); + processEvent(event); + } +} + +void X11Window::setMousePosition(int x, int y) +{ + XWarpPointer(mDisplay, None, mWindow, 0, 0, 0, 0, x, y); +} + +OSWindow *CreateOSWindow() +{ + return new X11Window(); +} + +bool X11Window::setPosition(int x, int y) +{ + XMoveWindow(mDisplay, mWindow, x, y); + XFlush(mDisplay); + return true; +} + +bool X11Window::resize(int width, int height) +{ + XResizeWindow(mDisplay, mWindow, width, height); + XFlush(mDisplay); + + Timer* timer = CreateTimer(); + timer->start(); + + // Wait until the window as actually been resized so that the code calling resize + // can assume the window has been resized. + const double kResizeWaitDelay = 0.2; + while (mHeight != height && mWidth != width && timer->getElapsedTime() < kResizeWaitDelay) + { + messageLoop(); + angle::Sleep(10); + } + + delete timer; + + return true; +} + +void X11Window::setVisible(bool isVisible) +{ + if (mVisible == isVisible) + { + return; + } + + if (isVisible) + { + XMapWindow(mDisplay, mWindow); + + // Wait until we get an event saying this window is mapped so that the + // code calling setVisible can assume the window is visible. + // This is important when creating a framebuffer as the framebuffer content + // is undefined when the window is not visible. + XEvent dummyEvent; + XIfEvent(mDisplay, &dummyEvent, WaitForMapNotify, reinterpret_cast<XPointer>(mWindow)); + } + else + { + XUnmapWindow(mDisplay, mWindow); + XFlush(mDisplay); + } + mVisible = isVisible; +} + +void X11Window::signalTestEvent() +{ + XEvent event; + event.type = ClientMessage; + event.xclient.message_type = TEST_EVENT; + // Format needs to be valid or a BadValue is generated + event.xclient.format = 32; + + // Hijack StructureNotifyMask as we know we will be listening for it. + XSendEvent(mDisplay, mWindow, False, StructureNotifyMask, &event); +} + +void X11Window::processEvent(const XEvent &xEvent) +{ + // TODO(cwallez) text events + switch (xEvent.type) + { + case ButtonPress: + { + Event event; + MouseButton button = MOUSEBUTTON_UNKNOWN; + int wheelX = 0; + int wheelY = 0; + + // The mouse wheel updates are sent via button events. + switch (xEvent.xbutton.button) + { + case Button4: + wheelY = 1; + break; + case Button5: + wheelY = -1; + break; + case 6: + wheelX = 1; + break; + case 7: + wheelX = -1; + break; + + case Button1: + button = MOUSEBUTTON_LEFT; + break; + case Button2: + button = MOUSEBUTTON_MIDDLE; + break; + case Button3: + button = MOUSEBUTTON_RIGHT; + break; + case 8: + button = MOUSEBUTTON_BUTTON4; + break; + case 9: + button = MOUSEBUTTON_BUTTON5; + break; + + default: + break; + } + + if (wheelY != 0) + { + event.Type = Event::EVENT_MOUSE_WHEEL_MOVED; + event.MouseWheel.Delta = wheelY; + pushEvent(event); + } + + if (button != MOUSEBUTTON_UNKNOWN) + { + event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; + event.MouseButton.Button = button; + event.MouseButton.X = xEvent.xbutton.x; + event.MouseButton.Y = xEvent.xbutton.y; + pushEvent(event); + } + } + break; + + case ButtonRelease: + { + Event event; + MouseButton button = MOUSEBUTTON_UNKNOWN; + + switch (xEvent.xbutton.button) + { + case Button1: + button = MOUSEBUTTON_LEFT; + break; + case Button2: + button = MOUSEBUTTON_MIDDLE; + break; + case Button3: + button = MOUSEBUTTON_RIGHT; + break; + case 8: + button = MOUSEBUTTON_BUTTON4; + break; + case 9: + button = MOUSEBUTTON_BUTTON5; + break; + + default: + break; + } + + if (button != MOUSEBUTTON_UNKNOWN) + { + event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; + event.MouseButton.Button = button; + event.MouseButton.X = xEvent.xbutton.x; + event.MouseButton.Y = xEvent.xbutton.y; + pushEvent(event); + } + } + break; + + case KeyPress: + { + Event event; + event.Type = Event::EVENT_KEY_PRESSED; + event.Key.Code = X11CodeToKey(mDisplay, xEvent.xkey.keycode); + AddX11KeyStateToEvent(&event, xEvent.xkey.state); + pushEvent(event); + } + break; + + case KeyRelease: + { + Event event; + event.Type = Event::EVENT_KEY_RELEASED; + event.Key.Code = X11CodeToKey(mDisplay, xEvent.xkey.keycode); + AddX11KeyStateToEvent(&event, xEvent.xkey.state); + pushEvent(event); + } + break; + + case EnterNotify: + { + Event event; + event.Type = Event::EVENT_MOUSE_ENTERED; + pushEvent(event); + } + break; + + case LeaveNotify: + { + Event event; + event.Type = Event::EVENT_MOUSE_LEFT; + pushEvent(event); + } + break; + + case MotionNotify: + { + Event event; + event.Type = Event::EVENT_MOUSE_MOVED; + event.MouseMove.X = xEvent.xmotion.x; + event.MouseMove.Y = xEvent.xmotion.y; + pushEvent(event); + } + break; + + case ConfigureNotify: + { + if (xEvent.xconfigure.width != mWidth || xEvent.xconfigure.height != mHeight) + { + Event event; + event.Type = Event::EVENT_RESIZED; + event.Size.Width = xEvent.xconfigure.width; + event.Size.Height = xEvent.xconfigure.height; + pushEvent(event); + } + if (xEvent.xconfigure.x != mX || xEvent.xconfigure.y != mY) + { + // Sometimes, the window manager reparents our window (for example + // when resizing) then the X and Y coordinates will be with respect to + // the new parent and not what the user wants to know. Use + // XTranslateCoordinates to get the coordinates on the screen. + int screen = DefaultScreen(mDisplay); + Window root = RootWindow(mDisplay, screen); + + int x, y; + Window child; + XTranslateCoordinates(mDisplay, mWindow, root, 0, 0, &x, &y, &child); + + if (x != mX || y != mY) + { + Event event; + event.Type = Event::EVENT_MOVED; + event.Move.X = x; + event.Move.Y = y; + pushEvent(event); + } + } + } + break; + + case FocusIn: + if (xEvent.xfocus.mode == NotifyNormal || xEvent.xfocus.mode == NotifyWhileGrabbed) + { + Event event; + event.Type = Event::EVENT_GAINED_FOCUS; + pushEvent(event); + } + break; + + case FocusOut: + if (xEvent.xfocus.mode == NotifyNormal || xEvent.xfocus.mode == NotifyWhileGrabbed) + { + Event event; + event.Type = Event::EVENT_LOST_FOCUS; + pushEvent(event); + } + break; + + case DestroyNotify: + // We already received WM_DELETE_WINDOW + break; + + case ClientMessage: + if (xEvent.xclient.message_type == WM_PROTOCOLS && + static_cast<Atom>(xEvent.xclient.data.l[0]) == WM_DELETE_WINDOW) + { + Event event; + event.Type = Event::EVENT_CLOSED; + pushEvent(event); + } + else if (xEvent.xclient.message_type == TEST_EVENT) + { + Event event; + event.Type = Event::EVENT_TEST; + pushEvent(event); + } + break; + } +} |