kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

commit 4bc4980e3d28a1df5b35963d426e20d820138477
parent 7b3b1a777a817f8eaae3c527de4473239f667d9f
Author: deurzen <max@deurzen.net>
Date:   Sat, 28 May 2022 01:18:08 +0200

restructures view {,de}registration processes

Diffstat:
Minclude/kranewl/cycle.t.hh | 2++
Minclude/kranewl/model.hh | 9++++-----
Minclude/kranewl/tree/view.hh | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Minclude/kranewl/tree/xdg_view.hh | 26+++++++++++++++++---------
Minclude/kranewl/tree/xwayland_view.hh | 26+++++++++++++++++---------
Msrc/kranewl/layout.cc | 10+++++-----
Msrc/kranewl/model.cc | 247++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/kranewl/server.cc | 5+++--
Msrc/kranewl/tree/view.cc | 321++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/kranewl/tree/xdg_view.cc | 308++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/kranewl/tree/xwayland_view.cc | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/kranewl/workspace.cc | 6+++---
12 files changed, 734 insertions(+), 443 deletions(-)

diff --git a/include/kranewl/cycle.t.hh b/include/kranewl/cycle.t.hh @@ -108,6 +108,8 @@ Cycle<T>::next_will_wrap(Direction direction) const case Direction::Backward: return m_index == 0; case Direction::Forward: return m_index == Util::last_index(m_elements); } + + return false; } template <typename T> diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh @@ -146,6 +146,10 @@ public: void spawn_external(std::string&&) const; + Output_ptr mp_output; + Context_ptr mp_context; + Workspace_ptr mp_workspace; + private: Server_ptr mp_server; Config const& m_config; @@ -156,11 +160,6 @@ private: Cycle<Context_ptr> m_contexts; Cycle<Workspace_ptr> m_workspaces; - Output_ptr mp_output; - Output_ptr mp_fallback_output; - Context_ptr mp_context; - Workspace_ptr mp_workspace; - Output_ptr mp_prev_output; Context_ptr mp_prev_context; Workspace_ptr mp_prev_workspace; diff --git a/include/kranewl/tree/view.hh b/include/kranewl/tree/view.hh @@ -30,6 +30,16 @@ typedef struct View { static constexpr Dim MIN_VIEW_DIM = Dim{25, 10}; static constexpr Dim PREFERRED_INIT_VIEW_DIM = Dim{480, 260}; + enum class OutsideState { + Focused, + FocusedDisowned, + FocusedSticky, + Unfocused, + UnfocusedDisowned, + UnfocusedSticky, + Urgent + }; + enum class Type { XDGShell, #ifdef XWAYLAND @@ -43,12 +53,7 @@ typedef struct View { Server_ptr, Model_ptr, Seat_ptr, - struct wlr_surface*, - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*) + struct wlr_surface* ); #ifdef XWAYLAND View( @@ -57,42 +62,87 @@ typedef struct View { Server_ptr, Model_ptr, Seat_ptr, - struct wlr_surface*, - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*), - void(*)(wl_listener*, void*) + struct wlr_surface* ); #endif virtual ~View(); - void map(struct wlr_surface*, bool, struct wlr_output*, bool); - void unmap(); + virtual Region constraints() = 0; + virtual pid_t pid() = 0; + virtual bool prefers_floating() = 0; + virtual View_ptr is_transient_for() = 0; + + virtual void map() = 0; + virtual void unmap() = 0; + virtual void activate(Toggle) = 0; + virtual void set_tiled(Toggle) = 0; + virtual void set_fullscreen(Toggle) = 0; + virtual void set_resizing(Toggle) = 0; + + virtual void configure(Region const&, Extents const&, bool) = 0; + virtual void close() = 0; + virtual void close_popups() = 0; + virtual void destroy() = 0; + + void render_decoration(); + + bool focused() const { return m_focused; } + bool mapped() const { return m_mapped; } + bool managed() const { return m_managed; } + bool urgent() const { return m_urgent; } + bool floating() const { return m_floating; } + bool fullscreen() const { return m_fullscreen; } + bool scratchpad() const { return m_scratchpad; } + bool contained() const { return m_contained; } + bool invincible() const { return m_invincible; } + bool sticky() const { return m_sticky; } + bool iconifyable() const { return m_iconifyable; } + bool iconified() const { return m_iconified; } + bool disowned() const { return m_disowned; } + void set_focused(bool); + void set_mapped(bool); + void set_managed(bool); + void set_urgent(bool); + void set_floating(bool); + void set_fullscreen(bool); + void set_scratchpad(bool); + void set_contained(bool); + void set_invincible(bool); + void set_sticky(bool); + void set_iconifyable(bool); + void set_iconified(bool); + void set_disowned(bool); - void touch(); + uint32_t free_decoration_to_wlr_edges() const; + uint32_t tile_decoration_to_wlr_edges() const; + Region const& free_region() const { return m_free_region; } + Region const& tile_region() const { return m_tile_region; } + Region const& active_region() const { return m_active_region; } + void set_free_region(Region const&); + void set_tile_region(Region const&); + Dim const& minimum_dim() const { return m_minimum_dim; } + Dim const& preferred_dim() const { return m_preferred_dim; } + void set_minimum_dim(Dim const& minimum_dim) { m_minimum_dim = minimum_dim; } + void set_preferred_dim(Dim const& preferred_dim) { m_preferred_dim = preferred_dim; } + + Decoration const& free_decoration() const { return m_free_decoration; } + Decoration const& tile_decoration() const { return m_tile_decoration; } + Decoration const& active_decoration() const { return m_active_decoration; } + void set_free_decoration(Decoration const&); + void set_tile_decoration(Decoration const&); - virtual void focus(bool) = 0; - virtual void moveresize(Region const&, Extents const&, bool) = 0; - virtual void kill() = 0; + void touch() { m_last_touched = std::chrono::steady_clock::now(); } static bool is_free(View_ptr view) { return (view->m_floating && (!view->m_fullscreen || view->m_contained)) - || !view->m_managed - || view->m_disowned; + || view->m_disowned + || !view->m_managed; } - uint32_t free_decoration_to_wlr_edges() const; - uint32_t tile_decoration_to_wlr_edges() const; - - void set_free_region(Region const&); - void set_tile_region(Region const&); - - void set_free_decoration(Decoration const&); - void set_tile_decoration(Decoration const&); + OutsideState outside_state() const; Uid m_uid; Type m_type; @@ -119,6 +169,17 @@ typedef struct View { pid_t m_pid; + std::chrono::time_point<std::chrono::steady_clock> m_last_focused; + std::chrono::time_point<std::chrono::steady_clock> m_last_touched; + std::chrono::time_point<std::chrono::steady_clock> m_managed_since; + +protected: + + struct { + struct wl_signal unmap; + } m_events; + +private: Decoration m_tile_decoration; Decoration m_free_decoration; Decoration m_active_decoration; @@ -145,26 +206,11 @@ typedef struct View { bool m_iconified; bool m_disowned; - std::chrono::time_point<std::chrono::steady_clock> m_last_focused; - std::chrono::time_point<std::chrono::steady_clock> m_last_touched; - std::chrono::time_point<std::chrono::steady_clock> m_managed_since; + OutsideState m_outside_state; -protected: void set_inner_region(Region const&); void set_active_region(Region const&); - struct wlr_foreign_toplevel_handle_v1* foreign_toplevel; - - struct wl_listener ml_foreign_activate_request; - struct wl_listener ml_foreign_fullscreen_request; - struct wl_listener ml_foreign_close_request; - struct wl_listener ml_foreign_destroy; - struct wl_listener ml_surface_new_subsurface; - - struct { - struct wl_signal unmap; - } m_events; - }* View_ptr; typedef struct ViewChild* ViewChild_ptr; diff --git a/include/kranewl/tree/xdg_view.hh b/include/kranewl/tree/xdg_view.hh @@ -22,15 +22,23 @@ typedef struct XDGView final : public View { ~XDGView(); - void focus(bool) override; - void moveresize(Region const&, Extents const&, bool) override; - void kill() override; - - static void handle_foreign_activate_request(struct wl_listener*, void*); - static void handle_foreign_fullscreen_request(struct wl_listener*, void*); - static void handle_foreign_close_request(struct wl_listener*, void*); - static void handle_foreign_destroy(struct wl_listener*, void*); - static void handle_surface_new_subsurface(struct wl_listener*, void*); + Region constraints() override; + pid_t pid() override; + bool prefers_floating() override; + View_ptr is_transient_for() override; + + void map() override; + void unmap() override; + void activate(Toggle) override; + void set_tiled(Toggle) override; + void set_fullscreen(Toggle) override; + void set_resizing(Toggle) override; + + void configure(Region const&, Extents const&, bool) override; + void close() override; + void close_popups() override; + void destroy() override; + static void handle_commit(struct wl_listener*, void*); static void handle_request_move(struct wl_listener*, void*); static void handle_request_resize(struct wl_listener*, void*); diff --git a/include/kranewl/tree/xwayland_view.hh b/include/kranewl/tree/xwayland_view.hh @@ -21,15 +21,23 @@ typedef struct XWaylandView final : public View { ~XWaylandView(); - void focus(bool) override; - void moveresize(Region const&, Extents const&, bool) override; - void kill() override; - - static void handle_foreign_activate_request(struct wl_listener*, void*); - static void handle_foreign_fullscreen_request(struct wl_listener*, void*); - static void handle_foreign_close_request(struct wl_listener*, void*); - static void handle_foreign_destroy(struct wl_listener*, void*); - static void handle_surface_new_subsurface(struct wl_listener*, void*); + Region constraints() override; + pid_t pid() override; + bool prefers_floating() override; + View_ptr is_transient_for() override; + + void map() override; + void unmap() override; + void activate(Toggle) override; + void set_tiled(Toggle) override; + void set_fullscreen(Toggle) override; + void set_resizing(Toggle) override; + + void configure(Region const&, Extents const&, bool) override; + void close() override; + void close_popups() override; + void destroy() override; + static void handle_commit(struct wl_listener*, void*); static void handle_request_move(struct wl_listener*, void*); static void handle_request_resize(struct wl_listener*, void*); diff --git a/src/kranewl/layout.cc b/src/kranewl/layout.cc @@ -522,7 +522,7 @@ LayoutHandler::arrange_float( mp_layout->config.method, view, mp_layout->config.decoration, - view->m_free_region + view->free_region() }; } ); @@ -560,7 +560,7 @@ LayoutHandler::arrange_single_float( mp_layout->config.method, view, mp_layout->config.decoration, - view->m_focused ? std::optional(view->m_free_region) : std::nullopt + view->focused() ? std::optional(view->free_region()) : std::nullopt }; } ); @@ -963,10 +963,10 @@ LayoutHandler::arrange_paper( begin, end, [&contains_active](const View_ptr lhs, const View_ptr rhs) { - if (lhs->m_focused) { + if (lhs->focused()) { contains_active = true; return false; - } else if (rhs->m_focused) { + } else if (rhs->focused()) { contains_active = true; return true; } @@ -985,7 +985,7 @@ LayoutHandler::arrange_paper( [=,this,&after_active,&i](View_ptr view) -> Placement { int x = screen_region.pos.x + static_cast<int>(i++ * w); - if ((!contains_active && *last_active == view) || view->m_focused) { + if ((!contains_active && *last_active == view) || view->focused()) { after_active = true; return Placement { diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc @@ -44,7 +44,6 @@ Model::Model( m_contexts{{}, true}, m_workspaces{{}, true}, mp_output{nullptr}, - mp_fallback_output{nullptr}, mp_context{nullptr}, mp_workspace{nullptr}, mp_prev_output{nullptr}, @@ -195,15 +194,17 @@ Model::unregister_output(Output_ptr output) } void -Model::map_view(View_ptr view) +Model::map_view(View_ptr) { TRACE(); + } void -Model::unmap_view(View_ptr view) +Model::unmap_view(View_ptr) { TRACE(); + } void @@ -240,7 +241,7 @@ Model::focus_view(View_ptr view) if (!output) return; - if (!view->m_sticky) { + if (!view->sticky()) { activate_workspace(view->mp_workspace); mp_workspace->activate_view(view); } @@ -248,7 +249,7 @@ Model::focus_view(View_ptr view) if (mp_focus && mp_focus != view) unfocus_view(mp_focus); - view->m_urgent = false; + view->set_urgent(false); mp_focus = view; if (mp_workspace->layout_is_persistent() || mp_workspace->layout_is_single()) @@ -304,12 +305,12 @@ Model::place_view(Placement& placement) } } - spdlog::info("Placing view {} at {}", view->m_uid, std::to_string(view->m_active_region)); + spdlog::info("Placing view {} at {}", view->m_uid, std::to_string(view->active_region())); map_view(view); - view->moveresize( - view->m_active_region, - view->m_active_decoration.extents(), + view->configure( + view->active_region(), + view->active_decoration().extents(), false ); } @@ -322,7 +323,7 @@ Model::sync_focus() View_ptr active = mp_workspace->active(); if (active && active != mp_focus) - active->focus(true); + active->activate(Toggle::On); else if (mp_workspace->empty()) { mp_server->relinquish_focus(); mp_focus = nullptr; @@ -364,7 +365,7 @@ Model::reverse_views() return; mp_workspace->reverse(); - mp_workspace->active()->focus(true); + /* mp_workspace->active()->focus(true); */ sync_focus(); apply_layout(mp_workspace); @@ -379,7 +380,7 @@ Model::rotate_views(Direction direction) return; mp_workspace->rotate(direction); - mp_workspace->active()->focus(true); + /* mp_workspace->active()->focus(true); */ sync_focus(); apply_layout(mp_workspace); @@ -413,7 +414,6 @@ Model::shuffle_main(Direction direction) } mp_workspace->shuffle_main(direction); - mp_workspace->active()->focus(true); sync_focus(); if (last_touched_index) @@ -450,7 +450,6 @@ Model::shuffle_stack(Direction direction) } mp_workspace->shuffle_stack(direction); - mp_workspace->active()->focus(true); sync_focus(); if (last_touched_index) @@ -480,26 +479,27 @@ Model::move_view_to_workspace(View_ptr view, Workspace_ptr workspace_to) view->mp_workspace = workspace_to; - Context_ptr context_from = workspace_from->context(); - Output_ptr output_from = context_from->output(); + if (workspace_from) { + Context_ptr context_from = workspace_from->context(); + Output_ptr output_from = context_from->output(); + + workspace_from->remove_view(view); + apply_layout(workspace_from); + } Context_ptr context_to = workspace_to->context(); Output_ptr output_to = context_to->output(); view->mp_context = context_to; - if (output_to != output_from) - view->mp_output = output_to; + view->mp_output = output_to; workspace_to->add_view(view); - workspace_from->remove_view(view); - apply_layout(workspace_to); - apply_layout(workspace_from); - if (!output_to) - unmap_view(view); - else + if (output_to) map_view(view); + else + unmap_view(view); sync_focus(); } @@ -518,15 +518,17 @@ Model::move_view_to_context(View_ptr view, Context_ptr context_to) { TRACE(); - Context_ptr context_from = view->mp_context; + Workspace_ptr workspace_from = view->mp_workspace; - if (!context_to || context_to == context_from) - return; + if (workspace_from) { + Context_ptr context_from = workspace_from->context(); + Output_ptr output_from = context_from->output(); - view->mp_context = context_to; + workspace_from->remove_view(view); + apply_layout(workspace_from); + } - Workspace_ptr workspace_from = view->mp_workspace; - Output_ptr output_from = context_from->output(); + view->mp_context = context_to; Workspace_ptr workspace_to = context_to->workspace(); Output_ptr output_to = context_to->output(); @@ -535,15 +537,12 @@ Model::move_view_to_context(View_ptr view, Context_ptr context_to) view->mp_output = output_to; workspace_to->add_view(view); - workspace_from->remove_view(view); - apply_layout(workspace_to); - apply_layout(workspace_from); - if (!output_to) - unmap_view(view); - else + if (output_to) map_view(view); + else + unmap_view(view); sync_focus(); } @@ -562,18 +561,22 @@ Model::move_view_to_output(View_ptr view, Output_ptr output_to) { TRACE(); - Output_ptr output_from = view->mp_output; + Workspace_ptr workspace_from = view->mp_workspace; - if (!output_to || output_to == output_from) - return; + if (workspace_from) { + Context_ptr context_from = workspace_from->context(); + Output_ptr output_from = context_from->output(); - if (output_from) { - Workspace_ptr workspace_from = view->mp_workspace; + workspace_from->remove_view(view); + apply_layout(workspace_from); + wlr_surface_send_leave(view->mp_wlr_surface, output_from->mp_wlr_output); + } - if (workspace_from) { - workspace_from->remove_view(view); - apply_layout(workspace_from); - } + if (!output_to || !output_to->context()) { + view->mp_output = nullptr; + view->mp_context = nullptr; + view->mp_workspace = nullptr; + return; } Context_ptr context_to = output_to->context(); @@ -586,9 +589,6 @@ Model::move_view_to_output(View_ptr view, Output_ptr output_to) workspace_to->add_view(view); apply_layout(workspace_to); - if (output_from) - wlr_surface_send_leave(view->mp_wlr_surface, output_from->mp_wlr_output); - if (output_to) { wlr_surface_send_enter(view->mp_wlr_surface, output_to->mp_wlr_output); map_view(view); @@ -684,9 +684,9 @@ Model::set_layout_retain_region(LayoutHandler::LayoutKind layout) std::back_inserter(regions), [=,this](View_ptr view) -> Region { if (is_free(view)) - return view->m_free_region; + return view->free_region(); else - return view->m_tile_region; + return view->tile_region(); } ); } @@ -854,8 +854,8 @@ Model::kill_view(View_ptr view) { TRACE(); - if (!view->m_invincible) - view->kill(); + if (!view->invincible()) + view->close(); } void @@ -873,9 +873,9 @@ Model::set_floating_view(Toggle toggle, View_ptr view) TRACE(); switch (toggle) { - case Toggle::On: view->m_floating = true; break; - case Toggle::Off: view->m_floating = false; break; - case Toggle::Reverse: view->m_floating = !view->m_floating; break; + case Toggle::On: view->set_floating(true); break; + case Toggle::Off: view->set_floating(false); break; + case Toggle::Reverse: view->set_floating(!view->floating()); break; default: return; } @@ -899,29 +899,29 @@ Model::set_fullscreen_view(Toggle toggle, View_ptr view) switch (toggle) { case Toggle::On: { - if (view->m_fullscreen) + if (view->fullscreen()) return; - view->m_fullscreen = true; + view->set_fullscreen(true); // TODO: set fullscreen state Workspace_ptr workspace = view->mp_workspace; apply_layout(workspace); - m_fullscreen_map[view] = view->m_free_region; + m_fullscreen_map[view] = view->free_region(); return; } case Toggle::Off: { - if (!view->m_fullscreen) + if (!view->fullscreen()) return; - if (!view->m_contained) + if (!view->contained()) view->set_free_region(m_fullscreen_map.at(view)); - view->m_fullscreen = false; + view->set_fullscreen(false); // TODO: unset fullscreen state @@ -935,7 +935,7 @@ Model::set_fullscreen_view(Toggle toggle, View_ptr view) case Toggle::Reverse: { set_fullscreen_view( - view->m_fullscreen + view->fullscreen() ? Toggle::Off : Toggle::On, view @@ -964,10 +964,10 @@ Model::set_sticky_view(Toggle toggle, View_ptr view) switch (toggle) { case Toggle::On: { - if (view->m_sticky) + if (view->sticky()) return; - if (view->m_iconified) + if (view->iconified()) set_iconify_view(Toggle::Off, view); std::for_each( @@ -990,7 +990,7 @@ Model::set_sticky_view(Toggle toggle, View_ptr view) } case Toggle::Off: { - if (!view->m_sticky) + if (!view->sticky()) return; std::for_each( @@ -1016,7 +1016,7 @@ Model::set_sticky_view(Toggle toggle, View_ptr view) case Toggle::Reverse: { set_sticky_view( - view->m_sticky + view->sticky() ? Toggle::Off : Toggle::On, view @@ -1045,7 +1045,7 @@ Model::set_contained_view(Toggle toggle, View_ptr view) switch (toggle) { case Toggle::On: { - view->m_contained = true; + view->set_contained(true); Workspace_ptr workspace = view->mp_workspace; @@ -1054,7 +1054,7 @@ Model::set_contained_view(Toggle toggle, View_ptr view) } case Toggle::Off: { - view->m_contained = false; + view->set_contained(false); Workspace_ptr workspace = view->mp_workspace; @@ -1064,7 +1064,7 @@ Model::set_contained_view(Toggle toggle, View_ptr view) case Toggle::Reverse: { set_contained_view( - view->m_contained + view->contained() ? Toggle::Off : Toggle::On, view @@ -1092,14 +1092,17 @@ Model::set_invincible_view(Toggle toggle, View_ptr view) if (toggle == Toggle::Reverse) set_invincible_view( - view->m_invincible + view->invincible() ? Toggle::Off : Toggle::On, view ); else - view->m_invincible - = toggle == Toggle::On ? true : false; + view->set_invincible( + toggle == Toggle::On + ? true + : false + ); } void @@ -1118,14 +1121,17 @@ Model::set_iconifyable_view(Toggle toggle, View_ptr view) if (toggle == Toggle::Reverse) set_iconifyable_view( - view->m_iconifyable + view->iconifyable() ? Toggle::Off : Toggle::On, view ); else - view->m_iconifyable - = toggle == Toggle::On ? true : false; + view->set_iconifyable( + toggle == Toggle::On + ? true + : false + ); } void @@ -1145,7 +1151,7 @@ Model::set_iconify_view(Toggle toggle, View_ptr view) switch (toggle) { case Toggle::On: { - if (view->m_iconified || view->m_sticky) + if (view->iconified() || view->sticky()) return; Workspace_ptr workspace = view->mp_workspace; @@ -1158,13 +1164,13 @@ Model::set_iconify_view(Toggle toggle, View_ptr view) apply_layout(workspace); sync_focus(); - view->m_iconified = true; + view->set_iconified(true); return; } case Toggle::Off: { - if (!view->m_iconified) + if (!view->iconified()) return; Workspace_ptr workspace = view->mp_workspace; @@ -1172,7 +1178,7 @@ Model::set_iconify_view(Toggle toggle, View_ptr view) // TODO: unset iconify state - view->m_iconified = false; + view->set_iconified(false); apply_layout(workspace); sync_focus(); @@ -1182,7 +1188,7 @@ Model::set_iconify_view(Toggle toggle, View_ptr view) case Toggle::Reverse: { set_iconify_view( - view->m_iconified + view->iconified() ? Toggle::Off : Toggle::On, view @@ -1211,7 +1217,7 @@ Model::center_view(View_ptr view) if (!is_free(view)) return; - Region region = view->m_free_region; + Region region = view->free_region(); const Region screen_region = view->mp_context->output()->placeable_region(); @@ -1224,7 +1230,7 @@ Model::center_view(View_ptr view) Placement placement = Placement { Placement::PlacementMethod::Free, view, - view->m_free_decoration, + view->free_decoration(), region }; @@ -1248,7 +1254,7 @@ Model::nudge_view(Edge edge, Util::Change<std::size_t> change, View_ptr view) if (!is_free(view)) return; - Region region = view->m_free_region; + Region region = view->free_region(); switch (edge) { case Edge::Left: @@ -1277,7 +1283,7 @@ Model::nudge_view(Edge edge, Util::Change<std::size_t> change, View_ptr view) Placement placement = Placement { Placement::PlacementMethod::Free, view, - view->m_free_decoration, + view->free_decoration(), region }; @@ -1299,7 +1305,7 @@ Model::stretch_view(Edge edge, Util::Change<int> change, View_ptr view) if (!is_free(view)) return; - Decoration decoration = view->m_free_decoration; + Decoration decoration = view->free_decoration(); Extents extents = Extents { 0, 0, 0, 0 }; if (decoration.frame) { @@ -1309,7 +1315,7 @@ Model::stretch_view(Edge edge, Util::Change<int> change, View_ptr view) extents.bottom += decoration.frame->extents.bottom; } - Region region = view->m_free_region; + Region region = view->free_region(); region.remove_extents(extents); switch (edge) { @@ -1371,7 +1377,7 @@ Model::stretch_view(Edge edge, Util::Change<int> change, View_ptr view) Placement placement = Placement { Placement::PlacementMethod::Free, view, - view->m_free_decoration, + view->free_decoration(), region }; @@ -1395,7 +1401,7 @@ Model::inflate_view(Util::Change<int> change, View_ptr view) if (!is_free(view)) return; - Decoration decoration = view->m_free_decoration; + Decoration decoration = view->free_decoration(); Extents extents = Extents { 0, 0, 0, 0 }; if (decoration.frame) { @@ -1405,7 +1411,7 @@ Model::inflate_view(Util::Change<int> change, View_ptr view) extents.bottom += decoration.frame->extents.bottom; } - Region region = view->m_free_region; + Region region = view->free_region(); region.remove_extents(extents); double ratio = static_cast<double>(region.dim.w) @@ -1430,8 +1436,8 @@ Model::inflate_view(Util::Change<int> change, View_ptr view) region.apply_extents(extents); - int dx = region.dim.w - view->m_free_region.dim.w; - int dy = region.dim.h - view->m_free_region.dim.h; + int dx = region.dim.w - view->free_region().dim.w; + int dy = region.dim.h - view->free_region().dim.h; dx = std::lround(dx / static_cast<double>(2)); dy = std::lround(dy / static_cast<double>(2)); @@ -1444,7 +1450,7 @@ Model::inflate_view(Util::Change<int> change, View_ptr view) Placement placement = Placement { Placement::PlacementMethod::Free, view, - view->m_free_decoration, + view->free_decoration(), region }; @@ -1468,7 +1474,7 @@ Model::snap_view(Edge edge, View_ptr view) if (!is_free(view)) return; - Region region = view->m_free_region; + Region region = view->free_region(); const Region screen_region = view->mp_context->output()->placeable_region(); @@ -1508,7 +1514,7 @@ Model::snap_view(Edge edge, View_ptr view) Placement placement = Placement { Placement::PlacementMethod::Free, view, - view->m_free_decoration, + view->free_decoration(), region }; @@ -1550,11 +1556,12 @@ Model::create_xdg_shell_view( seat ); - register_view(view); + m_view_map[view->m_uid] = view; return view; } +#ifdef XWAYLAND XWaylandView_ptr Model::create_xwayland_view( struct wlr_xwayland_surface* wlr_xwayland_surface, @@ -1570,21 +1577,30 @@ Model::create_xwayland_view( seat ); - register_view(view); + m_view_map[view->m_uid] = view; return view; } +#endif void Model::register_view(View_ptr view) { TRACE(); - m_view_map[view->m_uid] = view; + if (view->mp_workspace) + view->mp_workspace->add_view(view); + + std::stringstream uid_ss; + uid_ss << std::hex << view->m_uid; + spdlog::info( + "Registered view 0x{} [{}, PID {}]", + uid_ss.str(), + view->m_title, + view->m_pid + ); - std::stringstream uid_stream; - uid_stream << std::hex << view->m_uid; - spdlog::info("Registered view 0x{}", uid_stream.str()); + sync_focus(); } void @@ -1595,9 +1611,15 @@ Model::unregister_view(View_ptr view) if (view->mp_workspace) view->mp_workspace->remove_view(view); - std::stringstream uid_stream; - uid_stream << std::hex << view->m_uid; - spdlog::info("Unegistered view 0x{}", uid_stream.str()); + std::stringstream uid_ss; + uid_ss << std::hex << view->m_uid; + spdlog::info( + "Unregistered view 0x{} [{}, PID {}]", + uid_ss.str(), + view->m_title, + view->m_pid + ); + sync_focus(); } @@ -1606,21 +1628,26 @@ Model::destroy_view(View_ptr view) { TRACE(); - std::stringstream uid_stream; - uid_stream << std::hex << view->m_uid; - m_view_map.erase(view->m_uid); - delete view; - spdlog::info("Destroyed view 0x{}", uid_stream.str()); + std::stringstream uid_ss; + uid_ss << std::hex << view->m_uid; + spdlog::info( + "Destroyed view 0x{} [{}, PID {}]", + uid_ss.str(), + view->m_title, + view->m_pid + ); + + delete view; } bool Model::is_free(View_ptr view) const { return View::is_free(view) - || ((!view->m_fullscreen || view->m_contained) - && (view->m_sticky + || ((!view->fullscreen() || view->contained()) + && (view->sticky() ? mp_workspace : view->mp_workspace )->layout_is_free()); diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc @@ -385,9 +385,10 @@ Server::handle_new_xdg_surface(struct wl_listener* listener, void* data) if (!(view = view_from_popup(xdg_surface->popup)) || !view->mp_output) return; + Region const& active_region = view->active_region(); mappable_box = view->mp_output->placeable_region(); - mappable_box.x -= view->m_active_region.pos.x; - mappable_box.y -= view->m_active_region.pos.y; + mappable_box.x -= active_region.pos.x; + mappable_box.y -= active_region.pos.y; wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &mappable_box); diff --git a/src/kranewl/tree/view.cc b/src/kranewl/tree/view.cc @@ -28,12 +28,7 @@ View::View( Server_ptr server, Model_ptr model, Seat_ptr seat, - struct wlr_surface* wlr_surface, - void(*handle_foreign_activate_request)(wl_listener*, void*), - void(*handle_foreign_fullscreen_request)(wl_listener*, void*), - void(*handle_foreign_close_request)(wl_listener*, void*), - void(*handle_foreign_destroy)(wl_listener*, void*), - void(*handle_surface_new_subsurface)(wl_listener*, void*) + struct wlr_surface* wlr_surface ) : m_uid(uid), m_type(Type::XDGShell), @@ -45,6 +40,7 @@ View::View( mp_workspace(nullptr), mp_wlr_surface(wlr_surface), m_alpha(1.f), + m_resize(0), m_tile_decoration(FREE_DECORATION), m_free_decoration(FREE_DECORATION), m_active_decoration(FREE_DECORATION), @@ -71,11 +67,7 @@ View::View( m_last_focused(std::chrono::steady_clock::now()), m_last_touched(std::chrono::steady_clock::now()), m_managed_since(std::chrono::steady_clock::now()), - ml_foreign_activate_request({ .notify = handle_foreign_activate_request }), - ml_foreign_fullscreen_request({ .notify = handle_foreign_fullscreen_request }), - ml_foreign_close_request({ .notify = handle_foreign_close_request }), - ml_foreign_destroy({ .notify = handle_foreign_destroy }), - ml_surface_new_subsurface({ .notify = handle_surface_new_subsurface }) + m_outside_state(OutsideState::Unfocused) { wl_signal_init(&m_events.unmap); } @@ -87,128 +79,248 @@ View::View( Server_ptr server, Model_ptr model, Seat_ptr seat, - struct wlr_surface* wlr_surface, - void(*handle_foreign_activate_request)(wl_listener*, void*), - void(*handle_foreign_fullscreen_request)(wl_listener*, void*), - void(*handle_foreign_close_request)(wl_listener*, void*), - void(*handle_foreign_destroy)(wl_listener*, void*), - void(*handle_surface_new_subsurface)(wl_listener*, void*) + struct wlr_surface* wlr_surface ) : m_uid(uid), m_type(Type::XWayland), mp_server(server), mp_model(model), mp_seat(seat), + mp_output(nullptr), + mp_context(nullptr), + mp_workspace(nullptr), mp_wlr_surface(wlr_surface), - m_tile_decoration({}, DEFAULT_COLOR_SCHEME), - m_free_decoration({}, DEFAULT_COLOR_SCHEME), - m_active_decoration({}, DEFAULT_COLOR_SCHEME), - ml_foreign_activate_request({ .notify = handle_foreign_activate_request }), - ml_foreign_fullscreen_request({ .notify = handle_foreign_fullscreen_request }), - ml_foreign_close_request({ .notify = handle_foreign_close_request }), - ml_foreign_destroy({ .notify = handle_foreign_destroy }), - ml_surface_new_subsurface({ .notify = handle_surface_new_subsurface }) -{} + m_alpha(1.f), + m_resize(0), + m_tile_decoration(FREE_DECORATION), + m_free_decoration(FREE_DECORATION), + m_active_decoration(FREE_DECORATION), + m_minimum_dim({}), + m_preferred_dim({}), + m_free_region({}), + m_tile_region({}), + m_active_region({}), + m_previous_region({}), + m_inner_region({}), + m_focused(false), + m_mapped(false), + m_managed(true), + m_urgent(false), + m_floating(false), + m_fullscreen(false), + m_scratchpad(false), + m_contained(false), + m_invincible(false), + m_sticky(false), + m_iconifyable(true), + m_iconified(false), + m_disowned(false), + m_last_focused(std::chrono::steady_clock::now()), + m_last_touched(std::chrono::steady_clock::now()), + m_managed_since(std::chrono::steady_clock::now()) +{ + wl_signal_init(&m_events.unmap); +} #endif View::~View() {} -static inline void -set_view_pid(View_ptr view) +void +View::set_focused(bool focused) { - switch (view->m_type) { - case View::Type::XDGShell: - { - pid_t pid; - struct wl_client* client - = wl_resource_get_client(view->mp_wlr_surface->resource); + auto now = std::chrono::steady_clock::now(); + m_last_touched = now; + m_last_focused = now; + m_focused = focused; + + switch (focused) { + case true: + switch (m_outside_state) { + case OutsideState::Unfocused: m_outside_state = OutsideState::Focused; return; + case OutsideState::UnfocusedDisowned: m_outside_state = OutsideState::FocusedDisowned; return; + case OutsideState::UnfocusedSticky: m_outside_state = OutsideState::FocusedSticky; return; + default: return; + } + case false: + switch (m_outside_state) { + case OutsideState::Focused: m_outside_state = OutsideState::Unfocused; return; + case OutsideState::FocusedDisowned: m_outside_state = OutsideState::UnfocusedDisowned; return; + case OutsideState::FocusedSticky: m_outside_state = OutsideState::UnfocusedSticky; return; + default: return; + } + } +} - wl_client_get_credentials(client, &pid, nullptr, nullptr); - view->m_pid = pid; +void +View::set_mapped(bool mapped) +{ + m_mapped = mapped; +} - break; - } -#if HAVE_XWAYLAND - case View::Type::XWayland: - { - struct wlr_xwayland_surface* wlr_xwayland_surface - = wlr_xwayland_surface_from_wlr_surface(view->mp_wlr_surface); - view->m_pid = wlr_xwayland_surface->pid; +void +View::set_managed(bool managed) +{ + m_managed = managed; +} - break; - } -#endif - default: break; - } +void +View::set_urgent(bool urgent) +{ + m_urgent = urgent; } void -View::map( - struct wlr_surface* wlr_surface, - bool fullscreen, - struct wlr_output* fullscreen_output, - bool decorations -) +View::set_floating(bool floating) { - TRACE(); + m_floating = floating; +} - Server_ptr server = mp_server; - Model_ptr model = mp_model; - - mp_wlr_surface = wlr_surface; - set_view_pid(this); - - mp_scene = &wlr_scene_tree_create(mp_server->m_layers[Layer::Tile])->node; - mp_wlr_surface->data = mp_scene_surface = m_type == View::Type::XDGShell - ? wlr_scene_xdg_surface_create( - mp_scene, - reinterpret_cast<XDGView_ptr>(this)->mp_wlr_xdg_surface - ) - : wlr_scene_subsurface_tree_create(mp_scene, mp_wlr_surface); - mp_scene_surface->data = this; - - wlr_scene_node_reparent( - mp_scene, - server->m_layers[m_floating ? Layer::Free : Layer::Tile] - ); - - for (std::size_t i = 0; i < 4; ++i) { - m_protrusions[i] = wlr_scene_rect_create( - mp_scene, - 0, - 0, - m_active_decoration.colorscheme.unfocused.values - ); - m_protrusions[i]->node.data = this; - wlr_scene_rect_set_color( - m_protrusions[i], - m_active_decoration.colorscheme.unfocused.values - ); - wlr_scene_node_lower_to_bottom(&m_protrusions[i]->node); - } +void +View::set_fullscreen(bool fullscreen) +{ + m_fullscreen = fullscreen; +} - if (fullscreen_output && fullscreen_output->data) { - Output_ptr output = reinterpret_cast<Output_ptr>(fullscreen_output->data); +void +View::set_scratchpad(bool scratchpad) +{ + m_scratchpad = scratchpad; +} + +void +View::set_contained(bool contained) +{ + m_contained = contained; +} + +void +View::set_invincible(bool invincible) +{ + m_invincible = invincible; +} + +void +View::set_sticky(bool sticky) +{ + m_sticky = sticky; + + switch (sticky) { + case true: + switch (m_outside_state) { + case OutsideState::Focused: m_outside_state = OutsideState::FocusedSticky; return; + case OutsideState::Unfocused: m_outside_state = OutsideState::UnfocusedSticky; return; + default: return; + } + case false: + switch (m_outside_state) { + case OutsideState::FocusedSticky: m_outside_state = OutsideState::Focused; return; + case OutsideState::UnfocusedSticky: m_outside_state = OutsideState::Unfocused; return; + default: return; + } } +} - model->move_view_to_focused_output(this); - focus(true); +void +View::set_iconifyable(bool iconifyable) +{ + m_iconifyable = iconifyable; } void -View::unmap() +View::set_iconified(bool iconified) { - TRACE(); + m_iconified = iconified; +} - wlr_scene_node_destroy(mp_scene); - mp_wlr_surface = nullptr; +void +View::set_disowned(bool disowned) +{ + m_disowned = disowned; + + switch (disowned) { + case true: + switch (m_outside_state) { + case OutsideState::Focused: m_outside_state = OutsideState::FocusedDisowned; return; + case OutsideState::Unfocused: m_outside_state = OutsideState::UnfocusedDisowned; return; + default: return; + } + case false: + switch (m_outside_state) { + case OutsideState::FocusedDisowned: m_outside_state = OutsideState::Focused; return; + case OutsideState::UnfocusedDisowned: m_outside_state = OutsideState::Unfocused; return; + default: return; + } + } } void -View::touch() +View::render_decoration() { - m_last_touched = std::chrono::steady_clock::now(); + TRACE(); + + Decoration const& decoration = m_active_decoration; + ColorScheme const& colorscheme = decoration.colorscheme; + const float* colors = nullptr; + + switch (outside_state()) { + case OutsideState::Focused: + { + if (decoration.frame) + colors = colorscheme.focused.values; + + break; + } + case OutsideState::FocusedDisowned: + { + if (decoration.frame) + colors = colorscheme.fdisowned.values; + + break; + } + case OutsideState::FocusedSticky: + { + if (decoration.frame) + colors = colorscheme.fsticky.values; + + break; + } + case OutsideState::Unfocused: + { + if (decoration.frame) + colors = colorscheme.unfocused.values; + + break; + } + case OutsideState::UnfocusedDisowned: + { + if (decoration.frame) + colors = colorscheme.udisowned.values; + + break; + } + case OutsideState::UnfocusedSticky: + { + if (decoration.frame) + colors = colorscheme.usticky.values; + + break; + } + case OutsideState::Urgent: + { + if (decoration.frame) + colors = colorscheme.urgent.values; + + break; + } + } + + if (decoration.frame) + for (std::size_t i = 0; i < 4; ++i) + wlr_scene_rect_set_color( + m_protrusions[i], + colors + ); } static uint32_t @@ -271,6 +383,15 @@ View::set_tile_decoration(Decoration const& decoration) m_active_decoration = decoration; } +View::OutsideState +View::outside_state() const +{ + if (m_urgent) + return OutsideState::Urgent; + + return m_outside_state; +} + void View::set_active_region(Region const& region) { diff --git a/src/kranewl/tree/xdg_view.cc b/src/kranewl/tree/xdg_view.cc @@ -1,9 +1,13 @@ #include <trace.hh> +#include <kranewl/context.hh> #include <kranewl/layers.hh> +#include <kranewl/model.hh> #include <kranewl/server.hh> +#include <kranewl/tree/output.hh> #include <kranewl/tree/view.hh> #include <kranewl/tree/xdg_view.hh> +#include <kranewl/workspace.hh> // https://github.com/swaywm/wlroots/issues/682 #include <pthread.h> @@ -33,12 +37,7 @@ XDGView::XDGView( server, model, seat, - wlr_xdg_surface->surface, - XDGView::handle_foreign_activate_request, - XDGView::handle_foreign_fullscreen_request, - XDGView::handle_foreign_close_request, - XDGView::handle_foreign_destroy, - XDGView::handle_surface_new_subsurface + wlr_xdg_surface->toplevel->base->surface ), mp_wlr_xdg_surface(wlr_xdg_surface), mp_wlr_xdg_toplevel(wlr_xdg_surface->toplevel), @@ -61,147 +60,148 @@ XDGView::XDGView( XDGView::~XDGView() {} -void -XDGView::focus(bool raise) +Region +XDGView::constraints() { TRACE(); - struct wlr_surface* prev_focus - = mp_seat->mp_wlr_seat->keyboard_state.focused_surface; +} - if (raise) - wlr_scene_node_raise_to_top(mp_scene); +pid_t +XDGView::pid() +{ + TRACE(); - if (prev_focus == mp_wlr_surface) - return; + pid_t pid; + struct wl_client* client + = wl_resource_get_client(mp_wlr_surface->resource); - mp_model->focus_view(this); + wl_client_get_credentials(client, &pid, nullptr, nullptr); + return pid; +} - for (std::size_t i = 0; i < 4; ++i) - wlr_scene_rect_set_color( - m_protrusions[i], - m_active_decoration.colorscheme.focused.values - ); +bool +XDGView::prefers_floating() +{ + TRACE(); - if (prev_focus && prev_focus != mp_wlr_surface) { - if (wlr_surface_is_layer_surface(prev_focus)) { - struct wlr_layer_surface_v1* wlr_layer_surface - = wlr_layer_surface_v1_from_wlr_surface(prev_focus); - - if (wlr_layer_surface->mapped && ( - wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || - wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)) - { - return; - } - } else { - View_ptr prev_view; - struct wlr_scene_node* node - = reinterpret_cast<struct wlr_scene_node*>(prev_focus->data); - - if (prev_focus->role_data && (prev_view = reinterpret_cast<View_ptr>(node->data))) - for (std::size_t i = 0; i < 4; ++i) - wlr_scene_rect_set_color( - prev_view->m_protrusions[i], - m_active_decoration.colorscheme.unfocused.values - ); - - struct wlr_xdg_surface* wlr_xdg_surface; - if (wlr_surface_is_xdg_surface(prev_focus) - && (wlr_xdg_surface = wlr_xdg_surface_from_wlr_surface(prev_focus)) - && wlr_xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) - { - wlr_xdg_toplevel_set_activated(wlr_xdg_surface, false); - } - } - } + struct wlr_xdg_toplevel_state *state = &mp_wlr_xdg_toplevel->current; + return mp_wlr_xdg_toplevel->parent || (state->min_width != 0 && state->min_height != 0 + && (state->min_width == state->max_width || state->min_height == state->max_height)); +} - wlr_idle_set_enabled( - mp_seat->mp_idle, - mp_seat->mp_wlr_seat, - wl_list_empty(&mp_seat->mp_idle_inhibit_manager->inhibitors) - ); +View_ptr +XDGView::is_transient_for() +{ + TRACE(); - struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(mp_seat->mp_wlr_seat); - if (keyboard) - wlr_seat_keyboard_notify_enter( - mp_seat->mp_wlr_seat, - mp_wlr_surface, - keyboard->keycodes, - keyboard->num_keycodes, - &keyboard->modifiers - ); - else - wlr_seat_keyboard_notify_enter( - mp_seat->mp_wlr_seat, - mp_wlr_surface, - nullptr, - 0, - nullptr - ); +} + +void +XDGView::map() +{ + TRACE(); - wlr_xdg_toplevel_set_activated(mp_wlr_xdg_surface, true); } void -XDGView::moveresize(Region const& region, Extents const& extents, bool interactive) +XDGView::unmap() { TRACE(); - wlr_scene_node_set_position(mp_scene, region.pos.x, region.pos.y); - wlr_scene_node_set_position(mp_scene_surface, extents.left, extents.top); - wlr_scene_rect_set_size(m_protrusions[0], region.dim.w, extents.top); - wlr_scene_rect_set_size(m_protrusions[1], region.dim.w, extents.bottom); - wlr_scene_rect_set_size(m_protrusions[2], extents.left, region.dim.h - extents.top - extents.bottom); - wlr_scene_rect_set_size(m_protrusions[3], extents.right, region.dim.h - extents.top - extents.bottom); - wlr_scene_node_set_position(&m_protrusions[0]->node, 0, 0); - wlr_scene_node_set_position(&m_protrusions[1]->node, 0, region.dim.h - extents.bottom); - wlr_scene_node_set_position(&m_protrusions[2]->node, 0, extents.top); - wlr_scene_node_set_position(&m_protrusions[3]->node, region.dim.w - extents.right, extents.top); +} - m_resize = wlr_xdg_toplevel_set_size( - mp_wlr_xdg_surface, - region.dim.w - extents.left - extents.right, - region.dim.h - extents.top - extents.bottom - ); +void +XDGView::activate(Toggle toggle) +{ + TRACE(); + + switch (toggle) { + case Toggle::On: + { + wlr_xdg_toplevel_set_activated(mp_wlr_xdg_surface, true); + set_focused(true); + break; + } + case Toggle::Off: + { + wlr_xdg_toplevel_set_activated(mp_wlr_xdg_surface, false); + set_focused(false); + break; + } + case Toggle::Reverse: + { + activate( + focused() + ? Toggle::Off + : Toggle::On + ); + return; + } + default: break; + } } void -XDGView::kill() +XDGView::set_tiled(Toggle) { - wlr_xdg_toplevel_send_close(mp_wlr_xdg_surface); + TRACE(); + } void -XDGView::handle_foreign_activate_request(struct wl_listener* listener, void* data) +XDGView::set_fullscreen(Toggle) { TRACE(); } void -XDGView::handle_foreign_fullscreen_request(struct wl_listener* listener, void* data) +XDGView::set_resizing(Toggle) { TRACE(); } void -XDGView::handle_foreign_close_request(struct wl_listener* listener, void* data) +XDGView::configure(Region const& region, Extents const& extents, bool interactive) { TRACE(); + wlr_scene_node_set_position(mp_scene, region.pos.x, region.pos.y); + wlr_scene_node_set_position(mp_scene_surface, extents.left, extents.top); + wlr_scene_rect_set_size(m_protrusions[0], region.dim.w, extents.top); + wlr_scene_rect_set_size(m_protrusions[1], region.dim.w, extents.bottom); + wlr_scene_rect_set_size(m_protrusions[2], extents.left, region.dim.h - extents.top - extents.bottom); + wlr_scene_rect_set_size(m_protrusions[3], extents.right, region.dim.h - extents.top - extents.bottom); + wlr_scene_node_set_position(&m_protrusions[0]->node, 0, 0); + wlr_scene_node_set_position(&m_protrusions[1]->node, 0, region.dim.h - extents.bottom); + wlr_scene_node_set_position(&m_protrusions[2]->node, 0, extents.top); + wlr_scene_node_set_position(&m_protrusions[3]->node, region.dim.w - extents.right, extents.top); + + m_resize = wlr_xdg_toplevel_set_size( + mp_wlr_xdg_surface, + region.dim.w - extents.left - extents.right, + region.dim.h - extents.top - extents.bottom + ); +} + +void +XDGView::close() +{ + TRACE(); + wlr_xdg_toplevel_send_close(mp_wlr_xdg_surface); } void -XDGView::handle_foreign_destroy(struct wl_listener* listener, void* data) +XDGView::close_popups() { TRACE(); } void -XDGView::handle_surface_new_subsurface(struct wl_listener* listener, void* data) +XDGView::destroy() { TRACE(); @@ -271,36 +271,44 @@ XDGView::handle_map(struct wl_listener* listener, void* data) TRACE(); XDGView_ptr view = wl_container_of(listener, view, ml_map); + Server_ptr server = view->mp_server; + Model_ptr model = view->mp_model; + + view->m_pid = view->pid(); + view->set_floating(view->prefers_floating()); + struct wlr_xdg_surface* wlr_xdg_surface = view->mp_wlr_xdg_surface; struct wlr_xdg_toplevel* wlr_xdg_toplevel = view->mp_wlr_xdg_toplevel; - view->m_mapped = true; - view->m_preferred_dim = Dim{ + Dim preferred_dim = Dim{ .w = wlr_xdg_toplevel->base->current.geometry.width, .h = wlr_xdg_toplevel->base->current.geometry.height, }; - if (!view->m_preferred_dim.w && !view->m_preferred_dim.h) { - view->m_preferred_dim.w = wlr_xdg_toplevel->base->surface->current.width; - view->m_preferred_dim.h = wlr_xdg_toplevel->base->surface->current.height; + if (!preferred_dim.w && !preferred_dim.h) { + preferred_dim.w = wlr_xdg_toplevel->base->surface->current.width; + preferred_dim.h = wlr_xdg_toplevel->base->surface->current.height; } - view->mp_wlr_surface = wlr_xdg_toplevel->base->surface; + Extents const& extents = view->free_decoration().extents(); + preferred_dim.w += extents.left + extents.right; + preferred_dim.h += extents.top + extents.bottom; + view->set_preferred_dim(preferred_dim); - Extents const& extents = view->m_free_decoration.extents(); - struct wlr_box geometry; - wlr_xdg_surface_get_geometry(wlr_xdg_surface, &geometry); - view->m_preferred_dim.w = extents.left + extents.right + geometry.width; - view->m_preferred_dim.h = extents.top + extents.bottom + geometry.height; + struct wlr_xdg_toplevel_state* state = &wlr_xdg_toplevel->current; + view->set_minimum_dim(Dim{ + .w = state->min_width, + .h = state->min_height + }); view->set_free_region(Region{ - .pos = {0, 0}, - .dim = view->m_preferred_dim + .pos = Pos{0, 0}, + .dim = preferred_dim }); view->set_tile_region(Region{ - .pos = {0, 0}, - .dim = view->m_preferred_dim + .pos = Pos{0, 0}, + .dim = preferred_dim }); view->m_app_id = wlr_xdg_toplevel->app_id @@ -311,29 +319,37 @@ XDGView::handle_map(struct wl_listener* listener, void* data) : "N/a"; view->m_title_formatted = view->m_title; // TODO: format title - struct wlr_xdg_toplevel_state state = wlr_xdg_toplevel->current; - view->m_floating = wlr_xdg_toplevel->parent - || (state.min_width != 0 && state.min_height != 0 - && (state.min_width == state.max_width || state.min_height == state.max_height)); - - view->m_minimum_dim = Dim{ - .w = state.min_width, - .h = state.min_height - }; - - view->map( - wlr_xdg_toplevel->base->surface, - wlr_xdg_toplevel->requested.fullscreen, - wlr_xdg_toplevel->requested.fullscreen_output, - false // TODO: determine if client has decorations - ); - wlr_xdg_toplevel_set_tiled( wlr_xdg_surface, - // TODO: determine from view decorations view->free_decoration_to_wlr_edges() ); + view->mp_scene = &wlr_scene_tree_create(server->m_layers[Layer::Tile])->node; + view->mp_wlr_surface->data = view->mp_scene_surface = wlr_scene_xdg_surface_create( + view->mp_scene, + view->mp_wlr_xdg_surface + ); + view->mp_scene_surface->data = view; + + wlr_scene_node_reparent( + view->mp_scene, + server->m_layers[view->floating() ? Layer::Free : Layer::Tile] + ); + + for (std::size_t i = 0; i < 4; ++i) { + view->m_protrusions[i] = wlr_scene_rect_create( + view->mp_scene, + 0, 0, + view->active_decoration().colorscheme.unfocused.values + ); + view->m_protrusions[i]->node.data = view; + wlr_scene_rect_set_color( + view->m_protrusions[i], + view->active_decoration().colorscheme.unfocused.values + ); + wlr_scene_node_lower_to_bottom(&view->m_protrusions[i]->node); + } + wl_signal_add(&wlr_xdg_toplevel->base->surface->events.commit, &view->ml_commit); wl_signal_add(&wlr_xdg_toplevel->base->events.new_popup, &view->ml_new_popup); wl_signal_add(&wlr_xdg_toplevel->events.request_fullscreen, &view->ml_request_fullscreen); @@ -341,6 +357,26 @@ XDGView::handle_map(struct wl_listener* listener, void* data) wl_signal_add(&wlr_xdg_toplevel->events.request_resize, &view->ml_request_resize); wl_signal_add(&wlr_xdg_toplevel->events.set_title, &view->ml_set_title); wl_signal_add(&wlr_xdg_toplevel->events.set_app_id, &view->ml_set_app_id); + + Workspace_ptr workspace; + + if (wlr_xdg_toplevel->requested.fullscreen + && wlr_xdg_toplevel->requested.fullscreen_output->data) + { + Output_ptr output = reinterpret_cast<Output_ptr>( + wlr_xdg_toplevel->requested.fullscreen_output->data + ); + + Context_ptr context = output->context(); + workspace = context->workspace(); + } else + workspace = model->mp_workspace; + + model->move_view_to_workspace(view, workspace); + + view->set_mapped(true); + view->render_decoration(); + model->register_view(view); } void @@ -350,8 +386,6 @@ XDGView::handle_unmap(struct wl_listener* listener, void* data) XDGView_ptr view = wl_container_of(listener, view, ml_unmap); - view->mp_model->unmap_view(view); - wl_list_remove(&view->ml_commit.link); wl_list_remove(&view->ml_new_popup.link); wl_list_remove(&view->ml_request_fullscreen.link); @@ -360,8 +394,11 @@ XDGView::handle_unmap(struct wl_listener* listener, void* data) wl_list_remove(&view->ml_set_title.link); wl_list_remove(&view->ml_set_app_id.link); - view->unmap(); view->mp_model->unregister_view(view); + + wlr_scene_node_destroy(view->mp_scene); + view->mp_wlr_surface = nullptr; + view->set_managed(false); } void @@ -374,10 +411,9 @@ XDGView::handle_destroy(struct wl_listener* listener, void* data) wl_list_remove(&view->ml_map.link); wl_list_remove(&view->ml_unmap.link); wl_list_remove(&view->ml_destroy.link); + wl_list_remove(&view->m_events.unmap.listener_list); view->mp_wlr_xdg_toplevel = nullptr; view->mp_wlr_xdg_surface = nullptr; view->mp_model->destroy_view(view); - - wl_list_remove(&view->m_events.unmap.listener_list); } diff --git a/src/kranewl/tree/xwayland_view.cc b/src/kranewl/tree/xwayland_view.cc @@ -28,12 +28,7 @@ XWaylandView::XWaylandView( server, model, seat, - wlr_xwayland_surface->surface, - XWaylandView::handle_foreign_activate_request, - XWaylandView::handle_foreign_fullscreen_request, - XWaylandView::handle_foreign_close_request, - XWaylandView::handle_foreign_destroy, - XWaylandView::handle_surface_new_subsurface + wlr_xwayland_surface->surface ), mp_wlr_xwayland_surface(wlr_xwayland_surface), ml_commit({ .notify = XWaylandView::handle_commit }), @@ -59,61 +54,102 @@ XWaylandView::XWaylandView( XWaylandView::~XWaylandView() {} +Region +XWaylandView::constraints() +{ + TRACE(); + +} + +pid_t +XWaylandView::pid() +{ + TRACE(); + + struct wlr_xwayland_surface* wlr_xwayland_surface + = wlr_xwayland_surface_from_wlr_surface(mp_wlr_surface); + return wlr_xwayland_surface->pid; +} + +bool +XWaylandView::prefers_floating() +{ + TRACE(); + +} + +View_ptr +XWaylandView::is_transient_for() +{ + TRACE(); + +} + void -XWaylandView::focus(bool raise) -{} +XWaylandView::map() +{ + TRACE(); + +} void -XWaylandView::moveresize(Region const& region, Extents const& extents, bool interactive) +XWaylandView::unmap() { TRACE(); } void -XWaylandView::kill() +XWaylandView::activate(Toggle) { TRACE(); } -XWaylandUnmanaged::XWaylandUnmanaged(struct wlr_xwayland_surface* wlr_xwayland_surface) - : mp_wlr_xwayland_surface(wlr_xwayland_surface) -{} +void +XWaylandView::set_tiled(Toggle) +{ + TRACE(); -XWaylandUnmanaged::~XWaylandUnmanaged() -{} +} void -XWaylandView::handle_foreign_activate_request(struct wl_listener* listener, void* data) +XWaylandView::set_fullscreen(Toggle) { TRACE(); } void -XWaylandView::handle_foreign_fullscreen_request(struct wl_listener* listener, void* data) +XWaylandView::set_resizing(Toggle) { TRACE(); } void -XWaylandView::handle_foreign_close_request(struct wl_listener* listener, void* data) +XWaylandView::configure(Region const& region, Extents const& extents, bool interactive) { TRACE(); } void -XWaylandView::handle_foreign_destroy(struct wl_listener* listener, void* data) +XWaylandView::close() { TRACE(); } void -XWaylandView::handle_surface_new_subsurface(struct wl_listener* listener, void* data) +XWaylandView::close_popups() +{ + TRACE(); + +} + +void +XWaylandView::destroy() { TRACE(); @@ -244,4 +280,11 @@ XWaylandView::handle_override_redirect(struct wl_listener* listener, void* data) TRACE(); } + +XWaylandUnmanaged::XWaylandUnmanaged(struct wlr_xwayland_surface* wlr_xwayland_surface) + : mp_wlr_xwayland_surface(wlr_xwayland_surface) +{} + +XWaylandUnmanaged::~XWaylandUnmanaged() +{} #endif diff --git a/src/kranewl/workspace.cc b/src/kranewl/workspace.cc @@ -476,7 +476,7 @@ Workspace::arrange(Region region) const views.begin(), views.end(), [](const View_ptr view) -> bool { - return view->m_fullscreen && !view->m_contained; + return view->fullscreen() && !view->contained(); } ); @@ -511,7 +511,7 @@ Workspace::arrange(Region region) const Placement::PlacementMethod::Free, view, FREE_DECORATION, - view->m_free_region + view->free_region() }; } ); @@ -528,7 +528,7 @@ Workspace::arrange(Region region) const placements.begin(), placements.end(), [](Placement& placement) { - if (!placement.view->m_focused) + if (!placement.view->focused()) placement.region = std::nullopt; } );