commit 8752e09d79575a20a1a6c413fff9f6e77f7109cf
parent 57e3d1ce4b0480a4414c200fb693a79018462e35
Author: deurzen <max@deurzen.net>
Date: Thu, 26 May 2022 22:24:55 +0200
adds view {,un}mapping functionality
Diffstat:
17 files changed, 791 insertions(+), 193 deletions(-)
diff --git a/include/kranewl/cycle.hh b/include/kranewl/cycle.hh
@@ -71,6 +71,21 @@ public:
std::optional<T> element_at_front(T) const;
std::optional<T> element_at_back(T) const;
+ template<typename UnaryPredicate>
+ std::optional<T> first_element_with_condition(UnaryPredicate predicate)
+ {
+ auto it = std::find_if(
+ m_elements.begin(),
+ m_elements.end(),
+ predicate
+ );
+
+ if (it != m_elements.end())
+ return *it;
+
+ return {};
+ }
+
void activate_first();
void activate_last();
void activate_at_index(Index);
diff --git a/include/kranewl/decoration.hh b/include/kranewl/decoration.hh
@@ -58,12 +58,13 @@ struct Frame final {
struct Decoration final {
std::optional<Frame> frame;
- const Extents extents() const
+ Extents const& extents() const
{
+ static Extents NO_EXTENTS{0, 0, 0, 0};
if (frame)
return frame->extents;
- return Extents{0, 0, 0, 0};
+ return NO_EXTENTS;
}
};
diff --git a/include/kranewl/geometry.hh b/include/kranewl/geometry.hh
@@ -1,6 +1,7 @@
#pragma once
#include <ostream>
+#include <sstream>
extern "C" {
#include <wlr/util/box.h>
@@ -214,6 +215,17 @@ operator<<(std::ostream& os, Region const& region)
return os << "[" << region.pos << " " << region.dim << "]";
}
+namespace std {
+
+ inline std::string
+ to_string(Region const& region) {
+ std::ostringstream oss;
+ oss << region;
+ return oss.str();
+ }
+
+}
+
struct DRegion final {
DPos pos;
DDim dim;
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -4,6 +4,7 @@
#include <kranewl/common.hh>
#include <kranewl/cycle.hh>
#include <kranewl/geometry.hh>
+#include <kranewl/placement.hh>
#include <kranewl/tree/view.hh>
#include <optional>
@@ -35,7 +36,7 @@ public:
void register_server(Server_ptr);
void exit();
- Output_ptr create_output(struct wlr_output*, struct wlr_scene_output*);
+ Output_ptr create_output(struct wlr_output*, struct wlr_scene_output*, Region const&&);
void register_output(Output_ptr);
void unregister_output(Output_ptr);
@@ -46,6 +47,27 @@ public:
void register_view(View_ptr);
void unregister_view(View_ptr);
+ void map_view(View_ptr);
+ void unmap_view(View_ptr);
+ void iconify_view(View_ptr);
+ void deiconify_view(View_ptr);
+ void disown_view(View_ptr);
+ void reclaim_view(View_ptr);
+ void focus_view(View_ptr);
+ void place_view(Placement&);
+
+ void move_view_to_workspace(View_ptr, Index);
+ void move_view_to_workspace(View_ptr, Workspace_ptr);
+ void move_view_to_context(View_ptr, Index);
+ void move_view_to_context(View_ptr, Context_ptr);
+ void move_view_to_output(View_ptr, Index);
+ void move_view_to_output(View_ptr, Output_ptr);
+
+ void move_view_to_focused_output(View_ptr);
+
+ void apply_layout(Index);
+ void apply_layout(Workspace_ptr);
+
void spawn_external(std::string&&) const;
private:
diff --git a/include/kranewl/server.hh b/include/kranewl/server.hh
@@ -13,8 +13,9 @@ extern "C" {
#include <string>
typedef class Model* Model_ptr;
-typedef class Client* Client_ptr;
+typedef class View* View_ptr;
typedef class Server* Server_ptr;
+
typedef class Server final {
enum class CursorMode {
Passthrough,
@@ -28,6 +29,8 @@ public:
void run() noexcept;
+ void moveresize_view(View_ptr, Region const&, Extents const&, bool);
+
private:
static void handle_new_output(struct wl_listener*, void*);
static void handle_output_layout_change(struct wl_listener*, void*);
@@ -47,7 +50,7 @@ private:
static void handle_xdg_toplevel_destroy(struct wl_listener*, void*);
static void handle_xdg_toplevel_request_move(struct wl_listener*, void*);
static void handle_xdg_toplevel_request_resize(struct wl_listener*, void*);
- static void handle_xdg_toplevel_handle_moveresize(Client_ptr, CursorMode, uint32_t);
+ static void handle_xdg_toplevel_handle_moveresize(View_ptr, CursorMode, uint32_t);
#ifdef XWAYLAND
static void handle_xwayland_ready(struct wl_listener*, void*);
static void handle_new_xwayland_surface(struct wl_listener*, void*);
@@ -74,7 +77,6 @@ public:
struct wlr_xwayland* mp_xwayland;
#endif
- /* Root m_root; */
Seat m_seat;
diff --git a/include/kranewl/tree/output.hh b/include/kranewl/tree/output.hh
@@ -20,7 +20,8 @@ public:
Server_ptr,
Model_ptr,
struct wlr_output*,
- struct wlr_scene_output*
+ struct wlr_scene_output*,
+ Region const&&
);
~Output();
@@ -30,12 +31,12 @@ public:
static void handle_mode(struct wl_listener*, void*);
static void handle_destroy(struct wl_listener*, void*);
- void set_context(Context_ptr context);
+ void set_context(Context_ptr);
Context_ptr context() const;
Region full_region() const;
Region placeable_region() const;
- bool contains(Pos pos) const;
- bool contains(Region region) const;
+ bool contains(Pos) const;
+ bool contains(Region) const;
private:
Context_ptr mp_context;
@@ -46,6 +47,8 @@ public:
Server_ptr mp_server;
Model_ptr mp_model;
+ bool m_dirty;
+
struct wlr_output* mp_wlr_output;
struct wlr_scene_output* mp_wlr_scene_output;
diff --git a/include/kranewl/tree/view.hh b/include/kranewl/tree/view.hh
@@ -3,8 +3,6 @@
#include <kranewl/common.hh>
#include <kranewl/decoration.hh>
#include <kranewl/geometry.hh>
-#include <kranewl/context.hh>
-#include <kranewl/workspace.hh>
#include <kranewl/model.hh>
#include <kranewl/tree/surface.hh>
@@ -45,9 +43,6 @@ typedef struct View {
Server_ptr,
Model_ptr,
Seat_ptr,
- Output_ptr,
- Context_ptr,
- Workspace_ptr,
struct wlr_surface*,
void(*)(wl_listener*, void*),
void(*)(wl_listener*, void*),
@@ -62,9 +57,6 @@ typedef struct View {
Server_ptr,
Model_ptr,
Seat_ptr,
- Output_ptr,
- Context_ptr,
- Workspace_ptr,
struct wlr_surface*,
void(*)(wl_listener*, void*),
void(*)(wl_listener*, void*),
@@ -77,6 +69,7 @@ typedef struct View {
virtual ~View();
static void map_view(View_ptr, struct wlr_surface*, bool, struct wlr_output*, bool);
+ static void unmap_view(View_ptr);
static bool
is_free(View_ptr view)
@@ -86,6 +79,15 @@ typedef struct View {
|| view->m_disowned;
}
+ 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&);
+
Uid m_uid;
Type m_type;
@@ -104,6 +106,7 @@ typedef struct View {
std::string m_title;
std::string m_title_formatted;
+ std::string m_app_id;
float m_alpha;
uint32_t m_resize;
@@ -114,6 +117,7 @@ typedef struct View {
Decoration m_free_decoration;
Decoration m_active_decoration;
+ Dim m_minimum_dim;
Dim m_preferred_dim;
Region m_free_region;
Region m_tile_region;
@@ -138,6 +142,10 @@ typedef struct View {
std::chrono::time_point<std::chrono::steady_clock> m_last_focused;
std::chrono::time_point<std::chrono::steady_clock> m_managed_since;
+private:
+ 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;
diff --git a/include/kranewl/tree/xdg_view.hh b/include/kranewl/tree/xdg_view.hh
@@ -3,6 +3,8 @@
#include <kranewl/tree/view.hh>
#include <kranewl/util.hh>
+#include <cstdint>
+
typedef class Server* Server_ptr;
typedef class Model* Model_ptr;
typedef class Seat* Seat_ptr;
@@ -15,10 +17,7 @@ typedef struct XDGView final : public View {
struct wlr_xdg_surface*,
Server_ptr,
Model_ptr,
- Seat_ptr,
- Output_ptr,
- Context_ptr,
- Workspace_ptr
+ Seat_ptr
);
~XDGView();
diff --git a/include/kranewl/tree/xwayland_view.hh b/include/kranewl/tree/xwayland_view.hh
@@ -16,10 +16,7 @@ typedef struct XWaylandView final : public View {
struct wlr_xwayland_surface*,
Server_ptr,
Model_ptr,
- Seat_ptr,
- Output_ptr,
- Context_ptr,
- Workspace_ptr
+ Seat_ptr
);
~XWaylandView();
diff --git a/src/kranewl/layout.cc b/src/kranewl/layout.cc
@@ -1,3 +1,5 @@
+#include <trace.hh>
+
#include <kranewl/layout.hh>
#include <kranewl/cycle.t.hh>
@@ -72,6 +74,8 @@ LayoutHandler::arrange(
view_iter end
) const
{
+ TRACE();
+
if (mp_layout->config.margin) {
Layout::LayoutData_ptr data = *mp_layout->data.active_element();
@@ -83,91 +87,91 @@ LayoutHandler::arrange(
}
switch (m_kind) {
- case LayoutKind::Float:
- {
- arrange_float(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::FramelessFloat:
- {
- arrange_frameless_float(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::SingleFloat:
- {
- arrange_single_float(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::FramelessSingleFloat:
- {
- arrange_frameless_single_float(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::Center:
- {
- arrange_center(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::Monocle:
- {
- arrange_monocle(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::MainDeck:
- {
- arrange_main_deck(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::StackDeck:
- {
- arrange_stack_deck(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::DoubleDeck:
- {
- arrange_double_deck(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::Paper:
- {
- arrange_paper(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::CompactPaper:
- {
- arrange_compact_paper(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::DoubleStack:
- {
- arrange_double_stack(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::CompactDoubleStack:
- {
- arrange_compact_double_stack(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::HorizontalStack:
- {
- arrange_horizontal_stack(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::CompactHorizontalStack:
- {
- arrange_compact_horizontal_stack(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::VerticalStack:
- {
- arrange_vertical_stack(screen_region, placements, begin, end);
- break;
- }
- case LayoutKind::CompactVerticalStack:
- {
- arrange_compact_vertical_stack(screen_region, placements, begin, end);
- break;
- }
+ case LayoutKind::Float:
+ {
+ arrange_float(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::FramelessFloat:
+ {
+ arrange_frameless_float(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::SingleFloat:
+ {
+ arrange_single_float(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::FramelessSingleFloat:
+ {
+ arrange_frameless_single_float(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::Center:
+ {
+ arrange_center(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::Monocle:
+ {
+ arrange_monocle(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::MainDeck:
+ {
+ arrange_main_deck(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::StackDeck:
+ {
+ arrange_stack_deck(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::DoubleDeck:
+ {
+ arrange_double_deck(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::Paper:
+ {
+ arrange_paper(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::CompactPaper:
+ {
+ arrange_compact_paper(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::DoubleStack:
+ {
+ arrange_double_stack(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::CompactDoubleStack:
+ {
+ arrange_compact_double_stack(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::HorizontalStack:
+ {
+ arrange_horizontal_stack(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::CompactHorizontalStack:
+ {
+ arrange_compact_horizontal_stack(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::VerticalStack:
+ {
+ arrange_vertical_stack(screen_region, placements, begin, end);
+ break;
+ }
+ case LayoutKind::CompactVerticalStack:
+ {
+ arrange_compact_vertical_stack(screen_region, placements, begin, end);
+ break;
+ }
}
if (mp_layout->config.gap) {
@@ -427,6 +431,8 @@ LayoutHandler::cycle_layout_data(Direction direction)
void
LayoutHandler::save_layout(int number) const
{
+ TRACE();
+
std::stringstream datadir_ss;
std::string home_path = std::getenv("HOME");
@@ -458,6 +464,8 @@ LayoutHandler::save_layout(int number) const
void
LayoutHandler::load_layout(int number)
{
+ TRACE();
+
std::stringstream datadir_ss;
std::string home_path = std::getenv("HOME");
@@ -503,6 +511,8 @@ LayoutHandler::arrange_float(
view_iter end
) const
{
+ TRACE();
+
std::transform(
begin,
end,
@@ -526,6 +536,8 @@ LayoutHandler::arrange_frameless_float(
view_iter end
) const
{
+ TRACE();
+
arrange_float(screen_region, placements, begin, end);
}
@@ -537,6 +549,8 @@ LayoutHandler::arrange_single_float(
view_iter end
) const
{
+ TRACE();
+
std::transform(
begin,
end,
@@ -560,6 +574,8 @@ LayoutHandler::arrange_frameless_single_float(
view_iter end
) const
{
+ TRACE();
+
arrange_single_float(screen_region, placements, begin, end);
}
@@ -571,6 +587,8 @@ LayoutHandler::arrange_center(
view_iter end
) const
{
+ TRACE();
+
const Layout::LayoutData_ptr data = *mp_layout->data.active_element();
int h_comp = Layout::LayoutData::MAX_MAIN_COUNT;
@@ -614,6 +632,8 @@ LayoutHandler::arrange_monocle(
view_iter end
) const
{
+ TRACE();
+
std::transform(
begin,
end,
@@ -637,6 +657,8 @@ LayoutHandler::arrange_main_deck(
view_iter end
) const
{
+ TRACE();
+
const Layout::LayoutData_ptr data = *mp_layout->data.active_element();
int n = static_cast<int>(end - begin);
@@ -728,6 +750,8 @@ LayoutHandler::arrange_stack_deck(
view_iter end
) const
{
+ TRACE();
+
const Layout::LayoutData_ptr data = *mp_layout->data.active_element();
int n = static_cast<int>(end - begin);
@@ -817,6 +841,8 @@ LayoutHandler::arrange_double_deck(
view_iter end
) const
{
+ TRACE();
+
const Layout::LayoutData_ptr data = *mp_layout->data.active_element();
int n = static_cast<int>(end - begin);
@@ -904,6 +930,8 @@ LayoutHandler::arrange_paper(
view_iter end
) const
{
+ TRACE();
+
static const float MIN_W_RATIO = 0.5;
const Layout::LayoutData_ptr data = *mp_layout->data.active_element();
@@ -1007,6 +1035,8 @@ LayoutHandler::arrange_compact_paper(
view_iter end
) const
{
+ TRACE();
+
arrange_paper(screen_region, placements, begin, end);
}
@@ -1018,6 +1048,8 @@ LayoutHandler::arrange_double_stack(
view_iter end
) const
{
+ TRACE();
+
const Layout::LayoutData_ptr data = *mp_layout->data.active_element();
int n = static_cast<int>(end - begin);
@@ -1107,6 +1139,8 @@ LayoutHandler::arrange_compact_double_stack(
view_iter end
) const
{
+ TRACE();
+
arrange_double_stack(screen_region, placements, begin, end);
}
@@ -1118,6 +1152,8 @@ LayoutHandler::arrange_horizontal_stack(
view_iter end
) const
{
+ TRACE();
+
int n = static_cast<int>(end - begin);
if (n == 1) {
@@ -1166,6 +1202,8 @@ LayoutHandler::arrange_compact_horizontal_stack(
view_iter end
) const
{
+ TRACE();
+
arrange_horizontal_stack(screen_region, placements, begin, end);
}
@@ -1177,6 +1215,8 @@ LayoutHandler::arrange_vertical_stack(
view_iter end
) const
{
+ TRACE();
+
int n = static_cast<int>(end - begin);
if (n == 1) {
@@ -1225,6 +1265,8 @@ LayoutHandler::arrange_compact_vertical_stack(
view_iter end
) const
{
+ TRACE();
+
arrange_vertical_stack(screen_region, placements, begin, end);
}
@@ -1548,4 +1590,3 @@ LayoutHandler::Layout::kind_to_default_data(LayoutKind kind)
return kind_to_default_data(LayoutKind::Float);
}
-
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -5,7 +5,6 @@
#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/mouse.hh>
@@ -19,6 +18,19 @@
#include <spdlog/spdlog.h>
#include <iomanip>
+#include <optional>
+
+// https://github.com/swaywm/wlroots/issues/682
+#include <pthread.h>
+#define class class_
+#define namespace namespace_
+#define static
+extern "C" {
+#include <wlr/types/wlr_surface.h>
+}
+#undef static
+#undef class
+#undef namespace
Model::Model(
Config const& config,
@@ -94,14 +106,14 @@ void
Model::register_server(Server_ptr server)
{
TRACE();
-
mp_server = server;
}
Output_ptr
Model::create_output(
struct wlr_output* wlr_output,
- struct wlr_scene_output* wlr_scene_output
+ struct wlr_scene_output* wlr_scene_output,
+ Region const&& output_region
)
{
TRACE();
@@ -110,9 +122,30 @@ Model::create_output(
mp_server,
this,
wlr_output,
- wlr_scene_output
+ wlr_scene_output,
+ std::forward<Region const&&>(output_region)
);
+ std::optional<Context_ptr> context
+ = m_contexts.first_element_with_condition([](Context_ptr context) {
+ return !context->output();
+ });
+
+ if (context) {
+ output->set_context(*context);
+ (*context)->set_output(output);
+
+ spdlog::info("Assigned context {} to output {}",
+ (*context)->index(),
+ output->mp_wlr_output->name
+ );
+ } else
+ // TODO: dynamically generate new context
+ spdlog::error("Depleted allocatable contexts,"
+ " output {} will not house any workspaces",
+ output->mp_wlr_output->name
+ );
+
register_output(output);
return output;
@@ -124,6 +157,9 @@ Model::register_output(Output_ptr output)
TRACE();
m_outputs.insert_at_back(output);
+ mp_output = *m_outputs.active_element();
+ mp_context = mp_output->context();
+ mp_workspace = mp_context->workspace();
}
void
@@ -135,6 +171,265 @@ Model::unregister_output(Output_ptr output)
delete output;
}
+void
+Model::map_view(View_ptr view)
+{
+ TRACE();
+}
+
+void
+Model::unmap_view(View_ptr view)
+{
+ TRACE();
+}
+
+void
+Model::iconify_view(View_ptr)
+{
+ TRACE();
+}
+
+void
+Model::deiconify_view(View_ptr)
+{
+ TRACE();
+}
+
+void
+Model::disown_view(View_ptr)
+{
+ TRACE();
+}
+
+void
+Model::reclaim_view(View_ptr)
+{
+ TRACE();
+}
+
+void
+Model::focus_view(View_ptr)
+{
+ TRACE();
+}
+
+void
+Model::place_view(Placement& placement)
+{
+ TRACE();
+
+ View_ptr view = placement.view;
+
+ if (!placement.region) {
+ switch (placement.method) {
+ case Placement::PlacementMethod::Free:
+ {
+ view->set_free_decoration(placement.decoration);
+ break;
+ }
+ case Placement::PlacementMethod::Tile:
+ {
+ view->set_free_decoration(FREE_DECORATION);
+ view->set_tile_decoration(placement.decoration);
+ break;
+ }
+ }
+
+ unmap_view(view);
+ return;
+ }
+
+ switch (placement.method) {
+ case Placement::PlacementMethod::Free:
+ {
+ view->set_free_decoration(placement.decoration);
+ view->set_free_region(*placement.region);
+ break;
+ }
+ case Placement::PlacementMethod::Tile:
+ {
+ view->set_free_decoration(FREE_DECORATION);
+ view->set_tile_decoration(placement.decoration);
+ view->set_tile_region(*placement.region);
+ break;
+ }
+ }
+
+ spdlog::info("Placing view {} at {}", view->m_uid, std::to_string(view->m_active_region));
+
+ map_view(view);
+ mp_server->moveresize_view(
+ view,
+ view->m_active_region,
+ view->m_active_decoration.extents(),
+ false
+ );
+}
+
+void
+Model::move_view_to_workspace(View_ptr view, Index index)
+{
+ TRACE();
+
+ if (index < m_workspaces.size())
+ move_view_to_workspace(view, m_workspaces[index]);
+}
+
+void
+Model::move_view_to_workspace(View_ptr view, Workspace_ptr workspace_to)
+{
+ TRACE();
+
+ Workspace_ptr workspace_from = view->mp_workspace;
+
+ if (!workspace_to || workspace_to == workspace_from)
+ return;
+
+ view->mp_workspace = workspace_to;
+
+ Context_ptr context_from = workspace_from->context();
+ Output_ptr output_from = context_from->output();
+
+ 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;
+
+ 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
+ map_view(view);
+}
+
+void
+Model::move_view_to_context(View_ptr view, Index index)
+{
+ TRACE();
+
+ if (index < m_workspaces.size())
+ move_view_to_context(view, m_contexts[index]);
+}
+
+void
+Model::move_view_to_context(View_ptr view, Context_ptr context_to)
+{
+ TRACE();
+
+ Context_ptr context_from = view->mp_context;
+
+ if (!context_to || context_to == context_from)
+ return;
+
+ view->mp_context = context_to;
+
+ Workspace_ptr workspace_from = view->mp_workspace;
+ Output_ptr output_from = context_from->output();
+
+ Workspace_ptr workspace_to = context_to->workspace();
+ Output_ptr output_to = context_to->output();
+
+ view->mp_workspace = workspace_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
+ map_view(view);
+}
+
+void
+Model::move_view_to_output(View_ptr view, Index index)
+{
+ TRACE();
+
+ if (index < m_outputs.size())
+ move_view_to_output(view, m_outputs[index]);
+}
+
+void
+Model::move_view_to_output(View_ptr view, Output_ptr output_to)
+{
+ TRACE();
+
+ Output_ptr output_from = view->mp_output;
+
+ if (!output_to || output_to == output_from)
+ return;
+
+ if (output_from) {
+ Workspace_ptr workspace_from = view->mp_workspace;
+
+ if (workspace_from) {
+ workspace_from->remove_view(view);
+ apply_layout(workspace_from);
+ }
+ }
+
+ Context_ptr context_to = output_to->context();
+ Workspace_ptr workspace_to = context_to->workspace();
+
+ view->mp_output = output_to;
+ view->mp_context = context_to;
+ view->mp_workspace = workspace_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);
+ } else
+ unmap_view(view);
+}
+
+void
+Model::move_view_to_focused_output(View_ptr view)
+{
+ TRACE();
+ move_view_to_output(view, mp_output);
+}
+
+void
+Model::apply_layout(Index index)
+{
+ TRACE();
+
+ if (index < m_workspaces.size())
+ apply_layout(m_workspaces[index]);
+}
+
+void
+Model::apply_layout(Workspace_ptr workspace)
+{
+ TRACE();
+
+ Context_ptr context = workspace->context();
+ Output_ptr output = context->output();
+
+ if (!output)
+ return;
+
+ for (Placement placement : workspace->arrange(output->placeable_region()))
+ place_view(placement);
+}
+
XDGView_ptr
Model::create_xdg_shell_view(
struct wlr_xdg_surface* wlr_xdg_surface,
@@ -147,10 +442,7 @@ Model::create_xdg_shell_view(
wlr_xdg_surface,
mp_server,
this,
- seat,
- mp_output,
- mp_context,
- mp_workspace
+ seat
);
register_view(view);
@@ -170,10 +462,7 @@ Model::create_xwayland_view(
wlr_xwayland_surface,
mp_server,
this,
- seat,
- mp_output,
- mp_context,
- mp_workspace
+ seat
);
register_view(view);
diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc
@@ -233,6 +233,23 @@ Server::run() noexcept
}
void
+Server::moveresize_view(View_ptr view, Region const& region, Extents const& extents, bool interactive)
+{
+ TRACE();
+
+ wlr_scene_node_set_position(view->mp_scene, region.pos.x, region.pos.y);
+ wlr_scene_node_set_position(view->mp_scene_surface, extents.left, extents.top);
+ wlr_scene_rect_set_size(view->m_protrusions[0], region.dim.w, extents.top);
+ wlr_scene_rect_set_size(view->m_protrusions[1], region.dim.w, extents.bottom);
+ wlr_scene_rect_set_size(view->m_protrusions[2], extents.left, region.dim.h - extents.top - extents.bottom);
+ wlr_scene_rect_set_size(view->m_protrusions[3], extents.right, region.dim.h - extents.top - extents.bottom);
+ wlr_scene_node_set_position(&view->m_protrusions[0]->node, 0, 0);
+ wlr_scene_node_set_position(&view->m_protrusions[1]->node, 0, region.dim.h - extents.bottom);
+ wlr_scene_node_set_position(&view->m_protrusions[2]->node, 0, extents.top);
+ wlr_scene_node_set_position(&view->m_protrusions[3]->node, region.dim.w - extents.right, extents.top);
+}
+
+void
Server::handle_new_output(struct wl_listener* listener, void* data)
{
TRACE();
@@ -255,13 +272,26 @@ Server::handle_new_output(struct wl_listener* listener, void* data)
return;
}
+ wlr_output_layout_add_auto(server->mp_output_layout, wlr_output);
+ struct wlr_box output_box
+ = *wlr_output_layout_get_box(server->mp_output_layout, wlr_output);
+
Output_ptr output = server->mp_model->create_output(
wlr_output,
- wlr_scene_output_create(server->mp_scene, wlr_output)
+ wlr_scene_output_create(server->mp_scene, wlr_output),
+ Region{
+ .pos = Pos{
+ .x = output_box.x,
+ .y = output_box.y
+ },
+ .dim = Dim{
+ .w = output_box.width,
+ .h = output_box.height
+ }
+ }
);
wlr_output->data = output;
- wlr_output_layout_add_auto(server->mp_output_layout, wlr_output);
}
void
@@ -293,11 +323,13 @@ view_from_popup(struct wlr_xdg_popup* popup)
for (;;)
switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
+ {
if (!wlr_surface_is_xdg_surface(surface->popup->parent))
return nullptr;
surface = wlr_xdg_surface_from_wlr_surface(surface->popup->parent);
break;
+ }
case WLR_XDG_SURFACE_ROLE_TOPLEVEL: return reinterpret_cast<View_ptr>(surface->data);
case WLR_XDG_SURFACE_ROLE_NONE: return nullptr;
}
@@ -315,28 +347,29 @@ Server::handle_new_xdg_surface(struct wl_listener* listener, void* data)
switch (xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
- {
- struct wlr_box mappable_box;
+ {
+ struct wlr_box mappable_box;
+
+ struct wlr_xdg_surface* parent
+ = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent);
- struct wlr_xdg_surface* parent
- = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent);
+ struct wlr_scene_node* parent_node
+ = reinterpret_cast<struct wlr_scene_node*>(parent->data);
- struct wlr_scene_node* parent_node
- = reinterpret_cast<struct wlr_scene_node*>(parent->data);
+ xdg_surface->data
+ = wlr_scene_xdg_surface_create(parent_node, xdg_surface);
- xdg_surface->data
- = wlr_scene_xdg_surface_create(parent_node, xdg_surface);
+ if (!(view = view_from_popup(xdg_surface->popup)) || !view->mp_output)
+ return;
- if (!(view = view_from_popup(xdg_surface->popup)) || !view->mp_output)
- return;
+ 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 = view->mp_output->placeable_region();
- mappable_box.x -= view->m_active_region.pos.x;
- mappable_box.y -= view->m_active_region.pos.y;
+ wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &mappable_box);
- wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &mappable_box);
- }
return;
+ }
case WLR_XDG_SURFACE_ROLE_NONE: return;
default: break;
}
@@ -380,23 +413,26 @@ Server::handle_new_input(struct wl_listener* listener, void* data)
switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
- {
- Keyboard_ptr keyboard = server->m_seat.create_keyboard(device);
+ {
+ Keyboard_ptr keyboard = server->m_seat.create_keyboard(device);
- struct xkb_context* context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- struct xkb_keymap* keymap
- = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ struct xkb_context* context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ struct xkb_keymap* keymap
+ = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ wlr_keyboard_set_keymap(device->keyboard, keymap);
+ xkb_keymap_unref(keymap);
+ xkb_context_unref(context);
+ wlr_keyboard_set_repeat_info(device->keyboard, 200, 100);
+ wlr_seat_set_keyboard(server->m_seat.mp_seat, device);
- wlr_keyboard_set_keymap(device->keyboard, keymap);
- xkb_keymap_unref(keymap);
- xkb_context_unref(context);
- wlr_keyboard_set_repeat_info(device->keyboard, 200, 100);
- wlr_seat_set_keyboard(server->m_seat.mp_seat, device);
- }
break;
+ }
case WLR_INPUT_DEVICE_POINTER:
+ {
wlr_cursor_attach_input_device(server->m_seat.mp_cursor, device);
break;
+ }
default: break;
}
@@ -485,7 +521,7 @@ Server::handle_xdg_toplevel_request_resize(struct wl_listener*, void*)
}
void
-Server::handle_xdg_toplevel_handle_moveresize(Client_ptr, CursorMode, uint32_t)
+Server::handle_xdg_toplevel_handle_moveresize(View_ptr, CursorMode, uint32_t)
{
TRACE();
diff --git a/src/kranewl/tree/output.cc b/src/kranewl/tree/output.cc
@@ -22,12 +22,16 @@ Output::Output(
Server_ptr server,
Model_ptr model,
struct wlr_output* wlr_output,
- struct wlr_scene_output* wlr_scene_output
+ struct wlr_scene_output* wlr_scene_output,
+ Region const&& output_region
)
: Node(this),
mp_context(nullptr),
+ m_full_region(output_region),
+ m_placeable_region(output_region),
mp_server(server),
mp_model(model),
+ m_dirty(true),
mp_wlr_output(wlr_output),
mp_wlr_scene_output(wlr_scene_output),
m_subpixel(wlr_output->subpixel),
diff --git a/src/kranewl/tree/view.cc b/src/kranewl/tree/view.cc
@@ -2,6 +2,7 @@
#include <kranewl/layers.hh>
#include <kranewl/server.hh>
+#include <kranewl/model.hh>
#include <kranewl/tree/view.hh>
#include <kranewl/tree/xdg_view.hh>
@@ -14,6 +15,8 @@ extern "C" {
#include <sys/types.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_scene.h>
+#include <wlr/util/box.h>
+#include <wlr/util/edges.h>
}
#undef static
#undef class
@@ -25,9 +28,6 @@ View::View(
Server_ptr server,
Model_ptr model,
Seat_ptr seat,
- Output_ptr output,
- Context_ptr context,
- Workspace_ptr workspace,
struct wlr_surface* wlr_surface,
void(*handle_foreign_activate_request)(wl_listener*, void*),
void(*handle_foreign_fullscreen_request)(wl_listener*, void*),
@@ -40,14 +40,15 @@ View::View(
mp_server(server),
mp_model(model),
mp_seat(seat),
- mp_output(output),
- mp_context(context),
- mp_workspace(workspace),
+ mp_output(nullptr),
+ mp_context(nullptr),
+ mp_workspace(nullptr),
mp_wlr_surface(wlr_surface),
m_alpha(1.f),
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({}),
@@ -85,9 +86,6 @@ View::View(
Server_ptr server,
Model_ptr model,
Seat_ptr seat,
- Output_ptr output,
- Context_ptr context,
- Workspace_ptr workspace,
struct wlr_surface* wlr_surface,
void(*handle_foreign_activate_request)(wl_listener*, void*),
void(*handle_foreign_fullscreen_request)(wl_listener*, void*),
@@ -100,9 +98,6 @@ View::View(
mp_server(server),
mp_model(model),
mp_seat(seat),
- mp_output(output),
- mp_context(context),
- mp_workspace(workspace),
mp_wlr_surface(wlr_surface),
ml_foreign_activate_request({ .notify = handle_foreign_activate_request }),
ml_foreign_fullscreen_request({ .notify = handle_foreign_fullscreen_request }),
@@ -120,23 +115,25 @@ set_view_pid(View_ptr view)
{
switch (view->m_type) {
case View::Type::XDGShell:
- {
- pid_t pid;
- struct wl_client* client
- = wl_resource_get_client(view->mp_wlr_surface->resource);
-
- wl_client_get_credentials(client, &pid, NULL, NULL);
- view->m_pid = pid;
- }
+ {
+ pid_t pid;
+ struct wl_client* client
+ = wl_resource_get_client(view->mp_wlr_surface->resource);
+
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+ view->m_pid = pid;
+
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;
- }
+ {
+ struct wlr_xwayland_surface* wlr_xwayland_surface
+ = wlr_xwayland_surface_from_wlr_surface(view->mp_wlr_surface);
+ view->m_pid = wlr_xwayland_surface->pid;
+
break;
+ }
#endif
default: break;
}
@@ -153,6 +150,9 @@ View::map_view(
{
TRACE();
+ Server_ptr server = view->mp_server;
+ Model_ptr model = view->mp_model;
+
view->mp_wlr_surface = wlr_surface;
set_view_pid(view);
@@ -165,9 +165,120 @@ View::map_view(
: wlr_scene_subsurface_tree_create(view->mp_scene, view->mp_wlr_surface);
view->mp_scene_surface->data = view;
+ wlr_scene_node_reparent(
+ view->mp_scene,
+ server->m_layers[view->m_floating ? Layer::Free : Layer::Tile]
+ );
+
+ // TODO: globalize
+ static const float border_rgba[4] = {0.5, 0.5, 0.5, 1.0};
+
+ for (std::size_t i = 0; i < 4; ++i) {
+ view->m_protrusions[i] = wlr_scene_rect_create(view->mp_scene, 0, 0, border_rgba);
+ view->m_protrusions[i]->node.data = view;
+ wlr_scene_rect_set_color(view->m_protrusions[i], border_rgba);
+ wlr_scene_node_lower_to_bottom(&view->m_protrusions[i]->node);
+ }
+
if (fullscreen_output && fullscreen_output->data) {
Output_ptr output = reinterpret_cast<Output_ptr>(fullscreen_output->data);
}
+
+ model->move_view_to_focused_output(view);
+}
+
+
+void
+View::unmap_view(View_ptr view)
+{
+ TRACE();
+
+ wlr_scene_node_destroy(view->mp_scene);
+}
+
+static uint32_t
+extents_to_wlr_edges(Extents const& extents)
+{
+ uint32_t wlr_edges = WLR_EDGE_NONE;
+
+ if (extents.top)
+ wlr_edges |= WLR_EDGE_TOP;
+
+ if (extents.bottom)
+ wlr_edges |= WLR_EDGE_BOTTOM;
+
+ if (extents.left)
+ wlr_edges |= WLR_EDGE_LEFT;
+
+ if (extents.right)
+ wlr_edges |= WLR_EDGE_RIGHT;
+
+ return wlr_edges;
+}
+
+uint32_t
+View::free_decoration_to_wlr_edges() const
+{
+ return extents_to_wlr_edges(m_free_decoration.extents());
+}
+
+uint32_t
+View::tile_decoration_to_wlr_edges() const
+{
+ return extents_to_wlr_edges(m_tile_decoration.extents());
+}
+
+void
+View::set_free_region(Region const& region)
+{
+ m_free_region = region;
+ set_active_region(region);
+}
+
+void
+View::set_tile_region(Region const& region)
+{
+ m_tile_region = region;
+ set_active_region(region);
+}
+
+void
+View::set_free_decoration(Decoration const& decoration)
+{
+ m_free_decoration = decoration;
+ m_active_decoration = decoration;
+}
+
+void
+View::set_tile_decoration(Decoration const& decoration)
+{
+ m_tile_decoration = decoration;
+ m_active_decoration = decoration;
+}
+
+void
+View::set_active_region(Region const& region)
+{
+ m_previous_region = m_active_region;
+ set_inner_region(region);
+ m_active_region = region;
+}
+
+void
+View::set_inner_region(Region const& region)
+{
+ if (m_active_decoration.frame) {
+ Frame const& frame = *m_active_decoration.frame;
+
+ m_inner_region.pos.x = frame.extents.left;
+ m_inner_region.pos.y = frame.extents.top;
+ m_inner_region.dim.w = region.dim.w - frame.extents.left - frame.extents.right;
+ m_inner_region.dim.h = region.dim.h - frame.extents.top - frame.extents.bottom;
+ } else {
+ m_inner_region.pos.x = 0;
+ m_inner_region.pos.y = 0;
+ m_inner_region.dim = region.dim;
+ }
}
ViewChild::ViewChild(SubsurfaceViewChild_ptr)
diff --git a/src/kranewl/tree/xdg_view.cc b/src/kranewl/tree/xdg_view.cc
@@ -1,20 +1,28 @@
#include <trace.hh>
+#include <kranewl/layers.hh>
+#include <kranewl/server.hh>
#include <kranewl/tree/view.hh>
#include <kranewl/tree/xdg_view.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_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
}
+#undef static
+#undef class
+#undef namespace
XDGView::XDGView(
struct wlr_xdg_surface* wlr_xdg_surface,
Server_ptr server,
Model_ptr model,
- Seat_ptr seat,
- Output_ptr output,
- Context_ptr context,
- Workspace_ptr workspace
+ Seat_ptr seat
)
: View(
this,
@@ -22,9 +30,6 @@ XDGView::XDGView(
server,
model,
seat,
- output,
- context,
- workspace,
wlr_xdg_surface->surface,
XDGView::handle_foreign_activate_request,
XDGView::handle_foreign_fullscreen_request,
@@ -143,6 +148,7 @@ XDGView::handle_map(struct wl_listener* listener, void* data)
TRACE();
XDGView_ptr view = wl_container_of(listener, view, ml_map);
+ 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;
@@ -156,6 +162,40 @@ XDGView::handle_map(struct wl_listener* listener, void* data)
view->m_preferred_dim.h = wlr_xdg_toplevel->base->surface->current.height;
}
+ 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;
+
+ view->set_free_region(Region{
+ .pos = {0, 0},
+ .dim = view->m_preferred_dim
+ });
+
+ view->set_tile_region(Region{
+ .pos = {0, 0},
+ .dim = view->m_preferred_dim
+ });
+
+ view->m_app_id = wlr_xdg_toplevel->app_id
+ ? std::string(wlr_xdg_toplevel->app_id)
+ : "N/a";
+ view->m_title = wlr_xdg_toplevel->title
+ ? std::string(wlr_xdg_toplevel->title)
+ : "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_view(
view,
wlr_xdg_toplevel->base->surface,
@@ -164,6 +204,12 @@ XDGView::handle_map(struct wl_listener* listener, void* data)
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()
+ );
+
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);
@@ -178,6 +224,9 @@ XDGView::handle_unmap(struct wl_listener* listener, void* data)
{
TRACE();
+ XDGView_ptr view = wl_container_of(listener, view, ml_unmap);
+
+ View::unmap_view(view);
}
void
@@ -185,4 +234,15 @@ XDGView::handle_destroy(struct wl_listener* listener, void* data)
{
TRACE();
+ XDGView_ptr view = wl_container_of(listener, view, ml_destroy);
+
+ view->mp_model->unregister_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);
+ wl_list_remove(&view->ml_request_move.link);
+ wl_list_remove(&view->ml_request_resize.link);
+ wl_list_remove(&view->ml_set_title.link);
+ wl_list_remove(&view->ml_set_app_id.link);
}
diff --git a/src/kranewl/tree/xwayland_view.cc b/src/kranewl/tree/xwayland_view.cc
@@ -20,10 +20,7 @@ XWaylandView::XWaylandView(
struct wlr_xwayland_surface* wlr_xwayland_surface,
Server_ptr server,
Model_ptr model,
- Seat_ptr seat,
- Output_ptr output,
- Context_ptr context,
- Workspace_ptr workspace
+ Seat_ptr seat
)
: View(
this,
@@ -31,9 +28,6 @@ XWaylandView::XWaylandView(
server,
model,
seat,
- output,
- context,
- workspace,
wlr_xwayland_surface->surface,
XWaylandView::handle_foreign_activate_request,
XWaylandView::handle_foreign_fullscreen_request,
diff --git a/src/kranewl/workspace.cc b/src/kranewl/workspace.cc
@@ -1,3 +1,5 @@
+#include <trace.hh>
+
#include <kranewl/workspace.hh>
#include <kranewl/context.hh>
@@ -464,6 +466,8 @@ Workspace::set_layout(LayoutHandler::LayoutKind layout)
std::vector<Placement>
Workspace::arrange(Region region) const
{
+ TRACE();
+
std::deque<View_ptr> views = m_views.as_deque();
std::vector<Placement> placements;
placements.reserve(views.size());