diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd
index 2af1f0bc..984f35f0 100644
--- a/docs/labwc-actions.5.scd
+++ b/docs/labwc-actions.5.scd
@@ -73,6 +73,13 @@ Actions are used in menus and keyboard/mouse bindings.
**
Move to position (x, y)
+**
+ Resize window
+
+ *width* The width to resize the window to in pixels.
+
+ *height* The height to resize the window to in pixels.
+
**
Move to be centered on cursor.
Tries to prevent any part of the window from going off-screen.
diff --git a/include/common/scene-helpers.h b/include/common/scene-helpers.h
index 98c1bbd6..11697a94 100644
--- a/include/common/scene-helpers.h
+++ b/include/common/scene-helpers.h
@@ -5,13 +5,9 @@
#include
struct wlr_scene_node;
-struct wlr_scene_rect;
-struct wlr_scene_tree;
struct wlr_surface;
struct wlr_scene_output;
-struct wlr_scene_rect *lab_wlr_scene_get_rect(struct wlr_scene_node *node);
-struct wlr_scene_tree *lab_scene_tree_from_node(struct wlr_scene_node *node);
struct wlr_surface *lab_wlr_surface_from_node(struct wlr_scene_node *node);
/**
diff --git a/include/dnd.h b/include/dnd.h
index 431fbd6a..35ecc927 100644
--- a/include/dnd.h
+++ b/include/dnd.h
@@ -5,19 +5,6 @@
#include
struct seat;
-struct wlr_drag_icon;
-struct wlr_scene_tree;
-
-struct drag_icon {
- struct wlr_scene_tree *icon_tree;
- struct wlr_drag_icon *icon;
- struct {
- struct wl_listener map;
- struct wl_listener commit;
- struct wl_listener unmap;
- struct wl_listener destroy;
- } events;
-};
void dnd_init(struct seat *seat);
void dnd_icons_show(struct seat *seat, bool show);
diff --git a/include/labwc.h b/include/labwc.h
index 261883c5..f288de35 100644
--- a/include/labwc.h
+++ b/include/labwc.h
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -291,6 +292,9 @@ struct server {
*/
int pending_output_layout_change;
+ struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
+ struct wl_listener gamma_control_set_gamma;
+
struct session_lock *session_lock;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
@@ -343,6 +347,7 @@ struct output {
struct wl_listener request_state;
bool leased;
+ bool gamma_lut_changed;
};
#undef LAB_NR_LAYERS
diff --git a/src/action.c b/src/action.c
index 07a52dd2..3a97efe4 100644
--- a/src/action.c
+++ b/src/action.c
@@ -88,6 +88,7 @@ enum action_type {
ACTION_TYPE_RESIZE,
ACTION_TYPE_RESIZE_RELATIVE,
ACTION_TYPE_MOVETO,
+ ACTION_TYPE_RESIZETO,
ACTION_TYPE_MOVETO_CURSOR,
ACTION_TYPE_MOVE_RELATIVE,
ACTION_TYPE_SEND_TO_DESKTOP,
@@ -131,6 +132,7 @@ const char *action_names[] = {
"Resize",
"ResizeRelative",
"MoveTo",
+ "ResizeTo",
"MoveToCursor",
"MoveRelative",
"SendToDesktop",
@@ -327,6 +329,12 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
goto cleanup;
}
break;
+ case ACTION_TYPE_RESIZETO:
+ if (!strcmp(argument, "width") || !strcmp(argument, "height")) {
+ action_arg_add_int(action, argument, atoi(content));
+ goto cleanup;
+ }
+ break;
case ACTION_TYPE_SEND_TO_DESKTOP:
if (!strcmp(argument, "follow")) {
action_arg_add_bool(action, argument, parse_bool(content, true));
@@ -801,6 +809,25 @@ actions_run(struct view *activator, struct server *server,
view_move(view, x, y);
}
break;
+ case ACTION_TYPE_RESIZETO:
+ if (view) {
+ int width = action_get_int(action, "width", 0);
+ int height = action_get_int(action, "height", 0);
+
+ /*
+ * To support only setting one of width/height
+ * in
+ * we fall back to current dimension when unset.
+ */
+ struct wlr_box box = {
+ .x = view->pending.x,
+ .y = view->pending.y,
+ .width = width ? : view->pending.width,
+ .height = height ? : view->pending.height,
+ };
+ view_move_resize(view, box);
+ }
+ break;
case ACTION_TYPE_MOVE_RELATIVE:
if (view) {
int x = action_get_int(action, "x", 0);
diff --git a/src/common/scene-helpers.c b/src/common/scene-helpers.c
index 7f9a7d0b..b8a7ac47 100644
--- a/src/common/scene-helpers.c
+++ b/src/common/scene-helpers.c
@@ -6,20 +6,6 @@
#include
#include "common/scene-helpers.h"
-struct wlr_scene_rect *
-lab_wlr_scene_get_rect(struct wlr_scene_node *node)
-{
- assert(node->type == WLR_SCENE_NODE_RECT);
- return (struct wlr_scene_rect *)node;
-}
-
-struct wlr_scene_tree *
-lab_scene_tree_from_node(struct wlr_scene_node *node)
-{
- assert(node->type == WLR_SCENE_NODE_TREE);
- return (struct wlr_scene_tree *)node;
-}
-
struct wlr_surface *
lab_wlr_surface_from_node(struct wlr_scene_node *node)
{
diff --git a/src/debug.c b/src/debug.c
index b0548e74..bac6cbaa 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -170,7 +170,7 @@ dump_tree(struct server *server, struct wlr_scene_node *node,
if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_node *child;
- struct wlr_scene_tree *tree = lab_scene_tree_from_node(node);
+ struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
wl_list_for_each(child, &tree->children, link) {
dump_tree(server, child, pos + INDENT_SIZE,
x + child->x, y + child->y);
diff --git a/src/dnd.c b/src/dnd.c
index 695096f4..71685675 100644
--- a/src/dnd.c
+++ b/src/dnd.c
@@ -9,92 +9,6 @@
#include "labwc.h" /* for struct seat */
#include "view.h"
-/* Internal DnD icon handlers */
-static void
-handle_icon_map(struct wl_listener *listener, void *data)
-{
- struct drag_icon *self = wl_container_of(listener, self, events.map);
- struct wlr_drag_icon *icon = self->icon;
- if (icon->data) {
- struct wlr_scene_tree *surface_tree = icon->data;
- wlr_scene_node_set_enabled(&surface_tree->node, true);
- } else {
- icon->data = wlr_scene_subsurface_tree_create(
- self->icon_tree, icon->surface);
- }
-}
-
-static void
-handle_surface_commit(struct wl_listener *listener, void *data)
-{
- struct drag_icon *self = wl_container_of(listener, self, events.commit);
- struct wlr_surface *surface = data;
- struct wlr_scene_tree *surface_tree = self->icon->data;
- if (surface_tree) {
- wlr_scene_node_set_position(&surface_tree->node,
- surface_tree->node.x + surface->current.dx,
- surface_tree->node.y + surface->current.dy);
- }
-}
-
-static void
-handle_icon_unmap(struct wl_listener *listener, void *data)
-{
- struct drag_icon *self = wl_container_of(listener, self, events.unmap);
- struct wlr_drag_icon *icon = self->icon;
- struct wlr_scene_tree *surface_tree = icon->data;
- if (surface_tree) {
- wlr_scene_node_set_enabled(&surface_tree->node, false);
- }
-}
-
-static void
-handle_icon_destroy(struct wl_listener *listener, void *data)
-{
- struct drag_icon *self = wl_container_of(listener, self, events.destroy);
-
- wl_list_remove(&self->events.map.link);
- wl_list_remove(&self->events.commit.link);
- wl_list_remove(&self->events.unmap.link);
- wl_list_remove(&self->events.destroy.link);
-
- if (self->icon->data) {
- struct wlr_scene_tree *tree = self->icon->data;
- wlr_scene_node_destroy(&tree->node);
- }
-
- self->icon = NULL;
- self->icon_tree = NULL;
- free(self);
-}
-
-static void
-drag_icon_create(struct seat *seat, struct wlr_drag_icon *wlr_icon)
-{
- assert(seat);
- assert(wlr_icon);
- struct drag_icon *self = znew(*self);
-
- self->icon = wlr_icon;
- self->icon_tree = seat->drag.icons;
-
- /* Position will be updated by cursor movement */
- wlr_scene_node_set_position(&self->icon_tree->node,
- seat->cursor->x, seat->cursor->y);
- wlr_scene_node_raise_to_top(&self->icon_tree->node);
-
- /* Set up events */
- self->events.map.notify = handle_icon_map;
- self->events.commit.notify = handle_surface_commit;
- self->events.unmap.notify = handle_icon_unmap;
- self->events.destroy.notify = handle_icon_destroy;
-
- wl_signal_add(&wlr_icon->surface->events.map, &self->events.map);
- wl_signal_add(&wlr_icon->surface->events.commit, &self->events.commit);
- wl_signal_add(&wlr_icon->surface->events.unmap, &self->events.unmap);
- wl_signal_add(&wlr_icon->events.destroy, &self->events.destroy);
-}
-
/* Internal DnD handlers */
static void
handle_drag_request(struct wl_listener *listener, void *data)
@@ -122,8 +36,8 @@ handle_drag_start(struct wl_listener *listener, void *data)
seat->drag.active = true;
seat_reset_pressed(seat);
if (drag->icon) {
- /* Cleans up automatically on drag->icon->events.detroy */
- drag_icon_create(seat, drag->icon);
+ /* Cleans up automatically on drag->icon->events.destroy */
+ wlr_scene_drag_icon_create(seat->drag.icons, drag->icon);
wlr_scene_node_set_enabled(&seat->drag.icons->node, true);
}
wl_signal_add(&drag->events.destroy, &seat->drag.events.destroy);
diff --git a/src/menu/menu.c b/src/menu/menu.c
index 3e36d3ad..35f00b9f 100644
--- a/src/menu/menu.c
+++ b/src/menu/menu.c
@@ -87,19 +87,19 @@ menu_update_width(struct menu *menu)
/* Update all items for the new size */
wl_list_for_each(item, &menu->menuitems, link) {
wlr_scene_rect_set_size(
- lab_wlr_scene_get_rect(item->normal.background),
+ wlr_scene_rect_from_node(item->normal.background),
menu->size.width, item->height);
if (!item->selected.background) {
/* This is a separator. They don't have a selected background. */
wlr_scene_rect_set_size(
- lab_wlr_scene_get_rect(item->normal.text),
+ wlr_scene_rect_from_node(item->normal.text),
menu->size.width - 2 * theme->menu_separator_padding_width,
theme->menu_separator_line_thickness);
} else {
/* Usual menu item */
wlr_scene_rect_set_size(
- lab_wlr_scene_get_rect(item->selected.background),
+ wlr_scene_rect_from_node(item->selected.background),
menu->size.width, item->height);
if (item->native_width > max_width || item->submenu) {
scaled_font_buffer_set_max_width(item->normal.buffer,
diff --git a/src/output.c b/src/output.c
index 003be963..dc441f8f 100644
--- a/src/output.c
+++ b/src/output.c
@@ -33,6 +33,36 @@ output_frame_notify(struct wl_listener *listener, void *data)
if (!output_is_usable(output)) {
return;
}
+
+ struct wlr_output *wlr_output = output->wlr_output;
+ struct server *server = output->server;
+
+ if (output->gamma_lut_changed) {
+ struct wlr_output_state pending;
+ wlr_output_state_init(&pending);
+ if (!wlr_scene_output_build_state(output->scene_output, &pending, NULL)) {
+ return;
+ }
+ output->gamma_lut_changed = false;
+ struct wlr_gamma_control_v1 *gamma_control =
+ wlr_gamma_control_manager_v1_get_control(
+ server->gamma_control_manager_v1, wlr_output);
+ if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
+ wlr_output_state_finish(&pending);
+ return;
+ }
+
+ if (!wlr_output_commit_state(output->wlr_output, &pending)) {
+ wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
+ wlr_output_state_finish(&pending);
+ return;
+ }
+
+ wlr_damage_ring_rotate(&output->scene_output->damage_ring);
+ wlr_output_state_finish(&pending);
+ return;
+ }
+
if (lab_wlr_scene_output_commit(output->scene_output)) {
struct timespec now = { 0 };
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -69,6 +99,14 @@ output_destroy_notify(struct wl_listener *listener, void *data)
view_on_output_destroy(view);
}
}
+
+ /*
+ * Ensure that we don't accidentally try to dereference
+ * the output pointer in some output event handler like
+ * set_gamma.
+ */
+ output->wlr_output->data = NULL;
+
/*
* output->scene_output (if still around at this point) is
* destroyed automatically when the wlr_output is destroyed
@@ -314,6 +352,9 @@ new_output_notify(struct wl_listener *listener, void *data)
void
output_init(struct server *server)
{
+ server->gamma_control_manager_v1 =
+ wlr_gamma_control_manager_v1_create(server->wl_display);
+
server->new_output.notify = new_output_notify;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
@@ -529,6 +570,20 @@ handle_output_layout_change(struct wl_listener *listener, void *data)
do_output_layout_change(server);
}
+static void
+handle_gamma_control_set_gamma(struct wl_listener *listener, void *data)
+{
+ struct server *server = wl_container_of(listener, server, gamma_control_set_gamma);
+ const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
+
+ struct output *output = event->output->data;
+ if (!output_is_usable(output)) {
+ return;
+ }
+ output->gamma_lut_changed = true;
+ wlr_output_schedule_frame(output->wlr_output);
+}
+
void
output_manager_init(struct server *server)
{
@@ -541,6 +596,10 @@ output_manager_init(struct server *server)
server->output_manager_apply.notify = handle_output_manager_apply;
wl_signal_add(&server->output_manager->events.apply,
&server->output_manager_apply);
+
+ server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma;
+ wl_signal_add(&server->gamma_control_manager_v1->events.set_gamma,
+ &server->gamma_control_set_gamma);
}
struct output *
diff --git a/src/server.c b/src/server.c
index 26a41634..0aa07a09 100644
--- a/src/server.c
+++ b/src/server.c
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -30,7 +31,8 @@
#include "workspaces.h"
#include "xwayland.h"
-#define LAB_WLR_COMPOSITOR_VERSION (5)
+#define LAB_WLR_COMPOSITOR_VERSION 5
+#define LAB_WLR_FRACTIONAL_SCALE_V1_VERSION 1
static struct wlr_compositor *compositor;
static struct wl_event_source *sighup_source;
@@ -375,9 +377,10 @@ server_init(struct server *server)
wlr_export_dmabuf_manager_v1_create(server->wl_display);
wlr_screencopy_manager_v1_create(server->wl_display);
wlr_data_control_manager_v1_create(server->wl_display);
- wlr_gamma_control_manager_v1_create(server->wl_display);
wlr_viewporter_create(server->wl_display);
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
+ wlr_fractional_scale_manager_v1_create(server->wl_display,
+ LAB_WLR_FRACTIONAL_SCALE_V1_VERSION);
idle_manager_create(server->wl_display, server->seat.seat);
diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c
index 4580ec2f..0f1eafca 100644
--- a/src/ssd/ssd.c
+++ b/src/ssd/ssd.c
@@ -339,7 +339,7 @@ ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable)
: rc.theme->window_active_border_color;
struct ssd_part *part = ssd_get_part(&ssd->border.active.parts, LAB_SSD_PART_TOP);
- struct wlr_scene_rect *rect = lab_wlr_scene_get_rect(part->node);
+ struct wlr_scene_rect *rect = wlr_scene_rect_from_node(part->node);
wlr_scene_rect_set_color(rect, color);
}
diff --git a/src/ssd/ssd_border.c b/src/ssd/ssd_border.c
index 40be4f39..c12b07b2 100644
--- a/src/ssd/ssd_border.c
+++ b/src/ssd/ssd_border.c
@@ -91,7 +91,7 @@ ssd_border_update(struct ssd *ssd)
struct ssd_sub_tree *subtree;
FOR_EACH_STATE(ssd, subtree) {
wl_list_for_each(part, &subtree->parts, link) {
- rect = lab_wlr_scene_get_rect(part->node);
+ rect = wlr_scene_rect_from_node(part->node);
switch (part->type) {
case LAB_SSD_PART_LEFT:
wlr_scene_rect_set_size(rect,
diff --git a/src/ssd/ssd_extents.c b/src/ssd/ssd_extents.c
index 05869e21..22bfa579 100644
--- a/src/ssd/ssd_extents.c
+++ b/src/ssd/ssd_extents.c
@@ -138,7 +138,7 @@ ssd_extents_update(struct ssd *ssd)
struct wlr_box *target;
wl_list_for_each(part, &ssd->extents.parts, link) {
- rect = lab_wlr_scene_get_rect(part->node);
+ rect = wlr_scene_rect_from_node(part->node);
target = part->geometry;
switch (part->type) {
case LAB_SSD_PART_TOP:
diff --git a/src/ssd/ssd_titlebar.c b/src/ssd/ssd_titlebar.c
index 39baaadf..04c05eb7 100644
--- a/src/ssd/ssd_titlebar.c
+++ b/src/ssd/ssd_titlebar.c
@@ -131,7 +131,7 @@ set_squared_corners(struct ssd *ssd, bool enable)
struct ssd_button *button = node_ssd_button_from_node(part->node);
/* Toggle background between invisible and titlebar background color */
- struct wlr_scene_rect *rect = lab_wlr_scene_get_rect(button->background);
+ struct wlr_scene_rect *rect = wlr_scene_rect_from_node(button->background);
wlr_scene_rect_set_color(rect, !enable ? (float[4]) {0, 0, 0, 0} : (
subtree == &ssd->titlebar.active
? rc.theme->window_active_title_bg_color
@@ -170,7 +170,7 @@ ssd_titlebar_update(struct ssd *ssd)
switch (part->type) {
case LAB_SSD_PART_TITLEBAR:
wlr_scene_rect_set_size(
- lab_wlr_scene_get_rect(part->node),
+ wlr_scene_rect_from_node(part->node),
width - SSD_BUTTON_WIDTH * SSD_BUTTON_COUNT,
theme->title_height);
continue;