REFACTOR (wl_listeners isolated)

This commit is contained in:
Emile Clark-Boman 2025-08-28 02:03:35 +10:00
parent ab3942d3b5
commit b92eb285c0
31 changed files with 620 additions and 473 deletions

View file

@ -1,3 +1,7 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include "client.h" #include "client.h"
void applybounds(Client *c, struct wlr_box *bbox) { void applybounds(Client *c, struct wlr_box *bbox) {
@ -225,20 +229,6 @@ void updatetitle(struct wl_listener *listener, void *data) {
printstatus(); printstatus();
} }
void urgent(struct wl_listener *listener, void *data) {
struct wlr_xdg_activation_v1_request_activate_event *event = data;
Client *c = NULL;
toplevel_from_wlr_surface(event->surface, &c, NULL);
if (!c || c == focustop(selmon))
return;
c->isurgent = 1;
printstatus();
if (client_surface(c)->mapped)
client_set_border_color(c, urgentcolor);
}
void view(const Arg *arg) { void view(const Arg *arg) {
if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return; return;

View file

@ -7,7 +7,8 @@
#ifndef CRYWL_CLIENT_H #ifndef CRYWL_CLIENT_H
#define CRYWL_CLIENT_H #define CRYWL_CLIENT_H
#include "../wayland.h" #include <wlr/util/box.h>
#include "../util.h" #include "../util.h"
enum { XDGShell, LayerShell, X11 }; /* client types */ enum { XDGShell, LayerShell, X11 }; /* client types */
@ -61,14 +62,11 @@ void killclient(const Arg *arg);
void resize(Client *c, struct wlr_box geo, int interact); void resize(Client *c, struct wlr_box geo, int interact);
void setfloating(Client *c, int floating); void setfloating(Client *c, int floating);
void setfullscreen(Client *c, int fullscreen); void setfullscreen(Client *c, int fullscreen);
void setpsel(struct wl_listener *listener, void *data);
void setsel(struct wl_listener *listener, void *data);
void togglefloating(const Arg *arg); void togglefloating(const Arg *arg);
void togglefullscreen(const Arg *arg); void togglefullscreen(const Arg *arg);
void toggletag(const Arg *arg); void toggletag(const Arg *arg);
void toggleview(const Arg *arg); void toggleview(const Arg *arg);
void updatetitle(struct wl_listener *listener, void *data); void updatetitle(struct wl_listener *listener, void *data);
void urgent(struct wl_listener *listener, void *data);
void view(const Arg *arg); void view(const Arg *arg);
void zoom(const Arg *arg); void zoom(const Arg *arg);

View file

@ -305,42 +305,6 @@ void handlesig(int signo) {
quit(NULL); quit(NULL);
} }
void printstatus(void) {
Monitor *m = NULL;
Client *c;
uint32_t occ, urg, sel;
wl_list_for_each(m, &mons, link) {
occ = urg = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
}
if ((c = focustop(m))) {
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
sel = c->tags;
} else {
printf("%s title \n", m->wlr_output->name);
printf("%s appid \n", m->wlr_output->name);
printf("%s fullscreen \n", m->wlr_output->name);
printf("%s floating \n", m->wlr_output->name);
sel = 0;
}
printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
printf("%s tags %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
}
fflush(stdout);
}
void run(char *startup_cmd) { void run(char *startup_cmd) {
/* Add a Unix socket to the Wayland display. */ /* Add a Unix socket to the Wayland display. */
const char *socket = wl_display_add_socket_auto(dpy); const char *socket = wl_display_add_socket_auto(dpy);

View file

@ -1,5 +1,7 @@
#include <stddef.h> #include <stddef.h>
#include <wlr/types/wlr_cursor.h>
#include "cursor.h" #include "cursor.h"
#include "clientutil.h" #include "clientutil.h"

View file

@ -1,3 +1,10 @@
#include <stdlib.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
void checkidleinhibitor(struct wlr_surface *exclude) { void checkidleinhibitor(struct wlr_surface *exclude) {
int inhibited = 0, unused_lx, unused_ly; int inhibited = 0, unused_lx, unused_ly;
struct wlr_idle_inhibitor_v1 *inhibitor; struct wlr_idle_inhibitor_v1 *inhibitor;
@ -17,13 +24,7 @@ void checkidleinhibitor(struct wlr_surface *exclude) {
wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
} }
void createidleinhibitor(struct wl_listener *listener, void *data) { /* Helper listener used by `listeners/idle.h:createidleinhibitor` */
struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor);
checkidleinhibitor(NULL);
}
void destroyidleinhibitor(struct wl_listener *listener, void *data) { void destroyidleinhibitor(struct wl_listener *listener, void *data) {
/* `data` is the wlr_surface of the idle inhibitor being destroyed, /* `data` is the wlr_surface of the idle inhibitor being destroyed,
* at this point the idle inhibitor is still in the list of the manager */ * at this point the idle inhibitor is still in the list of the manager */

View file

@ -1,9 +1,11 @@
#ifndef CRYWL_IDLE_H #ifndef CRYWL_IDLE_H
#define CRYWL_IDLE_H #define CRYWL_IDLE_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
/* ===== Function Declarations ===== */ /* ===== Function Declarations ===== */
static void checkidleinhibitor(struct wlr_surface *exclude); void checkidleinhibitor(struct wlr_surface *exclude);
static void createidleinhibitor(struct wl_listener *listener, void *data); void destroyidleinhibitor(struct wl_listener *listener, void *data);
static void destroyidleinhibitor(struct wl_listener *listener, void *data);
#endif /* CRYWL_IDLE_H */ #endif /* CRYWL_IDLE_H */

View file

@ -65,14 +65,6 @@ void createpointer(struct wlr_pointer *pointer) {
wlr_cursor_attach_input_device(cursor, &pointer->base); wlr_cursor_attach_input_device(cursor, &pointer->base);
} }
void createpointerconstraint(struct wl_listener *listener, void *data) {
PointerConstraint *pointer_constraint =
ecalloc(1, sizeof(*pointer_constraint));
pointer_constraint->constraint = data;
LISTEN(&pointer_constraint->constraint->events.destroy,
&pointer_constraint->destroy, destroypointerconstraint);
}
KeyboardGroup *createkeyboardgroup(void) { KeyboardGroup *createkeyboardgroup(void) {
KeyboardGroup *group = ecalloc(1, sizeof(*group)); KeyboardGroup *group = ecalloc(1, sizeof(*group));
struct xkb_context *context; struct xkb_context *context;
@ -134,34 +126,6 @@ void destroykeyboardgroup(struct wl_listener *listener, void *data) {
free(group); free(group);
} }
void inputdevice(struct wl_listener *listener, void *data) {
/* This event is raised by the backend when a new input device becomes
* available. */
struct wlr_input_device *device = data;
uint32_t caps;
switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
createkeyboard(wlr_keyboard_from_input_device(device));
break;
case WLR_INPUT_DEVICE_POINTER:
createpointer(wlr_pointer_from_input_device(device));
break;
default:
/* TODO handle other input device types */
break;
}
/* We need to let the wlr_seat know what our capabilities are, which is
* communiciated to the client. In dwl we always have a cursor, even if
* there are no pointer devices, so we always include that capability. */
/* TODO do we actually require a cursor? */
caps = WL_SEAT_CAPABILITY_POINTER;
if (!wl_list_empty(&kb_group->wlr_group->devices))
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
wlr_seat_set_capabilities(seat, caps);
}
int keybinding(uint32_t mods, xkb_keysym_t sym) { int keybinding(uint32_t mods, xkb_keysym_t sym) {
/* /*
* Here we handle compositor keybindings. This is when the compositor is * Here we handle compositor keybindings. This is when the compositor is

View file

@ -40,18 +40,12 @@ typedef struct {
struct wl_listener destroy; struct wl_listener destroy;
} PointerConstraint; } PointerConstraint;
/* ===== Event Handlers ===== */
static void virtualkeyboard(struct wl_listener *listener, void *data);
static void virtualpointer(struct wl_listener *listener, void *data);
/* ===== Function Declarations ===== */ /* ===== Function Declarations ===== */
static void createkeyboard(struct wlr_keyboard *keyboard); static void createkeyboard(struct wlr_keyboard *keyboard);
static KeyboardGroup *createkeyboardgroup(void); static KeyboardGroup *createkeyboardgroup(void);
static void createpointer(struct wlr_pointer *pointer); static void createpointer(struct wlr_pointer *pointer);
static void createpointerconstraint(struct wl_listener *listener, void *data);
static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data);
static void destroykeyboardgroup(struct wl_listener *listener, void *data); static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static void inputdevice(struct wl_listener *listener, void *data);
static int keybinding(uint32_t mods, xkb_keysym_t sym); static int keybinding(uint32_t mods, xkb_keysym_t sym);
static void keypress(struct wl_listener *listener, void *data); static void keypress(struct wl_listener *listener, void *data);
static void keypressmod(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data);

View file

@ -1,4 +1,9 @@
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include "layers.h" #include "layers.h"
#include "notify.h"
#include "clientutil.h"
void commitlayersurfacenotify(struct wl_listener *listener, void *data) { void commitlayersurfacenotify(struct wl_listener *listener, void *data) {
LayerSurface *l = wl_container_of(listener, l, surface_commit); LayerSurface *l = wl_container_of(listener, l, surface_commit);
@ -64,43 +69,6 @@ void destroylayersurfacenotify(struct wl_listener *listener, void *data) {
free(l); free(l);
} }
/* Binds commitlayersurfacenotify, unmaplayersurfacenotify, destroylayersurfacenotify
*/
void createlayersurface(struct wl_listener *listener, void *data) {
struct wlr_layer_surface_v1 *layer_surface = data;
LayerSurface *l;
struct wlr_surface *surface = layer_surface->surface;
struct wlr_scene_tree *scene_layer =
layers[layermap[layer_surface->pending.layer]];
if (!layer_surface->output &&
!(layer_surface->output = selmon ? selmon->wlr_output : NULL)) {
wlr_layer_surface_v1_destroy(layer_surface);
return;
}
l = layer_surface->data = ecalloc(1, sizeof(*l));
l->type = LayerShell;
LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify);
LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify);
LISTEN(&layer_surface->events.destroy, &l->destroy,
destroylayersurfacenotify);
l->layer_surface = layer_surface;
l->mon = layer_surface->output->data;
l->scene_layer =
wlr_scene_layer_surface_v1_create(scene_layer, layer_surface);
l->scene = l->scene_layer->tree;
l->popups = surface->data = wlr_scene_tree_create(
layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP
? layers[LyrTop]
: scene_layer);
l->scene->node.data = l->popups->node.data = l;
wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link);
wlr_surface_send_enter(surface, layer_surface->output);
}
void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
LayerSurface **pl, double *nx, double *ny) { LayerSurface **pl, double *nx, double *ny) {
struct wlr_scene_node *node, *pnode; struct wlr_scene_node *node, *pnode;

View file

@ -24,8 +24,6 @@ typedef struct {
static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
// createlayersurface uses the (commit|unmap|destroy)layersurfacenotify callbacks
static void createlayersurface(struct wl_listener *listener, void *data);
void xytonode(double x, double y, struct wlr_surface **psurface, void xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny); Client **pc, LayerSurface **pl, double *nx, double *ny);

View file

@ -1,3 +1,15 @@
#include <stdlib.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include "clientutil.h"
#include "lock.h"
#include "monitor.h"
#include "notify.h"
void createlocksurface(struct wl_listener *listener, void *data) { void createlocksurface(struct wl_listener *listener, void *data) {
SessionLock *lock = wl_container_of(listener, lock, new_surface); SessionLock *lock = wl_container_of(listener, lock, new_surface);
struct wlr_session_lock_surface_v1 *lock_surface = data; struct wlr_session_lock_surface_v1 *lock_surface = data;
@ -61,29 +73,6 @@ void destroysessionlock(struct wl_listener *listener, void *data) {
destroylock(lock, 0); destroylock(lock, 0);
} }
void locksession(struct wl_listener *listener, void *data) {
struct wlr_session_lock_v1 *session_lock = data;
SessionLock *lock;
wlr_scene_node_set_enabled(&locked_bg->node, 1);
if (cur_lock) {
wlr_session_lock_v1_destroy(session_lock);
return;
}
lock = session_lock->data = ecalloc(1, sizeof(*lock));
focusclient(NULL, 0);
lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
cur_lock = lock->lock = session_lock;
locked = 1;
LISTEN(&session_lock->events.new_surface, &lock->new_surface,
createlocksurface);
LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
wlr_session_lock_v1_send_locked(session_lock);
}
void unlocksession(struct wl_listener *listener, void *data) { void unlocksession(struct wl_listener *listener, void *data) {
SessionLock *lock = wl_container_of(listener, lock, unlock); SessionLock *lock = wl_container_of(listener, lock, unlock);
destroylock(lock, 1); destroylock(lock, 1);

View file

@ -1,6 +1,8 @@
#ifndef CRYWL_LOCK_H #ifndef CRYWL_LOCK_H
#define CRYWL_LOCK_H #define CRYWL_LOCK_H
#include <wayland-server-core.h>
typedef struct { typedef struct {
struct wlr_scene_tree *scene; struct wlr_scene_tree *scene;
@ -15,7 +17,6 @@ static void createlocksurface(struct wl_listener *listener, void *data);
static void destroylock(SessionLock *lock, int unlocked); static void destroylock(SessionLock *lock, int unlocked);
static void destroylocksurface(struct wl_listener *listener, void *data); static void destroylocksurface(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data);
static void locksession(struct wl_listener *listener, void *data);
static void unlocksession(struct wl_listener *listener, void *data); static void unlocksession(struct wl_listener *listener, void *data);
#endif /* CRYWL_LOCK_H */ #endif /* CRYWL_LOCK_H */

44
src/lib/logging.c Normal file
View file

@ -0,0 +1,44 @@
#include <stdio.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_output.h>
#include "monitor.h"
#include "clientutil.h"
void printstatus(void) {
Monitor *m = NULL;
Client *c;
uint32_t occ, urg, sel;
wl_list_for_each(m, &mons, link) {
occ = urg = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
}
if ((c = focustop(m))) {
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
sel = c->tags;
} else {
printf("%s title \n", m->wlr_output->name);
printf("%s appid \n", m->wlr_output->name);
printf("%s fullscreen \n", m->wlr_output->name);
printf("%s floating \n", m->wlr_output->name);
sel = 0;
}
printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
printf("%s tags %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
}
fflush(stdout);
}

8
src/lib/logging.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef CRYWL_LOGGING_H
#define CRYWL_LOGGING_H
/* ===== Functional Declarations ===== */
static void printstatus(void);
#endif /* CRYWL_LOGGING_H */

View file

@ -1,11 +0,0 @@
#ifndef CRYWL_MGRS_H
#define CRYWL_MGRS_H
/* ===== Function Declarations ===== */
static void outputmgrapply(struct wl_listener *listener, void *data);
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config,
int test);
static void outputmgrtest(struct wl_listener *listener, void *data);
static void powermgrsetmode(struct wl_listener *listener, void *data);
#endif /* CRYWL_MGRS_H */

View file

@ -1,3 +1,7 @@
#include <string.h>
#include <wlr/types/wlr_scene.h>
#include "monitor.h" #include "monitor.h"
#include "clientutil.h" #include "clientutil.h"
@ -184,84 +188,6 @@ void closemon(Monitor *m) {
printstatus(); printstatus();
} }
void createmon(struct wl_listener *listener, void *data) {
/* This event is raised by the backend when a new output (aka a display or
* monitor) becomes available. */
struct wlr_output *wlr_output = data;
const MonitorRule *r;
size_t i;
struct wlr_output_state state;
Monitor *m;
if (!wlr_output_init_render(wlr_output, alloc, drw))
return;
m = wlr_output->data = ecalloc(1, sizeof(*m));
m->wlr_output = wlr_output;
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
wlr_output_state_init(&state);
/* Initialize monitor state using configured rules */
m->tagset[0] = m->tagset[1] = 1;
for (r = monrules; r < END(monrules); r++) {
if (!r->name || strstr(wlr_output->name, r->name)) {
m->m.x = r->x;
m->m.y = r->y;
m->mfact = r->mfact;
m->nmaster = r->nmaster;
m->lt[0] = r->lt;
m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
wlr_output_state_set_scale(&state, r->scale);
wlr_output_state_set_transform(&state, r->rr);
break;
}
}
/* The mode is a tuple of (width, height, refresh rate), and each
* monitor supports only a specific set of modes. We just pick the
* monitor's preferred mode; a more sophisticated compositor would let
* the user configure it. */
wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
/* Set up event listeners */
LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
wlr_output_state_set_enabled(&state, 1);
wlr_output_commit_state(wlr_output, &state);
wlr_output_state_finish(&state);
wl_list_insert(&mons, &m->link);
printstatus();
/* The xdg-protocol specifies:
*
* If the fullscreened surface is not opaque, the compositor must make
* sure that other screen content not part of the same surface tree (made
* up of subsurfaces, popups or similarly coupled surfaces) are not
* visible below the fullscreened surface.
*
*/
/* updatemons() will resize and set correct position */
m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg);
wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0);
/* Adds this to the output layout in the order it was configured.
*
* The output layout utility automatically adds a wl_output global to the
* display, which Wayland clients can see to find out information about the
* output (such as DPI, scale factor, manufacturer, etc).
*/
m->scene_output = wlr_scene_output_create(scene, wlr_output);
if (m->m.x == -1 && m->m.y == -1)
wlr_output_layout_add_auto(output_layout, wlr_output);
else
wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
}
Monitor *dirtomon(enum wlr_direction dir) { Monitor *dirtomon(enum wlr_direction dir) {
struct wlr_output *next; struct wlr_output *next;
@ -323,29 +249,6 @@ Client *focustop(Monitor *m) {
return NULL; return NULL;
} }
void gpureset(struct wl_listener *listener, void *data) {
struct wlr_renderer *old_drw = drw;
struct wlr_allocator *old_alloc = alloc;
struct Monitor *m;
if (!(drw = wlr_renderer_autocreate(backend)))
die("couldn't recreate renderer");
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
die("couldn't recreate allocator");
wl_list_remove(&gpu_reset.link);
wl_signal_add(&drw->events.lost, &gpu_reset);
wlr_compositor_set_renderer(compositor, drw);
wl_list_for_each(m, &mons, link) {
wlr_output_init_render(m->wlr_output, alloc, drw);
}
wlr_allocator_destroy(old_alloc);
wlr_renderer_destroy(old_drw);
}
void incnmaster(const Arg *arg) { void incnmaster(const Arg *arg) {
if (!arg || !selmon) if (!arg || !selmon)
return; return;
@ -394,12 +297,6 @@ skip:
wlr_output_state_finish(&pending); wlr_output_state_finish(&pending);
} }
void requestmonstate(struct wl_listener *listener, void *data) {
struct wlr_output_event_request_state *event = data;
wlr_output_commit_state(event->output, event->state);
updatemons(NULL, NULL);
}
void setlayout(const Arg *arg) { void setlayout(const Arg *arg) {
if (!selmon) if (!selmon)
return; return;
@ -506,113 +403,6 @@ void tile(Monitor *m) {
} }
} }
void updatemons(struct wl_listener *listener, void *data) {
/*
* Called whenever the output layout changes: adding or removing a
* monitor, changing an output's mode or position, etc. This is where
* the change officially happens and we update geometry, window
* positions, focus, and the stored configuration in wlroots'
* output-manager implementation.
*/
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
Client *c;
struct wlr_output_configuration_head_v1 *config_head;
Monitor *m;
/* First remove from the layout the disabled monitors */
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled || m->asleep)
continue;
config_head =
wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head->state.enabled = 0;
/* Remove this output from the layout to avoid cursor enter inside it */
wlr_output_layout_remove(output_layout, m->wlr_output);
closemon(m);
m->m = m->w = (struct wlr_box){0};
}
/* Insert outputs that need to */
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled &&
!wlr_output_layout_get(output_layout, m->wlr_output))
wlr_output_layout_add_auto(output_layout, m->wlr_output);
}
/* Now that we update the output layout we can get its box */
wlr_output_layout_get_box(output_layout, NULL, &sgeom);
wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y);
wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height);
/* Make sure the clients are hidden when dwl is locked */
wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y);
wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled)
continue;
config_head =
wlr_output_configuration_head_v1_create(config, m->wlr_output);
/* Get the effective monitor geometry to use for surfaces */
wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
m->w = m->m;
wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
if (m->lock_surface) {
struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width,
m->m.height);
}
/* Calculate the effective monitor geometry to use for clients */
arrangelayers(m);
/* Don't move clients to the left output when plugging monitors */
arrange(m);
/* make sure fullscreen clients have the right size */
if ((c = focustop(m)) && c->isfullscreen)
resize(c, m->m, 0);
/* Try to re-set the gamma LUT when updating monitors,
* it's only really needed when enabling a disabled output, but meh. */
m->gamma_lut_changed = 1;
config_head->state.x = m->m.x;
config_head->state.y = m->m.y;
if (!selmon) {
selmon = m;
}
}
if (selmon && selmon->wlr_output->enabled) {
wl_list_for_each(c, &clients, link) {
if (!c->mon && client_surface(c)->mapped)
setmon(c, selmon, c->tags);
}
focusclient(focustop(selmon), 1);
if (selmon->lock_surface) {
client_notify_enter(selmon->lock_surface->surface,
wlr_seat_get_keyboard(seat));
client_activate_surface(selmon->lock_surface->surface, 1);
}
}
/* FIXME: figure out why the cursor image is at 0,0 after turning all
* the monitors on.
* Move the cursor image where it used to be. It does not generate a
* wl_pointer.motion event for the clients, it's only the image what it's
* at the wrong position after all. */
wlr_cursor_move(cursor, NULL, 0, 0);
wlr_output_manager_v1_set_configuration(output_mgr, config);
}
Monitor *xytomon(double x, double y) { Monitor *xytomon(double x, double y) {
struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
return o ? o->data : NULL; return o ? o->data : NULL;

View file

@ -59,23 +59,19 @@ void arrangelayer(Monitor *m, struct wl_list *list,
void arrangelayers(Monitor *m); void arrangelayers(Monitor *m);
void cleanupmon(struct wl_listener *listener, void *data); void cleanupmon(struct wl_listener *listener, void *data);
void closemon(Monitor *m); void closemon(Monitor *m);
void createmon(struct wl_listener *listener, void *data);
Monitor *dirtomon(enum wlr_direction dir); Monitor *dirtomon(enum wlr_direction dir);
void focusmon(const Arg *arg); void focusmon(const Arg *arg);
void focusstack(const Arg *arg); void focusstack(const Arg *arg);
Client *focustop(Monitor *m); Client *focustop(Monitor *m);
void gpureset(struct wl_listener *listener, void *data);
void incnmaster(const Arg *arg); void incnmaster(const Arg *arg);
void monocle(Monitor *m); void monocle(Monitor *m);
void rendermon(struct wl_listener *listener, void *data); void rendermon(struct wl_listener *listener, void *data);
void requestmonstate(struct wl_listener *listener, void *data);
void setlayout(const Arg *arg); void setlayout(const Arg *arg);
void setmfact(const Arg *arg); void setmfact(const Arg *arg);
void setmon(Client *c, Monitor *m, uint32_t newtags); void setmon(Client *c, Monitor *m, uint32_t newtags);
void tag(const Arg *arg); void tag(const Arg *arg);
void tagmon(const Arg *arg); void tagmon(const Arg *arg);
void tile(Monitor *m); void tile(Monitor *m);
void updatemons(struct wl_listener *listener, void *data);
Monitor *xytomon(double x, double y); Monitor *xytomon(double x, double y);
#endif /* CRYWL_MONITOR_H */ #endif /* CRYWL_MONITOR_H */

View file

@ -29,27 +29,6 @@ void commitnotify(struct wl_listener *listener, void *data) {
c->resize = 0; c->resize = 0;
} }
void createnotify(struct wl_listener *listener, void *data) {
/* This event is raised when a client creates a new toplevel (application
* window). */
struct wlr_xdg_toplevel *toplevel = data;
Client *c = NULL;
/* Allocate a Client for this surface */
c = toplevel->base->data = ecalloc(1, sizeof(*c));
c->surface.xdg = toplevel->base;
c->bw = borderpx;
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify);
LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify);
LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen,
fullscreennotify);
LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify);
LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle);
}
void destroynotify(struct wl_listener *listener, void *data) { void destroynotify(struct wl_listener *listener, void *data) {
/* Called when the xdg_toplevel is destroyed. */ /* Called when the xdg_toplevel is destroyed. */
Client *c = wl_container_of(listener, c, destroy); Client *c = wl_container_of(listener, c, destroy);

View file

@ -3,7 +3,6 @@
/* ===== Function Declarations ===== */ /* ===== Function Declarations ===== */
static void commitnotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data);
static void createnotify(struct wl_listener *listener, void *data);
static void destroynotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data);
static void fullscreennotify(struct wl_listener *listener, void *data); static void fullscreennotify(struct wl_listener *listener, void *data);
static void mapnotify(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data);

