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 e75f96ea3604a6a9ef9b2b8402100f1f046b4957
parent 41f30261047f42b328fd2068b2486b496d1eb56d
Author: deurzen <m.deurzen@tum.de>
Date:   Fri, 20 May 2022 16:06:37 +0200

adds to server->server/model overhaul

Diffstat:
MCMakeLists.txt | 8++++++++
MMakefile | 1+
Minclude/kranewl/bindings.hh | 9++++++---
Dinclude/kranewl/client.hh | 193-------------------------------------------------------------------------------
Minclude/kranewl/common.hh | 2++
Ainclude/kranewl/context.hh | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/kranewl/decoration.hh | 21+++++++++++++++++++++
Minclude/kranewl/geometry.hh | 9+++++++++
Minclude/kranewl/input/keyboard.hh | 33++++++++++++++++++++++++++++-----
Ainclude/kranewl/input/mouse.hh | 24++++++++++++++++++++++++
Dinclude/kranewl/input/pointer.hh | 3---
Minclude/kranewl/layout.hh | 35+++++++++++++++--------------------
Minclude/kranewl/model.hh | 45++++++++++++++++++++++++++++++++++++++++++---
Ainclude/kranewl/tree/client.hh | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/kranewl/tree/output.hh | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Minclude/kranewl/tree/surface.hh | 39++++++++++++++++++++++++++++++++++++---
Minclude/kranewl/util.hh | 4----
Minclude/kranewl/workspace.hh | 3++-
Minclude/version.hh | 4++--
Dsrc/kranewl/client.cc | 221-------------------------------------------------------------------------------
Msrc/kranewl/geometry.cc | 45+++++++++++++++++++++++++++++++++++++++++++++
Dsrc/kranewl/input/keyboard.cc | 3---
Dsrc/kranewl/input/pointer.cc | 3---
Msrc/kranewl/layout.cc | 295++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/kranewl/model.cc | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/kranewl/server.cc | 76++++++++++++++++++++++++++++++++++++++--------------------------------------
Asrc/kranewl/tree/client.cc | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/kranewl/util.cc | 30------------------------------
28 files changed, 1195 insertions(+), 687 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -136,8 +136,16 @@ add_custom_target(run ALL DEPENDS ${CMAKE_SOURCE_DIR}/include/protocols/pointer-constraints-unstable-v1-protocol.h ) +set_source_files_properties(tags PROPERTIES GENERATED true) +add_custom_command (OUTPUT tags + COMMAND git ls-files | ctags -R --exclude=.git --c++-kinds=+p --links=no --fields=+iaS --extras=+q -L- + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Generating project tags" +) + add_executable(kranewl ${KRANEWL_SOURCES} + tags ) add_executable(kranec diff --git a/Makefile b/Makefile @@ -9,5 +9,6 @@ test: kranewl .PHONY: clean clean: + @rm -rf ./tags @rm -rf ./build @rm -f ./include/protocols/* diff --git a/include/kranewl/bindings.hh b/include/kranewl/bindings.hh @@ -1,5 +1,8 @@ #pragma once +#include <kranewl/input/keyboard.hh> +#include <kranewl/input/mouse.hh> + #include <functional> #include <optional> #include <cstdint> @@ -9,16 +12,16 @@ typedef class Client* Client_ptr; typedef std::function<void(Model&)> - KeyAction; + KeyboardAction; typedef std::function<bool(Model&, Client_ptr)> MouseAction; typedef - std::unordered_map<uint32_t, KeyAction> + std::unordered_map<KeyboardInput, KeyboardAction> KeyBindings; typedef - std::unordered_map<uint32_t, MouseAction> + std::unordered_map<MouseInput, MouseAction> MouseBindings; diff --git a/include/kranewl/client.hh b/include/kranewl/client.hh @@ -1,193 +0,0 @@ -#pragma once - -#include <kranewl/common.hh> -#include <kranewl/decoration.hh> -#include <kranewl/geometry.hh> -#include <kranewl/tree/surface.hh> - -extern "C" { -#include <wlr/backend.h> -} - -#include <chrono> -#include <optional> -#include <string> -#include <vector> - -typedef class Server* Server_ptr; -typedef class Partition* Partition_ptr; -typedef class Context* Context_ptr; -typedef class Workspace* Workspace_ptr; - -typedef struct Client* Client_ptr; -typedef struct Client final -{ - enum class OutsideState - { - Focused, - FocusedDisowned, - FocusedSticky, - Unfocused, - UnfocusedDisowned, - UnfocusedSticky, - Urgent - }; - - static bool - is_free(Client_ptr client) - { - return (client->floating && (!client->fullscreen || client->contained)) - || !client->managed - || client->disowned; - } - - Client(); - Client( - Surface surface, - Partition_ptr partition, - Context_ptr context, - Workspace_ptr workspace, - std::optional<Pid> pid, - std::optional<Pid> ppid - ); - - ~Client(); - - Client(Client const&) = default; - Client& operator=(Client const&) = default; - - OutsideState get_outside_state() const noexcept; - - struct wlr_surface* get_surface() noexcept; - - void focus() noexcept; - void unfocus() noexcept; - - void stick() noexcept; - void unstick() noexcept; - - void disown() noexcept; - void reclaim() noexcept; - - void set_urgent() noexcept; - void unset_urgent() noexcept; - - void expect_unmap() noexcept; - bool consume_unmap_if_expecting() noexcept; - - void set_tile_region(Region&) noexcept; - void set_free_region(Region&) noexcept; - - void set_tile_decoration(Decoration const&) noexcept; - void set_free_decoration(Decoration const&) noexcept; - - struct wl_list link; - Server_ptr server; - - SurfaceType surface_type; - Surface surface; - - struct wlr_scene_node* scene; - struct wlr_scene_node* scene_surface; - struct wlr_scene_rect* border[4]; // protrusions (top, bottom, left, right) - - std::string title; - - Partition_ptr partition; - Context_ptr context; - Workspace_ptr workspace; - - Region free_region; - Region tile_region; - Region active_region; - Region previous_region; - Region inner_region; - - Decoration tile_decoration; - Decoration free_decoration; - Decoration active_decoration; - - Client_ptr parent; - std::vector<Client_ptr> children; - Client_ptr producer; - std::vector<Client_ptr> consumers; - - bool focused; - bool mapped; - bool managed; - bool urgent; - bool floating; - bool fullscreen; - bool contained; - bool invincible; - bool sticky; - bool iconifyable; - bool iconified; - bool disowned; - bool producing; - bool attaching; - - std::optional<Pid> pid; - std::optional<Pid> ppid; - - std::chrono::time_point<std::chrono::steady_clock> last_focused; - std::chrono::time_point<std::chrono::steady_clock> managed_since; - - struct wl_listener l_commit; - struct wl_listener l_map; - struct wl_listener l_unmap; - struct wl_listener l_destroy; - struct wl_listener l_set_title; - struct wl_listener l_fullscreen; - struct wl_listener l_request_move; - struct wl_listener l_request_resize; -#ifdef XWAYLAND - struct wl_listener l_request_activate; - struct wl_listener l_request_configure; - struct wl_listener l_set_hints; -#else - struct wl_listener l_new_xdg_popup; -#endif - -private: - OutsideState m_outside_state; - - void set_inner_region(Region&) noexcept; - void set_active_region(Region&) noexcept; - -}* Client_ptr; - -inline bool -operator==(Client const& lhs, Client const& rhs) -{ - if (lhs.surface_type != rhs.surface_type) - return false; - - switch (lhs.surface_type) { - case SurfaceType::XDGShell: // fallthrough - case SurfaceType::LayerShell: return lhs.surface.xdg == rhs.surface.xdg; - case SurfaceType::X11Managed: // fallthrough - case SurfaceType::X11Unmanaged: return lhs.surface.xwayland == rhs.surface.xwayland; - } -} - -namespace std -{ - template <> - struct hash<Client> { - - std::size_t - operator()(Client const& client) const - { - switch (client.surface_type) { - case SurfaceType::XDGShell: // fallthrough - case SurfaceType::LayerShell: - return std::hash<wlr_xdg_surface*>{}(client.surface.xdg); - case SurfaceType::X11Managed: // fallthrough - case SurfaceType::X11Unmanaged: - return std::hash<wlr_xwayland_surface*>{}(client.surface.xwayland); - } - } - - }; -} diff --git a/include/kranewl/common.hh b/include/kranewl/common.hh @@ -1,8 +1,10 @@ #pragma once #include <cstddef> +#include <cstdint> typedef unsigned Pid; +typedef std::uintptr_t Uid; typedef std::size_t Ident; typedef std::size_t Index; diff --git a/include/kranewl/context.hh b/include/kranewl/context.hh @@ -0,0 +1,184 @@ +#pragma once + +#include <kranewl/common.hh> +#include <kranewl/cycle.hh> + +#include <string> +#include <unordered_set> + +typedef class Client* Client_ptr; +typedef class Workspace* Workspace_ptr; +typedef class Output* Output_ptr; +typedef class Context final +{ +public: + Context(Index index, std::string name) + : m_index(index), + m_name(name), + mp_output(nullptr), + mp_active(nullptr), + mp_prev_active(nullptr), + m_workspaces({}, true) + {} + + Index + index() const + { + return m_index; + } + + std::string const& + name() const + { + return m_name; + } + + std::size_t + size() const + { + return m_workspaces.size(); + } + + Workspace_ptr + workspace() const + { + return mp_active; + } + + Workspace_ptr + prev_workspace() const + { + return mp_prev_active; + } + + Output_ptr + output() const + { + return mp_output; + } + + bool + is_outputed() const + { + return mp_output != nullptr; + } + + void + set_output(Output_ptr output) + { + mp_output = output; + } + + void + register_workspace(Workspace_ptr workspace) + { + m_workspaces.insert_at_back(workspace); + } + + void + activate_workspace(Index index) + { + Workspace_ptr prev_active = mp_active; + m_workspaces.activate_at_index(index); + mp_active = *m_workspaces.active_element(); + + if (prev_active != mp_active) + mp_prev_active = prev_active; + } + + void + activate_workspace(Workspace_ptr workspace) + { + Workspace_ptr prev_active = mp_active; + m_workspaces.activate_element(workspace); + mp_active = workspace; + + if (prev_active != mp_active) + mp_prev_active = prev_active; + } + + Cycle<Workspace_ptr> const& + workspaces() const + { + return m_workspaces; + } + + void + register_sticky_client(Client_ptr client) + { + m_sticky_clients.insert(client); + } + + void + unregister_sticky_client(Client_ptr client) + { + m_sticky_clients.erase(client); + } + + std::unordered_set<Client_ptr> const& + sticky_clients() const + { + return m_sticky_clients; + } + + std::deque<Workspace_ptr>::iterator + begin() + { + return m_workspaces.begin(); + } + + std::deque<Workspace_ptr>::const_iterator + begin() const + { + return m_workspaces.begin(); + } + + std::deque<Workspace_ptr>::const_iterator + cbegin() const + { + return m_workspaces.cbegin(); + } + + std::deque<Workspace_ptr>::iterator + end() + { + return m_workspaces.end(); + } + + std::deque<Workspace_ptr>::const_iterator + end() const + { + return m_workspaces.end(); + } + + std::deque<Workspace_ptr>::const_iterator + cend() const + { + return m_workspaces.cend(); + } + + Workspace_ptr + operator[](std::size_t i) + { + return m_workspaces[i]; + } + + Workspace_ptr + operator[](std::size_t i) const + { + return m_workspaces[i]; + } + +private: + Index m_index; + std::string m_name; + + Output_ptr mp_output; + + Workspace_ptr mp_active; + Workspace_ptr mp_prev_active; + + Cycle<Workspace_ptr> m_workspaces; + std::unordered_set<Client_ptr> m_sticky_clients; + +}* Context_ptr; diff --git a/include/kranewl/decoration.hh b/include/kranewl/decoration.hh @@ -40,6 +40,16 @@ struct ColorScheme final { RGBA urgent; }; +const static ColorScheme DEFAULT_COLOR_SCHEME = ColorScheme{ + .focused = {0x8181A6FF}, + .fdisowned = {0xc1c1c1FF}, + .fsticky = {0x5F8787FF}, + .unfocused = {0x333333FF}, + .udisowned = {0x999999FF}, + .usticky = {0x444444FF}, + .urgent = {0x87875FFF}, +}; + struct Frame final { Extents extents; ColorScheme colorscheme; @@ -56,3 +66,14 @@ struct Decoration final { return Extents{0, 0, 0, 0}; } }; + +const Decoration NO_DECORATION = Decoration{ + std::nullopt, +}; + +const Decoration FREE_DECORATION = Decoration{ + Frame { + Extents{ 3, 1, 1, 1 }, + DEFAULT_COLOR_SCHEME + } +}; diff --git a/include/kranewl/geometry.hh b/include/kranewl/geometry.hh @@ -108,6 +108,15 @@ operator<<(std::ostream& os, Padding const& padding) struct Region final { Pos pos; Dim dim; + + void apply_minimum_dim(Dim const&); + void apply_extents(Extents const&); + void remove_extents(Extents const&); + + bool contains(Pos) const; + bool contains(Region const&) const; + + Pos center() const; }; inline bool diff --git a/include/kranewl/input/keyboard.hh b/include/kranewl/input/keyboard.hh @@ -2,16 +2,39 @@ extern "C" { #include <wlr/backend.h> +#include <xkbcommon/xkbcommon.h> } -class Server; -struct Keyboard { - struct wl_list link; +#include <cstdint> +#include <unordered_set> - Server* server; +typedef class Server* Server_ptr; +struct Keyboard { + Server_ptr p_server; - struct wlr_input_device* device; + struct wl_list link; + struct wlr_input_device* p_device; struct wl_listener l_modifiers; struct wl_listener l_key; }; + +struct KeyboardInput { + uint32_t mod; + xkb_keysym_t keysym; +}; + +namespace std +{ + template <> + struct hash<KeyboardInput> { + std::size_t + operator()(KeyboardInput const& input) const + { + std::size_t mod_hash = std::hash<uint32_t>()(input.mod); + std::size_t key_hash = std::hash<xkb_keysym_t>()(input.keysym); + + return mod_hash ^ key_hash; + } + }; +} diff --git a/include/kranewl/input/mouse.hh b/include/kranewl/input/mouse.hh @@ -0,0 +1,24 @@ +#pragma once + +#include <cstdint> +#include <unordered_set> + +struct MouseInput { + uint32_t mod; + unsigned button; +}; + +namespace std +{ + template <> + struct hash<MouseInput> { + std::size_t + operator()(MouseInput const& input) const + { + std::size_t mod_hash = std::hash<uint32_t>()(input.mod); + std::size_t button_hash = std::hash<unsigned>()(input.button); + + return mod_hash ^ button_hash; + } + }; +} diff --git a/include/kranewl/input/pointer.hh b/include/kranewl/input/pointer.hh @@ -1,3 +0,0 @@ -#pragma once - - diff --git a/include/kranewl/layout.hh b/include/kranewl/layout.hh @@ -9,14 +9,12 @@ #include <deque> #include <unordered_map> -class LayoutHandler final -{ +class LayoutHandler final { typedef std::deque<Client_ptr>::const_iterator client_iter; typedef std::vector<Placement>& placement_vector; public: - enum class LayoutKind - { + enum class LayoutKind { /// free layouts Float, FramelessFloat, @@ -42,19 +40,16 @@ public: }; private: - typedef struct Layout final - { - typedef struct LayoutData final - { - constexpr static std::size_t MAX_MAIN_COUNT = 16; - constexpr static std::size_t MAX_GAP_SIZE = 300; - constexpr static Extents MAX_MARGIN - = Extents { 700, 700, 400, 400 }; + typedef struct Layout final { + typedef struct LayoutData final { + constexpr static int MAX_MAIN_COUNT = 16; + constexpr static int MAX_GAP_SIZE = 300; + constexpr static Extents MAX_MARGIN = Extents{700, 700, 400, 400}; LayoutData( Extents margin, - std::size_t gap_size, - std::size_t main_count, + int gap_size, + int main_count, float main_factor ) : margin(margin), @@ -65,10 +60,10 @@ private: // generic layout data Extents margin; - std::size_t gap_size; + int gap_size; // tiled layout data - std::size_t main_count; + int main_count; float main_factor; }* LayoutData_ptr; @@ -122,8 +117,8 @@ public: bool layout_is_single() const; bool layout_wraps() const; - std::size_t gap_size() const; - std::size_t main_count() const; + int gap_size() const; + int main_count() const; float main_factor() const; Extents margin() const; @@ -140,8 +135,8 @@ public: void reset_layout_data(); void cycle_layout_data(Direction); - void save_layout(std::size_t) const; - void load_layout(std::size_t); + void save_layout(int) const; + void load_layout(int); private: LayoutKind m_kind; diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh @@ -1,10 +1,19 @@ #pragma once +#include <kranewl/bindings.hh> +#include <kranewl/common.hh> #include <kranewl/cycle.hh> +#include <kranewl/geometry.hh> +#include <kranewl/tree/client.hh> #include <optional> #include <string> +#include <unordered_map> +#include <variant> +typedef class Output* Output_ptr; +typedef class Context* Context_ptr; +typedef class Workspace* Workspace_ptr; class Server; class Config; class Model final @@ -16,14 +25,44 @@ public: void run(); void exit(); + Output_ptr create_output(Surface); + void register_output(Output_ptr); + void unregister_output(Output_ptr); + + Client_ptr create_client(Surface); + void register_client(Client_ptr); + void unregister_client(Client_ptr); + void spawn_external(std::string&&) const; private: Server& m_server; Config const& m_config; - /* Cycle<Partition_ptr> m_partitions; */ - /* Cycle<Context_ptr> m_contexts; */ - /* Cycle<Workspace_ptr> m_workspaces; */ + bool m_running; + + Cycle<Output_ptr> m_outputs; + Cycle<Context_ptr> m_contexts; + Cycle<Workspace_ptr> m_workspaces; + + Output_ptr mp_output; + Context_ptr mp_context; + Workspace_ptr mp_workspace; + + Output_ptr mp_prev_output; + Context_ptr mp_prev_context; + Workspace_ptr mp_prev_workspace; + + std::unordered_map<Uid, Client_ptr> m_client_map; + std::unordered_map<Pid, Client_ptr> m_pid_map; + std::unordered_map<Client_ptr, Region> m_fullscreen_map; + + std::vector<Client_ptr> m_sticky_clients; + std::vector<Client_ptr> m_unmanaged_clients; + + Client_ptr mp_focus; + + KeyBindings m_key_bindings; + MouseBindings m_mouse_bindings; }; diff --git a/include/kranewl/tree/client.hh b/include/kranewl/tree/client.hh @@ -0,0 +1,188 @@ +#pragma once + +#include <kranewl/common.hh> +#include <kranewl/decoration.hh> +#include <kranewl/geometry.hh> +#include <kranewl/tree/surface.hh> + +extern "C" { +#include <wlr/backend.h> +} + +#include <chrono> +#include <cstdint> +#include <optional> +#include <string> +#include <vector> + +typedef class Server* Server_ptr; +typedef class Output* Output_ptr; +typedef class Context* Context_ptr; +typedef class Workspace* Workspace_ptr; +typedef struct Client* Client_ptr; +typedef struct Client final { + static constexpr Dim MIN_CLIENT_DIM = Dim{25, 10}; + static constexpr Dim PREFERRED_INIT_CLIENT_DIM = Dim{480, 260}; + + enum class OutsideState { + Focused, + FocusedDisowned, + FocusedSticky, + Unfocused, + UnfocusedDisowned, + UnfocusedSticky, + Urgent + }; + + static bool + is_free(Client_ptr client) + { + return (client->floating && (!client->fullscreen || client->contained)) + || !client->managed + || client->disowned; + } + + Client( + Server_ptr server, + Surface surface, + Output_ptr output, + Context_ptr context, + Workspace_ptr workspace + ); + + ~Client(); + + Client(Client const&) = default; + Client& operator=(Client const&) = default; + + OutsideState get_outside_state() const noexcept; + + struct wlr_surface* get_surface() noexcept; + + void focus() noexcept; + void unfocus() noexcept; + + void stick() noexcept; + void unstick() noexcept; + + void disown() noexcept; + void reclaim() noexcept; + + void set_urgent() noexcept; + void unset_urgent() noexcept; + + void expect_unmap() noexcept; + bool consume_unmap_if_expecting() noexcept; + + void set_tile_region(Region&) noexcept; + void set_free_region(Region&) noexcept; + + void set_tile_decoration(Decoration const&) noexcept; + void set_free_decoration(Decoration const&) noexcept; + + Server_ptr p_server; + + Uid uid; + Surface surface; + + struct wlr_scene_node* p_scene; + struct wlr_scene_node* p_scene_surface; + struct wlr_scene_rect* protrusions[4]; // top, bottom, left, right + + std::string title; + + Output_ptr p_output; + Context_ptr p_context; + Workspace_ptr p_workspace; + + Region free_region; + Region tile_region; + Region active_region; + Region previous_region; + Region inner_region; + + Decoration tile_decoration; + Decoration free_decoration; + Decoration active_decoration; + + Client_ptr p_parent; + std::vector<Client_ptr> children; + Client_ptr p_producer; + std::vector<Client_ptr> consumers; + + bool focused; + bool mapped; + bool managed; + bool urgent; + bool floating; + bool fullscreen; + bool contained; + bool invincible; + bool sticky; + bool iconifyable; + bool iconified; + bool disowned; + bool producing; + bool attaching; + + std::chrono::time_point<std::chrono::steady_clock> last_focused; + std::chrono::time_point<std::chrono::steady_clock> managed_since; + + struct wl_listener l_commit; + struct wl_listener l_map; + struct wl_listener l_unmap; + struct wl_listener l_destroy; + struct wl_listener l_set_title; + struct wl_listener l_fullscreen; + struct wl_listener l_request_move; + struct wl_listener l_request_resize; +#ifdef XWAYLAND + struct wl_listener l_request_activate; + struct wl_listener l_request_configure; + struct wl_listener l_set_hints; +#else + struct wl_listener l_new_xdg_popup; +#endif + +private: + OutsideState m_outside_state; + + void set_inner_region(Region&) noexcept; + void set_active_region(Region&) noexcept; + +}* Client_ptr; + +inline bool +operator==(Client const& lhs, Client const& rhs) +{ + if (lhs.surface.type != rhs.surface.type) + return false; + + switch (lhs.surface.type) { + case SurfaceType::XDGShell: // fallthrough + case SurfaceType::LayerShell: return lhs.surface.xdg == rhs.surface.xdg; + case SurfaceType::X11Managed: // fallthrough + case SurfaceType::X11Unmanaged: return lhs.surface.xwayland == rhs.surface.xwayland; + } +} + +namespace std +{ + template <> + struct hash<Client> { + + std::size_t + operator()(Client const& client) const + { + switch (client.surface.type) { + case SurfaceType::XDGShell: // fallthrough + case SurfaceType::LayerShell: + return std::hash<wlr_xdg_surface*>{}(client.surface.xdg); + case SurfaceType::X11Managed: // fallthrough + case SurfaceType::X11Unmanaged: + return std::hash<wlr_xwayland_surface*>{}(client.surface.xwayland); + } + } + + }; +} diff --git a/include/kranewl/tree/output.hh b/include/kranewl/tree/output.hh @@ -1,15 +1,86 @@ #pragma once +#include <kranewl/common.hh> +#include <kranewl/geometry.hh> +#include <kranewl/context.hh> +#include <kranewl/util.hh> + +#include <spdlog/spdlog.h> + extern "C" { #include <wlr/backend.h> } -class Server; -struct Output { - struct wl_list link; +typedef class Server* Server_ptr; +typedef class Context* Context_ptr; +typedef class Output final { +public: + Output( + Server_ptr server, + struct wlr_output* wlr_output, + struct wlr_scene_output* wlr_scene_output + ) + : mp_context(nullptr), + mp_server(server), + mp_wlr_output(wlr_output), + mp_wlr_scene_output(wlr_scene_output) + {} + + void + set_context(Context_ptr context) + { + if (!context) + spdlog::error("output must contain a valid context"); + + if (mp_context) + mp_context->set_output(nullptr); + + context->set_output(this); + mp_context = context; + } + + Context_ptr + context() const + { + return mp_context; + } + + Region + full_region() const + { + return m_full_region; + } + + Region + placeable_region() const + { + return m_placeable_region; + } + + bool + contains(Pos pos) const + { + return m_full_region.contains(pos); + } + + bool + contains(Region region) const + { + return m_full_region.contains(region); + } + +private: + Context_ptr mp_context; + Region m_full_region; + Region m_placeable_region; + +public: + Server_ptr mp_server; + + struct wlr_output* mp_wlr_output; + struct wlr_scene_output* mp_wlr_scene_output; - Server* server; + struct wl_listener ml_frame; + struct wl_listener ml_destroy; - struct wlr_output* wlr_output; - struct wl_listener l_frame; -}; +}* Output_ptr; diff --git a/include/kranewl/tree/surface.hh b/include/kranewl/tree/surface.hh @@ -1,5 +1,7 @@ #pragma once +#include <kranewl/common.hh> + enum class SurfaceType { XDGShell, LayerShell, @@ -7,7 +9,38 @@ enum class SurfaceType { X11Unmanaged }; -union Surface { - struct wlr_xdg_surface* xdg; - struct wlr_xwayland_surface* xwayland; +struct Surface { + Surface(struct wlr_xdg_surface* xdg, bool toplevel) + : type{toplevel + ? SurfaceType::XDGShell + : SurfaceType::LayerShell}, + xdg{xdg} + {} + + Surface(struct wlr_xwayland_surface* xwayland, bool managed) + : type{managed + ? SurfaceType::X11Managed + : SurfaceType::X11Unmanaged}, + xwayland{xwayland} + {} + + Uid + uid() const + { + switch (type) { + case SurfaceType::XDGShell: // fallthrough + case SurfaceType::LayerShell: return reinterpret_cast<Uid>(xdg); + case SurfaceType::X11Managed: // fallthrough + case SurfaceType::X11Unmanaged: return reinterpret_cast<Uid>(xwayland); + default: break; + } + + return 0; + } + + SurfaceType type; + union { + struct wlr_xdg_surface* xdg; + struct wlr_xwayland_surface* xwayland; + }; }; diff --git a/include/kranewl/util.hh b/include/kranewl/util.hh @@ -11,10 +11,6 @@ namespace Util { - void die(const std::string&&); - void warn(const std::string&&); - void assert(bool, const std::string&&); - template < typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type diff --git a/include/kranewl/workspace.hh b/include/kranewl/workspace.hh @@ -1,9 +1,10 @@ #pragma once #include <kranewl/common.hh> +#include <kranewl/cycle.hh> #include <kranewl/geometry.hh> +#include <kranewl/layout.hh> #include <kranewl/placement.hh> -#include <kranewl/cycle.hh> #include <kranewl/util.hh> typedef class Client* Client_ptr; diff --git a/include/version.hh b/include/version.hh @@ -1 +1 @@ -#define VERSION "master/23f214f+" -\ No newline at end of file +#define VERSION "master/41f3026+" +\ No newline at end of file diff --git a/src/kranewl/client.cc b/src/kranewl/client.cc @@ -1,221 +0,0 @@ -#include <kranewl/client.hh> - -// https://github.com/swaywm/wlroots/issues/682 -#include <pthread.h> -#define class class_ -#define namespace namespace_ -#define static -extern "C" { -#include <wlr/types/wlr_xdg_shell.h> -#ifdef XWAYLAND -#include <wlr/xwayland.h> -#endif -} -#undef static -#undef class -#undef namespace - -Client::Client() -{ - wl_list_init(&link); -} - -Client::Client( - Surface surface, - Partition_ptr partition, - Context_ptr context, - Workspace_ptr workspace, - std::optional<Pid> pid, - std::optional<Pid> ppid -) - : surface(surface), - partition(partition), - context(context), - workspace(workspace), - free_region({}), - tile_region({}), - active_region({}), - previous_region({}), - inner_region({}), - tile_decoration({}), - free_decoration({}), - active_decoration({}), - parent(nullptr), - children({}), - producer(nullptr), - consumers({}), - focused(false), - mapped(false), - managed(true), - urgent(false), - floating(false), - fullscreen(false), - contained(false), - invincible(false), - sticky(false), - iconifyable(true), - iconified(false), - disowned(false), - producing(true), - attaching(false), - pid(pid), - ppid(ppid), - last_focused(std::chrono::steady_clock::now()), - managed_since(std::chrono::steady_clock::now()), - m_outside_state(OutsideState::Unfocused) -{ - wl_list_init(&link); -} - -Client::~Client() -{} - -Client::OutsideState -Client::get_outside_state() const noexcept -{ - if (urgent) - return Client::OutsideState::Urgent; - - return m_outside_state; -} - -struct wlr_surface* -Client::get_surface() noexcept -{ - switch (surface_type) { - case SurfaceType::XDGShell: //fallthrough - case SurfaceType::LayerShell: return surface.xdg->surface; - case SurfaceType::X11Managed: //fallthrough - case SurfaceType::X11Unmanaged: return surface.xwayland->surface; - } - - return nullptr; -} - -void -Client::focus() noexcept -{ - focused = true; - last_focused = std::chrono::steady_clock::now(); - - 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; - } -} - -void -Client::unfocus() noexcept -{ - focused = 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; - } -} - -void -Client::stick() noexcept -{ - sticky = 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; - } -} - -void -Client::unstick() noexcept -{ - sticky = 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; - } -} - -void -Client::disown() noexcept -{ - disowned = 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; - } -} - -void -Client::reclaim() noexcept -{ - disowned = 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 -Client::set_tile_region(Region& region) noexcept -{ - tile_region = region; - set_active_region(region); -} - -void -Client::set_free_region(Region& region) noexcept -{ - free_region = region; - set_active_region(region); -} - -void -Client::set_active_region(Region& region) noexcept -{ - previous_region = active_region; - set_inner_region(region); - active_region = region; -} - -void -Client::set_tile_decoration(Decoration const& decoration) noexcept -{ - tile_decoration = decoration; - active_decoration = decoration; -} - -void -Client::set_free_decoration(Decoration const& decoration) noexcept -{ - free_decoration = decoration; - active_decoration = decoration; -} - -void -Client::set_inner_region(Region& region) noexcept -{ - if (active_decoration.frame) { - Frame const& frame = *active_decoration.frame; - - inner_region.pos.x = frame.extents.left; - inner_region.pos.y = frame.extents.top; - inner_region.dim.w = region.dim.w - frame.extents.left - frame.extents.right; - inner_region.dim.h = region.dim.h - frame.extents.top - frame.extents.bottom; - } else { - inner_region.pos.x = 0; - inner_region.pos.y = 0; - inner_region.dim = region.dim; - } -} diff --git a/src/kranewl/geometry.cc b/src/kranewl/geometry.cc @@ -1,3 +1,48 @@ #include <kranewl/geometry.hh> +void +Region::apply_minimum_dim(Dim const& dim) +{ + this->dim.w = std::max(this->dim.w, dim.w); + this->dim.h = std::max(this->dim.h, dim.h); +} +void +Region::apply_extents(Extents const& extents) +{ + pos.x -= extents.left; + pos.y -= extents.top; + dim.w += extents.left + extents.right; + dim.h += extents.top + extents.bottom; +} + +void +Region::remove_extents(Extents const& extents) +{ + pos.x += extents.left; + pos.y += extents.top; + dim.w -= extents.left + extents.right; + dim.h -= extents.top + extents.bottom; +} + +bool +Region::contains(Pos pos) const +{ + return pos.x >= this->pos.x + && pos.y >= this->pos.y + && pos.x < this->pos.x + this->dim.w + && pos.y < this->pos.y + this->dim.h; +} + +bool +Region::contains(Region const& region) const +{ + return contains(region.pos) + && contains(region.pos + region.dim); +} + +Pos +Region::center() const +{ + return pos + Pos::from_center_of_dim(dim); +} diff --git a/src/kranewl/input/keyboard.cc b/src/kranewl/input/keyboard.cc @@ -1,3 +0,0 @@ -#include <kranewl/input/keyboard.hh> - - diff --git a/src/kranewl/input/pointer.cc b/src/kranewl/input/pointer.cc @@ -1,3 +0,0 @@ -#include <kranewl/input/pointer.hh> - - diff --git a/src/kranewl/layout.cc b/src/kranewl/layout.cc @@ -1,8 +1,10 @@ #include <kranewl/layout.hh> -#include <kranewl/util.hh> -#include <kranewl/client.hh> #include <kranewl/cycle.t.hh> +#include <kranewl/tree/client.hh> +#include <kranewl/util.hh> + +#include <spdlog/spdlog.h> #include <algorithm> #include <cmath> @@ -256,13 +258,13 @@ LayoutHandler::layout_wraps() const } -std::size_t +int LayoutHandler::gap_size() const { return (*mp_layout->data.active_element())->gap_size; } -std::size_t +int LayoutHandler::main_count() const { return (*mp_layout->data.active_element())->main_count; @@ -307,10 +309,10 @@ LayoutHandler::change_gap_size(Util::Change<int> change) if (value <= 0) data->gap_size = 0; - else if (static_cast<std::size_t>(value) >= Layout::LayoutData::MAX_GAP_SIZE) + else if (static_cast<int>(value) >= Layout::LayoutData::MAX_GAP_SIZE) data->gap_size = Layout::LayoutData::MAX_GAP_SIZE; else - data->gap_size = static_cast<std::size_t>(value); + data->gap_size = static_cast<int>(value); } void @@ -321,10 +323,10 @@ LayoutHandler::change_main_count(Util::Change<int> change) if (value <= 0) data->main_count = 0; - else if (static_cast<std::size_t>(value) >= Layout::LayoutData::MAX_MAIN_COUNT) + else if (static_cast<int>(value) >= Layout::LayoutData::MAX_MAIN_COUNT) data->main_count = Layout::LayoutData::MAX_MAIN_COUNT; else - data->main_count = static_cast<std::size_t>(value); + data->main_count = static_cast<int>(value); } void @@ -423,16 +425,17 @@ LayoutHandler::cycle_layout_data(Direction direction) void -LayoutHandler::save_layout(std::size_t number) const +LayoutHandler::save_layout(int number) const { std::stringstream datadir_ss; std::string home_path = std::getenv("HOME"); if (const char* env_xdgdata = std::getenv("XDG_DATA_HOME")) - datadir_ss << env_xdgdata << "/" << WM_NAME << "/"; + datadir_ss << env_xdgdata << "/kranewl/"; else - datadir_ss << home_path << "/.local/share/" << WM_NAME << "/" - << "layout_" << number; + datadir_ss << home_path << "/.local/share/kranewl/"; + + datadir_ss << "layout_" << number; std::string file_path = datadir_ss.str(); @@ -448,21 +451,22 @@ LayoutHandler::save_layout(std::size_t number) const out.write(reinterpret_cast<const char*>(&m_kind), sizeof(LayoutKind)); out.write(reinterpret_cast<const char*>(&size), sizeof(size)); out.write(reinterpret_cast<const char*>(&data[0]), - data.size() * sizeof(Layout::LayoutData)); + static_cast<long>(data.size() * sizeof(Layout::LayoutData))); out.close(); } void -LayoutHandler::load_layout(std::size_t number) +LayoutHandler::load_layout(int number) { std::stringstream datadir_ss; std::string home_path = std::getenv("HOME"); if (const char* env_xdgdata = std::getenv("XDG_DATA_HOME")) - datadir_ss << env_xdgdata << "/" << WM_NAME << "/"; + datadir_ss << env_xdgdata << "/kranewl/"; else - datadir_ss << home_path << "/.local/share/" << WM_NAME << "/" - << "layout_" << number; + datadir_ss << home_path << "/.local/share/kranewl/"; + + datadir_ss << "layout_" << number; std::string file_path = datadir_ss.str(); @@ -477,7 +481,7 @@ LayoutHandler::load_layout(std::size_t number) data.resize(size, mp_layout->default_data); in.read(reinterpret_cast<char*>(&data[0]), - data.size() * sizeof(Layout::LayoutData)); + static_cast<long>(data.size() * sizeof(Layout::LayoutData))); set_kind(kind); for (Layout::LayoutData_ptr data : mp_layout->data) @@ -569,8 +573,8 @@ LayoutHandler::arrange_center( { const Layout::LayoutData_ptr data = *mp_layout->data.active_element(); - std::size_t h_comp = Layout::LayoutData::MAX_MAIN_COUNT; - float w_ratio = data->main_factor / 0.95; + int h_comp = Layout::LayoutData::MAX_MAIN_COUNT; + float w_ratio = data->main_factor / 0.95f; float h_ratio = static_cast<float>((h_comp - data->main_count)) / static_cast<float>(h_comp); @@ -581,14 +585,14 @@ LayoutHandler::arrange_center( [=,this](Client_ptr client) -> Placement { Region region = screen_region; - int w = region.dim.w * w_ratio; - int h = region.dim.h * h_ratio; + int w = static_cast<int>(static_cast<float>(region.dim.w) * w_ratio); + int h = static_cast<int>(static_cast<float>(region.dim.h) * h_ratio); if (w <= region.dim.w) - region.pos.x += (region.dim.w - w) / 2.f; + region.pos.x += static_cast<int>(static_cast<float>(region.dim.w - w) / 2.f); if (h <= region.dim.h) - region.pos.y += (region.dim.h - h) / 2.f; + region.pos.y += static_cast<int>(static_cast<float>(region.dim.h - h) / 2.f); region.dim = { w, h }; @@ -634,21 +638,21 @@ LayoutHandler::arrange_main_deck( ) const { const Layout::LayoutData_ptr data = *mp_layout->data.active_element(); - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); return; } - std::size_t n_main; - std::size_t n_stack; + int n_main; + int n_stack; if (n <= data->main_count) { n_main = n; @@ -660,15 +664,17 @@ LayoutHandler::arrange_main_deck( int w_main = data->main_count > 0 - ? static_cast<float>(screen_region.dim.w) * data->main_factor + ? static_cast<int>(static_cast<float>(screen_region.dim.w) * data->main_factor) : 0; int x_stack = screen_region.pos.x + w_main; int w_stack = screen_region.dim.w - w_main; int h_main = n_main > 0 ? screen_region.dim.h : 0; - int h_stack = n_stack > 0 ? screen_region.dim.h / n_stack : 0; + int h_stack = n_stack > 0 + ? screen_region.dim.h / n_stack + : 0; - std::size_t i = 0; + int i = 0; std::transform( begin, @@ -723,21 +729,21 @@ LayoutHandler::arrange_stack_deck( ) const { const Layout::LayoutData_ptr data = *mp_layout->data.active_element(); - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); return; } - std::size_t n_main; - std::size_t n_stack; + int n_main; + int n_stack; if (n <= data->main_count) { n_main = n; @@ -749,7 +755,7 @@ LayoutHandler::arrange_stack_deck( int w_main = data->main_count > 0 - ? static_cast<float>(screen_region.dim.w) * data->main_factor + ? static_cast<int>(static_cast<float>(screen_region.dim.w) * data->main_factor) : 0; int x_stack = screen_region.pos.x + w_main; @@ -757,7 +763,7 @@ LayoutHandler::arrange_stack_deck( int h_main = n_main > 0 ? screen_region.dim.h / n_main : 0; int h_stack = n_stack > 0 ? screen_region.dim.h : 0; - std::size_t i = 0; + int i = 0; std::transform( begin, @@ -812,21 +818,21 @@ LayoutHandler::arrange_double_deck( ) const { const Layout::LayoutData_ptr data = *mp_layout->data.active_element(); - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); return; } - std::size_t n_main; - std::size_t n_stack; + int n_main; + int n_stack; if (n <= data->main_count) { n_main = n; @@ -838,7 +844,7 @@ LayoutHandler::arrange_double_deck( int w_main = data->main_count > 0 - ? static_cast<float>(screen_region.dim.w) * data->main_factor + ? static_cast<int>(static_cast<float>(screen_region.dim.w) * data->main_factor) : 0; int x_stack = screen_region.pos.x + w_main; @@ -846,7 +852,7 @@ LayoutHandler::arrange_double_deck( int h_main = n_main > 0 ? screen_region.dim.h : 0; int h_stack = n_stack > 0 ? screen_region.dim.h : 0; - std::size_t i = 0; + int i = 0; std::transform( begin, @@ -901,13 +907,13 @@ LayoutHandler::arrange_paper( static const float MIN_W_RATIO = 0.5; const Layout::LayoutData_ptr data = *mp_layout->data.active_element(); - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); @@ -916,13 +922,13 @@ LayoutHandler::arrange_paper( int cw; if (data->main_factor > MIN_W_RATIO) { - cw = screen_region.dim.w * data->main_factor; + cw = static_cast<int>(static_cast<float>(screen_region.dim.w) * data->main_factor); } else { - cw = screen_region.dim.w * MIN_W_RATIO; + cw = static_cast<int>(static_cast<float>(screen_region.dim.w) * MIN_W_RATIO); } - int w = static_cast<float>(screen_region.dim.w - cw) - / static_cast<float>(n - 1); + int w = static_cast<int>(static_cast<float>(screen_region.dim.w - cw) + / static_cast<float>(n - 1)); bool contains_active = false; const auto last_active = std::max_element( @@ -942,7 +948,7 @@ LayoutHandler::arrange_paper( ); bool after_active = false; - std::size_t i = 0; + int i = 0; std::transform( begin, @@ -1013,21 +1019,21 @@ LayoutHandler::arrange_double_stack( ) const { const Layout::LayoutData_ptr data = *mp_layout->data.active_element(); - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); return; } - std::size_t n_main; - std::size_t n_stack; + int n_main; + int n_stack; if (n <= data->main_count) { n_main = n; @@ -1039,7 +1045,7 @@ LayoutHandler::arrange_double_stack( int w_main = data->main_count > 0 - ? static_cast<float>(screen_region.dim.w) * data->main_factor + ? static_cast<int>(static_cast<float>(screen_region.dim.w) * data->main_factor) : 0; int x_stack = screen_region.pos.x + w_main; @@ -1047,7 +1053,7 @@ LayoutHandler::arrange_double_stack( int h_main = n_main > 0 ? screen_region.dim.h / n_main : 0; int h_stack = n_stack > 0 ? screen_region.dim.h / n_stack : 0; - std::size_t i = 0; + int i = 0; std::transform( begin, @@ -1112,21 +1118,21 @@ LayoutHandler::arrange_horizontal_stack( client_iter end ) const { - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); return; } - int w = std::lround(static_cast<float>(screen_region.dim.w) / n); - std::size_t i = 0; + int w = static_cast<int>(std::lround(screen_region.dim.w / n)); + int i = 0; std::transform( begin, @@ -1171,21 +1177,21 @@ LayoutHandler::arrange_vertical_stack( client_iter end ) const { - std::size_t n = end - begin; + int n = static_cast<int>(end - begin); if (n == 1) { placements.emplace_back(Placement { mp_layout->config.method, *begin, - Decoration::NO_DECORATION, + NO_DECORATION, screen_region }); return; } - int h = std::lround(static_cast<float>(screen_region.dim.h) / n); - std::size_t i = 0; + int h = static_cast<int>(std::lround(screen_region.dim.h / n)); + int i = 0; std::transform( begin, @@ -1229,9 +1235,9 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) switch (kind) { case LayoutKind::Float: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Free, - Decoration::FREE_DECORATION, + FREE_DECORATION, false, false, false, @@ -1241,9 +1247,9 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::FramelessFloat: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Free, - Decoration::NO_DECORATION, + NO_DECORATION, false, false, false, @@ -1253,9 +1259,9 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::SingleFloat: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Free, - Decoration::FREE_DECORATION, + FREE_DECORATION, false, false, true, @@ -1265,9 +1271,9 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::FramelessSingleFloat: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Free, - Decoration::NO_DECORATION, + NO_DECORATION, false, false, true, @@ -1277,9 +1283,9 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::Center: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration::NO_DECORATION, + NO_DECORATION, true, true, false, @@ -1289,9 +1295,9 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::Monocle: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration::NO_DECORATION, + NO_DECORATION, true, true, false, @@ -1301,13 +1307,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::MainDeck: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1319,13 +1324,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::StackDeck: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1337,13 +1341,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::DoubleDeck: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1355,13 +1358,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::Paper: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 1, 1, 0, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{1, 1, 0, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1373,13 +1375,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::CompactPaper: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 1, 1, 0, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{1, 1, 0, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1391,13 +1392,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::DoubleStack: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1409,13 +1409,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::CompactDoubleStack: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1427,13 +1426,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::HorizontalStack: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1445,13 +1443,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::CompactHorizontalStack: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 0, 0, 3, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{0, 0, 3, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1463,13 +1460,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::VerticalStack: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 3, 0, 0, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{3, 0, 0, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1481,13 +1477,12 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) } case LayoutKind::CompactVerticalStack: { - return LayoutConfig { + return LayoutConfig{ Placement::PlacementMethod::Tile, - Decoration { - std::nullopt, - Frame { - Extents { 3, 0, 0, 0 }, - ColorScheme::DEFAULT_COLOR_SCHEME + Decoration{ + Frame{ + Extents{3, 0, 0, 0}, + DEFAULT_COLOR_SCHEME } }, true, @@ -1497,7 +1492,11 @@ LayoutHandler::Layout::kind_to_config(LayoutKind kind) true }; } - default: Util::die("no associated configuration defined"); + default: + { + spdlog::critical("no associated configuration defined"); + std::exit(EXIT_FAILURE); + } } return kind_to_config(LayoutKind::Float); @@ -1510,7 +1509,7 @@ LayoutHandler::Layout::kind_to_default_data(LayoutKind kind) case LayoutKind::Center: { return Layout::LayoutData { - Extents { 0, 0, 0, 0 }, + Extents{0, 0, 0, 0}, 0, 5, .40f @@ -1534,13 +1533,17 @@ LayoutHandler::Layout::kind_to_default_data(LayoutKind kind) case LayoutKind::CompactVerticalStack: { return Layout::LayoutData { - Extents { 0, 0, 0, 0 }, + Extents{0, 0, 0, 0}, 0, 1, .50f }; } - default: Util::die("no associated default data defined"); + default: + { + spdlog::critical("no associated default data defined"); + std::exit(EXIT_FAILURE); + } } return kind_to_default_data(LayoutKind::Float); diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc @@ -1,8 +1,16 @@ #include <kranewl/model.hh> +#include <kranewl/common.hh> #include <kranewl/conf/config.hh> +#include <kranewl/context.hh> +#include <kranewl/context.hh> +#include <kranewl/cycle.t.hh> #include <kranewl/exec.hh> +#include <kranewl/input/keyboard.hh> +#include <kranewl/input/mouse.hh> #include <kranewl/server.hh> +#include <kranewl/tree/output.hh> +#include <kranewl/workspace.hh> #include <spdlog/spdlog.h> @@ -11,8 +19,26 @@ Model::Model( Config const& config, [[maybe_unused]] std::optional<std::string> autostart_path ) - : m_server(server), - m_config(config) + : m_server{server}, + m_config{config}, + m_running{true}, + m_outputs{{}, true}, + m_contexts{{}, true}, + m_workspaces{{}, true}, + mp_output{nullptr}, + mp_context{nullptr}, + mp_workspace{nullptr}, + mp_prev_output{nullptr}, + mp_prev_context{nullptr}, + mp_prev_workspace{nullptr}, + m_client_map{}, + m_pid_map{}, + m_fullscreen_map{}, + m_sticky_clients{}, + m_unmanaged_clients{}, + mp_focus(nullptr), + m_key_bindings{}, + m_mouse_bindings{} { #ifdef NDEBUG if (autostart_path) { @@ -21,6 +47,40 @@ Model::Model( } #endif + static const std::vector<std::string> context_names{ + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" + }; + + static const std::vector<std::string> workspace_names{ + "main", "web", "term", {}, {}, {}, {}, {}, {}, {} + }; + + for (std::size_t i = 0; i < context_names.size(); ++i) { + Context_ptr context = new Context(i, context_names[i]); + m_contexts.insert_at_back(context); + + for (std::size_t j = 0; j < workspace_names.size(); ++j) { + Workspace_ptr workspace = new Workspace( + workspace_names.size() * i + j, + workspace_names[j], + context + ); + + m_workspaces.insert_at_back(workspace); + context->register_workspace(workspace); + } + + context->activate_workspace(Index{0}); + } + + /* acquire_outputs(); */ + + m_contexts.activate_at_index(0); + m_workspaces.activate_at_index(0); + + mp_context = *m_contexts.active_element(); + mp_workspace = *m_workspaces.active_element(); + m_server.start(); } @@ -32,3 +92,45 @@ Model::run() { // TODO } + +Output_ptr +Model::create_output(Surface) +{ + Output_ptr output = new Output(); + +} + +void +Model::register_output(Output_ptr) +{ + +} + +void +Model::unregister_output(Output_ptr) +{ + +} + +Client_ptr +Model::create_client(Surface surface) +{ + Client_ptr client = new Client( + &m_server, + surface, + mp_output, + mp_context, + mp_workspace + ); + + register_client(client); +} + +void +Model::register_client(Client_ptr client) +{ +} + +void +Model::unregister_client(Client_ptr client) +{} diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc @@ -1,8 +1,8 @@ #include <kranewl/server.hh> -#include <kranewl/client.hh> #include <kranewl/exec.hh> #include <kranewl/input/keyboard.hh> +#include <kranewl/tree/client.hh> #include <kranewl/tree/output.hh> #include <spdlog/spdlog.h> @@ -241,23 +241,23 @@ Server::new_output(struct wl_listener* listener, void* data) Server_ptr server = wl_container_of(listener, server, ml_new_output); struct wlr_output* wlr_output = reinterpret_cast<struct wlr_output*>(data); - wlr_output_init_render(wlr_output, server->m_allocator, server->m_renderer); if (!wl_list_empty(&wlr_output->modes)) { struct wlr_output_mode* mode = wlr_output_preferred_mode(wlr_output); + wlr_output_set_mode(wlr_output, mode); wlr_output_enable(wlr_output, true); - if (!wlr_output_commit(wlr_output)) { + + if (!wlr_output_commit(wlr_output)) return; - } } Output* output = reinterpret_cast<Output*>(calloc(1, sizeof(Output))); output->wlr_output = wlr_output; output->server = server; - output->l_frame.notify = Server::output_frame; - wl_signal_add(&wlr_output->events.frame, &output->l_frame); + output->ml_frame.notify = Server::output_frame; + wl_signal_add(&wlr_output->events.frame, &output->ml_frame); wl_list_insert(&server->m_outputs, &output->link); wlr_output_layout_add_auto(server->m_output_layout, wlr_output); @@ -300,18 +300,20 @@ Server::new_xdg_surface(struct wl_listener* listener, void* data) } assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - Client_ptr client = new Client; + Client_ptr client = new Client( + server, + Surface{xdg_surface, true}, + nullptr, + nullptr, + nullptr + ); - client->server = server; xdg_surface->data = client->scene; - - client->surface = Surface{ .xdg = xdg_surface }; - client->surface_type = SurfaceType::XDGShell; - client->scene = wlr_scene_xdg_surface_create( &client->server->m_scene->node, client->surface.xdg ); + client->scene->data = client; client->l_map.notify = xdg_toplevel_map; @@ -705,16 +707,16 @@ Server::keyboard_handle_keybinding(Server_ptr server, xkb_keysym_t sym) if (wl_list_length(&server->m_clients) < 2) break; - Client_ptr prev_client = wl_container_of( - server->m_clients.prev, - prev_client, - link - ); + /* Client_ptr prev_client = wl_container_of( */ + /* server->m_clients.prev, */ + /* prev_client, */ + /* link */ + /* ); */ - focus_client( - prev_client, - prev_client->get_surface() - ); + /* focus_client( */ + /* prev_client, */ + /* prev_client->get_surface() */ + /* ); */ } break; case XKB_KEY_Return: @@ -760,11 +762,11 @@ Server::request_set_primary_selection(struct wl_listener* listener, void* data) void Server::output_frame(struct wl_listener* listener, void* data) { - Output* output = wl_container_of(listener, output, l_frame); - struct wlr_scene* scene = output->server->m_scene; + Output* output = wl_container_of(listener, output, ml_frame); + struct wlr_scene* scene = output->m_server->m_scene; struct wlr_scene_output* scene_output - = wlr_scene_get_scene_output(scene, output->wlr_output); + = wlr_scene_get_scene_output(scene, output->m_wlr_output); wlr_scene_output_commit(scene_output); @@ -826,10 +828,10 @@ Server::focus_client(Client_ptr client, struct wlr_surface* surface) if (client->scene) wlr_scene_node_raise_to_top(client->scene); - wl_list_remove(&client->link); - wl_list_insert(&server->m_clients, &client->link); + /* wl_list_remove(&client->link); */ + /* wl_list_insert(&server->m_clients, &client->link); */ - if (client->surface_type == SurfaceType::XDGShell || client->surface_type == SurfaceType::LayerShell) + if (client->surface.type == SurfaceType::XDGShell || client->surface.type == SurfaceType::LayerShell) wlr_xdg_toplevel_set_activated(client->surface.xdg, true); wlr_seat_keyboard_notify_enter( @@ -846,9 +848,7 @@ Server::xdg_toplevel_map(struct wl_listener* listener, void* data) { Client_ptr client = wl_container_of(listener, client, l_map); - printf("Address of x is %p\n", (void *)client); - - wl_list_insert(&client->server->m_clients, &client->link); + /* wl_list_insert(&client->server->m_clients, &client->link); */ focus_client(client, client->get_surface()); } @@ -856,7 +856,7 @@ void Server::xdg_toplevel_unmap(struct wl_listener* listener, void* data) { Client_ptr client = wl_container_of(listener, client, l_unmap); - wl_list_remove(&client->link); + /* wl_list_remove(&client->link); */ } void @@ -976,16 +976,16 @@ Server::new_xwayland_surface(struct wl_listener* listener, void* data) struct wlr_xwayland_surface* xwayland_surface = reinterpret_cast<wlr_xwayland_surface*>(data); - Client_ptr client = new Client; + Client_ptr client = new Client( + server, + Surface{xwayland_surface, xwayland_surface->override_redirect}, + nullptr, + nullptr, + nullptr + ); - client->server = server; xwayland_surface->data = client; - client->surface = Surface{ .xwayland = xwayland_surface }; - client->surface_type = xwayland_surface->override_redirect - ? SurfaceType::X11Unmanaged - : SurfaceType::X11Managed; - client->l_map = { .notify = Server::xdg_toplevel_map }; client->l_unmap = { .notify = Server::xdg_toplevel_unmap }; client->l_destroy = { .notify = Server::xdg_toplevel_destroy }; diff --git a/src/kranewl/tree/client.cc b/src/kranewl/tree/client.cc @@ -0,0 +1,213 @@ +#include <kranewl/tree/client.hh> + +// https://github.com/swaywm/wlroots/issues/682 +#include <pthread.h> +#define class class_ +#define namespace namespace_ +#define static +extern "C" { +#include <wlr/types/wlr_xdg_shell.h> +#ifdef XWAYLAND +#include <wlr/xwayland.h> +#endif +} +#undef static +#undef class +#undef namespace + +Client::Client( + Server_ptr server, + Surface surface, + Output_ptr output, + Context_ptr context, + Workspace_ptr workspace +) + : uid{surface.uid()}, + server{server}, + surface{surface}, + output{output}, + context{context}, + workspace{workspace}, + free_region{{}}, + tile_region{{}}, + active_region{{}}, + previous_region{{}}, + inner_region{{}}, + tile_decoration{{}}, + free_decoration{{}}, + active_decoration{{}}, + parent{nullptr}, + children{{}}, + producer{nullptr}, + consumers{{}}, + focused{false}, + mapped{false}, + managed{true}, + urgent{false}, + floating{false}, + fullscreen{false}, + contained{false}, + invincible{false}, + sticky{false}, + iconifyable{true}, + iconified{false}, + disowned{false}, + producing{true}, + attaching{false}, + last_focused{std::chrono::steady_clock::now()}, + managed_since{std::chrono::steady_clock::now()}, + m_outside_state{OutsideState::Unfocused} +{} + +Client::~Client() +{} + +Client::OutsideState +Client::get_outside_state() const noexcept +{ + if (urgent) + return Client::OutsideState::Urgent; + + return m_outside_state; +} + +struct wlr_surface* +Client::get_surface() noexcept +{ + switch (surface.type) { + case SurfaceType::XDGShell: //fallthrough + case SurfaceType::LayerShell: return surface.xdg->surface; + case SurfaceType::X11Managed: //fallthrough + case SurfaceType::X11Unmanaged: return surface.xwayland->surface; + } + + return nullptr; +} + +void +Client::focus() noexcept +{ + focused = true; + last_focused = std::chrono::steady_clock::now(); + + 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; + } +} + +void +Client::unfocus() noexcept +{ + focused = 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; + } +} + +void +Client::stick() noexcept +{ + sticky = 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; + } +} + +void +Client::unstick() noexcept +{ + sticky = 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; + } +} + +void +Client::disown() noexcept +{ + disowned = 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; + } +} + +void +Client::reclaim() noexcept +{ + disowned = 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 +Client::set_tile_region(Region& region) noexcept +{ + tile_region = region; + set_active_region(region); +} + +void +Client::set_free_region(Region& region) noexcept +{ + free_region = region; + set_active_region(region); +} + +void +Client::set_active_region(Region& region) noexcept +{ + previous_region = active_region; + set_inner_region(region); + active_region = region; +} + +void +Client::set_tile_decoration(Decoration const& decoration) noexcept +{ + tile_decoration = decoration; + active_decoration = decoration; +} + +void +Client::set_free_decoration(Decoration const& decoration) noexcept +{ + free_decoration = decoration; + active_decoration = decoration; +} + +void +Client::set_inner_region(Region& region) noexcept +{ + if (active_decoration.frame) { + Frame const& frame = *active_decoration.frame; + + inner_region.pos.x = frame.extents.left; + inner_region.pos.y = frame.extents.top; + inner_region.dim.w = region.dim.w - frame.extents.left - frame.extents.right; + inner_region.dim.h = region.dim.h - frame.extents.top - frame.extents.bottom; + } else { + inner_region.pos.x = 0; + inner_region.pos.y = 0; + inner_region.dim = region.dim; + } +} diff --git a/src/kranewl/util.cc b/src/kranewl/util.cc @@ -1,30 +0,0 @@ -#include <kranewl/util.hh> - -#define assert assert_ -#include <spdlog/spdlog.h> -#undef assert - -#include <utility> -extern "C" { -#include <unistd.h> -} - -void -Util::die(const std::string&& msg) -{ - spdlog::critical(msg); - exit(1); -} - -void -Util::warn(const std::string&& msg) -{ - spdlog::warn(msg); -} - -void -Util::assert(bool condition, std::string const&& msg) -{ - if (!condition) - Util::die(std::forward<const std::string&&>(msg)); -}