mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-22 10:20:53 +00:00
Implement mouse events and display on Linux/Skia port
This commit is contained in:
parent
706b9a84c6
commit
5e11bebaf0
@ -212,6 +212,7 @@ if(USE_SKIA_BACKEND)
|
|||||||
skia/skia_window_x11.cpp
|
skia/skia_window_x11.cpp
|
||||||
x11/event_queue.cpp
|
x11/event_queue.cpp
|
||||||
x11/keys.cpp
|
x11/keys.cpp
|
||||||
|
x11/window.cpp
|
||||||
x11/x11.cpp)
|
x11/x11.cpp)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -151,12 +151,7 @@ bool SkiaDisplay::setNativeMouseCursor(const she::Surface* surface,
|
|||||||
const gfx::Point& focus,
|
const gfx::Point& focus,
|
||||||
const int scale)
|
const int scale)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
|
||||||
return m_window.setNativeMouseCursor(surface, focus, scale);
|
return m_window.setNativeMouseCursor(surface, focus, scale);
|
||||||
#else
|
|
||||||
// TODO impl this for Linux
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkiaDisplay::setMousePosition(const gfx::Point& position)
|
void SkiaDisplay::setMousePosition(const gfx::Point& position)
|
||||||
|
@ -70,10 +70,8 @@ public:
|
|||||||
return Capabilities(
|
return Capabilities(
|
||||||
int(Capabilities::MultipleDisplays) |
|
int(Capabilities::MultipleDisplays) |
|
||||||
int(Capabilities::CanResizeDisplay) |
|
int(Capabilities::CanResizeDisplay) |
|
||||||
int(Capabilities::DisplayScale)
|
int(Capabilities::DisplayScale) |
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
int(Capabilities::CustomNativeMouseCursor)
|
||||||
| int(Capabilities::CustomNativeMouseCursor)
|
|
||||||
#endif
|
|
||||||
// TODO enable this when the GPU support is ready
|
// TODO enable this when the GPU support is ready
|
||||||
#if 0 // SK_SUPPORT_GPU
|
#if 0 // SK_SUPPORT_GPU
|
||||||
| int(Capabilities::GpuAccelerationSwitch)
|
| int(Capabilities::GpuAccelerationSwitch)
|
||||||
|
@ -14,17 +14,46 @@
|
|||||||
#include "she/event.h"
|
#include "she/event.h"
|
||||||
#include "she/event_queue.h"
|
#include "she/event_queue.h"
|
||||||
#include "she/skia/skia_display.h"
|
#include "she/skia/skia_display.h"
|
||||||
|
#include "she/skia/skia_surface.h"
|
||||||
#include "she/x11/x11.h"
|
#include "she/x11/x11.h"
|
||||||
|
|
||||||
|
#include "SkBitmap.h"
|
||||||
|
|
||||||
namespace she {
|
namespace she {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool convert_skia_bitmap_to_ximage(const SkBitmap& bitmap, XImage& image)
|
||||||
|
{
|
||||||
|
bitmap.lockPixels();
|
||||||
|
|
||||||
|
memset(&image, 0, sizeof(image));
|
||||||
|
int bpp = 8*bitmap.bytesPerPixel();
|
||||||
|
image.width = bitmap.width();
|
||||||
|
image.height = bitmap.height();
|
||||||
|
image.format = ZPixmap;
|
||||||
|
image.data = (char*)bitmap.getPixels();
|
||||||
|
image.byte_order = LSBFirst;
|
||||||
|
image.bitmap_unit = bpp;
|
||||||
|
image.bitmap_bit_order = LSBFirst;
|
||||||
|
image.bitmap_pad = bpp;
|
||||||
|
image.depth = 24;
|
||||||
|
image.bytes_per_line = bitmap.rowBytes() - 4*bitmap.width();
|
||||||
|
image.bits_per_pixel = bpp;
|
||||||
|
|
||||||
|
bool result = XInitImage(&image);
|
||||||
|
bitmap.unlockPixels();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
SkiaWindow::SkiaWindow(EventQueue* queue, SkiaDisplay* display,
|
SkiaWindow::SkiaWindow(EventQueue* queue, SkiaDisplay* display,
|
||||||
int width, int height, int scale)
|
int width, int height, int scale)
|
||||||
: X11Window(X11::instance()->display(), width, height)
|
: X11Window(X11::instance()->display(), width, height, scale)
|
||||||
, m_queue(queue)
|
, m_queue(queue)
|
||||||
, m_display(display)
|
, m_display(display)
|
||||||
, m_clientSize(width, height)
|
|
||||||
, m_scale(scale)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,22 +61,6 @@ SkiaWindow::~SkiaWindow()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkiaWindow::queueEventImpl(Event& ev)
|
|
||||||
{
|
|
||||||
ev.setDisplay(m_display);
|
|
||||||
m_queue->queueEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkiaWindow::scale() const
|
|
||||||
{
|
|
||||||
return m_scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkiaWindow::setScale(int scale)
|
|
||||||
{
|
|
||||||
m_scale = scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkiaWindow::setVisible(bool visible)
|
void SkiaWindow::setVisible(bool visible)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -66,39 +79,59 @@ bool SkiaWindow::isMinimized() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Size SkiaWindow::clientSize() const
|
void SkiaWindow::queueEvent(Event& ev)
|
||||||
{
|
{
|
||||||
return m_clientSize;
|
ev.setDisplay(m_display);
|
||||||
|
m_queue->queueEvent(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Size SkiaWindow::restoredSize() const
|
void SkiaWindow::paintGC(const gfx::Rect& rc)
|
||||||
{
|
{
|
||||||
return m_clientSize;
|
SkiaSurface* surface = static_cast<SkiaSurface*>(m_display->getSurface());
|
||||||
|
const SkBitmap& bitmap = surface->bitmap();
|
||||||
|
|
||||||
|
int scale = this->scale();
|
||||||
|
if (scale == 1) {
|
||||||
|
XImage image;
|
||||||
|
if (convert_skia_bitmap_to_ximage(bitmap, image)) {
|
||||||
|
XPutImage(
|
||||||
|
x11display(), handle(), gc(), &image,
|
||||||
|
rc.x, rc.y,
|
||||||
|
rc.x, rc.y,
|
||||||
|
rc.w, rc.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SkBitmap scaled;
|
||||||
|
if (scaled.tryAllocPixels(
|
||||||
|
SkImageInfo::Make(rc.w, rc.h,
|
||||||
|
bitmap.info().colorType(),
|
||||||
|
bitmap.info().alphaType()))) {
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setBlendMode(SkBlendMode::kSrc);
|
||||||
|
|
||||||
|
SkCanvas canvas(scaled);
|
||||||
|
SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(rc.x/scale, rc.y/scale, rc.w/scale, rc.h/scale));
|
||||||
|
SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, rc.w, rc.h));
|
||||||
|
canvas.drawBitmapRect(bitmap, srcRect, dstRect, &paint,
|
||||||
|
SkCanvas::kStrict_SrcRectConstraint);
|
||||||
|
|
||||||
|
XImage image;
|
||||||
|
if (convert_skia_bitmap_to_ximage(scaled, image)) {
|
||||||
|
XPutImage(
|
||||||
|
x11display(), handle(), gc(), &image,
|
||||||
|
0, 0,
|
||||||
|
rc.x, rc.y,
|
||||||
|
rc.w, rc.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkiaWindow::captureMouse()
|
void SkiaWindow::resizeDisplay(const gfx::Size& sz)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkiaWindow::releaseMouse()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkiaWindow::setMousePosition(const gfx::Point& position)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkiaWindow::setNativeMouseCursor(NativeCursor cursor)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkiaWindow::updateWindow(const gfx::Rect& bounds)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkiaWindow::onExpose()
|
|
||||||
{
|
{
|
||||||
|
m_display->resize(sz);
|
||||||
|
updateWindow(gfx::Rect(sz / scale()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace she
|
} // namespace she
|
||||||
|
@ -20,7 +20,7 @@ namespace she {
|
|||||||
class EventQueue;
|
class EventQueue;
|
||||||
class SkiaDisplay;
|
class SkiaDisplay;
|
||||||
|
|
||||||
class SkiaWindow : public X11Window<SkiaWindow> {
|
class SkiaWindow : public X11Window {
|
||||||
public:
|
public:
|
||||||
enum class Backend { NONE, GL };
|
enum class Backend { NONE, GL };
|
||||||
|
|
||||||
@ -28,21 +28,11 @@ public:
|
|||||||
int width, int height, int scale);
|
int width, int height, int scale);
|
||||||
~SkiaWindow();
|
~SkiaWindow();
|
||||||
|
|
||||||
void queueEventImpl(Event& ev);
|
|
||||||
|
|
||||||
int scale() const;
|
|
||||||
void setScale(int scale);
|
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
void maximize();
|
void maximize();
|
||||||
bool isMaximized() const;
|
bool isMaximized() const;
|
||||||
bool isMinimized() const;
|
bool isMinimized() const;
|
||||||
gfx::Size clientSize() const;
|
|
||||||
gfx::Size restoredSize() const;
|
|
||||||
void captureMouse();
|
|
||||||
void releaseMouse();
|
|
||||||
void setMousePosition(const gfx::Point& position);
|
|
||||||
bool setNativeMouseCursor(NativeCursor cursor);
|
|
||||||
void updateWindow(const gfx::Rect& bounds);
|
|
||||||
std::string getLayout() { return ""; }
|
std::string getLayout() { return ""; }
|
||||||
void setLayout(const std::string& layout) { }
|
void setLayout(const std::string& layout) { }
|
||||||
|
|
||||||
@ -51,12 +41,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onExpose() override;
|
void queueEvent(Event& ev) override;
|
||||||
|
void paintGC(const gfx::Rect& rc) override;
|
||||||
|
void resizeDisplay(const gfx::Size& sz) override;
|
||||||
|
|
||||||
EventQueue* m_queue;
|
EventQueue* m_queue;
|
||||||
SkiaDisplay* m_display;
|
SkiaDisplay* m_display;
|
||||||
gfx::Size m_clientSize;
|
|
||||||
int m_scale;
|
|
||||||
|
|
||||||
DISABLE_COPYING(SkiaWindow);
|
DISABLE_COPYING(SkiaWindow);
|
||||||
};
|
};
|
||||||
|
@ -10,10 +10,57 @@
|
|||||||
|
|
||||||
#include "she/x11/event_queue.h"
|
#include "she/x11/event_queue.h"
|
||||||
|
|
||||||
|
#include "she/x11/window.h"
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
namespace she {
|
namespace she {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char* get_event_name(XEvent& event)
|
||||||
|
{
|
||||||
|
switch (event.type) {
|
||||||
|
case KeyPress: return "KeyPress";
|
||||||
|
case KeyRelease: return "KeyRelease";
|
||||||
|
case ButtonPress: return "ButtonPress";
|
||||||
|
case ButtonRelease: return "ButtonRelease";
|
||||||
|
case MotionNotify: return "MotionNotify";
|
||||||
|
case EnterNotify: return "EnterNotify";
|
||||||
|
case LeaveNotify: return "LeaveNotify";
|
||||||
|
case FocusIn: return "FocusIn";
|
||||||
|
case FocusOut: return "FocusOut";
|
||||||
|
case KeymapNotify: return "KeymapNotify";
|
||||||
|
case Expose: return "Expose";
|
||||||
|
case GraphicsExpose: return "GraphicsExpose";
|
||||||
|
case NoExpose: return "NoExpose";
|
||||||
|
case VisibilityNotify: return "VisibilityNotify";
|
||||||
|
case CreateNotify: return "CreateNotify";
|
||||||
|
case DestroyNotify: return "DestroyNotify";
|
||||||
|
case UnmapNotify: return "UnmapNotify";
|
||||||
|
case MapNotify: return "MapNotify";
|
||||||
|
case MapRequest: return "MapRequest";
|
||||||
|
case ReparentNotify: return "ReparentNotify";
|
||||||
|
case ConfigureNotify: return "ConfigureNotify";
|
||||||
|
case ConfigureRequest: return "ConfigureRequest";
|
||||||
|
case GravityNotify: return "GravityNotify";
|
||||||
|
case ResizeRequest: return "ResizeRequest";
|
||||||
|
case CirculateNotify: return "CirculateNotify";
|
||||||
|
case CirculateRequest: return "CirculateRequest";
|
||||||
|
case PropertyNotify: return "PropertyNotify";
|
||||||
|
case SelectionClear: return "SelectionClear";
|
||||||
|
case SelectionRequest: return "SelectionRequest";
|
||||||
|
case SelectionNotify: return "SelectionNotify";
|
||||||
|
case ColormapNotify: return "ColormapNotify";
|
||||||
|
case ClientMessage: return "ClientMessage";
|
||||||
|
case MappingNotify: return "MappingNotify";
|
||||||
|
case GenericEvent: return "GenericEvent";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
void X11EventQueue::getEvent(Event& ev, bool canWait)
|
void X11EventQueue::getEvent(Event& ev, bool canWait)
|
||||||
{
|
{
|
||||||
::Display* display = X11::instance()->display();
|
::Display* display = X11::instance()->display();
|
||||||
@ -40,7 +87,12 @@ void X11EventQueue::getEvent(Event& ev, bool canWait)
|
|||||||
|
|
||||||
void X11EventQueue::processX11Event(XEvent& event)
|
void X11EventQueue::processX11Event(XEvent& event)
|
||||||
{
|
{
|
||||||
// TODO
|
TRACE("XEvent: %s (%d)\n", get_event_name(event), event.type);
|
||||||
|
|
||||||
|
X11Window* window = X11Window::getPointerFromHandle(event.xany.window);
|
||||||
|
ASSERT(window);
|
||||||
|
if (window)
|
||||||
|
window->processX11Event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace she
|
} // namespace she
|
||||||
|
229
src/she/x11/window.cpp
Normal file
229
src/she/x11/window.cpp
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
// SHE library
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This file is released under the terms of the MIT license.
|
||||||
|
// Read LICENSE.txt for more information.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "she/x11/window.h"
|
||||||
|
|
||||||
|
#include "gfx/rect.h"
|
||||||
|
#include "she/event.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace she {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// See https://bugs.freedesktop.org/show_bug.cgi?id=12871 for more
|
||||||
|
// information, it looks like the official way to convert a X Window
|
||||||
|
// into our own user data pointer (X11Window instance) is using a map.
|
||||||
|
std::map<::Window, X11Window*> g_activeWindows;
|
||||||
|
|
||||||
|
KeyModifiers get_modifiers_from_xevent(int state)
|
||||||
|
{
|
||||||
|
int modifiers = kKeyNoneModifier;
|
||||||
|
if (state & ShiftMask) modifiers |= kKeyShiftModifier;
|
||||||
|
if (state & LockMask) modifiers |= kKeyAltModifier;
|
||||||
|
if (state & ControlMask) modifiers |= kKeyCtrlModifier;
|
||||||
|
return (KeyModifiers)modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
// static
|
||||||
|
X11Window* X11Window::getPointerFromHandle(Window handle)
|
||||||
|
{
|
||||||
|
auto it = g_activeWindows.find(handle);
|
||||||
|
if (it != g_activeWindows.end())
|
||||||
|
return it->second;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void X11Window::addWindow(X11Window* window)
|
||||||
|
{
|
||||||
|
ASSERT(g_activeWindows.find(window->handle()) == g_activeWindows.end());
|
||||||
|
g_activeWindows[window->handle()] = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void X11Window::removeWindow(X11Window* window)
|
||||||
|
{
|
||||||
|
auto it = g_activeWindows.find(window->handle());
|
||||||
|
ASSERT(it != g_activeWindows.end());
|
||||||
|
if (it != g_activeWindows.end()) {
|
||||||
|
ASSERT(it->second == window);
|
||||||
|
g_activeWindows.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
X11Window::X11Window(::Display* display, int width, int height, int scale)
|
||||||
|
: m_display(display)
|
||||||
|
, m_scale(scale)
|
||||||
|
, m_clientSize(1, 1)
|
||||||
|
{
|
||||||
|
::Window root = XDefaultRootWindow(m_display);
|
||||||
|
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
swa.event_mask = (StructureNotifyMask | ExposureMask | PropertyChangeMask |
|
||||||
|
EnterWindowMask | LeaveWindowMask | FocusChangeMask |
|
||||||
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
||||||
|
KeyPressMask | KeyReleaseMask);
|
||||||
|
|
||||||
|
m_window = XCreateWindow(
|
||||||
|
m_display, root,
|
||||||
|
0, 0, width, height, 0,
|
||||||
|
CopyFromParent,
|
||||||
|
InputOutput,
|
||||||
|
CopyFromParent,
|
||||||
|
CWEventMask,
|
||||||
|
&swa);
|
||||||
|
|
||||||
|
XMapWindow(m_display, m_window);
|
||||||
|
|
||||||
|
m_gc = XCreateGC(m_display, m_window, 0, nullptr);
|
||||||
|
|
||||||
|
X11Window::addWindow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
X11Window::~X11Window()
|
||||||
|
{
|
||||||
|
XFreeGC(m_display, m_gc);
|
||||||
|
XDestroyWindow(m_display, m_window);
|
||||||
|
|
||||||
|
X11Window::removeWindow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setScale(const int scale)
|
||||||
|
{
|
||||||
|
m_scale = scale;
|
||||||
|
resizeDisplay(m_clientSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setTitle(const std::string& title)
|
||||||
|
{
|
||||||
|
XTextProperty prop;
|
||||||
|
prop.value = (unsigned char*)title.c_str();
|
||||||
|
prop.encoding = XA_STRING;
|
||||||
|
prop.format = 8;
|
||||||
|
prop.nitems = std::strlen((char*)title.c_str());
|
||||||
|
XSetWMName(m_display, m_window, &prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::captureMouse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::releaseMouse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setMousePosition(const gfx::Point& position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::updateWindow(const gfx::Rect& unscaledBounds)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
memset(&ev, 0, sizeof(ev));
|
||||||
|
ev.xexpose.type = Expose;
|
||||||
|
ev.xexpose.display = x11display();
|
||||||
|
ev.xexpose.window = handle();
|
||||||
|
ev.xexpose.x = unscaledBounds.x*m_scale;
|
||||||
|
ev.xexpose.y = unscaledBounds.y*m_scale;
|
||||||
|
ev.xexpose.width = unscaledBounds.w*m_scale;
|
||||||
|
ev.xexpose.height = unscaledBounds.h*m_scale;
|
||||||
|
XSendEvent(m_display, m_window, False,
|
||||||
|
ExposureMask, (XEvent*)&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X11Window::setNativeMouseCursor(NativeCursor cursor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X11Window::setNativeMouseCursor(const she::Surface* surface,
|
||||||
|
const gfx::Point& focus,
|
||||||
|
const int scale)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::processX11Event(XEvent& event)
|
||||||
|
{
|
||||||
|
switch (event.type) {
|
||||||
|
|
||||||
|
case ConfigureNotify: {
|
||||||
|
gfx::Size newSize(event.xconfigure.width,
|
||||||
|
event.xconfigure.height);
|
||||||
|
|
||||||
|
if (newSize.w > 0 &&
|
||||||
|
newSize.h > 0 &&
|
||||||
|
m_clientSize != newSize) {
|
||||||
|
m_clientSize = newSize;
|
||||||
|
resizeDisplay(m_clientSize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Expose: {
|
||||||
|
gfx::Rect rc(event.xexpose.x, event.xexpose.y,
|
||||||
|
event.xexpose.width, event.xexpose.height);
|
||||||
|
paintGC(rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ButtonPress: {
|
||||||
|
Event ev;
|
||||||
|
ev.setType(Event::MouseDown);
|
||||||
|
ev.setModifiers(get_modifiers_from_xevent(event.xbutton.state));
|
||||||
|
ev.setPosition(gfx::Point(event.xbutton.x / m_scale,
|
||||||
|
event.xbutton.y / m_scale));
|
||||||
|
ev.setButton(
|
||||||
|
event.xbutton.button == 1 ? Event::LeftButton:
|
||||||
|
event.xbutton.button == 2 ? Event::MiddleButton:
|
||||||
|
event.xbutton.button == 3 ? Event::RightButton:
|
||||||
|
event.xbutton.button == 4 ? Event::X1Button:
|
||||||
|
event.xbutton.button == 5 ? Event::X2Button: Event::NoneButton);
|
||||||
|
|
||||||
|
queueEvent(ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ButtonRelease: {
|
||||||
|
Event ev;
|
||||||
|
ev.setType(Event::MouseUp);
|
||||||
|
ev.setModifiers(get_modifiers_from_xevent(event.xbutton.state));
|
||||||
|
ev.setPosition(gfx::Point(event.xbutton.x / m_scale,
|
||||||
|
event.xbutton.y / m_scale));
|
||||||
|
ev.setButton(
|
||||||
|
event.xbutton.button == 1 ? Event::LeftButton:
|
||||||
|
event.xbutton.button == 2 ? Event::MiddleButton:
|
||||||
|
event.xbutton.button == 3 ? Event::RightButton:
|
||||||
|
event.xbutton.button == 4 ? Event::X1Button:
|
||||||
|
event.xbutton.button == 5 ? Event::X2Button: Event::NoneButton);
|
||||||
|
|
||||||
|
queueEvent(ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionNotify: {
|
||||||
|
Event ev;
|
||||||
|
ev.setType(Event::MouseMove);
|
||||||
|
ev.setModifiers(get_modifiers_from_xevent(event.xmotion.state));
|
||||||
|
ev.setPosition(gfx::Point(event.xmotion.x / m_scale,
|
||||||
|
event.xmotion.y / m_scale));
|
||||||
|
queueEvent(ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace she
|
@ -8,72 +8,64 @@
|
|||||||
#define SHE_X11_WINDOW_INCLUDED
|
#define SHE_X11_WINDOW_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "gfx/fwd.h"
|
||||||
|
#include "gfx/size.h"
|
||||||
|
#include "she/native_cursor.h"
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace she {
|
namespace she {
|
||||||
|
|
||||||
class Event;
|
class Event;
|
||||||
|
class Surface;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class X11Window {
|
class X11Window {
|
||||||
public:
|
public:
|
||||||
X11Window(::Display* display, int width, int height)
|
X11Window(::Display* display, int width, int height, int scale);
|
||||||
: m_display(display) {
|
~X11Window();
|
||||||
::Window root = XDefaultRootWindow(m_display);
|
|
||||||
|
|
||||||
XSetWindowAttributes swa;
|
int scale() const { return m_scale; }
|
||||||
swa.event_mask = (StructureNotifyMask | ExposureMask | PropertyChangeMask |
|
void setScale(const int scale);
|
||||||
EnterWindowMask | LeaveWindowMask | FocusChangeMask |
|
|
||||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
|
||||||
KeyPressMask | KeyReleaseMask);
|
|
||||||
|
|
||||||
m_window = XCreateWindow(
|
void setTitle(const std::string& title);
|
||||||
m_display, root,
|
|
||||||
0, 0, width, height, 0,
|
|
||||||
CopyFromParent,
|
|
||||||
InputOutput,
|
|
||||||
CopyFromParent,
|
|
||||||
CWEventMask,
|
|
||||||
&swa);
|
|
||||||
|
|
||||||
XMapWindow(m_display, m_window);
|
gfx::Size clientSize() const { return m_clientSize; }
|
||||||
XSelectInput(m_display, m_window, StructureNotifyMask);
|
gfx::Size restoredSize() const { return m_clientSize; }
|
||||||
|
void captureMouse();
|
||||||
|
void releaseMouse();
|
||||||
|
void setMousePosition(const gfx::Point& position);
|
||||||
|
void updateWindow(const gfx::Rect& bounds);
|
||||||
|
bool setNativeMouseCursor(NativeCursor cursor);
|
||||||
|
bool setNativeMouseCursor(const she::Surface* surface,
|
||||||
|
const gfx::Point& focus,
|
||||||
|
const int scale);
|
||||||
|
|
||||||
m_gc = XCreateGC(m_display, m_window, 0, nullptr);
|
::Display* x11display() const { return m_display; }
|
||||||
}
|
|
||||||
|
|
||||||
~X11Window() {
|
|
||||||
XFreeGC(m_display, m_gc);
|
|
||||||
XDestroyWindow(m_display, m_window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void queueEvent(Event& ev) {
|
|
||||||
static_cast<T*>(this)->queueEventImpl(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTitle(const std::string& title) {
|
|
||||||
XTextProperty prop;
|
|
||||||
prop.value = (unsigned char*)title.c_str();
|
|
||||||
prop.encoding = XA_STRING;
|
|
||||||
prop.format = 8;
|
|
||||||
prop.nitems = std::strlen((char*)title.c_str());
|
|
||||||
XSetWMName(m_display, m_window, &prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void onExpose() = 0;
|
|
||||||
|
|
||||||
::Display* display() const { return m_display; }
|
|
||||||
::Window handle() const { return m_window; }
|
::Window handle() const { return m_window; }
|
||||||
::GC gc() const { return m_gc; }
|
::GC gc() const { return m_gc; }
|
||||||
|
|
||||||
|
void processX11Event(XEvent& event);
|
||||||
|
static X11Window* getPointerFromHandle(Window handle);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void queueEvent(Event& event) = 0;
|
||||||
|
virtual void paintGC(const gfx::Rect& rc) = 0;
|
||||||
|
virtual void resizeDisplay(const gfx::Size& sz) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void addWindow(X11Window* window);
|
||||||
|
static void removeWindow(X11Window* window);
|
||||||
|
|
||||||
::Display* m_display;
|
::Display* m_display;
|
||||||
::Window m_window;
|
::Window m_window;
|
||||||
::GC m_gc;
|
::GC m_gc;
|
||||||
|
int m_scale;
|
||||||
|
gfx::Size m_clientSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace she
|
} // namespace she
|
||||||
|
Loading…
x
Reference in New Issue
Block a user