View file

@ -1,8 +0,0 @@
#ifndef CRYWL_POPUP_H
#define CRYWL_POPUP_H
/* ===== Function Declarations ===== */
static void commitpopup(struct wl_listener *listener, void *data);
static void createpopup(struct wl_listener *listener, void *data);
#endif /* CRYWL_POPUP_H */

44
src/listeners/client.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef CRYWL_LSTN_CLIENT_H
#define CRYWL_LSTN_CLIENT_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_xdg_activation_v1.h>
#include "../lib/clientutil.h"
/* This event is raised by the seat when a client wants to set the selection,
* usually when the user copies something. wlroots allows compositors to
* ignore such requests if they so choose, but in dwl we always honor them
*/
static void setpsel(struct wl_listener *listener, void *data) {
struct wlr_seat_request_set_primary_selection_event *event = data;
wlr_seat_set_primary_selection(seat, event->source, event->serial);
}
/* This event is raised by the seat when a client wants to set the selection,
* usually when the user copies something. wlroots allows compositors to
* ignore such requests if they so choose, but in dwl we always honor them
*/
static void setsel(struct wl_listener *listener, void *data) {
struct wlr_seat_request_set_selection_event *event = data;
wlr_seat_set_selection(seat, event->source, event->serial);
}
static void urgent(struct wl_listener *listener, void *data) {
struct wlr_xdg_activation_v1_request_activate_event *event = data;
Client *c = NULL;
toplevel_from_wlr_surface(event->surface, &c, NULL);
if (!c || c == focustop(selmon))
return;
c->isurgent = 1;
printstatus();
if (client_surface(c)->mapped)
client_set_border_color(c, urgentcolor);
}
#endif /* CRYWL_LSTN_CLIENT_H */

