Require wlroots 0.17.0

This commit is contained in:
Keith Bowes 2023-11-22 10:06:39 -05:00
parent 7fb889d171
commit bceafa5b6b
18 changed files with 305 additions and 400 deletions

View file

@ -17,8 +17,8 @@ jobs:
- name: packages
run: |
apk add clang gcc libevdev-dev libinput-dev libxkbcommon-dev libxml2-dev meson musl-dev wayland-dev wayland-protocols wlroots-dev xwayland
# actions/checkout@v3 clones the repository
- uses: actions/checkout@v3
# actions/checkout@v4 clones the repository
- uses: actions/checkout@v4
- name: build-gcc
run: |
CC=gcc meson setup build-gcc

View file

@ -1,7 +1,6 @@
#ifndef _WB_OUTPUT_H
#define _WB_OUTPUT_H
#include <stdlib.h>
#include <time.h>
#include "waybox/server.h"
@ -32,28 +31,6 @@ struct wb_output {
struct wl_list link;
};
struct wb_view {
struct wl_list link;
struct wb_server *server;
struct wlr_xdg_toplevel *xdg_toplevel;
struct wlr_scene_tree *scene_tree;
struct wlr_xdg_toplevel_decoration_v1 *decoration;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener new_popup;
struct wl_listener request_fullscreen;
struct wl_listener request_maximize;
struct wl_listener request_minimize;
struct wl_listener request_move;
struct wl_listener request_resize;
struct wlr_box geometry;
struct wlr_box previous_geometry;
};
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
void output_frame_notify(struct wl_listener *listener, void *data);
void output_destroy_notify(struct wl_listener *listener, void *data);

View file

