aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/cru/base/Guard.h26
-rw-r--r--include/cru/platform/GraphicsBase.h16
-rw-r--r--include/cru/platform/gui/Window.h3
-rw-r--r--include/cru/platform/gui/xcb/Base.h4
-rw-r--r--include/cru/platform/gui/xcb/Cursor.h44
-rw-r--r--include/cru/platform/gui/xcb/UiApplication.h30
-rw-r--r--include/cru/platform/gui/xcb/Window.h45
7 files changed, 127 insertions, 41 deletions
diff --git a/include/cru/base/Guard.h b/include/cru/base/Guard.h
index 5a9f9c5d..6b6cf851 100644
--- a/include/cru/base/Guard.h
+++ b/include/cru/base/Guard.h
@@ -1,5 +1,6 @@
#pragma once
+#include <cstdlib>
#include <functional>
namespace cru {
@@ -23,4 +24,29 @@ struct Guard {
ExitFunc on_exit;
};
+
+template <typename T>
+struct FreeLater {
+ FreeLater(T* ptr) : ptr(ptr) {}
+ ~FreeLater() { ::free(ptr); }
+
+ FreeLater(const FreeLater& other) = delete;
+ FreeLater& operator=(const FreeLater& other) = delete;
+
+ FreeLater(FreeLater&& other) : ptr(other.ptr) { other.ptr = nullptr; }
+ FreeLater& operator=(FreeLater&& other) {
+ if (this != &other) {
+ ::free(ptr);
+ ptr = other.ptr;
+ other.ptr = nullptr;
+ }
+ return *this;
+ }
+
+ operator T*() const { return ptr; }
+ T* operator->() { return ptr; }
+
+ T* ptr;
+};
+
} // namespace cru
diff --git a/include/cru/platform/GraphicsBase.h b/include/cru/platform/GraphicsBase.h
index b0f653ef..d5936476 100644
--- a/include/cru/platform/GraphicsBase.h
+++ b/include/cru/platform/GraphicsBase.h
@@ -206,10 +206,22 @@ struct Rect final {
height + thickness.GetVerticalTotal());
}
- constexpr Rect Shrink(const Thickness& thickness) const {
- return Rect(left + thickness.left, top + thickness.top,
+ constexpr Rect Shrink(const Thickness& thickness,
+ bool normalize = false) const {
+ Rect result(left + thickness.left, top + thickness.top,
width - thickness.GetHorizontalTotal(),
height - thickness.GetVerticalTotal());
+
+ if (normalize) {
+ if (result.width < 0) {
+ result.width = 0;
+ }
+ if (result.height < 0) {
+ result.height = 0;
+ }
+ }
+
+ return result;
}
constexpr bool IsPointInside(const Point& point) const {
diff --git a/include/cru/platform/gui/Window.h b/include/cru/platform/gui/Window.h
index 742ef798..885c1250 100644
--- a/include/cru/platform/gui/Window.h
+++ b/include/cru/platform/gui/Window.h
@@ -44,6 +44,7 @@ struct NativeKeyEventArgs {
// Represents a native window, which exposes some low-level events and
// operations.
struct INativeWindow : virtual IPlatformResource {
+ virtual bool IsCreated();
virtual void Close() = 0;
virtual INativeWindow* GetParent() = 0;
@@ -72,6 +73,8 @@ struct INativeWindow : virtual IPlatformResource {
// The lefttop of the rect is relative to screen lefttop.
virtual void SetWindowRect(const Rect& rect) = 0;
+ // Return true if window gained the focus. But the return value should be
+ // ignored, since it does not guarantee anything.
virtual bool RequestFocus() = 0;
// Relative to client lefttop.
diff --git a/include/cru/platform/gui/xcb/Base.h b/include/cru/platform/gui/xcb/Base.h
index f3bcfd01..ad571a40 100644
--- a/include/cru/platform/gui/xcb/Base.h
+++ b/include/cru/platform/gui/xcb/Base.h
@@ -7,13 +7,13 @@
namespace cru::platform::gui::xcb {
class XcbResource : public Object, public virtual IPlatformResource {
public:
- static String kPlatformId;
+ static constexpr const char16_t* kPlatformId = u"XCB";
protected:
XcbResource() = default;
public:
- String GetPlatformId() const final { return kPlatformId; }
+ String GetPlatformId() const final { return String(kPlatformId); }
};
class XcbException : public PlatformException {
diff --git a/include/cru/platform/gui/xcb/Cursor.h b/include/cru/platform/gui/xcb/Cursor.h
new file mode 100644
index 00000000..02ede7dd
--- /dev/null
+++ b/include/cru/platform/gui/xcb/Cursor.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <cru/base/io/Stream.h>
+#include "../Cursor.h"
+#include "Base.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xcb_cursor.h>
+#include <memory>
+#include <string_view>
+#include <unordered_map>
+
+namespace cru::platform::gui::xcb {
+class XcbUiApplication;
+
+class XcbCursor : public XcbResource, public virtual ICursor {
+ public:
+ XcbCursor(XcbUiApplication* application, xcb_cursor_t cursor, bool auto_free);
+ ~XcbCursor() override;
+
+ xcb_cursor_t GetXcbCursor();
+
+ private:
+ XcbUiApplication* application_;
+ xcb_cursor_t cursor_;
+ bool auto_free_;
+};
+
+class XcbCursorManager : public XcbResource, public virtual ICursorManager {
+ public:
+ explicit XcbCursorManager(XcbUiApplication* application);
+ ~XcbCursorManager() override;
+
+ std::shared_ptr<ICursor> GetSystemCursor(SystemCursorType type) override;
+
+ private:
+ std::shared_ptr<XcbCursor> LoadXCursor(std::string_view name);
+
+ private:
+ XcbUiApplication* application_;
+ xcb_cursor_context_t* xcb_cursor_context_;
+ std::unordered_map<SystemCursorType, std::shared_ptr<XcbCursor>> cursors_;
+};
+} // namespace cru::platform::gui::xcb
diff --git a/include/cru/platform/gui/xcb/UiApplication.h b/include/cru/platform/gui/xcb/UiApplication.h
index 6063a8ab..b8de86f2 100644
--- a/include/cru/platform/gui/xcb/UiApplication.h
+++ b/include/cru/platform/gui/xcb/UiApplication.h
@@ -12,6 +12,7 @@
namespace cru::platform::gui::xcb {
class XcbWindow;
+class XcbCursorManager;
class XcbUiApplication : public XcbResource, public virtual IUiApplication {
friend XcbWindow;
@@ -26,6 +27,7 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
void CheckXcbConnectionError();
xcb_connection_t* GetXcbConnection();
+ void XcbFlush();
// This API is weird, but before we have correct screen API, we still use it.
xcb_screen_t* GetFirstXcbScreen();
@@ -41,6 +43,9 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(_NET_WM_WINDOW_TYPE)
CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(_NET_WM_WINDOW_TYPE_NORMAL)
CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(_NET_WM_WINDOW_TYPE_UTILITY)
+ CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(_NET_FRAME_EXTENTS)
+ CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(WM_PROTOCOLS)
+ CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(WM_DELETE_WINDOW)
#undef CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM
@@ -61,29 +66,18 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
std::function<void()> action) override;
void CancelTimer(long long id) override;
- virtual std::vector<INativeWindow*> GetAllWindow() = 0;
+ std::vector<INativeWindow*> GetAllWindow() override;
- virtual INativeWindow* CreateWindow() = 0;
+ INativeWindow* CreateWindow() override;
- virtual cru::platform::graphics::IGraphicsFactory* GetGraphicsFactory() = 0;
+ cru::platform::graphics::IGraphicsFactory* GetGraphicsFactory() override;
- virtual ICursorManager* GetCursorManager() = 0;
+ ICursorManager* GetCursorManager() override;
- virtual IClipboard* GetClipboard() = 0;
+ IClipboard* GetClipboard() override;
// If return nullptr, it means the menu is not supported.
- virtual IMenu* GetApplicationMenu();
-
- /**
- * \todo Implement on Windows.
- */
- virtual std::optional<String> ShowSaveDialog(SaveDialogOptions options);
-
- /**
- * \todo Implement on Windows.
- */
- virtual std::optional<std::vector<String>> ShowOpenDialog(
- OpenDialogOptions options);
+ IMenu* GetApplicationMenu() override;
private:
void HandleXEvents();
@@ -104,5 +98,7 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
bool is_quit_on_all_window_closed_;
std::vector<XcbWindow*> windows_;
+
+ XcbCursorManager* cursor_manager_;
};
} // namespace cru::platform::gui::xcb
diff --git a/include/cru/platform/gui/xcb/Window.h b/include/cru/platform/gui/xcb/Window.h
index 6d923666..61e4b616 100644
--- a/include/cru/platform/gui/xcb/Window.h
+++ b/include/cru/platform/gui/xcb/Window.h
@@ -1,5 +1,6 @@
#pragma once
+#include "../../GraphicsBase.h"
#include "../Window.h"
#include "Base.h"
@@ -10,6 +11,7 @@
namespace cru::platform::gui::xcb {
class XcbUiApplication;
+class XcbCursor;
class XcbWindow : public XcbResource, public virtual INativeWindow {
friend XcbUiApplication;
@@ -18,6 +20,7 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
explicit XcbWindow(XcbUiApplication* application);
~XcbWindow() override;
+ bool IsCreated() override;
void Close() override;
INativeWindow* GetParent() override;
@@ -32,33 +35,27 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
WindowVisibilityType GetVisibility() override;
void SetVisibility(WindowVisibilityType visibility) override;
- virtual Size GetClientSize() = 0;
- virtual void SetClientSize(const Size& size) = 0;
+ Size GetClientSize() override;
+ void SetClientSize(const Size& size) override;
- virtual Rect GetClientRect() = 0;
- virtual void SetClientRect(const Rect& rect) = 0;
+ Rect GetClientRect() override;
+ void SetClientRect(const Rect& rect) override;
- // Get the rect of the window containing frame.
- // The lefttop of the rect is relative to screen lefttop.
- virtual Rect GetWindowRect() = 0;
+ Rect GetWindowRect() override;
+ void SetWindowRect(const Rect& rect) override;
- // Set the rect of the window containing frame.
- // The lefttop of the rect is relative to screen lefttop.
- virtual void SetWindowRect(const Rect& rect) = 0;
+ bool RequestFocus() override;
- virtual bool RequestFocus() = 0;
+ Point GetMousePosition() override;
- // Relative to client lefttop.
- virtual Point GetMousePosition() = 0;
+ bool CaptureMouse() override;
+ bool ReleaseMouse() override;
- virtual bool CaptureMouse() = 0;
- virtual bool ReleaseMouse() = 0;
+ void SetCursor(std::shared_ptr<ICursor> cursor) override;
- virtual void SetCursor(std::shared_ptr<ICursor> cursor) = 0;
+ void SetToForeground() override;
- virtual void SetToForeground() = 0;
-
- virtual void RequestRepaint() = 0;
+ void RequestRepaint() override;
std::unique_ptr<graphics::IPainter> BeginPaint() override;
@@ -78,7 +75,7 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
IEvent<NativeKeyEventArgs>* KeyDownEvent() override;
IEvent<NativeKeyEventArgs>* KeyUpEvent() override;
- virtual IInputMethodContext* GetInputMethodContext() = 0;
+ IInputMethodContext* GetInputMethodContext() override;
public:
std::optional<xcb_window_t> GetXcbWindow();
@@ -91,12 +88,19 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
void DoSetParent(xcb_window_t window);
void DoSetStyleFlags(xcb_window_t window);
void DoSetTitle(xcb_window_t window);
+ void DoSetClientRect(xcb_window_t window, const Rect& rect);
+ void DoSetCursor(xcb_window_t window, XcbCursor* cursor);
void* XcbGetProperty(xcb_window_t window, xcb_atom_t property,
xcb_atom_t type, std::uint32_t offset,
std::uint32_t length,
std::uint32_t* out_length = nullptr);
+ // Relative to screen lefttop.
+ Point GetXcbWindowPosition(xcb_window_t window);
+
+ std::optional<Thickness> Get_NET_FRAME_EXTENTS(xcb_window_t window);
+
private:
XcbUiApplication* application_;
std::optional<xcb_window_t> xcb_window_;
@@ -105,6 +109,7 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
WindowStyleFlag style_;
std::string title_;
bool mapped_;
+ std::shared_ptr<XcbCursor> cursor_;
XcbWindow* parent_;