16
src/listeners/idle.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef CRYWL_LSTN_IDLE_H
#define CRYWL_LSTN_IDLE_H
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include "../util.h"
#include "../lib/idle.h"
static void createidleinhibitor(struct wl_listener *listener, void *data) {
struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor);
checkidleinhibitor(NULL);
}
#endif /* CRYWL_LSTN_IDLE_H */

View file

@ -6,7 +6,7 @@
#include "../lib/cursor.h" #include "../lib/cursor.h"
#include "../lib/notify.h" #include "../lib/notify.h"
static inline void axisnotify(struct wl_listener *listener, void *data) { static void axisnotify(struct wl_listener *listener, void *data) {
/* This event is forwarded by the cursor when a pointer emits an axis event, /* This event is forwarded by the cursor when a pointer emits an axis event,
* for example when you move the scroll wheel. */ * for example when you move the scroll wheel. */
struct wlr_pointer_axis_event *event = data; struct wlr_pointer_axis_event *event = data;
@ -19,7 +19,7 @@ static inline void axisnotify(struct wl_listener *listener, void *data) {
event->source, event->relative_direction); event->source, event->relative_direction);
} }
static inline void motionabsolute(struct wl_listener *listener, void *data) { static void motionabsolute(struct wl_listener *listener, void *data) {
/* This event is forwarded by the cursor when a pointer emits an _absolute_ /* This event is forwarded by the cursor when a pointer emits an _absolute_
* motion event, from 0..1 on each axis. This happens, for example, when * motion event, from 0..1 on each axis. This happens, for example, when
* wlroots is running under a Wayland window rather than KMS+DRM, and you * wlroots is running under a Wayland window rather than KMS+DRM, and you
@ -39,7 +39,7 @@ static inline void motionabsolute(struct wl_listener *listener, void *data) {
motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy);
} }
static inline void motionrelative(struct wl_listener *listener, void *data) { static void motionrelative(struct wl_listener *listener, void *data) {
/* This event is forwarded by the cursor when a pointer emits a _relative_ /* This event is forwarded by the cursor when a pointer emits a _relative_
* pointer motion event (i.e. a delta) */ * pointer motion event (i.e. a delta) */
struct wlr_pointer_motion_event *event = data; struct wlr_pointer_motion_event *event = data;
@ -52,7 +52,7 @@ static inline void motionrelative(struct wl_listener *listener, void *data) {
event->delta_y, event->unaccel_dx, event->unaccel_dy); event->delta_y, event->unaccel_dx, event->unaccel_dy);
} }
static inline void virtualkeyboard(struct wl_listener *listener, void *data) { static void virtualkeyboard(struct wl_listener *listener, void *data) {
struct wlr_virtual_keyboard_v1 *kb = data; struct wlr_virtual_keyboard_v1 *kb = data;
/* virtual keyboards shouldn't share keyboard group */ /* virtual keyboards shouldn't share keyboard group */
KeyboardGroup *group = createkeyboardgroup(); KeyboardGroup *group = createkeyboardgroup();
@ -65,7 +65,7 @@ static inline void virtualkeyboard(struct wl_listener *listener, void *data) {
wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard);
} }
static inline void virtualpointer(struct wl_listener *listener, void *data) { static void virtualpointer(struct wl_listener *listener, void *data) {
struct wlr_virtual_pointer_v1_new_pointer_event *event = data; struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
struct wlr_input_device *device = &event->new_pointer->pointer.base; struct wlr_input_device *device = &event->new_pointer->pointer.base;
@ -74,8 +74,16 @@ static inline void virtualpointer(struct wl_listener *listener, void *data) {
wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
} }
static void createpointerconstraint(struct wl_listener *listener, void *data) {
PointerConstraint *pointer_constraint =
ecalloc(1, sizeof(*pointer_constraint));
pointer_constraint->constraint = data;
LISTEN(&pointer_constraint->constraint->events.destroy,
&pointer_constraint->destroy, destroypointerconstraint);
}
static inline void buttonpress(struct wl_listener *listener, void *data) {
static void buttonpress(struct wl_listener *listener, void *data) {
struct wlr_pointer_button_event *event = data; struct wlr_pointer_button_event *event = data;
struct wlr_keyboard *keyboard; struct wlr_keyboard *keyboard;
uint32_t mods; uint32_t mods;
@ -127,7 +135,7 @@ static inline void buttonpress(struct wl_listener *listener, void *data) {
event->state); event->state);
} }
static inline void cursorframe(struct wl_listener *listener, void *data) { static void cursorframe(struct wl_listener *listener, void *data) {
/* This event is forwarded by the cursor when a pointer emits a frame /* This event is forwarded by the cursor when a pointer emits a frame
* event. Frame events are sent after regular pointer events to group * event. Frame events are sent after regular pointer events to group
* multiple events together. For instance, two axis events may happen at the * multiple events together. For instance, two axis events may happen at the
@ -136,7 +144,7 @@ static inline void cursorframe(struct wl_listener *listener, void *data) {
wlr_seat_pointer_notify_frame(seat); wlr_seat_pointer_notify_frame(seat);
} }
static inline void setcursor(struct wl_listener *listener, void *data) { static void setcursor(struct wl_listener *listener, void *data) {
/* This event is raised by the seat when a client provides a cursor image */ /* This event is raised by the seat when a client provides a cursor image */
struct wlr_seat_pointer_request_set_cursor_event *event = data; struct wlr_seat_pointer_request_set_cursor_event *event = data;
/* If we're "grabbing" the cursor, don't use the client's image, we will /* If we're "grabbing" the cursor, don't use the client's image, we will
@ -154,7 +162,7 @@ static inline void setcursor(struct wl_listener *listener, void *data) {
event->hotspot_y); event->hotspot_y);
} }
static inline void setcursorshape(struct wl_listener *listener, void *data) { static void setcursorshape(struct wl_listener *listener, void *data) {
struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
if (cursor_mode != CurNormal && cursor_mode != CurPressed) if (cursor_mode != CurNormal && cursor_mode != CurPressed)
return; return;
@ -166,4 +174,33 @@ static inline void setcursorshape(struct wl_listener *listener, void *data) {
wlr_cursor_shape_v1_name(event->shape)); wlr_cursor_shape_v1_name(event->shape));
} }
static void inputdevice(struct wl_listener *listener, void *data) {
/* This event is raised by the backend when a new input device becomes
* available. */
struct wlr_input_device *device = data;
uint32_t caps;
switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
createkeyboard(wlr_keyboard_from_input_device(device));
break;
case WLR_INPUT_DEVICE_POINTER:
createpointer(wlr_pointer_from_input_device(device));
break;
default:
/* TODO handle other input device types */
break;
}
/* We need to let the wlr_seat know what our capabilities are, which is
* communiciated to the client. In dwl we always have a cursor, even if
* there are no pointer devices, so we always include that capability. */
/* TODO do we actually require a cursor? */
caps = WL_SEAT_CAPABILITY_POINTER;
if (!wl_list_empty(&kb_group->wlr_group->devices))
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
wlr_seat_set_capabilities(seat, caps);
}
#endif /* CRYWL_LSTN_INPUT_H */ #endif /* CRYWL_LSTN_INPUT_H */