@ -22,6 +22,8 @@
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include <stdlib.h>
#ifdef USE_NLS
# include <libintl.h>
# include <locale.h>
@ -34,7 +36,7 @@
#include "waybox/cursor.h"
#include "decoration.h"
#include "layer_shell.h"
#include "waybox/output.h"
#include "waybox/xdg_shell.h"
#include "waybox/seat.h"
struct wb_server {
@ -58,11 +60,11 @@ struct wb_server {
struct wb_cursor *cursor;
struct wb_seat *seat;
struct wb_view *grabbed_view;
struct wb_toplevel *grabbed_toplevel;
struct wlr_box grab_geo_box;
double grab_x, grab_y;
uint32_t resize_edges;
struct wl_list views;
struct wl_list toplevels;
struct wlr_layer_shell_v1 *layer_shell;
struct wlr_xdg_shell *xdg_shell;

View file

@ -3,10 +3,32 @@
#include "waybox/server.h"
struct wb_toplevel {
struct wl_list link;
struct wb_server *server;
struct wlr_xdg_toplevel *xdg_toplevel;
struct wlr_scene_tree *scene_tree;
struct wlr_xdg_toplevel_decoration_v1 *decoration;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener new_popup;
struct wl_listener request_fullscreen;
struct wl_listener request_maximize;
struct wl_listener request_minimize;
struct wl_listener request_move;
struct wl_listener request_resize;
struct wlr_box geometry;
struct wlr_box previous_geometry;
};
void init_xdg_shell(struct wb_server *server);
void focus_view(struct wb_view *view, struct wlr_surface *surface);
struct wlr_output *get_active_output(struct wb_view *view);
struct wb_view *get_view_at(
void focus_toplevel(struct wb_toplevel *toplevel, struct wlr_surface *surface);
struct wlr_output *get_active_output(struct wb_toplevel *toplevel);
struct wb_toplevel *get_toplevel_at(
struct wb_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy);
#endif

View file

@ -28,7 +28,7 @@ inc_dir = include_directories('include')
libevdev = dependency('libevdev')
libinput = dependency('libinput', version: '>=1.21.0')
libxml2 = dependency('libxml-2.0')
wlroots = dependency('wlroots', version: '>=0.16.0')
wlroots = dependency('wlroots', version: '>=0.17.0')
wayland_server = dependency('wayland-server', version: '>=1.15')
wayland_protos = dependency('wayland-protocols', version: '>=1.27')
xkbcommon = dependency('xkbcommon')

View file

@ -11,8 +11,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Waybox 0.0.1\n"
"Report-Msgid-Bugs-To: https://github.com/wizbright/waybox/issues\n"
"POT-Creation-Date: 2022-12-06 22:27-0500\n"
"PO-Revision-Date: 2022-12-06 22:30-0500\n"
"POT-Creation-Date: 2023-11-21 15:47-0500\n"
"PO-Revision-Date: 2023-11-21 12:49-0500\n"
"Last-Translator: Volker Ribbert <volker.nospam@netcologne.de>\n"
"Language-Team: <de@li.org>\n"
"Language: de\n"
@ -39,14 +39,14 @@ msgstr "Kein nodeset"
msgid ""
"Unable to parse the configuration file. Consult stderr for more information."
msgstr ""
"Kann nicht die Einstullungsdatei analisieren. Für mehr Informationen die "
"Kann nicht die Einstellungsdatei analisieren. Für weitere Informationen die "
"Standardfehlerausgabe lesen."
msgid "Couldn't create new context!"
msgstr "Konnte einen neuen Zusammenhang nicht erstellen"
msgstr "Konnte keinen neuen Zusammenhang erstellen"
msgid "Couldn't register the namespace"
msgstr "Konte dem Namensnraum nicht registrieren"
msgstr "Konnte dem Namensraum nicht registrieren"
#, c-format
msgid "Syntax: %s [options]\n"
@ -118,8 +118,8 @@ msgstr "Der Server wurde nicht erfolgreich gestartet"
msgid "New output device detected"
msgstr "Neue Ausgabegerät entdeckt"
msgid "Couldn't commit pending frame to output"
msgstr "Konnte sich nicht an den anstehenden Rahmen an die Ausgabe eintragen"
msgid "Could not add an output layout."
msgstr "Konnte keine neue Ausgabenanordnung hinzufügen."
msgid "New keyboard detected"
msgstr "Neue Tastatur entdeckt"
@ -151,8 +151,12 @@ msgstr "Display zerstört"
msgid "Keyboard focus is now on surface"
msgstr "Tastaturfokus ist jetzt auf Oberfläche"
msgid "Focusing next view"
msgstr "Fokussiert nächste Ansicht"
msgid "Focusing next toplevel"
msgstr "Fokussiert nächstes Spitzenniveau"
#~ msgid "Couldn't commit pending frame to output"
#~ msgstr ""
#~ "Konnte sich nicht an den anstehenden Rahmen an die Ausgabe eintragen"
#, fuzzy
#~ msgid "Failed to create wlr_backend"

View file

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Waybox 0.0.1\n"
"Report-Msgid-Bugs-To: https://github.com/wizbright/waybox/issues\n"
"POT-Creation-Date: 2022-12-06 22:27-0500\n"
"PO-Revision-Date: 2022-12-06 22:33-0500\n"
"POT-Creation-Date: 2023-11-21 15:47-0500\n"
"PO-Revision-Date: 2023-11-21 15:58-0500\n"
"Last-Translator: Keith <keith@localhost>\n"
"Language-Team: Esperanto\n"
"Language: eo\n"
@ -24,7 +24,7 @@ msgid "ERROR: No configuration file found."
msgstr "ERARO: Neniu agordo-dosiero trovita."
msgid "Unable to evaluate expression"
msgstr "Ne povas taksi esprimon"
msgstr "Ne eblis taksi esprimon"
msgid "No nodesetval"
msgstr "Neniu nodara valoro"
@ -41,7 +41,7 @@ msgid "Couldn't create new context!"
msgstr "Ne povis krei novan kuntekston!"
msgid "Couldn't register the namespace"
msgstr "Ne povas registri lo nomspacon"
msgstr "Ne eblis registri la nomspacon"
#, c-format
msgid "Syntax: %s [options]\n"
@ -98,13 +98,13 @@ msgstr "%s postulas argumenton\n"
#, c-format
msgid "%s hasn't been implemented yet.\n"
msgstr "%s ankoraŭ ne estas efektigita.\n"
msgstr "%s ankoraŭ ne estas efektivigita.\n"
msgid "Successfully created backend"
msgstr "Sukcese kreis servilan dorson"
msgid "Failed to create backend"
msgstr "Malsukesis krei servilan dorson"
msgstr "Malsukcesis krei servilan dorson"
msgid "Successfully started server"
msgstr "Sukcese startigis servilon"
@ -115,8 +115,8 @@ msgstr "Malsukcesis startigi servilon"
msgid "New output device detected"
msgstr "Nova enigilo malkovrita"
msgid "Couldn't commit pending frame to output"
msgstr "Ne povis surmeti atendantan framon sur eligon"
msgid "Could not add an output layout."
msgstr "Ne eblis aldoni eligan aranĝon."
msgid "New keyboard detected"
msgstr "Nova klavaro malkovrita"
@ -131,13 +131,13 @@ msgid "Failed to connect to a Wayland display"
msgstr "Malsukcesis konektiĝi al Wayland-ekrano"
msgid "Failed to create renderer"
msgstr "Malsukesis krei servilan bildigilon"
msgstr "Malsukcesis krei servilan bildigilon"
msgid "Failed to create allocator"
msgstr "Malsukesis krei servilan asignilon"
msgstr "Malsukcesis krei servilan asignilon"
msgid "Failed to start backend"
msgstr "Malsukesis startigi servilan dorson"
msgstr "Malsukcesis startigi servilan dorson"
msgid "Running Wayland compositor on Wayland display"
msgstr "Plenumas Wayland-komponilon sur Wayland-ekrano"
@ -148,8 +148,11 @@ msgstr "Ekrano finigita"
msgid "Keyboard focus is now on surface"
msgstr "Klavara fokuso nun estas sur surfaco"
msgid "Focusing next view"
msgstr "Fokusas la sekvan vidon"
msgid "Focusing next toplevel"
msgstr "Fokusas la sekvan supran nivelon"
#~ msgid "Couldn't commit pending frame to output"
#~ msgstr "Ne eblis surmeti atendantan framon sur eligon"
#, fuzzy
#~ msgid "Failed to create wlr_backend"

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: waybox\n"
"Report-Msgid-Bugs-To: https://github.com/wizbright/waybox/issues\n"
"POT-Creation-Date: 2022-12-06 22:27-0500\n"
"POT-Creation-Date: 2023-11-21 15:47-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -107,7 +107,7 @@ msgstr ""
msgid "New output device detected"
msgstr ""
msgid "Couldn't commit pending frame to output"
msgid "Could not add an output layout."
msgstr ""
msgid "New keyboard detected"
@ -140,5 +140,5 @@ msgstr ""
msgid "Keyboard focus is now on surface"
msgstr ""
msgid "Focusing next view"
msgid "Focusing next toplevel"
msgstr ""

View file

@ -29,14 +29,14 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
'wlr-gamma-control-unstable-v1.xml',
'wlr-screencopy-unstable-v1.xml',
'wlr-layer-shell-unstable-v1.xml',
'wlr-screencopy-unstable-v1.xml',
]
client_protocols = [
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
'wlr-screencopy-unstable-v1.xml',
'wlr-layer-shell-unstable-v1.xml',
'wlr-screencopy-unstable-v1.xml',
]
wl_protos_src = []

View file

@ -4,22 +4,22 @@
void reset_cursor_mode(struct wb_server *server) {
/* Reset the cursor mode to passthrough */
server->cursor->cursor_mode = WB_CURSOR_PASSTHROUGH;
server->grabbed_view = NULL;
server->grabbed_toplevel = NULL;
}
static void process_cursor_move(struct wb_server *server) {
/* Move the grabbed view to the new position. */
struct wb_view *view = server->grabbed_view;
if (view->scene_tree->node.type == WLR_SCENE_NODE_TREE) {
view->geometry.x = server->cursor->cursor->x - server->grab_x;
view->geometry.y = server->cursor->cursor->y - server->grab_y;
wlr_scene_node_set_position(&view->scene_tree->node,
view->geometry.x, view->geometry.y);
/* Move the grabbed toplevel to the new position. */
struct wb_toplevel *toplevel = server->grabbed_toplevel;
if (toplevel->scene_tree->node.type == WLR_SCENE_NODE_TREE) {
toplevel->geometry.x = server->cursor->cursor->x - server->grab_x;
toplevel->geometry.y = server->cursor->cursor->y - server->grab_y;
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->geometry.x, toplevel->geometry.y);
}
}
static void process_cursor_resize(struct wb_server *server) {
struct wb_view *view = server->grabbed_view;
struct wb_toplevel *toplevel = server->grabbed_toplevel;
double border_x = server->cursor->cursor->x - server->grab_x;
double border_y = server->cursor->cursor->y - server->grab_y;
int new_left = server->grab_geo_box.x;
@ -51,15 +51,15 @@ static void process_cursor_resize(struct wb_server *server) {
}
struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
view->geometry.x = new_left - geo_box.x;
view->geometry.y = new_top - geo_box.y;
wlr_scene_node_set_position(&view->scene_tree->node,
view->geometry.x, view->geometry.y);
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
toplevel->geometry.x = new_left - geo_box.x;
toplevel->geometry.y = new_top - geo_box.y;
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->geometry.x, toplevel->geometry.y);
int new_width = new_right - new_left;
int new_height = new_bottom - new_top;
wlr_xdg_toplevel_set_size(view->xdg_toplevel, new_width, new_height);
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
}
static void process_cursor_motion(struct wb_server *server, uint32_t time) {
@ -72,23 +72,18 @@ static void process_cursor_motion(struct wb_server *server, uint32_t time) {
return;
}
/* Otherwise, find the view under the pointer and send the event along. */
/* Otherwise, find the toplevel under the pointer and send the event along. */
double sx, sy;
struct wlr_seat *seat = server->seat->seat;
struct wlr_surface *surface = NULL;
struct wb_view *view = get_view_at(server,
struct wb_toplevel *toplevel = get_toplevel_at(server,
server->cursor->cursor->x, server->cursor->cursor->y, &surface, &sx, &sy);
if (!view) {
/* If there's no view under the cursor, set the cursor image to a
if (!toplevel) {
/* If there's no toplevel under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it
* around the screen, not over any views. */
#if WLR_CHECK_VERSION(0, 17, 0)
* around the screen, not over any toplevels. */
wlr_cursor_set_xcursor(
server->cursor->cursor, server->cursor->xcursor_manager, "default");
#else
wlr_xcursor_manager_set_cursor_image(
server->cursor->xcursor_manager, "left_ptr", server->cursor->cursor);
#endif
}
if (surface) {
/*
@ -139,14 +134,14 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
event->time_msec, event->button, event->state);
double sx, sy;
struct wlr_surface *surface = NULL;
struct wb_view *view = get_view_at(cursor->server,
struct wb_toplevel *toplevel = get_toplevel_at(cursor->server,
cursor->server->cursor->cursor->x, cursor->server->cursor->cursor->y, &surface, &sx, &sy);
if (event->state == WLR_BUTTON_RELEASED) {
/* If you released any buttons, we exit interactive move/resize mode. */
reset_cursor_mode(cursor->server);
} else {
/* Focus that client if the button was _pressed_ */
focus_view(view, surface);
focus_toplevel(toplevel, surface);
}
wlr_idle_notifier_v1_notify_activity(cursor->server->idle_notifier, cursor->server->seat->seat);
@ -203,9 +198,6 @@ struct wb_cursor *wb_cursor_create(struct wb_server *server) {
const char *xcursor_size = getenv("XCURSOR_SIZE");
cursor->xcursor_manager = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"),
xcursor_size ? strtoul(xcursor_size, (char **) NULL, 10) : 24);
#if !WLR_CHECK_VERSION(0, 17, 0)
wlr_xcursor_manager_load(cursor->xcursor_manager, 1);
#endif
cursor->cursor_motion.notify = handle_cursor_motion;
wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion);

View file

@ -15,9 +15,9 @@ static void free_xdg_decoration_mode(struct wl_listener *listener, void *data) {
static void handle_xdg_decoration_mode(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel_decoration_v1 *toplevel_decoration = data;
struct wb_decoration *decoration = wl_container_of(listener, decoration, request_mode);
struct wb_view *view = wl_container_of(decoration->server->views.next, view, link);
struct wb_toplevel *toplevel = wl_container_of(decoration->server->toplevels.next, toplevel, link);
wlr_xdg_toplevel_decoration_v1_set_mode(toplevel_decoration, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
view->decoration = toplevel_decoration;
toplevel->decoration = toplevel_decoration;
}
static void handle_new_xdg_toplevel_decoration(struct wl_listener *listener, void *data) {

View file

@ -121,13 +121,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);
}
#if WLR_CHECK_VERSION(0, 17, 0)
if (committed || layer_surface->surface->mapped != surface->mapped) {
surface->mapped = layer_surface->surface->mapped;
#else
if (committed || layer_surface->mapped != surface->mapped) {
surface->mapped = layer_surface->mapped;
#endif
arrange_layers(surface->output);
struct timespec now;
@ -175,9 +170,9 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
seat_set_focus_layer(seat, NULL);
}
struct wb_view *view = wl_container_of(surface->server->views.next, view, link);
if (view && view->scene_tree && view->scene_tree->node.enabled) {
focus_view(view, view->xdg_toplevel->base->surface);
struct wb_toplevel *toplevel = wl_container_of(surface->server->toplevels.next, toplevel, link);
if (toplevel && toplevel->scene_tree && toplevel->scene_tree->node.enabled) {
focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
}
}
@ -310,9 +305,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
if (layer_surface->output == NULL) {
struct wb_server *server =
wl_container_of(listener, server, new_layer_surface);
struct wb_view *view =
wl_container_of(server->views.next, view, link);
layer_surface->output = get_active_output(view);
struct wb_toplevel *toplevel =
wl_container_of(server->toplevels.next, toplevel, link);
layer_surface->output = get_active_output(toplevel);
}
struct wb_output *output = layer_surface->output->data;
@ -348,17 +343,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
wl_signal_add(&layer_surface->surface->events.commit,
&surface->surface_commit);
surface->map.notify = handle_map;
#if WLR_CHECK_VERSION(0, 17, 0)
wl_signal_add(&layer_surface->surface->events.map, &surface->map);
#else
wl_signal_add(&layer_surface->events.map, &surface->map);
#endif
surface->unmap.notify = handle_unmap;
#if WLR_CHECK_VERSION(0, 17, 0)
wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
#else
wl_signal_add(&layer_surface->events.unmap, &surface->unmap);
#endif
surface->destroy.notify = handle_destroy;
wl_signal_add(&layer_surface->events.destroy, &surface->destroy);
surface->new_popup.notify = handle_new_popup;
@ -373,11 +360,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
}
void init_layer_shell(struct wb_server *server) {
#if WLR_CHECK_VERSION(0, 17, 0)
server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, 4);
#else
server->layer_shell = wlr_layer_shell_v1_create(server->wl_display);
#endif
server->new_layer_surface.notify = handle_layer_shell_surface;
wl_signal_add(&server->layer_shell->events.new_surface,
&server->new_layer_surface);

View file

@ -2,7 +2,7 @@
#define _WB_LAYERS_H
#include <wlr/types/wlr_layer_shell_v1.h>
struct wb_server;
#include "waybox/output.h"
struct wb_layer_surface {
struct wb_output *output;

View file

@ -28,8 +28,8 @@ void signal_handler(int sig) {
wl_display_terminate(server.wl_display);
break;
case SIGUSR1:
/* Openbox uses SIGUSR1 to restart. I'm not sure of the
* difference between restarting and reconfiguring.
/* Openbox uses SIGUSR1 to restart and SIGUSR2 to reconfigure.
* What's the difference?
*/
case SIGUSR2:
deinit_config(server.config);

View file

@ -18,28 +18,21 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
if (output->gamma_lut_changed) {
output->gamma_lut_changed = false;
#if WLR_CHECK_VERSION(0, 17, 0)
struct wlr_gamma_control_v1 *gamma_control =
wlr_gamma_control_manager_v1_get_control(output->server->gamma_control_manager,
output->wlr_output);
if (!wlr_gamma_control_v1_apply(gamma_control, &output->wlr_output->pending)) {
return;
}
#endif
if (!wlr_output_test(output->wlr_output)) {
wlr_output_rollback(output->wlr_output);
#if WLR_CHECK_VERSION(0, 17, 0)
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
#endif
}
}
/* Render the scene if needed and commit the output */
#if WLR_CHECK_VERSION(0, 17, 0)
wlr_scene_output_commit(scene_output, NULL);
#else
wlr_scene_output_commit(scene_output);
#endif
/* This lets the client know that we've displayed that frame and it can
* prepare another one now if it likes. */
@ -48,7 +41,6 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
wlr_scene_output_send_frame_done(scene_output, &now);
}
#if WLR_CHECK_VERSION(0, 17, 0)
void output_request_state_notify(struct wl_listener *listener, void *data) {
struct wb_output *output = wl_container_of(listener, output, request_state);
const struct wlr_output_event_request_state *event = data;
@ -61,16 +53,13 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
output->gamma_lut_changed = true;
wlr_output_schedule_frame(output->wlr_output);
}
#endif
void output_destroy_notify(struct wl_listener *listener, void *data) {
struct wb_output *output = wl_container_of(listener, output, destroy);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->frame.link);
#if WLR_CHECK_VERSION(0, 17, 0)
wl_list_remove(&output->request_state.link);
#endif
/* Frees the layers */
size_t num_layers = sizeof(output->layers) / sizeof(struct wlr_scene_node *);
@ -95,7 +84,6 @@ void new_output_notify(struct wl_listener *listener, void *data) {
* and our renderer */
wlr_output_init_render(wlr_output, server->allocator, server->renderer);
#if WLR_CHECK_VERSION(0, 17, 0)
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
struct wlr_output_state state;
wlr_output_state_init(&state);
@ -107,18 +95,6 @@ void new_output_notify(struct wl_listener *listener, void *data) {
wlr_output_commit_state(wlr_output, &state);
wlr_output_state_finish(&state);
#else
if (!wl_list_empty(&wlr_output->modes)) {
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
wlr_output_set_mode(wlr_output, mode);
wlr_output_enable(wlr_output, true);
if (!wlr_output_commit(wlr_output)) {
wlr_log_errno(WLR_ERROR, "%s", _("Couldn't commit pending frame to output"));
return;
}
}
#endif
struct wb_output *output = calloc(1, sizeof(struct wb_output));
output->server = server;
@ -145,10 +121,8 @@ void new_output_notify(struct wl_listener *listener, void *data) {
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->frame.notify = output_frame_notify;
wl_signal_add(&wlr_output->events.frame, &output->frame);
#if WLR_CHECK_VERSION(0, 17, 0)
output->request_state.notify = output_request_state_notify;
wl_signal_add(&wlr_output->events.request_state, &output->request_state);
#endif
/* Adds this to the output layout. The add_auto function arranges outputs
* from left-to-right in the order they appear. A more sophisticated
@ -159,7 +133,6 @@ void new_output_notify(struct wl_listener *listener, void *data) {
* display, which Wayland clients can see to find out information about the
* output (such as DPI, scale factor, manufacturer, etc).
*/
#if WLR_CHECK_VERSION(0, 17, 0)
struct wlr_output_layout_output *l_output =
wlr_output_layout_add_auto(server->output_layout, wlr_output);
if (!l_output) {
@ -169,7 +142,4 @@ void new_output_notify(struct wl_listener *listener, void *data) {
struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output);
wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);
#else
wlr_output_layout_add_auto(server->output_layout, wlr_output);
#endif
}

View file

@ -8,45 +8,45 @@
#include "waybox/seat.h"
#include "waybox/xdg_shell.h"
static void deiconify_view(struct wb_view *view) {
if (view->xdg_toplevel->requested.minimized) {
view->xdg_toplevel->requested.minimized = false;
wl_signal_emit(&view->xdg_toplevel->events.request_minimize, NULL);
static void deiconify_toplevel(struct wb_toplevel *toplevel) {
if (toplevel->xdg_toplevel->requested.minimized) {
toplevel->xdg_toplevel->requested.minimized = false;
wl_signal_emit(&toplevel->xdg_toplevel->events.request_minimize, NULL);
}
}
static void cycle_views(struct wb_server *server) {
/* Cycle to the next view */
if (wl_list_length(&server->views) < 1) {
static void cycle_toplevels(struct wb_server *server) {
/* Cycle to the next toplevel */
if (wl_list_length(&server->toplevels) < 1) {
return;
}
struct wb_view *current_view = wl_container_of(
server->views.prev, current_view, link);
deiconify_view(current_view);
focus_view(current_view, current_view->xdg_toplevel->base->surface);
struct wb_toplevel *current_toplevel = wl_container_of(
server->toplevels.prev, current_toplevel, link);
deiconify_toplevel(current_toplevel);
focus_toplevel(current_toplevel, current_toplevel->xdg_toplevel->base->surface);
/* Move the current view to the beginning of the list */
wl_list_remove(&current_view->link);
wl_list_insert(&server->views, &current_view->link);
/* Move the current toplevel to the beginning of the list */
wl_list_remove(&current_toplevel->link);
wl_list_insert(&server->toplevels, &current_toplevel->link);
}
static void cycle_views_reverse(struct wb_server *server) {
/* Cycle to the previous view */
if (wl_list_length(&server->views) < 1) {
static void cycle_toplevels_reverse(struct wb_server *server) {
/* Cycle to the previous toplevel */
if (wl_list_length(&server->toplevels) < 1) {
return;
}
struct wb_view *current_view = wl_container_of(
server->views.next, current_view, link);
struct wb_view *next_view = wl_container_of(
current_view->link.next, next_view, link);
deiconify_view(next_view);
focus_view(next_view, next_view->xdg_toplevel->base->surface);
struct wb_toplevel *current_toplevel = wl_container_of(
server->toplevels.next, current_toplevel, link);
struct wb_toplevel *next_toplevel = wl_container_of(
current_toplevel->link.next, next_toplevel, link);
deiconify_toplevel(next_toplevel);
focus_toplevel(next_toplevel, next_toplevel->xdg_toplevel->base->surface);
/* Move the current view to after the previous view in the list */
wl_list_remove(&current_view->link);
wl_list_insert(server->views.prev, &current_view->link);
/* Move the current toplevel to after the previous toplevel in the list */
wl_list_remove(&current_toplevel->link);
wl_list_insert(server->toplevels.prev, &current_toplevel->link);
}
static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32_t modifiers) {
@ -62,10 +62,10 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
/* Some default key bindings, when the rc.xml file can't be
* parsed. */
if (modifiers & WLR_MODIFIER_ALT && sym == XKB_KEY_Tab)
cycle_views(server);
cycle_toplevels(server);
else if (modifiers & (WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT) &&
sym == XKB_KEY_Tab)
cycle_views_reverse(server);
cycle_toplevels_reverse(server);
else if (sym == XKB_KEY_Escape && modifiers & WLR_MODIFIER_CTRL)
wl_display_terminate(server->wl_display);
else
@ -77,14 +77,14 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
wl_list_for_each(key_binding, &server->config->key_bindings, link) {
if (sym == key_binding->sym && modifiers == key_binding->modifiers) {
if (key_binding->action & ACTION_NEXT_WINDOW)
cycle_views(server);
cycle_toplevels(server);
if (key_binding->action & ACTION_PREVIOUS_WINDOW)
cycle_views_reverse(server);
cycle_toplevels_reverse(server);
if (key_binding->action & ACTION_CLOSE) {
struct wb_view *current_view = wl_container_of(
server->views.next, current_view, link);
if (current_view->scene_tree->node.enabled)
wlr_xdg_toplevel_send_close(current_view->xdg_toplevel);
struct wb_toplevel *current_toplevel = wl_container_of(
server->toplevels.next, current_toplevel, link);
if (current_toplevel->scene_tree->node.enabled)
wlr_xdg_toplevel_send_close(current_toplevel->xdg_toplevel);
}
if (key_binding->action & ACTION_EXECUTE) {
if (fork() == 0) {
@ -92,34 +92,34 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
}
}
if (key_binding->action & ACTION_TOGGLE_MAXIMIZE) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (view->scene_tree->node.enabled)
wl_signal_emit(&view->xdg_toplevel->events.request_maximize, NULL);
struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
if (toplevel->scene_tree->node.enabled)
wl_signal_emit(&toplevel->xdg_toplevel->events.request_maximize, NULL);
}
if (key_binding->action & ACTION_ICONIFY) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (view->scene_tree->node.enabled) {
view->xdg_toplevel->requested.minimized = true;
wl_signal_emit(&view->xdg_toplevel->events.request_minimize, NULL);
struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
if (toplevel->scene_tree->node.enabled) {
toplevel->xdg_toplevel->requested.minimized = true;
wl_signal_emit(&toplevel->xdg_toplevel->events.request_minimize, NULL);
}
}
if (key_binding->action & ACTION_SHADE) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (view->scene_tree->node.enabled) {
struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
if (toplevel->scene_tree->node.enabled) {
struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
int decoration_height = MAX(geo_box.y - view->geometry.y, TITLEBAR_HEIGHT);
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
int decoration_height = MAX(geo_box.y - toplevel->geometry.y, TITLEBAR_HEIGHT);
view->previous_geometry = view->geometry;
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
view->geometry.width, decoration_height);
toplevel->previous_geometry = toplevel->geometry;
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
toplevel->geometry.width, decoration_height);
}
}
if (key_binding->action & ACTION_UNSHADE) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (view->scene_tree->node.enabled) {
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
view->previous_geometry.width, view->previous_geometry.height);
struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link);
if (toplevel->scene_tree->node.enabled) {
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
toplevel->previous_geometry.width, toplevel->previous_geometry.height);
}
}
if (key_binding->action & ACTION_RECONFIGURE) {

View file

@ -14,11 +14,7 @@ bool wb_create_backend(struct wb_server* server) {
* output hardware. The autocreate option will choose the most suitable
* backend based on the current environment, such as opening an X11 window
* if an X11 server is running. */
#if ! WLR_CHECK_VERSION(0, 13, 0) || WLR_CHECK_VERSION(0, 17, 0)
server->backend = wlr_backend_autocreate(server->wl_display, NULL);
#else
server->backend = wlr_backend_autocreate(server->wl_display);
#endif
if (server->backend == NULL) {
wlr_log(WLR_ERROR, "%s", _("Failed to create backend"));
return false;
@ -46,13 +42,8 @@ bool wb_create_backend(struct wb_server* server) {
return false;
}
#if WLR_CHECK_VERSION(0, 17, 0)
server->compositor =
wlr_compositor_create(server->wl_display, 5, server->renderer);
#else
server->compositor = wlr_compositor_create(server->wl_display,
server->renderer);
#endif
server->subcompositor = wlr_subcompositor_create(server->wl_display);
server->output_layout = wlr_output_layout_create();
server->seat = wb_seat_create(server);
@ -78,9 +69,7 @@ bool wb_start_server(struct wb_server* server) {
* necessary.
*/
server->scene = wlr_scene_create();
#if WLR_CHECK_VERSION(0, 17, 0)
server->scene_layout =
#endif
wlr_scene_attach_output_layout(server->scene, server->output_layout);
const char *socket = wl_display_add_socket_auto(server->wl_display);
@ -103,22 +92,18 @@ bool wb_start_server(struct wb_server* server) {
server->gamma_control_manager =
wlr_gamma_control_manager_v1_create(server->wl_display);
#if WLR_CHECK_VERSION(0, 17, 0)
server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma;
wl_signal_add(&server->gamma_control_manager->events.set_gamma, &server->gamma_control_set_gamma);
#endif
wlr_screencopy_manager_v1_create(server->wl_display);
server->idle_notifier = wlr_idle_notifier_v1_create(server->wl_display);
wl_list_init(&server->views);
wl_list_init(&server->toplevels);
init_xdg_decoration(server);
init_layer_shell(server);
/* Set up the xdg-shell. The xdg-shell is a Wayland protocol which is used
* for application windows. For more detail on shells, refer to Drew
* DeVault's article:
*
* for application windows. For more detail on shells, refer to
* https://drewdevault.com/2018/07/29/Wayland-shells.html
*/
init_xdg_shell(server);

View file

@ -1,11 +1,11 @@
#include "waybox/xdg_shell.h"
struct wb_view *get_view_at(
struct wb_toplevel *get_toplevel_at(
struct wb_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
/* This returns the topmost node in the scene at the given layout coords.
* we only care about surface nodes as we are specifically looking for a
* surface in the surface tree of a wb_view. */
* surface in the surface tree of a wb_toplevel. */
struct wlr_scene_node *node =
wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy);
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
@ -13,17 +13,13 @@ struct wb_view *get_view_at(
}
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_surface *scene_surface =
#if WLR_CHECK_VERSION(0, 17, 0)
wlr_scene_surface_try_from_buffer(scene_buffer);
#else
wlr_scene_surface_from_buffer(scene_buffer);
#endif
if (!scene_surface) {
return NULL;
}
*surface = scene_surface->surface;
/* Find the node corresponding to the wb_view at the root of this
/* Find the node corresponding to the wb_toplevel at the root of this
* surface tree, it is the only one for which we set the data field. */
struct wlr_scene_tree *tree = node->parent;
while (tree != NULL && tree->node.data == NULL) {
@ -32,25 +28,18 @@ struct wb_view *get_view_at(
return tree->node.data;
}
void focus_view(struct wb_view *view, struct wlr_surface *surface) {
void focus_toplevel(struct wb_toplevel *toplevel, struct wlr_surface *surface) {
/* Note: this function only deals with keyboard focus. */
if (view == NULL) {
if (toplevel == NULL) {
return;
}
#if WLR_CHECK_VERSION(0, 17, 0)
struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_try_from_wlr_surface(surface);
#else
if (surface == NULL || !wlr_surface_is_xdg_surface(surface))
return;
struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface);
#endif
if (xdg_surface)
wlr_log(WLR_INFO, "%s: %s", _("Keyboard focus is now on surface"),
xdg_surface->toplevel->app_id);
struct wb_server *server = view->server;
struct wb_server *server = toplevel->server;
struct wlr_seat *seat = server->seat->seat;
struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
if (prev_surface == surface) {
@ -63,48 +52,40 @@ void focus_view(struct wb_view *view, struct wlr_surface *surface) {
* it no longer has focus and the client will repaint accordingly, e.g.
* stop displaying a caret.
*/
#if WLR_CHECK_VERSION(0, 17, 0)
struct wlr_xdg_surface *previous =
wlr_xdg_surface_try_from_wlr_surface(prev_surface);
#else
struct wlr_xdg_surface *previous = NULL;
if (wlr_surface_is_xdg_surface(prev_surface)) {
previous = wlr_xdg_surface_from_wlr_surface(prev_surface);
}
#endif
if (previous != NULL && previous->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL &&
previous->toplevel != NULL) {
wlr_xdg_toplevel_set_activated(previous->toplevel, false);
struct wlr_xdg_toplevel *prev_toplevel =
wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
if (prev_toplevel != NULL) {
wlr_xdg_toplevel_set_activated(prev_toplevel, false);
}
}
/* Move the view to the front */
/* Move the toplevel to the front */
if (!server->seat->focused_layer) {
wlr_scene_node_raise_to_top(&view->scene_tree->node);
wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
}
wl_list_remove(&view->link);
wl_list_insert(&server->views, &view->link);
wl_list_remove(&toplevel->link);
wl_list_insert(&server->toplevels, &toplevel->link);
/* Activate the new surface */
wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
wlr_xdg_toplevel_set_activated(toplevel->xdg_toplevel, true);
/*
* Tell the seat to have the keyboard enter this surface. wlroots will keep
* track of this and automatically send key events to the appropriate
* clients without additional work on your part.
*/
seat_focus_surface(server->seat, view->xdg_toplevel->base->surface);
seat_focus_surface(server->seat, toplevel->xdg_toplevel->base->surface);
}
struct wlr_output *get_active_output(struct wb_view *view) {
struct wlr_output *get_active_output(struct wb_toplevel *toplevel) {
double closest_x, closest_y;
struct wlr_output *output = NULL;
wlr_output_layout_closest_point(view->server->output_layout, output,
view->geometry.x + view->geometry.width / 2,
view->geometry.y + view->geometry.height / 2,
wlr_output_layout_closest_point(toplevel->server->output_layout, output,
toplevel->geometry.x + toplevel->geometry.width / 2,
toplevel->geometry.y + toplevel->geometry.height / 2,
&closest_x, &closest_y);
return wlr_output_layout_output_at(view->server->output_layout, closest_x, closest_y);
return wlr_output_layout_output_at(toplevel->server->output_layout, closest_x, closest_y);
}
static struct wlr_box get_usable_area(struct wb_view *view) {
struct wlr_output *output = get_active_output(view);
static struct wlr_box get_usable_area(struct wb_toplevel *toplevel) {
struct wlr_output *output = get_active_output(toplevel);
struct wlr_box usable_area = {0};
wlr_output_effective_resolution(output, &usable_area.width, &usable_area.height);
return usable_area;
@ -112,79 +93,79 @@ static struct wlr_box get_usable_area(struct wb_view *view) {
static void xdg_toplevel_map(struct wl_listener *listener, void *data) {
/* Called when the surface is mapped, or ready to display on-screen. */
struct wb_view *view = wl_container_of(listener, view, map);
if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, map);
if (toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return;
struct wb_config *config = view->server->config;
struct wb_config *config = toplevel->server->config;
struct wlr_box geo_box = {0};
struct wlr_box usable_area = get_usable_area(view);
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
struct wlr_box usable_area = get_usable_area(toplevel);
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
if (config) {
view->geometry.height = MIN(geo_box.height,
toplevel->geometry.height = MIN(geo_box.height,
usable_area.height - config->margins.top - config->margins.bottom);
view->geometry.width = MIN(geo_box.width,
toplevel->geometry.width = MIN(geo_box.width,
usable_area.width - config->margins.left - config->margins.right);
view->geometry.x = config->margins.left;
view->geometry.y = config->margins.top;
toplevel->geometry.x = config->margins.left;
toplevel->geometry.y = config->margins.top;
} else {
view->geometry.height = MIN(geo_box.height, usable_area.height);
view->geometry.width = MIN(geo_box.width, usable_area.width);
view->geometry.x = 0;
view->geometry.y = 0;
toplevel->geometry.height = MIN(geo_box.height, usable_area.height);
toplevel->geometry.width = MIN(geo_box.width, usable_area.width);
toplevel->geometry.x = 0;
toplevel->geometry.y = 0;
}
/* A view no larger than a title bar shouldn't be sized or focused */
if (view->geometry.height > TITLEBAR_HEIGHT &&
view->geometry.height > TITLEBAR_HEIGHT *
/* A toplevel no larger than a title bar shouldn't be sized or focused */
if (toplevel->geometry.height > TITLEBAR_HEIGHT &&
toplevel->geometry.height > TITLEBAR_HEIGHT *
(usable_area.width / usable_area.height)) {
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
view->geometry.width, view->geometry.height);
focus_view(view, view->xdg_toplevel->base->surface);
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel,
toplevel->geometry.width, toplevel->geometry.height);
focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
}
wlr_scene_node_set_position(&view->scene_tree->node,
view->geometry.x, view->geometry.y);
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->geometry.x, toplevel->geometry.y);
}
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
/* Called when the surface is unmapped, and should no longer be shown. */
struct wb_view *view = wl_container_of(listener, view, unmap);
if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, unmap);
if (toplevel->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return;
reset_cursor_mode(view->server);
reset_cursor_mode(toplevel->server);
/* Focus the next view, if any. */
if (wl_list_length(&view->link) > 1) {
struct wb_view *next_view = wl_container_of(view->link.next, next_view, link);
if (next_view && next_view->xdg_toplevel && next_view->scene_tree && next_view->scene_tree->node.enabled) {
wlr_log(WLR_INFO, "%s: %s", _("Focusing next view"),
next_view->xdg_toplevel->app_id);
focus_view(next_view, next_view->xdg_toplevel->base->surface);
/* Focus the next toplevel, if any. */
if (wl_list_length(&toplevel->link) > 1) {
struct wb_toplevel *next_toplevel = wl_container_of(toplevel->link.next, next_toplevel, link);
if (next_toplevel && next_toplevel->xdg_toplevel && next_toplevel->scene_tree && next_toplevel->scene_tree->node.enabled) {
wlr_log(WLR_INFO, "%s: %s", _("Focusing next toplevel"),
next_toplevel->xdg_toplevel->app_id);
focus_toplevel(next_toplevel, next_toplevel->xdg_toplevel->base->surface);
}
}
}
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
/* Called when the surface is destroyed and should never be shown again. */
struct wb_view *view = wl_container_of(listener, view, destroy);
/* Called when the xdg_toplevel is destroyed and should never be shown again. */
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
wl_list_remove(&view->map.link);
wl_list_remove(&view->unmap.link);
wl_list_remove(&view->destroy.link);
wl_list_remove(&view->new_popup.link);
wl_list_remove(&toplevel->map.link);
wl_list_remove(&toplevel->unmap.link);
wl_list_remove(&toplevel->destroy.link);
wl_list_remove(&toplevel->new_popup.link);
if (view->xdg_toplevel->base->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wl_list_remove(&view->request_fullscreen.link);
wl_list_remove(&view->request_minimize.link);
wl_list_remove(&view->request_maximize.link);
wl_list_remove(&view->request_move.link);
wl_list_remove(&view->request_resize.link);
wl_list_remove(&view->link);
if (toplevel->xdg_toplevel->base->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wl_list_remove(&toplevel->request_fullscreen.link);
wl_list_remove(&toplevel->request_minimize.link);
wl_list_remove(&toplevel->request_maximize.link);
wl_list_remove(&toplevel->request_move.link);
wl_list_remove(&toplevel->request_resize.link);
wl_list_remove(&toplevel->link);
}
free(view);
free(toplevel);
}
static void xdg_toplevel_request_fullscreen(
@ -194,9 +175,9 @@ static void xdg_toplevel_request_fullscreen(
* conform to xdg-shell protocol we still must send a configure.
* wlr_xdg_surface_schedule_configure() is used to send an empty reply.
*/
struct wb_view *view =
wl_container_of(listener, view, request_fullscreen);
wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
struct wb_toplevel *toplevel =
wl_container_of(listener, toplevel, request_fullscreen);
wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
}
static void xdg_toplevel_request_maximize(struct wl_listener *listener, void *data) {
@ -204,85 +185,85 @@ static void xdg_toplevel_request_maximize(struct wl_listener *listener, void *da
* typically because the user clicked on the maximize button on
* client-side decorations.
*/
struct wb_view *view = wl_container_of(listener, view, request_maximize);
struct wlr_box usable_area = get_usable_area(view);
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_maximize);
struct wlr_box usable_area = get_usable_area(toplevel);
bool is_maximized = view->xdg_toplevel->current.maximized;
bool is_maximized = toplevel->xdg_toplevel->current.maximized;
if (!is_maximized) {
struct wb_config *config = view->server->config;
view->previous_geometry = view->geometry;
struct wb_config *config = toplevel->server->config;
toplevel->previous_geometry = toplevel->geometry;
if (config) {
view->geometry.x = config->margins.left;
view->geometry.y = config->margins.top;
toplevel->geometry.x = config->margins.left;
toplevel->geometry.y = config->margins.top;
usable_area.height -= config->margins.top + config->margins.bottom;
usable_area.width -= config->margins.left + config->margins.right;
} else {
view->geometry.x = 0;
view->geometry.y = 0;
toplevel->geometry.x = 0;
toplevel->geometry.y = 0;
}
} else {
usable_area = view->previous_geometry;
view->geometry.x = view->previous_geometry.x;
view->geometry.y = view->previous_geometry.y;
usable_area = toplevel->previous_geometry;
toplevel->geometry.x = toplevel->previous_geometry.x;
toplevel->geometry.y = toplevel->previous_geometry.y;
}
wlr_xdg_toplevel_set_size(view->xdg_toplevel, usable_area.width, usable_area.height);
wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, !is_maximized);
wlr_scene_node_set_position(&view->scene_tree->node,
view->geometry.x, view->geometry.y);
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, usable_area.width, usable_area.height);
wlr_xdg_toplevel_set_maximized(toplevel->xdg_toplevel, !is_maximized);
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->geometry.x, toplevel->geometry.y);
}
static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data) {
struct wb_view *view = wl_container_of(listener, view, request_minimize);
bool minimize_requested = view->xdg_toplevel->requested.minimized;
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_minimize);
bool minimize_requested = toplevel->xdg_toplevel->requested.minimized;
if (minimize_requested) {
view->previous_geometry = view->geometry;
view->geometry.y = -view->geometry.height;
toplevel->previous_geometry = toplevel->geometry;
toplevel->geometry.y = -toplevel->geometry.height;
struct wb_view *next_view = wl_container_of(view->link.next, next_view, link);
if (wl_list_length(&view->link) > 1)
focus_view(next_view, next_view->xdg_toplevel->base->surface);
struct wb_toplevel *next_toplevel = wl_container_of(toplevel->link.next, next_toplevel, link);
if (wl_list_length(&toplevel->link) > 1)
focus_toplevel(next_toplevel, next_toplevel->xdg_toplevel->base->surface);
else
focus_view(view, view->xdg_toplevel->base->surface);
focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
} else {
view->geometry = view->previous_geometry;
toplevel->geometry = toplevel->previous_geometry;
}
wlr_scene_node_set_position(&view->scene_tree->node,
view->geometry.x, view->geometry.y);
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->geometry.x, toplevel->geometry.y);
}
static void begin_interactive(struct wb_view *view,
static void begin_interactive(struct wb_toplevel *toplevel,
enum wb_cursor_mode mode, uint32_t edges) {
/* This function sets up an interactive move or resize operation, where the
* compositor stops propagating pointer events to clients and instead
* consumes them itself, to move or resize windows. */
struct wb_server *server = view->server;
struct wb_server *server = toplevel->server;
struct wlr_surface *focused_surface =
server->seat->seat->pointer_state.focused_surface;
if (view->xdg_toplevel->base->surface != wlr_surface_get_root_surface(focused_surface)) {
if (toplevel->xdg_toplevel->base->surface != wlr_surface_get_root_surface(focused_surface)) {
/* Deny move/resize requests from unfocused clients. */
return;
}
server->grabbed_view = view;
server->grabbed_toplevel = toplevel;
server->cursor->cursor_mode = mode;
if (mode == WB_CURSOR_MOVE) {
server->grab_x = server->cursor->cursor->x - view->geometry.x;
server->grab_y = server->cursor->cursor->y - view->geometry.y;
server->grab_x = server->cursor->cursor->x - toplevel->geometry.x;
server->grab_y = server->cursor->cursor->y - toplevel->geometry.y;
} else if (mode == WB_CURSOR_RESIZE) {
struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
double border_x = (view->geometry.x + geo_box.x) +
double border_x = (toplevel->geometry.x + geo_box.x) +
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
double border_y = (view->geometry.y + geo_box.y) +
double border_y = (toplevel->geometry.y + geo_box.y) +
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
server->grab_x = server->cursor->cursor->x - border_x;
server->grab_y = server->cursor->cursor->y - border_y;
server->grab_geo_box = geo_box;
server->grab_geo_box.x += view->geometry.x;
server->grab_geo_box.y += view->geometry.y;
server->grab_geo_box.x += toplevel->geometry.x;
server->grab_geo_box.y += toplevel->geometry.y;
server->resize_edges = edges;
}
@ -293,8 +274,8 @@ static void xdg_toplevel_request_move(
/* This event is raised when a client would like to begin an interactive
* move, typically because the user clicked on their client-side
* decorations. */
struct wb_view *view = wl_container_of(listener, view, request_move);
begin_interactive(view, WB_CURSOR_MOVE, 0);
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_move);
begin_interactive(toplevel, WB_CURSOR_MOVE, 0);
}
static void xdg_toplevel_request_resize(
@ -303,29 +284,29 @@ static void xdg_toplevel_request_resize(
* resize, typically because the user clicked on their client-side
* decorations. */
struct wlr_xdg_toplevel_resize_event *event = data;
struct wb_view *view = wl_container_of(listener, view, request_resize);
begin_interactive(view, WB_CURSOR_RESIZE, event->edges);
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, request_resize);
begin_interactive(toplevel, WB_CURSOR_RESIZE, event->edges);
}
static void handle_new_popup(struct wl_listener *listener, void *data) {
struct wlr_xdg_popup *popup = data;
struct wb_view *view = wl_container_of(listener, view, new_popup);
struct wb_toplevel *toplevel = wl_container_of(listener, toplevel, new_popup);
struct wlr_output *wlr_output = wlr_output_layout_output_at(
view->server->output_layout,
view->geometry.x + popup->current.geometry.x,
view->geometry.y + popup->current.geometry.y);
toplevel->server->output_layout,
toplevel->geometry.x + popup->current.geometry.x,
toplevel->geometry.y + popup->current.geometry.y);
if (!wlr_output) {
return;
}
struct wb_output *output = wlr_output->data;
int top_margin = (view->server->config) ?
view->server->config->margins.top : 0;
int top_margin = (toplevel->server->config) ?
toplevel->server->config->margins.top : 0;
struct wlr_box output_toplevel_box = {
.x = output->geometry.x - view->geometry.x,
.y = output->geometry.y - view->geometry.y,
.x = output->geometry.x - toplevel->geometry.x,
.y = output->geometry.y - toplevel->geometry.y,
.width = output->geometry.width,
.height = output->geometry.height - top_margin,
};
@ -345,15 +326,9 @@ static void handle_new_xdg_surface(struct wl_listener *listener, void *data) {
* we always set the user data field of xdg_surfaces to the corresponding
* scene node. */
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
#if WLR_CHECK_VERSION(0, 17, 0)
struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(
xdg_surface->popup->parent);
if (parent != NULL) {
#else
if (wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) {
struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(
xdg_surface->popup->parent);
#endif
struct wlr_scene_tree *parent_tree = parent->data;
xdg_surface->data = wlr_scene_xdg_surface_create(
@ -365,49 +340,41 @@ static void handle_new_xdg_surface(struct wl_listener *listener, void *data) {
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)
return;
/* Allocate a wb_view for this surface */
struct wb_view *view =
calloc(1, sizeof(struct wb_view));
view->server = server;
view->xdg_toplevel = xdg_surface->toplevel;
/* Allocate a wb_toplevel for this surface */
struct wb_toplevel *toplevel =
calloc(1, sizeof(struct wb_toplevel));
toplevel->server = server;
toplevel->xdg_toplevel = xdg_surface->toplevel;
/* Listen to the various events it can emit */
view->map.notify = xdg_toplevel_map;
#if WLR_CHECK_VERSION(0, 17, 0)
wl_signal_add(&xdg_surface->surface->events.map, &view->map);
#else
wl_signal_add(&xdg_surface->events.map, &view->map);
#endif
view->unmap.notify = xdg_toplevel_unmap;
#if WLR_CHECK_VERSION(0, 17, 0)
wl_signal_add(&xdg_surface->surface->events.unmap, &view->unmap);
#else
wl_signal_add(&xdg_surface->events.unmap, &view->unmap);
#endif
view->destroy.notify = xdg_toplevel_destroy;
wl_signal_add(&xdg_surface->events.destroy, &view->destroy);
view->new_popup.notify = handle_new_popup;
wl_signal_add(&xdg_surface->events.new_popup, &view->new_popup);
toplevel->map.notify = xdg_toplevel_map;
wl_signal_add(&xdg_surface->surface->events.map, &toplevel->map);
toplevel->unmap.notify = xdg_toplevel_unmap;
wl_signal_add(&xdg_surface->surface->events.unmap, &toplevel->unmap);
toplevel->destroy.notify = xdg_toplevel_destroy;
wl_signal_add(&xdg_surface->events.destroy, &toplevel->destroy);
toplevel->new_popup.notify = handle_new_popup;
wl_signal_add(&xdg_surface->events.new_popup, &toplevel->new_popup);
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
view->scene_tree = wlr_scene_xdg_surface_create(
&view->server->scene->tree, view->xdg_toplevel->base);
view->scene_tree->node.data = view;
xdg_surface->data = view->scene_tree;
toplevel->scene_tree = wlr_scene_xdg_surface_create(
&toplevel->server->scene->tree, toplevel->xdg_toplevel->base);
toplevel->scene_tree->node.data = toplevel;
xdg_surface->data = toplevel->scene_tree;
struct wlr_xdg_toplevel *toplevel = view->xdg_toplevel;
view->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
wl_signal_add(&toplevel->events.request_fullscreen, &view->request_fullscreen);
view->request_maximize.notify = xdg_toplevel_request_maximize;
wl_signal_add(&toplevel->events.request_maximize, &view->request_maximize);
view->request_minimize.notify = xdg_toplevel_request_minimize;
wl_signal_add(&toplevel->events.request_minimize, &view->request_minimize);
view->request_move.notify = xdg_toplevel_request_move;
wl_signal_add(&toplevel->events.request_move, &view->request_move);
view->request_resize.notify = xdg_toplevel_request_resize;
wl_signal_add(&toplevel->events.request_resize, &view->request_resize);
struct wlr_xdg_toplevel *xdg_toplevel = toplevel->xdg_toplevel;
toplevel->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
wl_signal_add(&xdg_toplevel->events.request_fullscreen, &toplevel->request_fullscreen);
toplevel->request_maximize.notify = xdg_toplevel_request_maximize;
wl_signal_add(&xdg_toplevel->events.request_maximize, &toplevel->request_maximize);
toplevel->request_minimize.notify = xdg_toplevel_request_minimize;
wl_signal_add(&xdg_toplevel->events.request_minimize, &toplevel->request_minimize);
toplevel->request_move.notify = xdg_toplevel_request_move;
wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move);
toplevel->request_resize.notify = xdg_toplevel_request_resize;
wl_signal_add(&xdg_toplevel->events.request_resize, &toplevel->request_resize);
wl_list_insert(&view->server->views, &view->link);
wl_list_insert(&toplevel->server->toplevels, &toplevel->link);
}
}