diff options
author | jvanverth <jvanverth@google.com> | 2016-05-23 13:13:36 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-05-23 13:13:36 -0700 |
commit | 1d1559620058365e0de25636f1bcf07fcc071c3d (patch) | |
tree | aa9cae557fade884de8c1a5359dc0624cd44a288 /tools/viewer/sk_app/unix | |
parent | 50134ccafdc509d4d430d068d7e68e38473ffe0a (diff) |
Add Xlib support to viewer
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=1999213002
Review-Url: https://codereview.chromium.org/1999213002
Diffstat (limited to 'tools/viewer/sk_app/unix')
-rw-r--r-- | tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp | 74 | ||||
-rw-r--r-- | tools/viewer/sk_app/unix/Window_unix.cpp | 221 | ||||
-rw-r--r-- | tools/viewer/sk_app/unix/Window_unix.h | 86 | ||||
-rw-r--r-- | tools/viewer/sk_app/unix/main_unix.cpp | 90 |
4 files changed, 471 insertions, 0 deletions
diff --git a/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp b/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp new file mode 100644 index 0000000000..ddfc8e3068 --- /dev/null +++ b/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp @@ -0,0 +1,74 @@ + +/* + * 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 "../VulkanWindowContext.h" +#include "Window_unix.h" + +#include "vk/GrVkInterface.h" +#include "vk/GrVkUtil.h" + +#include <X11/Xlib-xcb.h> + +namespace sk_app { + +// Platform dependant call +VkSurfaceKHR VulkanWindowContext::createVkSurface(VkInstance instance, void* platformData) { + static PFN_vkCreateXcbSurfaceKHR createXcbSurfaceKHR = nullptr; + if (!createXcbSurfaceKHR) { + createXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) vkGetInstanceProcAddr(instance, + "vkCreateXcbSurfaceKHR"); + } + + if (!platformData) { + return VK_NULL_HANDLE; + } + ContextPlatformData_unix* unixPlatformData = + reinterpret_cast<ContextPlatformData_unix*>(platformData); + + + VkSurfaceKHR surface; + + VkXcbSurfaceCreateInfoKHR surfaceCreateInfo; + memset(&surfaceCreateInfo, 0, sizeof(VkXcbSurfaceCreateInfoKHR)); + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + surfaceCreateInfo.pNext = nullptr; + surfaceCreateInfo.flags = 0; + surfaceCreateInfo.connection = XGetXCBConnection(unixPlatformData->fDisplay); + surfaceCreateInfo.window = unixPlatformData->fHWnd; + + VkResult res = createXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface); + if (VK_SUCCESS != res) { + return VK_NULL_HANDLE; + } + + return surface; +} + +// Platform dependant call +bool VulkanWindowContext::canPresent(VkInstance instance, VkPhysicalDevice physDev, + uint32_t queueFamilyIndex, void* platformData) { + static PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR + getPhysicalDeviceXcbPresentationSupportKHR = nullptr; + if (!getPhysicalDeviceXcbPresentationSupportKHR) { + getPhysicalDeviceXcbPresentationSupportKHR = + (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) vkGetInstanceProcAddr(instance, + "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + } + + ContextPlatformData_unix* unixPlatformData = + reinterpret_cast<ContextPlatformData_unix*>(platformData); + + Display* display = unixPlatformData->fDisplay; + VkBool32 check = getPhysicalDeviceXcbPresentationSupportKHR(physDev, + queueFamilyIndex, + XGetXCBConnection(display), + unixPlatformData->fVisualID); + return (VK_FALSE != check); +} + +} // namespace sk_app 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 0000000000..953eb36d74 --- /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 diff --git a/tools/viewer/sk_app/unix/Window_unix.h b/tools/viewer/sk_app/unix/Window_unix.h new file mode 100644 index 0000000000..c2156fc6ae --- /dev/null +++ b/tools/viewer/sk_app/unix/Window_unix.h @@ -0,0 +1,86 @@ +/* +* Copyright 2016 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef Window_unix_DEFINED +#define Window_unix_DEFINED + +#include <X11/Xlib.h> +#include "../Window.h" +#include "SkChecksum.h" +#include "SkTDynamicHash.h" + +typedef Window XWindow; + +namespace sk_app { + +struct ContextPlatformData_unix { + Display* fDisplay; + XWindow fHWnd; + VisualID fVisualID; +}; + +class Window_unix : public Window { +public: + Window_unix() : Window() {} + ~Window_unix() override {} + + bool init(Display* display); + + void setTitle(const char*) override; + void show() override; + + bool attach(BackendType attachType, const DisplayParams& params) override; + + void onInval() override; + + bool handleEvent(const XEvent& event); + + static const XWindow& GetKey(const Window_unix& w) { + return w.fHWnd; + } + + static uint32_t Hash(const XWindow& w) { + return SkChecksum::Mix(w); + } + + static SkTDynamicHash<Window_unix, XWindow> gWindowMap; + + void markPendingPaint() { fPendingPaint = true; } + void finishPaint() { + if (fPendingPaint) { + this->onPaint(); + fPendingPaint = false; + } + } + + void markPendingResize(int width, int height) { + fPendingWidth = width; + fPendingHeight = height; + fPendingResize = true; + } + void finishResize() { + if (fPendingResize) { + this->onResize(fPendingWidth, fPendingHeight); + fPendingResize = false; + } + } + +private: + Display* fDisplay; + XWindow fHWnd; + + Atom fWmDeleteMessage; + + bool fPendingPaint; + int fPendingWidth; + int fPendingHeight; + bool fPendingResize; +}; + +} // namespace sk_app + +#endif diff --git a/tools/viewer/sk_app/unix/main_unix.cpp b/tools/viewer/sk_app/unix/main_unix.cpp new file mode 100644 index 0000000000..d595379174 --- /dev/null +++ b/tools/viewer/sk_app/unix/main_unix.cpp @@ -0,0 +1,90 @@ +/* +* 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 "SkTypes.h" +#include "SkTHash.h" +#include "Timer.h" +#include "Window_unix.h" +#include "../Application.h" + +using sk_app::Application; + +static double now_ms() { return SkTime::GetNSecs() * 1e-6; } + +void finishWindow(sk_app::Window_unix* win) { + win->finishResize(); + win->finishPaint(); +} + +int main(int argc, char**argv) { + + Display* display = XOpenDisplay(nullptr); + + Application* app = Application::Create(argc, argv, (void*)display); + + double currentTime = 0.0; + double previousTime = 0.0; + + // Get the file descriptor for the X display + int x11_fd = ConnectionNumber(display); + fd_set in_fds; + + SkTHashSet<sk_app::Window_unix*> pendingWindows; + bool done = false; + while (!done) { + // Create a file description set containing x11_fd + FD_ZERO(&in_fds); + FD_SET(x11_fd, &in_fds); + + // Set a sleep timer + struct timeval tv; + tv.tv_usec = 100; + tv.tv_sec = 0; + + // Wait for an event on the file descriptor or for timer expiration + (void) select(1, &in_fds, NULL, NULL, &tv); + + // Handle XEvents (if any) and flush the input + XEvent event; + while (XPending(display) && !done) { + XNextEvent(display, &event); + + sk_app::Window_unix* win = sk_app::Window_unix::gWindowMap.find(event.xany.window); + // paint and resize events get collapsed + switch (event.type) { + case Expose: + win->markPendingPaint(); + pendingWindows.add(win); + break; + case ConfigureNotify: + win->markPendingResize(event.xconfigurerequest.width, + event.xconfigurerequest.height); + pendingWindows.add(win); + break; + default: + if (win->handleEvent(event)) { + done = true; + } + break; + } + } + + pendingWindows.foreach(finishWindow); + if (pendingWindows.count() > 0) { + previousTime = currentTime; + currentTime = now_ms(); + app->onIdle(currentTime - previousTime); + } + pendingWindows.reset(); + } + + delete app; + + XCloseDisplay(display); + + return 0; +} |