aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/platform/gui/xcb/UiApplication.h8
-rw-r--r--include/cru/platform/gui/xcb/Window.h8
-rw-r--r--src/platform/gui/xcb/UiApplication.cpp26
-rw-r--r--src/platform/gui/xcb/Window.cpp45
4 files changed, 78 insertions, 9 deletions
diff --git a/include/cru/platform/gui/xcb/UiApplication.h b/include/cru/platform/gui/xcb/UiApplication.h
index 2a9ea517..87fd1063 100644
--- a/include/cru/platform/gui/xcb/UiApplication.h
+++ b/include/cru/platform/gui/xcb/UiApplication.h
@@ -7,6 +7,8 @@
#include <xcb/xcb.h>
#include <functional>
+#include <string>
+#include <unordered_map>
namespace cru::platform::gui::xcb {
class XcbWindow;
@@ -28,6 +30,11 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
// This API is weird, but before we have correct screen API, we still use it.
xcb_screen_t* GetFirstXcbScreen();
+ xcb_atom_t GetOrCreateXcbAtom(std::string 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();
+
public:
int Run() override;
@@ -81,6 +88,7 @@ class XcbUiApplication : public XcbResource, public virtual IUiApplication {
xcb_connection_t* xcb_connection_;
xcb_screen_t* screen_;
+ std::unordered_map<std::string, xcb_atom_t> xcb_atom_;
cru::platform::unix::UnixEventLoop event_loop_;
std::vector<std::function<void()>> quit_handlers_;
diff --git a/include/cru/platform/gui/xcb/Window.h b/include/cru/platform/gui/xcb/Window.h
index f9fbf735..43cd3b53 100644
--- a/include/cru/platform/gui/xcb/Window.h
+++ b/include/cru/platform/gui/xcb/Window.h
@@ -23,8 +23,8 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
INativeWindow* GetParent() override;
void SetParent(INativeWindow* parent) override;
- virtual WindowStyleFlag GetStyleFlag() = 0;
- virtual void SetStyleFlag(WindowStyleFlag flag) = 0;
+ WindowStyleFlag GetStyleFlag() override;
+ void SetStyleFlag(WindowStyleFlag flag) override;
virtual String GetTitle() = 0;
virtual void SetTitle(String title) = 0;
@@ -88,11 +88,15 @@ class XcbWindow : public XcbResource, public virtual INativeWindow {
void HandleEvent(xcb_generic_event_t* event);
static std::optional<xcb_window_t> GetEventWindow(xcb_generic_event_t* event);
+ void DoSetParent(xcb_window_t window);
+ void DoSetStyleFlags(xcb_window_t window);
+
private:
XcbUiApplication* application_;
std::optional<xcb_window_t> xcb_window_;
cairo_surface_t* cairo_surface_;
Size current_size_;
+ WindowStyleFlag style_;
XcbWindow* parent_;
diff --git a/src/platform/gui/xcb/UiApplication.cpp b/src/platform/gui/xcb/UiApplication.cpp
index 462e2fde..2fceac30 100644
--- a/src/platform/gui/xcb/UiApplication.cpp
+++ b/src/platform/gui/xcb/UiApplication.cpp
@@ -49,6 +49,32 @@ xcb_connection_t *XcbUiApplication::GetXcbConnection() {
xcb_screen_t *XcbUiApplication::GetFirstXcbScreen() { return screen_; }
+xcb_atom_t XcbUiApplication::GetOrCreateXcbAtom(std::string name) {
+ auto iter = xcb_atom_.find(name);
+ if (iter != xcb_atom_.cend()) {
+ return iter->second;
+ }
+
+ auto cookie =
+ xcb_intern_atom(xcb_connection_, false, name.size(), name.data());
+ auto reply = xcb_intern_atom_reply(xcb_connection_, cookie, nullptr);
+ auto atom = reply->atom;
+ xcb_atom_.emplace(std::move(name), atom);
+ return atom;
+}
+
+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 9dd510e9..9b72789b 100644
--- a/src/platform/gui/xcb/Window.cpp
+++ b/src/platform/gui/xcb/Window.cpp
@@ -76,13 +76,16 @@ INativeWindow *XcbWindow::GetParent() { return parent_; }
void XcbWindow::SetParent(INativeWindow *parent) {
parent_ = CheckPlatform<XcbWindow>(parent, GetPlatformIdUtf8());
if (xcb_window_) {
- auto real_parent = application_->GetFirstXcbScreen()->root;
- if (parent_ && parent_->xcb_window_) {
- real_parent = *parent_->xcb_window_;
- }
- xcb_reparent_window(application_->GetXcbConnection(), *xcb_window_,
- real_parent, 0, 0);
- // TODO: Maybe restore position?
+ DoSetParent(*xcb_window_);
+ }
+}
+
+WindowStyleFlag XcbWindow::GetStyleFlag() { return style_; }
+
+void XcbWindow::SetStyleFlag(WindowStyleFlag flag) {
+ style_ = flag;
+ if (xcb_window_) {
+ DoSetStyleFlags(*xcb_window_);
}
}
@@ -160,6 +163,9 @@ xcb_window_t XcbWindow::DoCreateWindow() {
screen->root_visual, mask, values);
current_size_ = Size(width, height);
+ DoSetStyleFlags(window);
+ DoSetParent(window);
+
xcb_visualtype_t *visual_type;
for (xcb_depth_iterator_t depth_iter =
@@ -361,4 +367,29 @@ std::optional<xcb_window_t> XcbWindow::GetEventWindow(
return std::nullopt;
}
}
+
+void XcbWindow::DoSetParent(xcb_window_t window) {
+ auto real_parent =
+ application_->GetFirstXcbScreen()->root; // init to desktop
+ if (parent_ && parent_->xcb_window_) {
+ real_parent = *parent_->xcb_window_;
+ }
+ xcb_reparent_window(application_->GetXcbConnection(), window, real_parent, 0,
+ 0);
+ // TODO: Maybe restore position?
+}
+
+void XcbWindow::DoSetStyleFlags(xcb_window_t window) {
+ std::vector<xcb_atom_t> atoms;
+ if (style_.Has(WindowStyleFlags::NoCaptionAndBorder)) {
+ atoms = {application_->GetXcbAtom_NET_WM_WINDOW_TYPE_UTILITY()};
+ } else {
+ atoms = {application_->GetXcbAtom_NET_WM_WINDOW_TYPE_NORMAL()};
+ }
+
+ xcb_change_property(application_->GetXcbConnection(), XCB_PROP_MODE_REPLACE,
+ window, application_->GetXcbAtom_NET_WM_WINDOW_TYPE(),
+ XCB_ATOM_ATOM, 32, atoms.size(), atoms.data());
+}
+
} // namespace cru::platform::gui::xcb