49
src/listeners/layer.h Normal file
View file

@ -0,0 +1,49 @@
#ifndef CRYWL_LSTN_LAYER_H
#define CRYWL_LSTN_LAYER_H
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_scene.h>
#include "../lib/layers.h"
/* Binds commitlayersurfacenotify, unmaplayersurfacenotify,
* destroylayersurfacenotify. createlayersurface() uses the
* (commit|unmap|destroy)layersurfacenotify callbacks.
*/
static void createlayersurface(struct wl_listener *listener, void *data) {
struct wlr_layer_surface_v1 *layer_surface = data;
LayerSurface *l;
struct wlr_surface *surface = layer_surface->surface;
struct wlr_scene_tree *scene_layer =
layers[layermap[layer_surface->pending.layer]];
if (!layer_surface->output &&
!(layer_surface->output = selmon ? selmon->wlr_output : NULL)) {
wlr_layer_surface_v1_destroy(layer_surface);
return;
}
l = layer_surface->data = ecalloc(1, sizeof(*l));
l->type = LayerShell;
LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify);
LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify);
LISTEN(&layer_surface->events.destroy, &l->destroy,
destroylayersurfacenotify);
l->layer_surface = layer_surface;
l->mon = layer_surface->output->data;
l->scene_layer =
wlr_scene_layer_surface_v1_create(scene_layer, layer_surface);
l->scene = l->scene_layer->tree;
l->popups = surface->data = wlr_scene_tree_create(
layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP
? layers[LyrTop]
: scene_layer);
l->scene->node.data = l->popups->node.data = l;
wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link);
wlr_surface_send_enter(surface, layer_surface->output);
}
#endif /* CRYWL_LSTN_LAYER_H */

