| Index: tools/viewer/sk_app/unix/Window_unix.cpp
|
| diff --git a/tools/viewer/sk_app/unix/Window_unix.cpp b/tools/viewer/sk_app/unix/Window_unix.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..953eb36d74413ea41568de340883f28f6e7e43e5
|
| --- /dev/null
|
| +++ b/tools/viewer/sk_app/unix/Window_unix.cpp
|
| @@ -0,0 +1,221 @@
|
| +/*
|
| +* Copyright 2016 Google Inc.
|
| +*
|
| +* Use of this source code is governed by a BSD-style license that can be
|
| +* found in the LICENSE file.
|
| +*/
|
| +
|
| +//#include <tchar.h>
|
| +
|
| +#include "SkUtils.h"
|
| +#include "Timer.h"
|
| +#include "../VulkanWindowContext.h"
|
| +#include "Window_unix.h"
|
| +
|
| +extern "C" {
|
| + #include "keysym2ucs.h"
|
| +}
|
| +#include <X11/Xutil.h>
|
| +#include <X11/XKBlib.h>
|
| +
|
| +namespace sk_app {
|
| +
|
| +SkTDynamicHash<Window_unix, XWindow> Window_unix::gWindowMap;
|
| +
|
| +Window* Window::CreateNativeWindow(void* platformData) {
|
| + Display* display = (Display*)platformData;
|
| +
|
| + Window_unix* window = new Window_unix();
|
| + if (!window->init(display)) {
|
| + delete window;
|
| + return nullptr;
|
| + }
|
| +
|
| + return window;
|
| +}
|
| +
|
| +bool Window_unix::init(Display* display) {
|
| + fDisplay = display;
|
| +
|
| + fWidth = 1280;
|
| + fHeight = 960;
|
| + fHWnd = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, fWidth, fHeight,
|
| + 0, BlackPixel(display, DefaultScreen(display)),
|
| + BlackPixel(display, DefaultScreen(display)));
|
| +
|
| + if (!fHWnd) {
|
| + return false;
|
| + }
|
| +
|
| + // choose the events we care about
|
| + XSelectInput(display, fHWnd,
|
| + ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
|
| + PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
|
| +
|
| + // set up to catch window delete message
|
| + fWmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
| + XSetWMProtocols(display, fHWnd, &fWmDeleteMessage, 1);
|
| +
|
| + // add to hashtable of windows
|
| + gWindowMap.add(this);
|
| +
|
| + // init event variables
|
| + fPendingPaint = false;
|
| + fPendingResize = false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +static Window::Key get_key(KeySym keysym) {
|
| + static const struct {
|
| + KeySym fXK;
|
| + Window::Key fKey;
|
| + } gPair[] = {
|
| + { XK_BackSpace, Window::Key::kBack },
|
| + { XK_Clear, Window::Key::kBack },
|
| + { XK_Return, Window::Key::kOK },
|
| + { XK_Up, Window::Key::kUp },
|
| + { XK_Down, Window::Key::kDown },
|
| + { XK_Left, Window::Key::kLeft },
|
| + { XK_Right, Window::Key::kRight }
|
| + };
|
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
|
| + if (gPair[i].fXK == keysym) {
|
| + return gPair[i].fKey;
|
| + }
|
| + }
|
| + return Window::Key::kNONE;
|
| +}
|
| +
|
| +static uint32_t get_modifiers(const XEvent& event) {
|
| + static const struct {
|
| + unsigned fXMask;
|
| + unsigned fSkMask;
|
| + } gModifiers[] = {
|
| + { ShiftMask, Window::kShift_ModifierKey },
|
| + { ControlMask, Window::kControl_ModifierKey },
|
| + { Mod1Mask, Window::kOption_ModifierKey },
|
| + };
|
| +
|
| + auto modifiers = 0;
|
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
|
| + if (event.xkey.state & gModifiers[i].fXMask) {
|
| + modifiers |= gModifiers[i].fSkMask;
|
| + }
|
| + }
|
| + return modifiers;
|
| +}
|
| +
|
| +bool Window_unix::handleEvent(const XEvent& event) {
|
| + switch (event.type) {
|
| + case ClientMessage:
|
| + if ((Atom)event.xclient.data.l[0] == fWmDeleteMessage &&
|
| + gWindowMap.count() == 1) {
|
| + return true;
|
| + }
|
| + break;
|
| +
|
| + case ButtonPress:
|
| + if (event.xbutton.button == Button1) {
|
| + this->onMouse(event.xbutton.x, event.xbutton.y,
|
| + Window::kDown_InputState, get_modifiers(event));
|
| + }
|
| + break;
|
| +
|
| + case ButtonRelease:
|
| + if (event.xbutton.button == Button1) {
|
| + this->onMouse(event.xbutton.x, event.xbutton.y,
|
| + Window::kUp_InputState, get_modifiers(event));
|
| + }
|
| + break;
|
| +
|
| + case MotionNotify:
|
| + // only track if left button is down
|
| + if (event.xmotion.state & Button1Mask) {
|
| + this->onMouse(event.xmotion.x, event.xmotion.y,
|
| + Window::kMove_InputState, get_modifiers(event));
|
| + }
|
| + break;
|
| +
|
| + case KeyPress: {
|
| + int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0;
|
| + KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode,
|
| + 0, shiftLevel);
|
| + if (keysym == XK_Escape) {
|
| + return true;
|
| + }
|
| + Window::Key key = get_key(keysym);
|
| + if (key != Window::Key::kNONE) {
|
| + (void) this->onKey(key, Window::kDown_InputState,
|
| + get_modifiers(event));
|
| + } else {
|
| + long uni = keysym2ucs(keysym);
|
| + if (uni != -1) {
|
| + (void) this->onChar((SkUnichar) uni,
|
| + get_modifiers(event));
|
| + }
|
| + }
|
| + } break;
|
| +
|
| + case KeyRelease: {
|
| + int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0;
|
| + KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode,
|
| + 0, shiftLevel);
|
| + Window::Key key = get_key(keysym);
|
| + (void) this->onKey(key, Window::kUp_InputState,
|
| + get_modifiers(event));
|
| + } break;
|
| +
|
| +
|
| + default:
|
| + // these events should be handled in the main event loop
|
| + SkASSERT(event.type != Expose && event.type != ConfigureNotify);
|
| + break;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void Window_unix::setTitle(const char* title) {
|
| + XTextProperty textproperty;
|
| + XStringListToTextProperty(const_cast<char**>(&title), 1, &textproperty);
|
| + XSetWMName(fDisplay, fHWnd, &textproperty);
|
| +}
|
| +
|
| +void Window_unix::show() {
|
| + XMapWindow(fDisplay, fHWnd);
|
| +}
|
| +
|
| +bool Window_unix::attach(BackendType attachType, const DisplayParams& params) {
|
| + ContextPlatformData_unix platformData;
|
| + platformData.fDisplay = fDisplay;
|
| + platformData.fHWnd = fHWnd;
|
| + XWindowAttributes attribs;
|
| + XGetWindowAttributes(fDisplay, fHWnd, &attribs);
|
| + platformData.fVisualID = XVisualIDFromVisual(attribs.visual);
|
| + switch (attachType) {
|
| + case kVulkan_BackendType:
|
| + default:
|
| + fWindowContext = VulkanWindowContext::Create((void*)&platformData, params);
|
| + break;
|
| + }
|
| +
|
| + return (SkToBool(fWindowContext));
|
| +}
|
| +
|
| +void Window_unix::onInval() {
|
| + XEvent event;
|
| + event.type = Expose;
|
| + event.xexpose.send_event = True;
|
| + event.xexpose.display = fDisplay;
|
| + event.xexpose.window = fHWnd;
|
| + event.xexpose.x = 0;
|
| + event.xexpose.y = 0;
|
| + event.xexpose.width = fWidth;
|
| + event.xexpose.height = fHeight;
|
| + event.xexpose.count = 0;
|
| +
|
| + XSendEvent(fDisplay, fHWnd, False, 0, &event);
|
| +}
|
| +
|
| +} // namespace sk_app
|
|
|