commit b610179a4d714cfefb7af519dc8be3349f80954e
parent 9884692d54433f5fca0c3dcb77bc4df01116c608
Author: deurzen <max@deurzen.net>
Date: Tue, 31 May 2022 10:29:32 +0200
adds xwayland shell {,un}mapping functionality
Diffstat:
18 files changed, 842 insertions(+), 205 deletions(-)
diff --git a/include/kranewl/input/cursor.hh b/include/kranewl/input/cursor.hh
@@ -5,6 +5,7 @@
extern "C" {
#include <linux/input-event-codes.h>
#include <wlr/backend.h>
+#include <wlr/util/edges.h>
#include <xkbcommon/xkbcommon.h>
}
@@ -39,6 +40,7 @@ struct CursorInput {
typedef class Server* Server_ptr;
typedef class Seat* Seat_ptr;
typedef struct View* View_ptr;
+typedef struct Node* Node_ptr;
typedef struct Cursor {
enum class Mode {
@@ -58,7 +60,9 @@ typedef struct Cursor {
~Cursor();
View_ptr view_under_cursor() const;
+ Node_ptr node_under_cursor() const;
+ void initiate_cursor_interactive(Mode, View_ptr, uint32_t);
void initiate_cursor_interactive(Mode, View_ptr);
void abort_cursor_interactive();
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -27,6 +27,7 @@ typedef struct XWayland* XWayland_ptr;
typedef struct XDGView* XDGView_ptr;
#ifdef XWAYLAND
typedef struct XWaylandView* XWaylandView_ptr;
+typedef struct XWaylandUnmanaged* XWaylandUnmanaged_ptr;
#endif
class Config;
@@ -54,7 +55,17 @@ public:
XDGView_ptr create_xdg_shell_view(struct wlr_xdg_surface*, Seat_ptr);
#ifdef XWAYLAND
- XWaylandView_ptr create_xwayland_view(struct wlr_xwayland_surface*, Seat_ptr, XWayland_ptr);
+ XWaylandView_ptr create_xwayland_view(
+ struct wlr_xwayland_surface*,
+ Seat_ptr,
+ XWayland_ptr
+ );
+
+ XWaylandUnmanaged_ptr create_xwayland_unmanaged(
+ struct wlr_xwayland_surface*,
+ Seat_ptr,
+ XWayland_ptr
+ );
#endif
void register_view(View_ptr, Workspace_ptr);
void unregister_view(View_ptr);
@@ -191,11 +202,11 @@ private:
Workspace_ptr mp_prev_workspace;
std::unordered_map<Uid, View_ptr> m_view_map;
+ std::unordered_map<Uid, Node_ptr> m_unmanaged_map;
std::unordered_map<pid_t, View_ptr> m_pid_map;
std::unordered_map<View_ptr, Region> m_fullscreen_map;
std::vector<View_ptr> m_sticky_views;
- std::vector<View_ptr> m_unmanaged_views;
View_ptr mp_focus;
diff --git a/include/kranewl/tree/layer.hh b/include/kranewl/tree/layer.hh
@@ -13,19 +13,25 @@ extern "C" {
typedef class Server* Server_ptr;
typedef class Model* Model_ptr;
+typedef class Seat* Seat_ptr;
typedef class Output* Output_ptr;
-typedef struct Layer : public Node {
+typedef struct Layer final : public Node {
Layer(
struct wlr_layer_surface_v1*,
Server_ptr,
Model_ptr,
+ Seat_ptr,
Output_ptr,
SceneLayer
);
~Layer();
+ void format_uid() override;
+
+ pid_t pid();
+
static void handle_map(struct wl_listener*, void*);
static void handle_unmap(struct wl_listener*, void*);
static void handle_surface_commit(struct wl_listener*, void*);
@@ -37,11 +43,9 @@ typedef struct Layer : public Node {
Region const& region() { return m_region; }
void set_region(Region const&);
- Uid m_uid;
- std::string m_uid_formatted;
-
Server_ptr mp_server;
Model_ptr mp_model;
+ Seat_ptr mp_seat;
Output_ptr mp_output;
diff --git a/include/kranewl/tree/node.hh b/include/kranewl/tree/node.hh
@@ -1,5 +1,10 @@
#pragma once
+#include <kranewl/common.hh>
+
+#include <string>
+#include <sstream>
+
typedef struct Node {
enum class Type {
XDGShell,
@@ -10,7 +15,8 @@ typedef struct Node {
#endif
};
- virtual bool is_focusable() const
+ virtual bool
+ is_focusable() const
{
#ifdef XWAYLAND
return m_type == Type::XDGShell
@@ -20,14 +26,38 @@ typedef struct Node {
#endif
}
+ virtual bool
+ is_view() const
+ {
+#ifdef XWAYLAND
+ return m_type != Type::LayerShell
+ && m_type != Type::XWaylandUnmanaged;
+#else
+ return m_type != Type::LayerShell;
+#endif
+ }
+
+ virtual Uid uid() const { return m_uid; }
+ virtual std::string const& uid_formatted() const { return m_uid_formatted; }
+
+ virtual void format_uid() = 0;
+
protected:
- Node(Type type)
- : m_type(type)
+ Node(Type type, Uid uid)
+ : m_type(type),
+ m_uid(uid),
+ m_uid_formatted([uid]() {
+ std::stringstream uid_ss;
+ uid_ss << "0x" << std::hex << uid;
+ return uid_ss.str();
+ }())
{}
~Node()
{}
Type m_type;
+ Uid m_uid;
+ std::string m_uid_formatted;
}* Node_ptr;
diff --git a/include/kranewl/tree/output.hh b/include/kranewl/tree/output.hh
@@ -24,6 +24,7 @@ public:
Output(
Server_ptr,
Model_ptr,
+ Seat_ptr,
struct wlr_output*,
struct wlr_scene_output*,
Region const&&
@@ -67,6 +68,7 @@ private:
public:
Server_ptr mp_server;
Model_ptr mp_model;
+ Seat_ptr mp_seat;
bool m_dirty;
diff --git a/include/kranewl/tree/view.hh b/include/kranewl/tree/view.hh
@@ -61,21 +61,19 @@ typedef struct View : public Node {
virtual ~View();
+ void format_uid() override;
+
virtual Region constraints() = 0;
virtual pid_t pid() = 0;
virtual bool prefers_floating() = 0;
- virtual View_ptr is_transient_for() = 0;
virtual void focus(Toggle) = 0;
virtual void activate(Toggle) = 0;
- virtual void set_tiled(Toggle) = 0;
virtual void set_fullscreen(Toggle) = 0;
- virtual void set_resizing(Toggle) = 0;
virtual void configure(Region const&, Extents const&, bool) = 0;
virtual void close() = 0;
virtual void close_popups() = 0;
- virtual void destroy() = 0;
void map();
void unmap();
@@ -125,6 +123,7 @@ typedef struct View : public Node {
Pos const& free_pos() const { return m_free_region.pos; }
Region const& tile_region() const { return m_tile_region; }
Region const& active_region() const { return m_active_region; }
+ Region const& inner_region() const { return m_inner_region; }
Region const& prev_region() const { return m_prev_region; }
void set_free_region(Region const&);
void set_free_pos(Pos const&);
@@ -141,21 +140,16 @@ typedef struct View : public Node {
void set_tile_decoration(Decoration const&);
void touch() { m_last_touched = std::chrono::steady_clock::now(); }
- void format_uid();
static bool
is_free(View_ptr view)
{
return (view->m_floating && (!view->m_fullscreen || view->m_contained))
- || view->m_disowned
- || !view->m_managed;
+ || view->m_disowned;
}
OutsideState outside_state() const;
- Uid m_uid;
- std::string m_uid_formatted;
-
Server_ptr mp_server;
Model_ptr mp_model;
Seat_ptr mp_seat;
diff --git a/include/kranewl/tree/xdg-view.hh b/include/kranewl/tree/xdg-view.hh
@@ -25,18 +25,14 @@ typedef struct XDGView final : public View {
Region constraints() override;
pid_t pid() override;
bool prefers_floating() override;
- View_ptr is_transient_for() override;
void focus(Toggle) override;
void activate(Toggle) override;
- void set_tiled(Toggle) override;
void set_fullscreen(Toggle) override;
- void set_resizing(Toggle) override;
void configure(Region const&, Extents const&, bool) override;
void close() override;
void close_popups() override;
- void destroy() override;
static void handle_commit(struct wl_listener*, void*);
static void handle_request_move(struct wl_listener*, void*);
diff --git a/include/kranewl/tree/xwayland-view.hh b/include/kranewl/tree/xwayland-view.hh
@@ -23,85 +23,105 @@ typedef struct XWaylandView final : public View {
~XWaylandView();
+ void format_uid() override;
+
Region constraints() override;
pid_t pid() override;
bool prefers_floating() override;
- View_ptr is_transient_for() override;
void focus(Toggle) override;
void activate(Toggle) override;
- void set_tiled(Toggle) override;
void set_fullscreen(Toggle) override;
- void set_resizing(Toggle) override;
void configure(Region const&, Extents const&, bool) override;
void close() override;
void close_popups() override;
- void destroy() override;
+ static void handle_map(struct wl_listener*, void*);
+ static void handle_unmap(struct wl_listener*, void*);
static void handle_commit(struct wl_listener*, void*);
- static void handle_request_move(struct wl_listener*, void*);
- static void handle_request_resize(struct wl_listener*, void*);
- static void handle_request_maximize(struct wl_listener*, void*);
- static void handle_request_minimize(struct wl_listener*, void*);
+ static void handle_request_activate(struct wl_listener*, void*);
static void handle_request_configure(struct wl_listener*, void*);
static void handle_request_fullscreen(struct wl_listener*, void*);
- static void handle_request_activate(struct wl_listener*, void*);
+ static void handle_request_minimize(struct wl_listener*, void*);
+ static void handle_request_maximize(struct wl_listener*, void*);
+ static void handle_request_move(struct wl_listener*, void*);
+ static void handle_request_resize(struct wl_listener*, void*);
+ static void handle_set_override_redirect(struct wl_listener*, void*);
static void handle_set_title(struct wl_listener*, void*);
static void handle_set_class(struct wl_listener*, void*);
- static void handle_set_role(struct wl_listener*, void*);
- static void handle_set_window_type(struct wl_listener*, void*);
static void handle_set_hints(struct wl_listener*, void*);
- static void handle_set_decorations(struct wl_listener*, void*);
- static void handle_map(struct wl_listener*, void*);
- static void handle_unmap(struct wl_listener*, void*);
static void handle_destroy(struct wl_listener*, void*);
- static void handle_override_redirect(struct wl_listener*, void*);
XWayland_ptr mp_xwayland;
+ std::string m_class;
+ std::string m_instance;
+
struct wlr_xwayland_surface* mp_wlr_xwayland_surface;
+ struct wl_listener ml_map;
+ struct wl_listener ml_unmap;
struct wl_listener ml_commit;
- struct wl_listener ml_request_move;
- struct wl_listener ml_request_resize;
- struct wl_listener ml_request_maximize;
- struct wl_listener ml_request_minimize;
+ struct wl_listener ml_request_activate;
struct wl_listener ml_request_configure;
struct wl_listener ml_request_fullscreen;
- struct wl_listener ml_request_activate;
+ struct wl_listener ml_request_minimize;
+ struct wl_listener ml_request_maximize;
+ struct wl_listener ml_request_move;
+ struct wl_listener ml_request_resize;
+ struct wl_listener ml_set_override_redirect;
struct wl_listener ml_set_title;
struct wl_listener ml_set_class;
- struct wl_listener ml_set_role;
- struct wl_listener ml_set_window_type;
struct wl_listener ml_set_hints;
- struct wl_listener ml_set_decorations;
- struct wl_listener ml_map;
- struct wl_listener ml_unmap;
struct wl_listener ml_destroy;
- struct wl_listener ml_override_redirect;
}* XWaylandView_ptr;
-typedef struct XWaylandUnmanaged final {
- XWaylandUnmanaged(struct wlr_xwayland_surface*, XWayland_ptr);
+typedef struct XWaylandUnmanaged final : public Node {
+ XWaylandUnmanaged(
+ struct wlr_xwayland_surface*,
+ Server_ptr,
+ Model_ptr,
+ Seat_ptr,
+ XWayland_ptr
+ );
+
~XWaylandUnmanaged();
+ void format_uid() override;
+
+ static void handle_map(struct wl_listener*, void*);
+ static void handle_unmap(struct wl_listener*, void*);
+ static void handle_commit(struct wl_listener*, void*);
+ static void handle_set_override_redirect(struct wl_listener*, void*);
+ static void handle_set_geometry(struct wl_listener*, void*);
+ static void handle_request_activate(struct wl_listener*, void*);
+ static void handle_request_configure(struct wl_listener*, void*);
+ static void handle_request_fullscreen(struct wl_listener*, void*);
+ static void handle_destroy(struct wl_listener*, void*);
+
+ Server_ptr mp_server;
+ Model_ptr mp_model;
+ Seat_ptr mp_seat;
+
+ Output_ptr mp_output;
+
XWayland_ptr mp_xwayland;
- Pos m_pos;
+ Region m_region;
struct wlr_xwayland_surface* mp_wlr_xwayland_surface;
+ struct wl_listener ml_map;
+ struct wl_listener ml_unmap;
+ struct wl_listener ml_commit;
+ struct wl_listener ml_set_override_redirect;
+ struct wl_listener ml_set_geometry;
struct wl_listener ml_request_activate;
struct wl_listener ml_request_configure;
struct wl_listener ml_request_fullscreen;
- struct wl_listener ml_commit;
- struct wl_listener ml_set_geometry;
- struct wl_listener ml_map;
- struct wl_listener ml_unmap;
struct wl_listener ml_destroy;
- struct wl_listener ml_override_redirect;
}* XWaylandUnmanaged_ptr;
#endif
diff --git a/include/kranewl/xwayland.hh b/include/kranewl/xwayland.hh
@@ -11,6 +11,8 @@ extern "C" {
#include <array>
typedef class Server* Server_ptr;
+typedef class Model* Model_ptr;
+typedef class Seat* Seat_ptr;
typedef struct XWayland final {
enum XAtom {
@@ -28,7 +30,13 @@ typedef struct XWayland final {
XATOM_LAST,
};
- XWayland(struct wlr_xwayland*, Server_ptr);
+ XWayland(
+ struct wlr_xwayland*,
+ Server_ptr,
+ Model_ptr,
+ Seat_ptr
+ );
+
~XWayland();
static void handle_ready(struct wl_listener*, void*);
@@ -40,6 +48,8 @@ typedef struct XWayland final {
std::array<xcb_atom_t, XATOM_LAST> m_atoms;
Server_ptr mp_server;
+ Model_ptr mp_model;
+ Seat_ptr mp_seat;
struct wl_listener ml_ready;
struct wl_listener ml_new_surface;
diff --git a/src/kranewl/input/cursor.cc b/src/kranewl/input/cursor.cc
@@ -72,8 +72,8 @@ Cursor::~Cursor()
}
-static inline View_ptr
-view_at(
+static inline Node_ptr
+node_at(
Server_ptr server,
double lx, double ly,
struct wlr_surface** surface,
@@ -99,8 +99,8 @@ view_at(
while (node && !node->data)
node = node->parent;
- if (node && node->data && static_cast<Node_ptr>(node->data)->is_focusable())
- return reinterpret_cast<View_ptr>(node->data);
+ if (node && node->data)
+ return reinterpret_cast<Node_ptr>(node->data);
return nullptr;
}
@@ -109,6 +109,39 @@ view_at(
return nullptr;
}
+static inline View_ptr
+view_at(
+ Server_ptr server,
+ double lx, double ly,
+ struct wlr_surface** surface,
+ double* sx, double* sy
+)
+{
+ Node_ptr node = node_at(server, lx, ly, surface, sx, sy);
+
+ if (node && node->is_view())
+ return reinterpret_cast<View_ptr>(node);
+
+ return nullptr;
+}
+
+Node_ptr
+Cursor::node_under_cursor() const
+{
+ double sx, sy;
+ struct wlr_surface* surface = nullptr;
+
+ Node_ptr node = node_at(
+ mp_server,
+ mp_wlr_cursor->x,
+ mp_wlr_cursor->y,
+ &surface,
+ &sx, &sy
+ );
+
+ return node;
+}
+
View_ptr
Cursor::view_under_cursor() const
{
@@ -127,6 +160,62 @@ Cursor::view_under_cursor() const
}
void
+Cursor::initiate_cursor_interactive(
+ Mode mode,
+ View_ptr view,
+ uint32_t edges
+)
+{
+ TRACE();
+
+ m_grab_state = {
+ .view = view,
+ .x = mp_wlr_cursor->x,
+ .y = mp_wlr_cursor->y,
+ .region = view->free_region(),
+ .edges = edges
+ };
+
+ switch (mode) {
+ case Mode::Move:
+ {
+ wlr_xcursor_manager_set_cursor_image(
+ mp_cursor_manager,
+ "grab",
+ mp_wlr_cursor
+ );
+ break;
+ }
+ case Mode::Resize:
+ {
+ char const* cursor;
+ if ((edges & WLR_EDGE_LEFT)) {
+ if ((edges & WLR_EDGE_TOP))
+ cursor = "top_left_corner";
+ else
+ cursor = "bottom_left_corner";
+ } else {
+ if ((edges & WLR_EDGE_TOP))
+ cursor = "top_right_corner";
+ else
+ cursor = "bottom_right_corner";
+ }
+
+ wlr_xcursor_manager_set_cursor_image(
+ mp_cursor_manager,
+ cursor,
+ mp_wlr_cursor
+ );
+
+ break;
+ }
+ default: break;
+ }
+
+ m_cursor_mode = mode;
+}
+
+void
Cursor::initiate_cursor_interactive(Mode mode, View_ptr view)
{
TRACE();
@@ -144,7 +233,7 @@ Cursor::initiate_cursor_interactive(Mode mode, View_ptr view)
{
wlr_xcursor_manager_set_cursor_image(
mp_cursor_manager,
- "fleur",
+ "grab",
mp_wlr_cursor
);
break;
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -51,10 +51,10 @@ Model::Model(
mp_prev_context{nullptr},
mp_prev_workspace{nullptr},
m_view_map{},
+ m_unmanaged_map{},
m_pid_map{},
m_fullscreen_map{},
m_sticky_views{},
- m_unmanaged_views{},
mp_focus(nullptr),
m_key_bindings(Bindings::key_bindings),
m_cursor_bindings(Bindings::cursor_bindings)
@@ -177,6 +177,7 @@ Model::create_output(
Output_ptr output = new Output(
mp_server,
this,
+ &mp_server->m_seat,
wlr_output,
wlr_scene_output,
std::forward<Region const&&>(output_region)
@@ -339,7 +340,7 @@ Model::place_view(Placement& placement)
spdlog::info(
"Placing view {} at {}",
- view->m_uid_formatted,
+ view->uid_formatted(),
std::to_string(view->active_region())
);
@@ -1814,7 +1815,7 @@ Model::create_xdg_shell_view(
seat
);
- m_view_map[view->m_uid] = view;
+ m_view_map[view->uid()] = view;
return view;
}
@@ -1837,10 +1838,32 @@ Model::create_xwayland_view(
xwayland
);
- m_view_map[view->m_uid] = view;
+ m_view_map[view->uid()] = view;
return view;
}
+
+XWaylandUnmanaged_ptr
+Model::create_xwayland_unmanaged(
+ struct wlr_xwayland_surface* wlr_xwayland_surface,
+ Seat_ptr seat,
+ XWayland_ptr xwayland
+)
+{
+ TRACE();
+
+ XWaylandUnmanaged_ptr node = new XWaylandUnmanaged(
+ wlr_xwayland_surface,
+ mp_server,
+ this,
+ seat,
+ xwayland
+ );
+
+ m_unmanaged_map[node->uid()] = node;
+
+ return node;
+}
#endif
void
@@ -1850,7 +1873,7 @@ Model::register_view(View_ptr view, Workspace_ptr workspace)
view->format_uid();
move_view_to_workspace(view, workspace);
- spdlog::info("Registered view {}", view->m_uid_formatted);
+ spdlog::info("Registered view {}", view->uid_formatted());
sync_focus();
}
@@ -1864,7 +1887,7 @@ Model::unregister_view(View_ptr view)
apply_layout(view->mp_workspace);
}
- spdlog::info("Unregistered view {}", view->m_uid_formatted);
+ spdlog::info("Unregistered view {}", view->uid_formatted());
mp_output->focus_at_cursor();
sync_focus();
}
@@ -1874,8 +1897,8 @@ Model::destroy_view(View_ptr view)
{
TRACE();
- m_view_map.erase(view->m_uid);
- spdlog::info("Destroyed view {}", view->m_uid_formatted);
+ m_view_map.erase(view->uid());
+ spdlog::info("Destroyed view {}", view->uid_formatted());
delete view;
}
@@ -1892,6 +1915,7 @@ Model::create_layer(
layer_surface,
mp_server,
this,
+ &mp_server->m_seat,
output,
scene_layer
);
@@ -1905,7 +1929,7 @@ Model::register_layer(Layer_ptr layer)
TRACE();
layer->mp_output->add_layer(layer);
- spdlog::info("Registered layer {}", layer->m_uid_formatted);
+ spdlog::info("Registered layer {}", layer->uid_formatted());
}
bool
diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc
@@ -132,7 +132,7 @@ Server::Server(Model_ptr model)
}()),
#ifdef XWAYLAND
mp_wlr_xwayland(wlr_xwayland_create(mp_display, mp_compositor, true)),
- m_xwayland({mp_wlr_xwayland, this}),
+ m_xwayland({mp_wlr_xwayland, this, model, &m_seat}),
#endif
mp_layer_shell(wlr_layer_shell_v1_create(mp_display)),
mp_xdg_shell(wlr_xdg_shell_create(mp_display)),
@@ -433,13 +433,6 @@ Server::handle_new_layer_shell_surface(struct wl_listener* listener, void* data)
layer_surface->surface
);
layer->mp_scene->data = layer;
-
- server->mp_model->register_layer(layer);
-
- struct wlr_layer_surface_v1_state initial_state = layer_surface->current;
- layer_surface->current = layer_surface->pending;
- output->arrange_layers();
- layer_surface->current = initial_state;
}
void
diff --git a/src/kranewl/tree/layer.cc b/src/kranewl/tree/layer.cc
@@ -23,18 +23,14 @@ Layer::Layer(
struct wlr_layer_surface_v1* layer_surface,
Server_ptr server,
Model_ptr model,
+ Seat_ptr seat,
Output_ptr output,
SceneLayer scene_layer
)
- : Node(Type::LayerShell),
- m_uid(reinterpret_cast<std::uintptr_t>(layer_surface)),
- m_uid_formatted([this]() {
- std::stringstream uid_ss;
- uid_ss << "0x" << std::hex << m_uid;
- return uid_ss.str();
- }()),
+ : Node(Type::LayerShell, reinterpret_cast<std::uintptr_t>(layer_surface)),
mp_server(server),
mp_model(model),
+ mp_seat(seat),
mp_output(output),
m_scene_layer(scene_layer),
mp_layer_surface(layer_surface),
@@ -55,6 +51,29 @@ Layer::~Layer()
{}
void
+Layer::format_uid()
+{
+ std::stringstream uid_ss;
+ uid_ss << "0x" << std::hex << uid() << std::dec;
+ uid_ss << " [" << m_pid << "]";
+ uid_ss << " (L)";
+ m_uid_formatted = uid_ss.str();
+}
+
+pid_t
+Layer::pid()
+{
+ TRACE();
+
+ pid_t pid;
+ struct wl_client* client
+ = wl_resource_get_client(mp_layer_surface->surface->resource);
+
+ wl_client_get_credentials(client, &pid, nullptr, nullptr);
+ return pid;
+}
+
+void
Layer::set_mapped(bool mapped)
{
m_mapped = mapped;
@@ -73,13 +92,23 @@ Layer::handle_map(struct wl_listener* listener, void*)
Layer_ptr layer = wl_container_of(listener, layer, ml_map);
+ layer->m_pid = layer->pid();
+ layer->format_uid();
+
+ layer->mp_model->register_layer(layer);
+
+ struct wlr_layer_surface_v1_state initial_state = layer->mp_layer_surface->current;
+ layer->mp_layer_surface->current = layer->mp_layer_surface->pending;
+ layer->mp_output->arrange_layers();
+ layer->mp_layer_surface->current = initial_state;
+
wlr_surface_send_enter(
layer->mp_layer_surface->surface,
layer->mp_layer_surface->output
);
- if (layer->mp_server->m_seat.mp_cursor)
- layer->mp_server->m_seat.mp_cursor->process_cursor_motion(0);
+ if (layer->mp_seat->mp_cursor)
+ layer->mp_seat->mp_cursor->process_cursor_motion(0);
}
static inline void
@@ -88,13 +117,13 @@ unmap_layer(Layer_ptr layer)
TRACE();
layer->mp_layer_surface->mapped = 0;
- struct wlr_seat* seat = layer->mp_server->m_seat.mp_wlr_seat;
+ struct wlr_seat* seat = layer->mp_seat->mp_wlr_seat;
if (layer->mp_layer_surface->surface == seat->keyboard_state.focused_surface)
layer->mp_model->refocus();
- if (layer->mp_server->m_seat.mp_cursor)
- layer->mp_server->m_seat.mp_cursor->process_cursor_motion(0);
+ if (layer->mp_seat->mp_cursor)
+ layer->mp_seat->mp_cursor->process_cursor_motion(0);
}
void
diff --git a/src/kranewl/tree/output.cc b/src/kranewl/tree/output.cc
@@ -27,6 +27,7 @@ extern "C" {
Output::Output(
Server_ptr server,
Model_ptr model,
+ Seat_ptr seat,
struct wlr_output* wlr_output,
struct wlr_scene_output* wlr_scene_output,
Region const&& output_region
@@ -36,6 +37,7 @@ Output::Output(
m_placeable_region(output_region),
mp_server(server),
mp_model(model),
+ mp_seat(seat),
m_dirty(true),
m_cursor_focus_on_present(false),
m_layer_map{
@@ -98,7 +100,7 @@ Output::handle_present(struct wl_listener* listener, void*)
if (output->m_cursor_focus_on_present && output == output->mp_model->mp_output) {
if (true /* TODO: focus_follows_mouse */) {
View_ptr view_under_cursor
- = output->mp_server->m_seat.mp_cursor->view_under_cursor();
+ = output->mp_seat->mp_cursor->view_under_cursor();
if (view_under_cursor && view_under_cursor->managed())
output->mp_model->focus_view(view_under_cursor);
@@ -427,7 +429,7 @@ Output::arrange_layers()
Region placeable_region = m_full_region;
struct wlr_keyboard* keyboard
- = wlr_seat_get_keyboard(mp_server->m_seat.mp_wlr_seat);
+ = wlr_seat_get_keyboard(mp_seat->mp_wlr_seat);
// exclusive surfaces
for (SceneLayer scene_layer : scene_layers_top_bottom)
@@ -452,7 +454,7 @@ Output::arrange_layers()
if (keyboard)
wlr_seat_keyboard_notify_enter(
- mp_server->m_seat.mp_wlr_seat,
+ mp_seat->mp_wlr_seat,
layer->mp_layer_surface->surface,
keyboard->keycodes,
keyboard->num_keycodes,
@@ -460,7 +462,7 @@ Output::arrange_layers()
);
else
wlr_seat_keyboard_notify_enter(
- mp_server->m_seat.mp_wlr_seat,
+ mp_seat->mp_wlr_seat,
layer->mp_layer_surface->surface,
nullptr,
0,
diff --git a/src/kranewl/tree/view.cc b/src/kranewl/tree/view.cc
@@ -30,13 +30,7 @@ View::View(
Seat_ptr seat,
struct wlr_surface* wlr_surface
)
- : Node(Type::XDGShell),
- m_uid(uid),
- m_uid_formatted([uid]() {
- std::stringstream uid_ss;
- uid_ss << "0x" << std::hex << uid;
- return uid_ss.str();
- }()),
+ : Node(Type::XDGShell, uid),
mp_server(server),
mp_model(model),
mp_seat(seat),
@@ -88,8 +82,7 @@ View::View(
Seat_ptr seat,
struct wlr_surface* wlr_surface
)
- : Node(Type::XWaylandManaged),
- m_uid(uid),
+ : Node(Type::XWaylandManaged, uid),
mp_server(server),
mp_model(model),
mp_seat(seat),
@@ -109,6 +102,7 @@ View::View(
m_active_region({}),
m_prev_region({}),
m_inner_region({}),
+ m_activated(false),
m_focused(false),
m_mapped(false),
m_managed(true),
@@ -125,7 +119,8 @@ View::View(
m_scene_layer(SCENE_LAYER_NONE),
m_last_focused(std::chrono::steady_clock::now()),
m_last_touched(std::chrono::steady_clock::now()),
- m_managed_since(std::chrono::steady_clock::now())
+ m_managed_since(std::chrono::steady_clock::now()),
+ m_outside_state(OutsideState::Unfocused)
{
wl_signal_init(&m_events.unmap);
}
@@ -512,10 +507,10 @@ void
View::format_uid()
{
std::stringstream uid_ss;
- uid_ss << "0x" << std::hex << m_uid << std::dec;
+ uid_ss << "0x" << std::hex << uid() << std::dec;
uid_ss << " [" << m_title;
uid_ss << ", " << m_pid << "]";
- uid_ss << " (" << (m_type == Type::XDGShell ? "W" : "X") << ")";
+ uid_ss << " (W)";
m_uid_formatted = uid_ss.str();
}
diff --git a/src/kranewl/tree/xdg-view.cc b/src/kranewl/tree/xdg-view.cc
@@ -90,13 +90,6 @@ XDGView::prefers_floating()
&& (state->min_width == state->max_width || state->min_height == state->max_height));
}
-View_ptr
-XDGView::is_transient_for()
-{
- TRACE();
-
-}
-
void
XDGView::focus(Toggle toggle)
{
@@ -111,6 +104,7 @@ XDGView::focus(Toggle toggle)
set_focused(true);
activate(toggle);
render_decoration();
+ raise();
break;
}
case Toggle::Off:
@@ -193,24 +187,10 @@ XDGView::activate(Toggle toggle)
}
void
-XDGView::set_tiled(Toggle)
-{
- TRACE();
-
-}
-
-void
XDGView::set_fullscreen(Toggle)
{
TRACE();
-
-}
-
-void
-XDGView::set_resizing(Toggle)
-{
- TRACE();
-
+ // TODO
}
void
@@ -251,13 +231,6 @@ XDGView::close_popups()
}
void
-XDGView::destroy()
-{
- TRACE();
-
-}
-
-void
XDGView::handle_commit(struct wl_listener* listener, void* data)
{
TRACE();
@@ -295,7 +268,9 @@ XDGView::handle_set_title(struct wl_listener* listener, void* data)
TRACE();
XDGView_ptr view = wl_container_of(listener, view, ml_set_title);
- view->m_title = view->mp_wlr_xdg_toplevel->title;
+ view->m_title = view->mp_wlr_xdg_toplevel->title
+ ? view->mp_wlr_xdg_toplevel->title
+ : "N/a";
view->m_title_formatted = view->m_title;
view->format_uid();
}
@@ -327,6 +302,8 @@ XDGView::handle_map(struct wl_listener* listener, void* data)
Model_ptr model = view->mp_model;
view->m_pid = view->pid();
+ view->format_uid();
+
view->set_floating(view->prefers_floating());
struct wlr_xdg_surface* wlr_xdg_surface = view->mp_wlr_xdg_surface;
@@ -357,17 +334,13 @@ XDGView::handle_map(struct wl_listener* listener, void* data)
.pos = Pos{0, 0},
.dim = preferred_dim
});
-
- view->set_tile_region(Region{
- .pos = Pos{0, 0},
- .dim = preferred_dim
- });
+ view->set_tile_region(view->free_region());
view->m_app_id = wlr_xdg_toplevel->app_id
- ? std::string(wlr_xdg_toplevel->app_id)
+ ? wlr_xdg_toplevel->app_id
: "N/a";
view->m_title = wlr_xdg_toplevel->title
- ? std::string(wlr_xdg_toplevel->title)
+ ? wlr_xdg_toplevel->title
: "N/a";
view->m_title_formatted = view->m_title; // TODO: format title
diff --git a/src/kranewl/tree/xwayland-view.cc b/src/kranewl/tree/xwayland-view.cc
@@ -1,8 +1,14 @@
#ifdef XWAYLAND
#include <trace.hh>
+#include <kranewl/context.hh>
+#include <kranewl/model.hh>
+#include <kranewl/scene-layer.hh>
+#include <kranewl/server.hh>
+#include <kranewl/tree/output.hh>
#include <kranewl/tree/view.hh>
#include <kranewl/tree/xwayland-view.hh>
+#include <kranewl/workspace.hh>
// https://github.com/swaywm/wlroots/issues/682
#include <pthread.h>
@@ -10,6 +16,10 @@
#define namespace namespace_
#define static
extern "C" {
+#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_idle_inhibit_v1.h>
+#include <wlr/types/wlr_layer_shell_v1.h>
+#include <wlr/types/wlr_scene.h>
#include <wlr/xwayland.h>
}
#undef static
@@ -33,29 +43,54 @@ XWaylandView::XWaylandView(
),
mp_xwayland(xwayland),
mp_wlr_xwayland_surface(wlr_xwayland_surface),
+ ml_map({ .notify = XWaylandView::handle_map }),
+ ml_unmap({ .notify = XWaylandView::handle_unmap }),
ml_commit({ .notify = XWaylandView::handle_commit }),
- ml_request_move({ .notify = XWaylandView::handle_request_move }),
- ml_request_resize({ .notify = XWaylandView::handle_request_resize }),
- ml_request_maximize({ .notify = XWaylandView::handle_request_maximize }),
- ml_request_minimize({ .notify = XWaylandView::handle_request_minimize }),
+ ml_request_activate({ .notify = XWaylandView::handle_request_activate }),
ml_request_configure({ .notify = XWaylandView::handle_request_configure }),
ml_request_fullscreen({ .notify = XWaylandView::handle_request_fullscreen }),
- ml_request_activate({ .notify = XWaylandView::handle_request_activate }),
+ ml_request_minimize({ .notify = XWaylandView::handle_request_minimize }),
+ ml_request_maximize({ .notify = XWaylandView::handle_request_maximize }),
+ ml_request_move({ .notify = XWaylandView::handle_request_move }),
+ ml_request_resize({ .notify = XWaylandView::handle_request_resize }),
+ ml_set_override_redirect({ .notify = XWaylandView::handle_set_override_redirect }),
ml_set_title({ .notify = XWaylandView::handle_set_title }),
ml_set_class({ .notify = XWaylandView::handle_set_class }),
- ml_set_role({ .notify = XWaylandView::handle_set_role }),
- ml_set_window_type({ .notify = XWaylandView::handle_set_window_type }),
ml_set_hints({ .notify = XWaylandView::handle_set_hints }),
- ml_set_decorations({ .notify = XWaylandView::handle_set_decorations }),
- ml_map({ .notify = XWaylandView::handle_map }),
- ml_unmap({ .notify = XWaylandView::handle_unmap }),
- ml_destroy({ .notify = XWaylandView::handle_destroy }),
- ml_override_redirect({ .notify = XWaylandView::handle_override_redirect })
-{}
+ ml_destroy({ .notify = XWaylandView::handle_destroy })
+{
+ wl_signal_add(&mp_wlr_xwayland_surface->events.map, &ml_map);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.unmap, &ml_unmap);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_activate, &ml_request_activate);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_configure, &ml_request_configure);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_fullscreen, &ml_request_fullscreen);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_minimize, &ml_request_minimize);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_maximize, &ml_request_maximize);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_move, &ml_request_move);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_resize, &ml_request_resize);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.set_override_redirect, &ml_set_override_redirect);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.set_title, &ml_set_title);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.set_class, &ml_set_class);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.set_hints, &ml_set_hints);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.destroy, &ml_destroy);
+}
XWaylandView::~XWaylandView()
{}
+void
+XWaylandView::format_uid()
+{
+ std::stringstream uid_ss;
+ uid_ss << "0x" << std::hex << uid() << std::dec;
+ uid_ss << " [" << m_title;
+ uid_ss << "; " << m_class;
+ uid_ss << "; " << m_instance;
+ uid_ss << ", " << m_pid << "]";
+ uid_ss << " (XM)";
+ m_uid_formatted = uid_ss.str();
+}
+
Region
XWaylandView::constraints()
{
@@ -67,10 +102,7 @@ pid_t
XWaylandView::pid()
{
TRACE();
-
- struct wlr_xwayland_surface* wlr_xwayland_surface
- = wlr_xwayland_surface_from_wlr_surface(mp_wlr_surface);
- return wlr_xwayland_surface->pid;
+ return mp_wlr_xwayland_surface->pid;
}
bool
@@ -78,212 +110,623 @@ XWaylandView::prefers_floating()
{
TRACE();
+ struct wlr_xwayland_surface* xwayland_surface = mp_wlr_xwayland_surface;
+
+ if (xwayland_surface->modal)
+ return true;
+
+ for (std::size_t i = 0; i < xwayland_surface->window_type_len; ++i) {
+ xcb_atom_t type = xwayland_surface->window_type[i];
+
+ if (type == mp_xwayland->m_atoms[XWayland::NET_WM_WINDOW_TYPE_DIALOG]
+ || type == mp_xwayland->m_atoms[XWayland::NET_WM_WINDOW_TYPE_UTILITY]
+ || type == mp_xwayland->m_atoms[XWayland::NET_WM_WINDOW_TYPE_TOOLBAR]
+ || type == mp_xwayland->m_atoms[XWayland::NET_WM_WINDOW_TYPE_SPLASH])
+ {
+ return true;
+ }
+ }
+
+ struct wlr_xwayland_surface_size_hints* size_hints = xwayland_surface->size_hints;
+ if (size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
+ && (size_hints->max_width == size_hints->min_width
+ || size_hints->max_height == size_hints->min_height))
+ {
+ return true;
+ }
+
+ return false;
}
-View_ptr
-XWaylandView::is_transient_for()
+void
+XWaylandView::focus(Toggle toggle)
{
TRACE();
+ switch (toggle) {
+ case Toggle::On:
+ {
+ if (focused())
+ return;
+
+ set_focused(true);
+ activate(toggle);
+ render_decoration();
+ raise();
+ break;
+ }
+ case Toggle::Off:
+ {
+ if (!focused())
+ return;
+
+ set_focused(false);
+ activate(toggle);
+ render_decoration();
+ break;
+ }
+ case Toggle::Reverse:
+ {
+ focus(
+ focused()
+ ? Toggle::Off
+ : Toggle::On
+ );
+ return;
+ }
+ default: break;
+ }
}
void
-XWaylandView::focus(Toggle)
+XWaylandView::activate(Toggle toggle)
{
TRACE();
+ switch (toggle) {
+ case Toggle::On:
+ {
+ if (activated())
+ return;
+
+ set_activated(true);
+
+ struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(mp_seat->mp_wlr_seat);
+ if (keyboard)
+ wlr_seat_keyboard_notify_enter(
+ mp_seat->mp_wlr_seat,
+ mp_wlr_surface,
+ keyboard->keycodes,
+ keyboard->num_keycodes,
+ &keyboard->modifiers
+ );
+ else
+ wlr_seat_keyboard_notify_enter(
+ mp_seat->mp_wlr_seat,
+ mp_wlr_surface,
+ nullptr,
+ 0,
+ nullptr
+ );
+
+ wlr_xwayland_surface_activate(mp_wlr_xwayland_surface, true);
+ wlr_xwayland_surface_restack(
+ mp_wlr_xwayland_surface,
+ nullptr,
+ XCB_STACK_MODE_ABOVE
+ );
+ break;
+ }
+ case Toggle::Off:
+ {
+ if (!activated())
+ return;
+
+ set_activated(false);
+ wlr_xwayland_surface_activate(mp_wlr_xwayland_surface, false);
+ break;
+ }
+ case Toggle::Reverse:
+ {
+ activate(
+ activated()
+ ? Toggle::Off
+ : Toggle::On
+ );
+ return;
+ }
+ default: break;
+ }
}
void
-XWaylandView::activate(Toggle)
+XWaylandView::set_fullscreen(Toggle)
{
TRACE();
-
+ // TODO
}
void
-XWaylandView::set_tiled(Toggle)
+XWaylandView::configure(Region const& region, Extents const& extents, bool interactive)
{
TRACE();
+ wlr_scene_node_set_position(mp_scene, region.pos.x, region.pos.y);
+ wlr_scene_node_set_position(mp_scene_surface, extents.left, extents.top);
+ wlr_scene_rect_set_size(m_protrusions[0], region.dim.w, extents.top);
+ wlr_scene_rect_set_size(m_protrusions[1], region.dim.w, extents.bottom);
+ wlr_scene_rect_set_size(m_protrusions[2], extents.left, region.dim.h - extents.top - extents.bottom);
+ wlr_scene_rect_set_size(m_protrusions[3], extents.right, region.dim.h - extents.top - extents.bottom);
+ wlr_scene_node_set_position(&m_protrusions[0]->node, 0, 0);
+ wlr_scene_node_set_position(&m_protrusions[1]->node, 0, region.dim.h - extents.bottom);
+ wlr_scene_node_set_position(&m_protrusions[2]->node, 0, extents.top);
+ wlr_scene_node_set_position(&m_protrusions[3]->node, region.dim.w - extents.right, extents.top);
+
+ wlr_xwayland_surface_configure(
+ mp_wlr_xwayland_surface,
+ region.pos.x,
+ region.pos.y,
+ region.dim.w - extents.left - extents.right,
+ region.dim.h - extents.top - extents.bottom
+ );
+
+ m_resize = 0;
}
void
-XWaylandView::set_fullscreen(Toggle)
+XWaylandView::close()
{
TRACE();
-
+ wlr_xwayland_surface_close(mp_wlr_xwayland_surface);
}
void
-XWaylandView::set_resizing(Toggle)
+XWaylandView::close_popups()
{
TRACE();
}
void
-XWaylandView::configure(Region const& region, Extents const& extents, bool interactive)
+XWaylandView::handle_map(struct wl_listener* listener, void* data)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_map);
+ Server_ptr server = view->mp_server;
+ Model_ptr model = view->mp_model;
+
+ view->m_pid = view->pid();
+ view->format_uid();
+
+ view->set_floating(view->prefers_floating());
+
+ struct wlr_xwayland_surface* xwayland_surface
+ = reinterpret_cast<struct wlr_xwayland_surface*>(data);
+ view->mp_wlr_surface = xwayland_surface->surface;
+
+ Dim preferred_dim = Dim{
+ .w = xwayland_surface->width,
+ .h = xwayland_surface->height,
+ };
+
+ Extents const& extents = view->free_decoration().extents();
+ preferred_dim.w += extents.left + extents.right;
+ preferred_dim.h += extents.top + extents.bottom;
+ view->set_preferred_dim(preferred_dim);
+
+ view->set_free_region(Region{
+ .pos = Pos{
+ .x = xwayland_surface->x - extents.left,
+ .y = xwayland_surface->y - extents.top
+ },
+ .dim = preferred_dim
+ });
+ view->set_tile_region(view->free_region());
+
+ view->m_app_id = view->m_class = xwayland_surface->class_
+ ? xwayland_surface->class_
+ : "N/a";
+ view->m_instance = xwayland_surface->instance
+ ? xwayland_surface->instance
+ : "N/a";
+ view->m_title = xwayland_surface->title
+ ? xwayland_surface->title
+ : "N/a";
+ view->m_title_formatted = view->m_title; // TODO: format title
+
+ view->mp_scene = &wlr_scene_tree_create(
+ server->m_scene_layers[SCENE_LAYER_TILE]
+ )->node;
+
+ view->mp_wlr_surface->data = view->mp_scene_surface = wlr_scene_subsurface_tree_create(
+ view->mp_scene,
+ view->mp_wlr_surface
+ );
+ view->mp_scene_surface->data = view;
+
+ view->relayer(
+ view->floating()
+ ? SCENE_LAYER_FREE
+ : SCENE_LAYER_TILE
+ );
+
+ for (std::size_t i = 0; i < 4; ++i) {
+ view->m_protrusions[i] = wlr_scene_rect_create(
+ view->mp_scene,
+ 0, 0,
+ view->active_decoration().colorscheme.unfocused.values
+ );
+ view->m_protrusions[i]->node.data = view;
+ wlr_scene_rect_set_color(
+ view->m_protrusions[i],
+ view->active_decoration().colorscheme.unfocused.values
+ );
+ wlr_scene_node_lower_to_bottom(&view->m_protrusions[i]->node);
+ }
+
+ wl_signal_add(&xwayland_surface->surface->events.commit, &view->ml_commit);
+
+ Workspace_ptr workspace = model->mp_workspace;
+
+ view->set_mapped(true);
+ view->render_decoration();
+ model->register_view(view, workspace);
}
void
-XWaylandView::close()
+XWaylandView::handle_unmap(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_unmap);
+
+ wl_list_remove(&view->ml_commit.link);
+
+ view->activate(Toggle::Off);
+ view->mp_model->unregister_view(view);
+
+ wlr_scene_node_destroy(view->mp_scene);
+ view->mp_wlr_surface = nullptr;
+ view->set_managed(false);
+
+ if (view->mp_model->mp_workspace)
+ view->mp_model->apply_layout(view->mp_workspace);
}
void
-XWaylandView::close_popups()
+XWaylandView::handle_commit(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::destroy()
+XWaylandView::handle_request_activate(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_request_activate);
+ struct wlr_xwayland_surface* xwayland_surface = view->mp_wlr_xwayland_surface;
+
+ if (!xwayland_surface->mapped)
+ return;
+
+ view->mp_model->focus_view(view);
}
void
-XWaylandView::handle_commit(struct wl_listener* listener, void* data)
+XWaylandView::handle_request_configure(struct wl_listener* listener, void* data)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_request_configure);
+ struct wlr_xwayland_surface_configure_event* event
+ = reinterpret_cast<struct wlr_xwayland_surface_configure_event*>(data);
+ struct wlr_xwayland_surface* xwayland_surface = view->mp_wlr_xwayland_surface;
+
+ if (!xwayland_surface->mapped) {
+ wlr_xwayland_surface_configure(
+ xwayland_surface,
+ event->x, event->y,
+ event->width, event->height
+ );
+
+ return;
+ }
+
+ if (view->mp_model->is_free(view)) {
+ view->set_preferred_dim(Dim{
+ .w = event->width,
+ .h = event->height,
+ });
+
+ view->set_free_region(Region{
+ .pos = Pos{
+ .x = event->x,
+ .y = event->y
+ },
+ .dim = view->preferred_dim()
+ });
+
+ view->configure(
+ view->free_region(),
+ FREE_DECORATION.extents(),
+ false
+ );
+ } else
+ view->configure(
+ view->active_region(),
+ view->active_decoration().extents(),
+ false
+ );
}
void
-XWaylandView::handle_request_move(struct wl_listener* listener, void* data)
+XWaylandView::handle_request_fullscreen(struct wl_listener*, void*)
{
TRACE();
-
+ // TODO
}
void
-XWaylandView::handle_request_resize(struct wl_listener* listener, void* data)
+XWaylandView::handle_request_minimize(struct wl_listener*, void*)
{
TRACE();
+ // TODO
+}
+void
+XWaylandView::handle_request_maximize(struct wl_listener*, void*)
+{
+ TRACE();
+ // TODO
}
void
-XWaylandView::handle_request_maximize(struct wl_listener* listener, void* data)
+XWaylandView::handle_request_move(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_request_move);
+ struct wlr_xwayland_surface* xwayland_surface = view->mp_wlr_xwayland_surface;
+
+ if (!xwayland_surface->mapped)
+ return;
+
+ if (!view->mp_model->is_free(view) || view->fullscreen())
+ return;
+
+ view->mp_model->cursor_interactive(Cursor::Mode::Move, view);
}
void
-XWaylandView::handle_request_minimize(struct wl_listener* listener, void* data)
+XWaylandView::handle_request_resize(struct wl_listener* listener, void* data)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_request_resize);
+ struct wlr_xwayland_surface* xwayland_surface = view->mp_wlr_xwayland_surface;
+
+ if (!xwayland_surface->mapped)
+ return;
+
+ if (!view->mp_model->is_free(view) || view->fullscreen())
+ return;
+
+ struct wlr_xwayland_resize_event* event
+ = reinterpret_cast<struct wlr_xwayland_resize_event*>(data);
+
+ view->mp_seat->mp_cursor->initiate_cursor_interactive(
+ Cursor::Mode::Resize,
+ view,
+ event->edges
+ );
}
void
-XWaylandView::handle_request_configure(struct wl_listener* listener, void* data)
+XWaylandView::handle_set_override_redirect(struct wl_listener* listener, void* data)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_set_override_redirect);
+ struct wlr_xwayland_surface* xwayland_surface
+ = reinterpret_cast<struct wlr_xwayland_surface*>(data);
+
+ if (xwayland_surface->mapped)
+ handle_unmap(&view->ml_unmap, nullptr);
+
+ handle_destroy(&view->ml_destroy, view);
+ xwayland_surface->data = nullptr;
+
+ XWaylandUnmanaged_ptr unmanaged = view->mp_model->create_xwayland_unmanaged(
+ xwayland_surface,
+ view->mp_seat,
+ view->mp_xwayland
+ );
+
+ if (xwayland_surface->mapped)
+ XWaylandUnmanaged::handle_map(&unmanaged->ml_map, xwayland_surface);
}
void
-XWaylandView::handle_request_fullscreen(struct wl_listener* listener, void* data)
+XWaylandView::handle_set_title(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_set_title);
+ view->m_title = view->mp_wlr_xwayland_surface->title
+ ? view->mp_wlr_xwayland_surface->title
+ : "N/a";
+ view->m_title_formatted = view->m_title; // TODO: format title
+ view->format_uid();
}
void
-XWaylandView::handle_request_activate(struct wl_listener* listener, void* data)
+XWaylandView::handle_set_class(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_set_class);
+ view->m_class = view->mp_wlr_xwayland_surface->class_
+ ? view->mp_wlr_xwayland_surface->class_
+ : "N/a";
+ view->format_uid();
}
void
-XWaylandView::handle_set_title(struct wl_listener* listener, void* data)
+XWaylandView::handle_set_hints(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_set_hints);
+ struct wlr_xwayland_surface* xwayland_surface = view->mp_wlr_xwayland_surface;
+
+ if (!xwayland_surface->mapped)
+ return;
+
+ const bool urgent = xwayland_surface->hints_urgency;
+
+ if (urgent) {
+ view->set_urgent(true);
+ view->render_decoration();
+ }
}
void
-XWaylandView::handle_set_class(struct wl_listener* listener, void* data)
+XWaylandView::handle_destroy(struct wl_listener* listener, void*)
{
TRACE();
+ XWaylandView_ptr view = wl_container_of(listener, view, ml_destroy);
+
+ wl_list_remove(&view->ml_map.link);
+ wl_list_remove(&view->ml_unmap.link);
+ wl_list_remove(&view->ml_request_activate.link);
+ wl_list_remove(&view->ml_request_configure.link);
+ wl_list_remove(&view->ml_request_fullscreen.link);
+ wl_list_remove(&view->ml_request_minimize.link);
+ wl_list_remove(&view->ml_request_maximize.link);
+ wl_list_remove(&view->ml_request_move.link);
+ wl_list_remove(&view->ml_request_resize.link);
+ wl_list_remove(&view->ml_set_override_redirect.link);
+ wl_list_remove(&view->ml_set_title.link);
+ wl_list_remove(&view->ml_set_class.link);
+ wl_list_remove(&view->ml_set_hints.link);
+ wl_list_remove(&view->ml_destroy.link);
+
+ view->mp_wlr_xwayland_surface = nullptr;
+ view->mp_model->destroy_view(view);
+}
+
+
+XWaylandUnmanaged::XWaylandUnmanaged(
+ struct wlr_xwayland_surface* wlr_xwayland_surface,
+ Server_ptr server,
+ Model_ptr model,
+ Seat_ptr seat,
+ XWayland_ptr xwayland
+)
+ : Node(Type::XWaylandUnmanaged, reinterpret_cast<std::uintptr_t>(wlr_xwayland_surface)),
+ mp_wlr_xwayland_surface(wlr_xwayland_surface),
+ mp_server(server),
+ mp_model(model),
+ mp_seat(seat),
+ mp_output(nullptr),
+ mp_xwayland(xwayland),
+ m_region({}),
+ ml_map({ .notify = handle_map }),
+ ml_unmap({ .notify = handle_unmap }),
+ ml_commit({ .notify = handle_commit }),
+ ml_set_override_redirect({ .notify = handle_set_override_redirect }),
+ ml_set_geometry({ .notify = handle_set_geometry }),
+ ml_request_activate({ .notify = handle_request_activate }),
+ ml_request_configure({ .notify = handle_request_configure }),
+ ml_request_fullscreen({ .notify = handle_request_fullscreen }),
+ ml_destroy({ .notify = handle_destroy })
+{
+ wl_signal_add(&mp_wlr_xwayland_surface->events.map, &ml_map);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.unmap, &ml_unmap);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.set_override_redirect, &ml_set_override_redirect);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.set_geometry, &ml_set_geometry);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_activate, &ml_request_activate);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_configure, &ml_request_configure);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.request_fullscreen, &ml_request_fullscreen);
+ wl_signal_add(&mp_wlr_xwayland_surface->events.destroy, &ml_destroy);
+}
+
+XWaylandUnmanaged::~XWaylandUnmanaged()
+{}
+
+void
+XWaylandUnmanaged::format_uid()
+{
+ std::stringstream uid_ss;
+ uid_ss << "0x" << std::hex << uid() << std::dec;
+ uid_ss << " (XU)";
+ m_uid_formatted = uid_ss.str();
}
void
-XWaylandView::handle_set_role(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_map(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_set_window_type(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_unmap(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_set_hints(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_commit(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_set_decorations(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_set_override_redirect(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_map(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_set_geometry(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_unmap(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_request_activate(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_destroy(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_request_configure(struct wl_listener*, void*)
{
TRACE();
}
void
-XWaylandView::handle_override_redirect(struct wl_listener* listener, void* data)
+XWaylandUnmanaged::handle_request_fullscreen(struct wl_listener*, void*)
{
TRACE();
}
-XWaylandUnmanaged::XWaylandUnmanaged(
- struct wlr_xwayland_surface* wlr_xwayland_surface,
- XWayland_ptr xwayland
-)
- : mp_wlr_xwayland_surface(wlr_xwayland_surface),
- mp_xwayland(xwayland)
-{}
+void
+XWaylandUnmanaged::handle_destroy(struct wl_listener*, void*)
+{
+ TRACE();
-XWaylandUnmanaged::~XWaylandUnmanaged()
-{}
+}
#endif
diff --git a/src/kranewl/xwayland.cc b/src/kranewl/xwayland.cc
@@ -1,7 +1,9 @@
#include <trace.hh>
#include <kranewl/input/seat.hh>
+#include <kranewl/model.hh>
#include <kranewl/server.hh>
+#include <kranewl/tree/xwayland-view.hh>
#include <kranewl/xwayland.hh>
// https://github.com/swaywm/wlroots/issues/682
@@ -25,11 +27,18 @@ extern "C" {
#include <cstdlib>
-XWayland::XWayland(struct wlr_xwayland* xwayland, Server_ptr server)
+XWayland::XWayland(
+ struct wlr_xwayland* xwayland,
+ Server_ptr server,
+ Model_ptr model,
+ Seat_ptr seat
+)
: mp_wlr_xwayland(xwayland),
mp_cursor_manager(wlr_xcursor_manager_create(nullptr, 24)),
m_atoms({}),
mp_server(server),
+ mp_model(model),
+ mp_seat(seat),
ml_ready({ .notify = XWayland::handle_ready }),
ml_new_surface({ .notify = XWayland::handle_new_surface })
{
@@ -115,7 +124,7 @@ XWayland::handle_ready(struct wl_listener* listener, void*)
wlr_xwayland_set_seat(
xwayland->mp_wlr_xwayland,
- xwayland->mp_server->m_seat.mp_wlr_seat
+ xwayland->mp_seat->mp_wlr_seat
);
struct wlr_xcursor* xcursor;
@@ -139,4 +148,13 @@ XWayland::handle_new_surface(struct wl_listener* listener, void* data)
{
TRACE();
+ XWayland_ptr xwayland = wl_container_of(listener, xwayland, ml_new_surface);
+ struct wlr_xwayland_surface* xwayland_surface
+ = reinterpret_cast<struct wlr_xwayland_surface*>(data);
+
+ XWaylandView_ptr xwayland_view = xwayland->mp_model->create_xwayland_view(
+ xwayland_surface,
+ xwayland->mp_seat,
+ xwayland
+ );
}