View file

@ -1,9 +1,19 @@
#ifndef CRYWL_LSTN_ALL_H #ifndef CRYWL_LSTN_ALL_H
#define CRYWL_LSTN_ALL_H #define CRYWL_LSTN_ALL_H
#include "input.h" #include "client.h"
#include "decoration.h" #include "decoration.h"
#include "drag.h" #include "drag.h"
#include "idle.h"
#include "input.h"
#include "layer.h"
#include "lock.h"
#include "mgrs.h"
#include "monitor.h"
#include "notify.h"
#include "popup.h"
static struct wl_listener new_xdg_toplevel = {.notify = createnotify};
static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_button = {.notify = buttonpress};
static struct wl_listener cursor_frame = {.notify = cursorframe}; static struct wl_listener cursor_frame = {.notify = cursorframe};
@ -13,11 +23,38 @@ static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
static struct wl_listener cursor_axis = {.notify = axisnotify}; static struct wl_listener cursor_axis = {.notify = axisnotify};
static struct wl_listener cursor_motion = {.notify = motionrelative}; static struct wl_listener cursor_motion = {.notify = motionrelative};
static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
static struct wl_listener new_input_device = {.notify = inputdevice};
static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard};
static struct wl_listener new_virtual_pointer = {.notify = virtualpointer}; static struct wl_listener new_virtual_pointer = {.notify = virtualpointer};
static struct wl_listener new_pointer_constraint = {
.notify = createpointerconstraint};
static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; static struct wl_listener new_xdg_decoration = {.notify = createdecoration};
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener start_drag = {.notify = startdrag}; static struct wl_listener start_drag = {.notify = startdrag};
#endif /*CRYWL_LSTN_ALL_H*/ static struct wl_listener output_mgr_apply = {.notify = outputmgrapply};
static struct wl_listener output_mgr_test = {.notify = outputmgrtest};
static struct wl_listener output_power_mgr_set_mode = {.notify =
powermgrsetmode};
static struct wl_listener new_session_lock = {.notify = locksession};
static struct wl_listener new_xdg_popup = {.notify = createpopup};
static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
static struct wl_listener request_set_psel = {.notify = setpsel};
static struct wl_listener request_set_sel = {.notify = setsel};
static struct wl_listener gpu_reset = {.notify = gpureset};
static struct wl_listener layout_change = {.notify = updatemons};
static struct wl_listener new_output = {.notify = createmon};
static struct wl_listener new_layer_surface = {.notify = createlayersurface};
static struct wl_listener request_activate = {.notify = urgent};
#endif /* CRYWL_LSTN_ALL_H */

