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 |