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;