33
src/listeners/lock.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef CRYWL_LSTN_LOCK_H
#define CRYWL_LSTN_LOCK_H
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include "../lib/lock.h"
#include "../lib/clientutil.h"
static void locksession(struct wl_listener *listener, void *data) {
struct wlr_session_lock_v1 *session_lock = data;
SessionLock *lock;
wlr_scene_node_set_enabled(&locked_bg->node, 1);
if (cur_lock) {
wlr_session_lock_v1_destroy(session_lock);
return;
}
lock = session_lock->data = ecalloc(1, sizeof(*lock));
focusclient(NULL, 0);
lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
cur_lock = lock->lock = session_lock;
locked = 1;
LISTEN(&session_lock->events.new_surface, &lock->new_surface,
createlocksurface);
LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
wlr_session_lock_v1_send_locked(session_lock);
}
#endif /* CRYWL_LSTN_LOCK_H */

View file

@ -1,10 +1,15 @@
void outputmgrapply(struct wl_listener *listener, void *data) { #ifndef CRYWL_LSTN_MGRS_H
struct wlr_output_configuration_v1 *config = data; #define CRYWL_LSTN_MGRS_H
outputmgrapplyortest(config, 0);
}
void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, #include <wlr/types/wlr_output.h>
int test) { #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include "../lib/monitor.h"
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config,
int test) {
/* /*
* Called when a client such as wlr-randr requests a change in output * Called when a client such as wlr-randr requests a change in output
* configuration. This is only one way that the layout can be changed, * configuration. This is only one way that the layout can be changed,
@ -66,12 +71,17 @@ void outputmgrapplyortest(struct wlr_output_configuration_v1 *config,
updatemons(NULL, NULL); updatemons(NULL, NULL);
} }
void outputmgrtest(struct wl_listener *listener, void *data) { static void outputmgrapply(struct wl_listener *listener, void *data) {
struct wlr_output_configuration_v1 *config = data;
outputmgrapplyortest(config, 0);
}
static void outputmgrtest(struct wl_listener *listener, void *data) {
struct wlr_output_configuration_v1 *config = data; struct wlr_output_configuration_v1 *config = data;
outputmgrapplyortest(config, 1); outputmgrapplyortest(config, 1);
} }
void powermgrsetmode(struct wl_listener *listener, void *data) { static void powermgrsetmode(struct wl_listener *listener, void *data) {
struct wlr_output_power_v1_set_mode_event *event = data; struct wlr_output_power_v1_set_mode_event *event = data;
struct wlr_output_state state = {0}; struct wlr_output_state state = {0};
Monitor *m = event->output->data; Monitor *m = event->output->data;
@ -86,3 +96,5 @@ void powermgrsetmode(struct wl_listener *listener, void *data) {
m->asleep = !event->mode; m->asleep = !event->mode;
updatemons(NULL, NULL); updatemons(NULL, NULL);
} }
#endif /* CRYWL_LSTN_MGRS_H */

230
src/listeners/monitor.h Normal file
View file

@ -0,0 +1,230 @@
#ifndef CRYWL_LSTN_MONITOR_H
#define CRYWL_LSTN_MONITOR_H
#include <wayland-server-core.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include "../lib/monitor.h"
static void gpureset(struct wl_listener *listener, void *data) {
struct wlr_renderer *old_drw = drw;
struct wlr_allocator *old_alloc = alloc;
struct Monitor *m;
if (!(drw = wlr_renderer_autocreate(backend)))
die("couldn't recreate renderer");
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
die("couldn't recreate allocator");
wl_list_remove(&gpu_reset.link);
wl_signal_add(&drw->events.lost, &gpu_reset);
wlr_compositor_set_renderer(compositor, drw);
wl_list_for_each(m, &mons, link) {
wlr_output_init_render(m->wlr_output, alloc, drw);
}
wlr_allocator_destroy(old_alloc);
wlr_renderer_destroy(old_drw);
}
/*
* Called whenever the output layout changes: adding or removing a
* monitor, changing an output's mode or position, etc. This is where
* the change officially happens and we update geometry, window
* positions, focus, and the stored configuration in wlroots'
* output-manager implementation.
*/
static void updatemons(struct wl_listener *listener, void *data) {
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
Client *c;
struct wlr_output_configuration_head_v1 *config_head;
Monitor *m;
/* First remove from the layout the disabled monitors */
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled || m->asleep)
continue;
config_head =
wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head->state.enabled = 0;
/* Remove this output from the layout to avoid cursor enter inside it */
wlr_output_layout_remove(output_layout, m->wlr_output);
closemon(m);
m->m = m->w = (struct wlr_box){0};
}
/* Insert outputs that need to */
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled &&
!wlr_output_layout_get(output_layout, m->wlr_output))
wlr_output_layout_add_auto(output_layout, m->wlr_output);
}
/* Now that we update the output layout we can get its box */
wlr_output_layout_get_box(output_layout, NULL, &sgeom);
wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y);
wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height);
/* Make sure the clients are hidden when dwl is locked */
wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y);
wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled)
continue;
config_head =
wlr_output_configuration_head_v1_create(config, m->wlr_output);
/* Get the effective monitor geometry to use for surfaces */
wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
m->w = m->m;
wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
if (m->lock_surface) {
struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width,
m->m.height);
}
/* Calculate the effective monitor geometry to use for clients */
arrangelayers(m);
/* Don't move clients to the left output when plugging monitors */
arrange(m);
/* make sure fullscreen clients have the right size */
if ((c = focustop(m)) && c->isfullscreen)
resize(c, m->m, 0);
/* Try to re-set the gamma LUT when updating monitors,
* it's only really needed when enabling a disabled output, but meh. */
m->gamma_lut_changed = 1;
config_head->state.x = m->m.x;
config_head->state.y = m->m.y;
if (!selmon) {
selmon = m;
}
}
if (selmon && selmon->wlr_output->enabled) {
wl_list_for_each(c, &clients, link) {
if (!c->mon && client_surface(c)->mapped)
setmon(c, selmon, c->tags);
}
focusclient(focustop(selmon), 1);
if (selmon->lock_surface) {
client_notify_enter(selmon->lock_surface->surface,
wlr_seat_get_keyboard(seat));
client_activate_surface(selmon->lock_surface->surface, 1);
}
}
/* FIXME: figure out why the cursor image is at 0,0 after turning all
* the monitors on.
* Move the cursor image where it used to be. It does not generate a
* wl_pointer.motion event for the clients, it's only the image what it's
* at the wrong position after all. */
wlr_cursor_move(cursor, NULL, 0, 0);
wlr_output_manager_v1_set_configuration(output_mgr, config);
}
/* Helper listener for listeners/monitor.h:createmon() */
static void requestmonstate(struct wl_listener *listener, void *data) {
struct wlr_output_event_request_state *event = data;
wlr_output_commit_state(event->output, event->state);
updatemons(NULL, NULL);
}
/* This event is raised by the backend when a new output (aka a display or
* monitor) becomes available. */
static void createmon(struct wl_listener *listener, void *data) {
struct wlr_output *wlr_output = data;
const MonitorRule *r;
size_t i;
struct wlr_output_state state;
Monitor *m;
if (!wlr_output_init_render(wlr_output, alloc, drw))
return;
m = wlr_output->data = ecalloc(1, sizeof(*m));
m->wlr_output = wlr_output;
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
wlr_output_state_init(&state);
/* Initialize monitor state using configured rules */
m->tagset[0] = m->tagset[1] = 1;
for (r = monrules; r < END(monrules); r++) {
if (!r->name || strstr(wlr_output->name, r->name)) {
m->m.x = r->x;
m->m.y = r->y;
m->mfact = r->mfact;
m->nmaster = r->nmaster;
m->lt[0] = r->lt;
m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
wlr_output_state_set_scale(&state, r->scale);
wlr_output_state_set_transform(&state, r->rr);
break;
}
}
/* The mode is a tuple of (width, height, refresh rate), and each
* monitor supports only a specific set of modes. We just pick the
* monitor's preferred mode; a more sophisticated compositor would let
* the user configure it. */
wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
/* Set up event listeners */
LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
wlr_output_state_set_enabled(&state, 1);
wlr_output_commit_state(wlr_output, &state);
wlr_output_state_finish(&state);
wl_list_insert(&mons, &m->link);
printstatus();
/* The xdg-protocol specifies:
*
* If the fullscreened surface is not opaque, the compositor must make
* sure that other screen content not part of the same surface tree (made
* up of subsurfaces, popups or similarly coupled surfaces) are not
* visible below the fullscreened surface.
*
*/
/* updatemons() will resize and set correct position */
m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg);
wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0);
/* Adds this to the output layout in the order it was configured.
*
* The output layout utility automatically adds a wl_output global to the
* display, which Wayland clients can see to find out information about the
* output (such as DPI, scale factor, manufacturer, etc).
*/
m->scene_output = wlr_scene_output_create(scene, wlr_output);
if (m->m.x == -1 && m->m.y == -1)
wlr_output_layout_add_auto(output_layout, wlr_output);
else
wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
}
#endif /* CRYWL_LSTN_MONITOR_H */

