aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/platform/gui/xcb/UiApplication.h16
-rw-r--r--include/cru/platform/gui/xcb/Window.h10
-rw-r--r--src/platform/gui/xcb/UiApplication.cpp16
-rw-r--r--src/platform/gui/xcb/Window.cpp99
4 files changed, 119 insertions, 22 deletions
diff --git a/include/cru/platform/gui/xcb/UiApplication.h b/include/cru/platform/gui/xcb/UiApplication.h
index cc38b3ed..6063a8ab 100644
--- a/include/cru/platform/gui/xcb/UiApplication.h
+++ b/include/cru/platform/gui/xcb/UiApplication.h
@@ -31,10 +31,18 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
xcb_screen_t* GetFirstXcbScreen();
xcb_atom_t GetOrCreateXcbAtom(std::string name);
- xcb_atom_t GetXcbAtom_NET_WM_NAME();
- xcb_atom_t GetXcbAtom_NET_WM_WINDOW_TYPE();
- xcb_atom_t GetXcbAtom_NET_WM_WINDOW_TYPE_NORMAL();
- xcb_atom_t GetXcbAtom_NET_WM_WINDOW_TYPE_UTILITY();
+
+#define CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(name) \
+ xcb_atom_t GetXcbAtom##name() { return GetOrCreateXcbAtom(#name); }
+
+ CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(WM_NAME)
+ CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(WM_STATE)
+ CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM(_NET_WM_NAME)
+ 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)
+
+#undef CRU_XCB_UI_APPLICATION_DEFINE_XCB_ATOM
public:
int Run() override;
diff --git a/include/cru/platform/gui/xcb/Window.h b/include/cru/platform/gui/xcb/Window.h
index f118ed66..6d923666 100644
--- a/include/cru/platform/gui/xcb/Window.h
+++ b/include/cru/platform/gui/xcb/Window.h
@@ -29,8 +29,8 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
String GetTitle() override;
void SetTitle(String title) override;
- virtual WindowVisibilityType GetVisibility() = 0;
- virtual void SetVisibility(WindowVisibilityType visibility) = 0;
+ WindowVisibilityType GetVisibility() override;
+ void SetVisibility(WindowVisibilityType visibility) override;
virtual Size GetClientSize() = 0;
virtual void SetClientSize(const Size& size) = 0;
@@ -92,6 +92,11 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
void DoSetStyleFlags(xcb_window_t window);
void DoSetTitle(xcb_window_t window);
+ 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);
+
private:
XcbUiApplication* application_;
std::optional<xcb_window_t> xcb_window_;
@@ -99,6 +104,7 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
Size current_size_;
WindowStyleFlag style_;
std::string title_;
+ bool mapped_;
XcbWindow* parent_;
diff --git a/src/platform/gui/xcb/UiApplication.cpp b/src/platform/gui/xcb/UiApplication.cpp
index e5cab19f..0a6ab07f 100644
--- a/src/platform/gui/xcb/UiApplication.cpp
+++ b/src/platform/gui/xcb/UiApplication.cpp
@@ -63,22 +63,6 @@ xcb_atom_t XcbUiApplication::GetOrCreateXcbAtom(std::string name) {
return atom;
}
-xcb_atom_t XcbUiApplication::GetXcbAtom_NET_WM_NAME() {
- return GetOrCreateXcbAtom("_NET_WM_NAME");
-}
-
-xcb_atom_t XcbUiApplication::GetXcbAtom_NET_WM_WINDOW_TYPE() {
- return GetOrCreateXcbAtom("_NET_WM_WINDOW_TYPE");
-}
-
-xcb_atom_t XcbUiApplication::GetXcbAtom_NET_WM_WINDOW_TYPE_NORMAL() {
- return GetOrCreateXcbAtom("_NET_WM_WINDOW_TYPE_NORMAL");
-}
-
-xcb_atom_t XcbUiApplication::GetXcbAtom_NET_WM_WINDOW_TYPE_UTILITY() {
- return GetOrCreateXcbAtom("_NET_WM_WINDOW_TYPE_UTILITY");
-}
-
int XcbUiApplication::Run() {
auto exit_code = event_loop_.Run();
diff --git a/src/platform/gui/xcb/Window.cpp b/src/platform/gui/xcb/Window.cpp
index b56b8fa9..188f62b8 100644
--- a/src/platform/gui/xcb/Window.cpp
+++ b/src/platform/gui/xcb/Window.cpp
@@ -1,4 +1,5 @@
#include "cru/platform/gui/xcb/Window.h"
+#include "cru/base/Base.h"
#include "cru/platform/Check.h"
#include "cru/platform/graphics/Painter.h"
#include "cru/platform/graphics/cairo/CairoPainter.h"
@@ -98,6 +99,84 @@ void XcbWindow::SetTitle(String title) {
}
}
+namespace {
+constexpr int WithdrawnState = 0;
+constexpr int NormalState = 1;
+constexpr int IconicState = 3;
+} // namespace
+
+WindowVisibilityType XcbWindow::GetVisibility() {
+ if (!xcb_window_) return WindowVisibilityType::Hide;
+ auto value = static_cast<std::uint32_t *>(
+ XcbGetProperty(*xcb_window_, application_->GetXcbAtomWM_STATE(),
+ application_->GetXcbAtomWM_STATE(), 0, 1));
+ if (value != nullptr && *value == IconicState) {
+ return WindowVisibilityType::Minimize;
+ }
+ if (!mapped_) return WindowVisibilityType::Hide;
+ return WindowVisibilityType::Show;
+}
+
+void XcbWindow::SetVisibility(WindowVisibilityType visibility) {
+ auto update_wm_state = [this, visibility] {
+ auto atom = application_->GetXcbAtomWM_STATE();
+ auto window = *xcb_window_;
+
+ std::uint32_t value[2];
+ switch (visibility) {
+ case WindowVisibilityType::Show:
+ value[0] = NormalState;
+ break;
+ case WindowVisibilityType::Minimize:
+ value[0] = IconicState;
+ break;
+ case WindowVisibilityType::Hide:
+ value[0] = WithdrawnState;
+ break;
+ default:
+ UnreachableCode();
+ }
+
+ auto old_value = static_cast<std::uint32_t *>(
+ XcbGetProperty(*xcb_window_, atom, atom, 0, 2));
+ if (old_value) value[1] = old_value[1];
+ UnreachableCode();
+
+ xcb_change_property(application_->GetXcbConnection(), XCB_PROP_MODE_REPLACE,
+ window, atom, atom, 32, sizeof(value) / sizeof(*value),
+ value);
+ };
+
+ switch (visibility) {
+ case WindowVisibilityType::Show: {
+ if (!xcb_window_) {
+ DoCreateWindow();
+ }
+ update_wm_state();
+ xcb_map_window(application_->GetXcbConnection(), *xcb_window_);
+ break;
+ }
+ case WindowVisibilityType::Minimize: {
+ if (!xcb_window_) {
+ DoCreateWindow();
+ }
+ update_wm_state();
+ xcb_unmap_window(application_->GetXcbConnection(), *xcb_window_);
+ break;
+ }
+ case WindowVisibilityType::Hide: {
+ if (!xcb_window_) {
+ return;
+ }
+ update_wm_state();
+ xcb_unmap_window(application_->GetXcbConnection(), *xcb_window_);
+ break;
+ }
+ default:
+ UnreachableCode();
+ }
+}
+
std::unique_ptr<graphics::IPainter> XcbWindow::BeginPaint() {
assert(cairo_surface_);
@@ -172,6 +251,8 @@ xcb_window_t XcbWindow::DoCreateWindow() {
screen->root_visual, mask, values);
current_size_ = Size(width, height);
+ xcb_window_ = window;
+
DoSetStyleFlags(window);
DoSetParent(window);
@@ -226,10 +307,12 @@ void XcbWindow::HandleEvent(xcb_generic_event_t *event) {
}
case XCB_MAP_NOTIFY: {
visibility_change_event_.Raise(WindowVisibilityType::Show);
+ mapped_ = true;
break;
}
case XCB_UNMAP_NOTIFY: {
visibility_change_event_.Raise(WindowVisibilityType::Hide);
+ mapped_ = false;
break;
}
case XCB_FOCUS_IN: {
@@ -410,4 +493,20 @@ void XcbWindow::DoSetTitle(xcb_window_t window) {
}
}
+void *XcbWindow::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) {
+ auto cookie = xcb_get_property(application_->GetXcbConnection(), false,
+ window, property, type, offset, length);
+ auto reply =
+ xcb_get_property_reply(application_->GetXcbConnection(), cookie, NULL);
+ if (reply->type == XCB_ATOM_NONE) {
+ return nullptr;
+ }
+ if (out_length != nullptr) {
+ *out_length = xcb_get_property_value_length(reply);
+ }
+ return xcb_get_property_value(reply);
+}
} // namespace cru::platform::gui::xcb