OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 //#include <tchar.h> |
| 9 |
| 10 #include "SkUtils.h" |
| 11 #include "Timer.h" |
| 12 #include "../VulkanWindowContext.h" |
| 13 #include "Window_unix.h" |
| 14 |
| 15 extern "C" { |
| 16 #include "keysym2ucs.h" |
| 17 } |
| 18 #include <X11/Xutil.h> |
| 19 #include <X11/XKBlib.h> |
| 20 |
| 21 static double now_ms() { return SkTime::GetNSecs() * 1e-6; } |
| 22 |
| 23 namespace sk_app { |
| 24 |
| 25 SkTDynamicHash<Window_unix,::Window> Window_unix::gWindowMap; |
| 26 |
| 27 Window* Window::CreateNativeWindow(void* platformData) { |
| 28 Display* display = (Display*)platformData; |
| 29 |
| 30 Window_unix* window = new Window_unix(); |
| 31 if (!window->init(display)) { |
| 32 delete window; |
| 33 return nullptr; |
| 34 } |
| 35 |
| 36 return window; |
| 37 } |
| 38 |
| 39 bool Window_unix::init(Display* display) { |
| 40 fDisplay = display; |
| 41 |
| 42 fWidth = 1280; |
| 43 fHeight = 960; |
| 44 fHWnd = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, fWidt
h, fHeight, |
| 45 0, BlackPixel(display, DefaultScreen(display)), |
| 46 BlackPixel(display, DefaultScreen(display))); |
| 47 |
| 48 if (!fHWnd) { |
| 49 return false; |
| 50 } |
| 51 |
| 52 // choose the events we care about |
| 53 XSelectInput(display, fHWnd, |
| 54 ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseM
ask | |
| 55 PointerMotionMask | ButtonPressMask | ButtonReleaseMask); |
| 56 |
| 57 // set up to catch window delete message |
| 58 fWmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False); |
| 59 XSetWMProtocols(display, fHWnd, &fWmDeleteMessage, 1); |
| 60 |
| 61 // add to hashtable of windows |
| 62 gWindowMap.add(this); |
| 63 |
| 64 // init event variables |
| 65 fResizeTimer = -200.0; |
| 66 fExposeCount = 0; |
| 67 |
| 68 return true; |
| 69 } |
| 70 |
| 71 static Window::Key get_key(KeySym keysym) { |
| 72 static const struct { |
| 73 KeySym fXK; |
| 74 Window::Key fKey; |
| 75 } gPair[] = { |
| 76 { XK_BackSpace, Window::Key::kBack }, |
| 77 { XK_Clear, Window::Key::kBack }, |
| 78 { XK_Return, Window::Key::kOK }, |
| 79 { XK_Up, Window::Key::kUp }, |
| 80 { XK_Down, Window::Key::kDown }, |
| 81 { XK_Left, Window::Key::kLeft }, |
| 82 { XK_Right, Window::Key::kRight } |
| 83 }; |
| 84 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { |
| 85 if (gPair[i].fXK == keysym) { |
| 86 return gPair[i].fKey; |
| 87 } |
| 88 } |
| 89 return Window::Key::kNONE; |
| 90 } |
| 91 |
| 92 static uint32_t get_modifiers(const XEvent& event) { |
| 93 static const struct { |
| 94 unsigned fXMask; |
| 95 unsigned fSkMask; |
| 96 } gModifiers[] = { |
| 97 { ShiftMask, Window::kShift_ModifierKey }, |
| 98 { ControlMask, Window::kControl_ModifierKey }, |
| 99 { Mod1Mask, Window::kOption_ModifierKey }, |
| 100 }; |
| 101 |
| 102 auto modifiers = 0; |
| 103 for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) { |
| 104 if (event.xkey.state & gModifiers[i].fXMask) { |
| 105 modifiers |= gModifiers[i].fSkMask; |
| 106 } |
| 107 } |
| 108 return modifiers; |
| 109 } |
| 110 |
| 111 bool Window_unix::handleEvent(const XEvent& event) { |
| 112 switch (event.type) { |
| 113 case ClientMessage: |
| 114 if ((Atom)event.xclient.data.l[0] == fWmDeleteMessage && |
| 115 gWindowMap.count() == 1) { |
| 116 return true; |
| 117 } |
| 118 break; |
| 119 |
| 120 case Expose: |
| 121 if (event.xexpose.count == 0 && (now_ms() - fResizeTimer) > 200.0) { |
| 122 this->onPaint(); |
| 123 fResizeTimer = -200.0; |
| 124 } |
| 125 if (event.xexpose.send_event) { |
| 126 --fExposeCount; |
| 127 } |
| 128 break; |
| 129 |
| 130 case ConfigureNotify: |
| 131 if ((int)fWidth != event.xconfigurerequest.width || |
| 132 (int)fHeight != event.xconfigurerequest.height) { |
| 133 this->onResize(event.xconfigurerequest.width, event.xconfigurere
quest.height); |
| 134 fWidth = event.xconfigurerequest.width; |
| 135 fHeight = event.xconfigurerequest.height; |
| 136 } |
| 137 if (fResizeTimer < 0.0) { |
| 138 fResizeTimer = now_ms(); |
| 139 } |
| 140 break; |
| 141 |
| 142 case ButtonPress: |
| 143 if (event.xbutton.button == Button1) { |
| 144 this->onMouse(event.xbutton.x, event.xbutton.y, |
| 145 Window::kDown_InputState, get_modifiers(event)); |
| 146 } |
| 147 break; |
| 148 |
| 149 case ButtonRelease: |
| 150 if (event.xbutton.button == Button1) { |
| 151 this->onMouse(event.xbutton.x, event.xbutton.y, |
| 152 Window::kUp_InputState, get_modifiers(event)); |
| 153 } |
| 154 break; |
| 155 |
| 156 case MotionNotify: |
| 157 // only track if left button is down |
| 158 if (event.xmotion.state & Button1Mask) { |
| 159 this->onMouse(event.xmotion.x, event.xmotion.y, |
| 160 Window::kMove_InputState, get_modifiers(event)); |
| 161 } |
| 162 break; |
| 163 |
| 164 case KeyPress: { |
| 165 int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0; |
| 166 KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, |
| 167 0, shiftLevel); |
| 168 if (keysym == XK_Escape) { |
| 169 return true; |
| 170 } |
| 171 Window::Key key = get_key(keysym); |
| 172 if (key != Window::Key::kNONE) { |
| 173 (void) this->onKey(key, Window::kDown_InputState, |
| 174 get_modifiers(event)); |
| 175 } else { |
| 176 long uni = keysym2ucs(keysym); |
| 177 if (uni != -1) { |
| 178 (void) this->onChar((SkUnichar) uni, |
| 179 get_modifiers(event)); |
| 180 } |
| 181 } |
| 182 } break; |
| 183 |
| 184 case KeyRelease: { |
| 185 int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0; |
| 186 KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, |
| 187 0, shiftLevel); |
| 188 Window::Key key = get_key(keysym); |
| 189 (void) this->onKey(key, Window::kUp_InputState, |
| 190 get_modifiers(event)); |
| 191 } break; |
| 192 |
| 193 |
| 194 default: |
| 195 break; |
| 196 } |
| 197 |
| 198 return false; |
| 199 } |
| 200 |
| 201 void Window_unix::setTitle(const char* title) { |
| 202 XTextProperty textproperty; |
| 203 XStringListToTextProperty(const_cast<char**>(&title), 1, &textproperty); |
| 204 XSetWMName(fDisplay, fHWnd, &textproperty); |
| 205 } |
| 206 |
| 207 void Window_unix::show() { |
| 208 XMapWindow(fDisplay, fHWnd); |
| 209 } |
| 210 |
| 211 bool Window_unix::attach(BackendType attachType, const DisplayParams& params) { |
| 212 ContextPlatformData_unix platformData; |
| 213 platformData.fDisplay = fDisplay; |
| 214 platformData.fHWnd = fHWnd; |
| 215 XWindowAttributes attribs; |
| 216 XGetWindowAttributes(fDisplay, fHWnd, &attribs); |
| 217 platformData.fVisualID = XVisualIDFromVisual(attribs.visual); |
| 218 switch (attachType) { |
| 219 case kVulkan_BackendType: |
| 220 default: |
| 221 fWindowContext = VulkanWindowContext::Create((void*)&platformData, p
arams); |
| 222 break; |
| 223 } |
| 224 |
| 225 return (SkToBool(fWindowContext)); |
| 226 } |
| 227 |
| 228 void Window_unix::inval() { |
| 229 XEvent event; |
| 230 event.type = Expose; |
| 231 event.xexpose.send_event = True; |
| 232 event.xexpose.display = fDisplay; |
| 233 event.xexpose.window = fHWnd; |
| 234 event.xexpose.x = 0; |
| 235 event.xexpose.y = 0; |
| 236 event.xexpose.width = fWidth; |
| 237 event.xexpose.height = fHeight; |
| 238 event.xexpose.count = fExposeCount; |
| 239 |
| 240 // Tracking an expose count keeps us from having bursty renders |
| 241 XSendEvent(fDisplay, fHWnd, False, 0, &event); |
| 242 ++fExposeCount; |
| 243 } |
| 244 |
| 245 } // namespace sk_app |
OLD | NEW |