29
src/listeners/notify.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef CRYWL_LSTN_NOTIFY_H
#define CRYWL_LSTN_NOTIFY_H
#include <wlr/types/wlr_xdg_shell.h>
#include "../lib/client.h"
/* This event is raised when a client creates a new toplevel (application
* window). */
static void createnotify(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel *toplevel = data;
Client *c = NULL;
/* Allocate a Client for this surface */
c = toplevel->base->data = ecalloc(1, sizeof(*c));
c->surface.xdg = toplevel->base;
c->bw = borderpx;
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify);
LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify);
LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen,
fullscreennotify);
LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify);
LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle);
}
#endif CRYWL_LSTN_NOTIFY_H

View file

@ -1,4 +1,16 @@
void commitpopup(struct wl_listener *listener, void *data) { #ifndef CRYWL_LSTN_POPUP_H
#define CRYWL_LSTN_POPUP_H
#include <stdlib.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include "../lib/layers.h"
#include "../lib/clientutil.h"
/* Helper listener for listeners/popup.h:createpopup() */
static void commitpopup(struct wl_listener *listener, void *data) {
struct wlr_surface *surface = data; struct wlr_surface *surface = data;
struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface);
LayerSurface *l = NULL; LayerSurface *l = NULL;
@ -26,9 +38,11 @@ void commitpopup(struct wl_listener *listener, void *data) {
free(listener); free(listener);
} }
void createpopup(struct wl_listener *listener, void *data) { /* This event is raised when a client (either xdg-shell or layer-shell) creates a new popup. */
/* This event is raised when a client (either xdg-shell or layer-shell) static void createpopup(struct wl_listener *listener, void *data) {
* creates a new popup. */
struct wlr_xdg_popup *popup = data; struct wlr_xdg_popup *popup = data;
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
} }
#endif /* CRYWL_LSTN_POPUP_H */

View file

@ -71,30 +71,8 @@
#include "util.h" #include "util.h"
/* global event handlers */ /* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify};
static struct wl_listener cursor_motion = {.notify = motionrelative};
static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
static struct wl_listener gpu_reset = {.notify = gpureset};
static struct wl_listener layout_change = {.notify = updatemons};
static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
static struct wl_listener new_input_device = {.notify = inputdevice};
static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard};
static struct wl_listener new_virtual_pointer = {.notify = virtualpointer};
static struct wl_listener new_pointer_constraint = {
.notify = createpointerconstraint};
static struct wl_listener new_output = {.notify = createmon};
static struct wl_listener new_xdg_toplevel = {.notify = createnotify}; static struct wl_listener new_xdg_toplevel = {.notify = createnotify};
static struct wl_listener new_xdg_popup = {.notify = createpopup};
static struct wl_listener new_layer_surface = {.notify = createlayersurface};
static struct wl_listener output_mgr_apply = {.notify = outputmgrapply};
static struct wl_listener output_mgr_test = {.notify = outputmgrtest};
static struct wl_listener output_power_mgr_set_mode = {.notify =
powermgrsetmode};
static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_activate = {.notify = urgent};
static struct wl_listener request_set_psel = {.notify = setpsel};
static struct wl_listener request_set_sel = {.notify = setsel};
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener new_session_lock = {.notify = locksession};
/* configuration, allows nested code to access above variables */ /* configuration, allows nested code to access above variables */
#include "config.h" #include "config.h"