|
|
|
@@ -13,6 +13,7 @@
|
|
|
|
|
#include <libinput.h>
|
|
|
|
|
#include <wayland-server-core.h>
|
|
|
|
|
#include <wlr/backend.h>
|
|
|
|
|
#include <wlr/render/allocator.h>
|
|
|
|
|
#include <wlr/render/wlr_renderer.h>
|
|
|
|
|
#include <wlr/types/wlr_compositor.h>
|
|
|
|
|
#include <wlr/types/wlr_cursor.h>
|
|
|
|
@@ -29,13 +30,16 @@
|
|
|
|
|
#include <wlr/types/wlr_output_layout.h>
|
|
|
|
|
#include <wlr/types/wlr_output_management_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_pointer.h>
|
|
|
|
|
#include <wlr/types/wlr_presentation_time.h>
|
|
|
|
|
#include <wlr/types/wlr_primary_selection.h>
|
|
|
|
|
#include <wlr/types/wlr_primary_selection_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_screencopy_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_server_decoration.h>
|
|
|
|
|
#include <wlr/types/wlr_seat.h>
|
|
|
|
|
#include <wlr/types/wlr_viewporter.h>
|
|
|
|
|
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_xcursor_manager.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_activation_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_output_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_shell.h>
|
|
|
|
@@ -95,6 +99,7 @@ typedef struct {
|
|
|
|
|
struct wl_listener map;
|
|
|
|
|
struct wl_listener unmap;
|
|
|
|
|
struct wl_listener destroy;
|
|
|
|
|
struct wl_listener set_title;
|
|
|
|
|
struct wl_listener fullscreen;
|
|
|
|
|
struct wlr_box geom; /* layout-relative, includes border */
|
|
|
|
|
Monitor *mon;
|
|
|
|
@@ -105,7 +110,7 @@ typedef struct {
|
|
|
|
|
#endif
|
|
|
|
|
int bw;
|
|
|
|
|
unsigned int tags;
|
|
|
|
|
int isfloating;
|
|
|
|
|
int isfloating, isurgent;
|
|
|
|
|
uint32_t resize; /* configure serial of a pending resize */
|
|
|
|
|
int prevx;
|
|
|
|
|
int prevy;
|
|
|
|
@@ -228,18 +233,15 @@ static void createmon(struct wl_listener *listener, void *data);
|
|
|
|
|
static void createnotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void createlayersurface(struct wl_listener *listener, void *data);
|
|
|
|
|
static void createpointer(struct wlr_input_device *device);
|
|
|
|
|
static void createxdeco(struct wl_listener *listener, void *data);
|
|
|
|
|
static void cursorframe(struct wl_listener *listener, void *data);
|
|
|
|
|
static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void destroynotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void destroyxdeco(struct wl_listener *listener, void *data);
|
|
|
|
|
static Monitor *dirtomon(enum wlr_direction dir);
|
|
|
|
|
static void focusclient(Client *c, int lift);
|
|
|
|
|
static void focusmon(const Arg *arg);
|
|
|
|
|
static void focusstack(const Arg *arg);
|
|
|
|
|
static void fullscreennotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static Client *focustop(Monitor *m);
|
|
|
|
|
static void getxdecomode(struct wl_listener *listener, void *data);
|
|
|
|
|
static void incnmaster(const Arg *arg);
|
|
|
|
|
static void inputdevice(struct wl_listener *listener, void *data);
|
|
|
|
|
static int keybinding(uint32_t mods, xkb_keysym_t sym);
|
|
|
|
@@ -260,6 +262,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface,
|
|
|
|
|
double sx, double sy, uint32_t time);
|
|
|
|
|
static void printstatus(void);
|
|
|
|
|
static void quit(const Arg *arg);
|
|
|
|
|
static void quitsignal(int signo);
|
|
|
|
|
static void render(struct wlr_surface *surface, int sx, int sy, void *data);
|
|
|
|
|
static void renderclients(Monitor *m, struct timespec *now);
|
|
|
|
|
static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now);
|
|
|
|
@@ -290,6 +293,8 @@ static void unmaplayersurface(LayerSurface *layersurface);
|
|
|
|
|
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void unmapnotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void updatemons(struct wl_listener *listener, void *data);
|
|
|
|
|
static void updatetitle(struct wl_listener *listener, void *data);
|
|
|
|
|
static void urgent(struct wl_listener *listener, void *data);
|
|
|
|
|
static void view(const Arg *arg);
|
|
|
|
|
static void virtualkeyboard(struct wl_listener *listener, void *data);
|
|
|
|
|
static Client *xytoclient(double x, double y);
|
|
|
|
@@ -303,25 +308,23 @@ static const char broken[] = "broken";
|
|
|
|
|
static struct wl_display *dpy;
|
|
|
|
|
static struct wlr_backend *backend;
|
|
|
|
|
static struct wlr_renderer *drw;
|
|
|
|
|
static struct wlr_allocator *alloc;
|
|
|
|
|
static struct wlr_compositor *compositor;
|
|
|
|
|
|
|
|
|
|
static struct wlr_xdg_shell *xdg_shell;
|
|
|
|
|
static struct wlr_xdg_activation_v1 *activation;
|
|
|
|
|
static struct wl_list clients; /* tiling order */
|
|
|
|
|
static struct wl_list fstack; /* focus order */
|
|
|
|
|
static struct wl_list stack; /* stacking z-order */
|
|
|
|
|
static struct wl_list independents;
|
|
|
|
|
static struct wlr_idle *idle;
|
|
|
|
|
static struct wlr_layer_shell_v1 *layer_shell;
|
|
|
|
|
static struct wlr_xdg_decoration_manager_v1 *xdeco_mgr;
|
|
|
|
|
static struct wlr_output_manager_v1 *output_mgr;
|
|
|
|
|
static struct wlr_presentation *presentation;
|
|
|
|
|
static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
|
|
|
|
|
|
|
|
|
|
static struct wlr_cursor *cursor;
|
|
|
|
|
static struct wlr_xcursor_manager *cursor_mgr;
|
|
|
|
|
#ifdef XWAYLAND
|
|
|
|
|
static struct wlr_xcursor *xcursor;
|
|
|
|
|
static struct wlr_xcursor_manager *xcursor_mgr;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static struct wlr_seat *seat;
|
|
|
|
|
static struct wl_list keyboards;
|
|
|
|
@@ -344,11 +347,11 @@ static struct wl_listener layout_change = {.notify = updatemons};
|
|
|
|
|
static struct wl_listener new_input = {.notify = inputdevice};
|
|
|
|
|
static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard};
|
|
|
|
|
static struct wl_listener new_output = {.notify = createmon};
|
|
|
|
|
static struct wl_listener new_xdeco = {.notify = createxdeco};
|
|
|
|
|
static struct wl_listener new_xdg_surface = {.notify = createnotify};
|
|
|
|
|
static struct wl_listener new_layer_shell_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 request_activate = {.notify = urgent};
|
|
|
|
|
static struct wl_listener request_cursor = {.notify = setcursor};
|
|
|
|
|
static struct wl_listener request_set_psel = {.notify = setpsel};
|
|
|
|
|
static struct wl_listener request_set_sel = {.notify = setsel};
|
|
|
|
@@ -550,7 +553,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
|
|
|
|
|
box.y -= state->margin.bottom;
|
|
|
|
|
}
|
|
|
|
|
if (box.width < 0 || box.height < 0) {
|
|
|
|
|
wlr_layer_surface_v1_close(wlr_layer_surface);
|
|
|
|
|
wlr_layer_surface_v1_destroy(wlr_layer_surface);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
layersurface->geo = box;
|
|
|
|
@@ -774,7 +777,7 @@ commitnotify(struct wl_listener *listener, void *data)
|
|
|
|
|
Client *c = wl_container_of(listener, c, commit);
|
|
|
|
|
|
|
|
|
|
/* mark a pending resize as completed */
|
|
|
|
|
if (c->resize && c->resize <= c->surface.xdg->configure_serial)
|
|
|
|
|
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
|
|
|
|
|
c->resize = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -788,7 +791,7 @@ createkeyboard(struct wlr_input_device *device)
|
|
|
|
|
|
|
|
|
|
/* Prepare an XKB keymap and assign it to the keyboard. */
|
|
|
|
|
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
|
|
|
|
keymap = xkb_map_new_from_names(context, &xkb_rules,
|
|
|
|
|
keymap = xkb_keymap_new_from_names(context, &xkb_rules,
|
|
|
|
|
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
|
|
|
|
|
|
|
|
wlr_keyboard_set_keymap(device->keyboard, keymap);
|
|
|
|
@@ -817,6 +820,8 @@ createmon(struct wl_listener *listener, void *data)
|
|
|
|
|
Monitor *m = wlr_output->data = calloc(1, sizeof(*m));
|
|
|
|
|
m->wlr_output = wlr_output;
|
|
|
|
|
|
|
|
|
|
wlr_output_init_render(wlr_output, alloc, drw);
|
|
|
|
|
|
|
|
|
|
/* Initialize monitor state using configured rules */
|
|
|
|
|
for (size_t i = 0; i < LENGTH(m->layers); i++)
|
|
|
|
|
wl_list_init(&m->layers[i]);
|
|
|
|
@@ -844,11 +849,13 @@ createmon(struct wl_listener *listener, void *data)
|
|
|
|
|
LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
|
|
|
|
|
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
|
|
|
|
|
|
|
|
|
|
wl_list_insert(&mons, &m->link);
|
|
|
|
|
wlr_output_enable(wlr_output, 1);
|
|
|
|
|
if (!wlr_output_commit(wlr_output))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
wl_list_insert(&mons, &m->link);
|
|
|
|
|
printstatus();
|
|
|
|
|
|
|
|
|
|
/* Adds this to the output layout in the order it was configured in.
|
|
|
|
|
*
|
|
|
|
|
* The output layout utility automatically adds a wl_output global to the
|
|
|
|
@@ -887,14 +894,11 @@ createnotify(struct wl_listener *listener, void *data)
|
|
|
|
|
c->surface.xdg = xdg_surface;
|
|
|
|
|
c->bw = borderpx;
|
|
|
|
|
|
|
|
|
|
/* Tell the client not to try anything fancy */
|
|
|
|
|
wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP |
|
|
|
|
|
WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
|
|
|
|
|
|
|
|
|
|
LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify);
|
|
|
|
|
LISTEN(&xdg_surface->events.map, &c->map, mapnotify);
|
|
|
|
|
LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);
|
|
|
|
|
LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);
|
|
|
|
|
LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle);
|
|
|
|
|
LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen,
|
|
|
|
|
fullscreennotify);
|
|
|
|
|
c->isfullscreen = 0;
|
|
|
|
@@ -926,13 +930,13 @@ createlayersurface(struct wl_listener *listener, void *data)
|
|
|
|
|
wlr_layer_surface->data = layersurface;
|
|
|
|
|
|
|
|
|
|
m = wlr_layer_surface->output->data;
|
|
|
|
|
wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer],
|
|
|
|
|
wl_list_insert(&m->layers[wlr_layer_surface->pending.layer],
|
|
|
|
|
&layersurface->link);
|
|
|
|
|
|
|
|
|
|
// Temporarily set the layer's current state to client_pending
|
|
|
|
|
// Temporarily set the layer's current state to pending
|
|
|
|
|
// so that we can easily arrange it
|
|
|
|
|
old_state = wlr_layer_surface->current;
|
|
|
|
|
wlr_layer_surface->current = wlr_layer_surface->client_pending;
|
|
|
|
|
wlr_layer_surface->current = wlr_layer_surface->pending;
|
|
|
|
|
arrangelayers(m);
|
|
|
|
|
wlr_layer_surface->current = old_state;
|
|
|
|
|
}
|
|
|
|
@@ -958,18 +962,6 @@ createpointer(struct wlr_input_device *device)
|
|
|
|
|
wlr_cursor_attach_input_device(cursor, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createxdeco(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data;
|
|
|
|
|
Decoration *d = wlr_deco->data = calloc(1, sizeof(*d));
|
|
|
|
|
|
|
|
|
|
LISTEN(&wlr_deco->events.request_mode, &d->request_mode, getxdecomode);
|
|
|
|
|
LISTEN(&wlr_deco->events.destroy, &d->destroy, destroyxdeco);
|
|
|
|
|
|
|
|
|
|
getxdecomode(&d->request_mode, wlr_deco);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
cursorframe(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
@@ -1010,6 +1002,7 @@ destroynotify(struct wl_listener *listener, void *data)
|
|
|
|
|
wl_list_remove(&c->map.link);
|
|
|
|
|
wl_list_remove(&c->unmap.link);
|
|
|
|
|
wl_list_remove(&c->destroy.link);
|
|
|
|
|
wl_list_remove(&c->set_title.link);
|
|
|
|
|
wl_list_remove(&c->fullscreen.link);
|
|
|
|
|
#ifdef XWAYLAND
|
|
|
|
|
if (c->type == X11Managed)
|
|
|
|
@@ -1020,17 +1013,6 @@ destroynotify(struct wl_listener *listener, void *data)
|
|
|
|
|
free(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
destroyxdeco(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data;
|
|
|
|
|
Decoration *d = wlr_deco->data;
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&d->destroy.link);
|
|
|
|
|
wl_list_remove(&d->request_mode.link);
|
|
|
|
|
free(d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
togglefullscreen(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -1043,7 +1025,7 @@ void
|
|
|
|
|
setfullscreen(Client *c, int fullscreen)
|
|
|
|
|
{
|
|
|
|
|
c->isfullscreen = fullscreen;
|
|
|
|
|
c->bw = (1 - fullscreen) * borderpx;
|
|
|
|
|
c->bw = fullscreen ? 0 : borderpx;
|
|
|
|
|
client_set_fullscreen(c, fullscreen);
|
|
|
|
|
|
|
|
|
|
if (fullscreen) {
|
|
|
|
@@ -1101,8 +1083,8 @@ focusclient(Client *c, int lift)
|
|
|
|
|
wl_list_remove(&c->flink);
|
|
|
|
|
wl_list_insert(&fstack, &c->flink);
|
|
|
|
|
selmon = c->mon;
|
|
|
|
|
c->isurgent = 0;
|
|
|
|
|
}
|
|
|
|
|
printstatus();
|
|
|
|
|
|
|
|
|
|
/* Deactivate old client if focus is changing */
|
|
|
|
|
if (old && (!c || client_surface(c) != old)) {
|
|
|
|
@@ -1125,6 +1107,8 @@ focusclient(Client *c, int lift)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printstatus();
|
|
|
|
|
|
|
|
|
|
if (!c) {
|
|
|
|
|
/* With no client, all we have left is to clear focus */
|
|
|
|
|
wlr_seat_keyboard_notify_clear_focus(seat);
|
|
|
|
@@ -1185,14 +1169,6 @@ focustop(Monitor *m)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
getxdecomode(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data;
|
|
|
|
|
wlr_xdg_toplevel_decoration_v1_set_mode(wlr_deco,
|
|
|
|
|
WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
incnmaster(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -1339,6 +1315,9 @@ mapnotify(struct wl_listener *listener, void *data)
|
|
|
|
|
c->geom.width += 2 * c->bw;
|
|
|
|
|
c->geom.height += 2 * c->bw;
|
|
|
|
|
|
|
|
|
|
/* Tell the client not to try anything fancy */
|
|
|
|
|
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
|
|
|
|
|
|
|
|
|
|
/* Set initial monitor, tags, floating status, and focus */
|
|
|
|
|
applyrules(c);
|
|
|
|
|
}
|
|
|
|
@@ -1581,22 +1560,29 @@ void
|
|
|
|
|
printstatus(void)
|
|
|
|
|
{
|
|
|
|
|
Monitor *m = NULL;
|
|
|
|
|
Client *c = NULL;
|
|
|
|
|
unsigned int activetags;
|
|
|
|
|
Client *c;
|
|
|
|
|
unsigned int occ, urg, sel;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(m, &mons, link) {
|
|
|
|
|
activetags=0;
|
|
|
|
|
occ = urg = 0;
|
|
|
|
|
wl_list_for_each(c, &clients, link) {
|
|
|
|
|
if (c->mon == m)
|
|
|
|
|
activetags |= c->tags;
|
|
|
|
|
if (c->mon != m)
|
|
|
|
|
continue;
|
|
|
|
|
occ |= c->tags;
|
|
|
|
|
if (c->isurgent)
|
|
|
|
|
urg |= c->tags;
|
|
|
|
|
}
|
|
|
|
|
if (focustop(m))
|
|
|
|
|
if ((c = focustop(m))) {
|
|
|
|
|
printf("%s title %s\n", m->wlr_output->name, client_get_title(focustop(m)));
|
|
|
|
|
else
|
|
|
|
|
sel = c->tags;
|
|
|
|
|
} else {
|
|
|
|
|
printf("%s title \n", m->wlr_output->name);
|
|
|
|
|
sel = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
|
|
|
|
|
printf("%s tags %u %u\n", m->wlr_output->name, activetags, m->tagset[m->seltags]);
|
|
|
|
|
printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags],
|
|
|
|
|
sel, urg);
|
|
|
|
|
printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol);
|
|
|
|
|
}
|
|
|
|
|
fflush(stdout);
|
|
|
|
@@ -1608,6 +1594,12 @@ quit(const Arg *arg)
|
|
|
|
|
wl_display_terminate(dpy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
quitsignal(int signo)
|
|
|
|
|
{
|
|
|
|
|
quit(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
render(struct wlr_surface *surface, int sx, int sy, void *data)
|
|
|
|
|
{
|
|
|
|
@@ -1664,6 +1656,8 @@ render(struct wlr_surface *surface, int sx, int sy, void *data)
|
|
|
|
|
/* This lets the client know that we've displayed that frame and it can
|
|
|
|
|
* prepare another one now if it likes. */
|
|
|
|
|
wlr_surface_send_frame_done(surface, rdata->when);
|
|
|
|
|
|
|
|
|
|
wlr_presentation_surface_sampled_on_output(presentation, surface, output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@@ -1756,6 +1750,10 @@ rendermon(struct wl_listener *listener, void *data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* HACK: This loop is the simplest way to handle ephemeral pageflip
|
|
|
|
|
* failures but probably not the best. Revisit if damage tracking is
|
|
|
|
|
* added. */
|
|
|
|
|
do {
|
|
|
|
|
/* wlr_output_attach_render makes the OpenGL context current. */
|
|
|
|
|
if (!wlr_output_attach_render(m->wlr_output, NULL))
|
|
|
|
|
return;
|
|
|
|
@@ -1787,7 +1785,7 @@ rendermon(struct wl_listener *listener, void *data)
|
|
|
|
|
wlr_renderer_end(drw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wlr_output_commit(m->wlr_output);
|
|
|
|
|
} while (!wlr_output_commit(m->wlr_output));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@@ -1818,6 +1816,27 @@ run(char *startup_cmd)
|
|
|
|
|
const char *socket = wl_display_add_socket_auto(dpy);
|
|
|
|
|
if (!socket)
|
|
|
|
|
BARF("startup: display_add_socket_auto");
|
|
|
|
|
setenv("WAYLAND_DISPLAY", socket, 1);
|
|
|
|
|
|
|
|
|
|
/* Now that the socket exists, run the startup command */
|
|
|
|
|
if (startup_cmd) {
|
|
|
|
|
int piperw[2];
|
|
|
|
|
pipe(piperw);
|
|
|
|
|
startup_pid = fork();
|
|
|
|
|
if (startup_pid < 0)
|
|
|
|
|
EBARF("startup: fork");
|
|
|
|
|
if (startup_pid == 0) {
|
|
|
|
|
dup2(piperw[0], STDIN_FILENO);
|
|
|
|
|
close(piperw[1]);
|
|
|
|
|
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
|
|
|
|
|
EBARF("startup: execl");
|
|
|
|
|
}
|
|
|
|
|
dup2(piperw[1], STDOUT_FILENO);
|
|
|
|
|
close(piperw[0]);
|
|
|
|
|
}
|
|
|
|
|
/* If nobody is reading the status output, don't terminate */
|
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
printstatus();
|
|
|
|
|
|
|
|
|
|
/* Start the backend. This will enumerate outputs and inputs, become the DRM
|
|
|
|
|
* master, etc */
|
|
|
|
@@ -1835,21 +1854,6 @@ run(char *startup_cmd)
|
|
|
|
|
wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
|
|
|
|
|
wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor);
|
|
|
|
|
|
|
|
|
|
/* Set the WAYLAND_DISPLAY environment variable to our socket and run the
|
|
|
|
|
* startup command if requested. */
|
|
|
|
|
setenv("WAYLAND_DISPLAY", socket, 1);
|
|
|
|
|
|
|
|
|
|
if (startup_cmd) {
|
|
|
|
|
startup_pid = fork();
|
|
|
|
|
if (startup_pid < 0)
|
|
|
|
|
EBARF("startup: fork");
|
|
|
|
|
if (startup_pid == 0) {
|
|
|
|
|
dup2(STDERR_FILENO, STDOUT_FILENO);
|
|
|
|
|
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
|
|
|
|
|
EBARF("startup: execl");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Run the Wayland event loop. This does not return until you exit the
|
|
|
|
|
* compositor. Starting the backend rigged up all of the necessary event
|
|
|
|
|
* loop configuration to listen to libinput events, DRM events, generate
|
|
|
|
@@ -1986,8 +1990,10 @@ setup(void)
|
|
|
|
|
* clients from the Unix socket, manging Wayland globals, and so on. */
|
|
|
|
|
dpy = wl_display_create();
|
|
|
|
|
|
|
|
|
|
/* clean up child processes immediately */
|
|
|
|
|
/* Set up signal handlers */
|
|
|
|
|
sigchld(0);
|
|
|
|
|
signal(SIGINT, quitsignal);
|
|
|
|
|
signal(SIGTERM, quitsignal);
|
|
|
|
|
|
|
|
|
|
/* The backend is a wlroots feature which abstracts the underlying input and
|
|
|
|
|
* output hardware. The autocreate option will choose the most suitable
|
|
|
|
@@ -2000,12 +2006,15 @@ setup(void)
|
|
|
|
|
if (!(backend = wlr_backend_autocreate(dpy)))
|
|
|
|
|
BARF("couldn't create backend");
|
|
|
|
|
|
|
|
|
|
/* If we don't provide a renderer, autocreate makes a GLES2 renderer for us.
|
|
|
|
|
* The renderer is responsible for defining the various pixel formats it
|
|
|
|
|
* supports for shared memory, this configures that for clients. */
|
|
|
|
|
drw = wlr_backend_get_renderer(backend);
|
|
|
|
|
/* Create a renderer with the default implementation */
|
|
|
|
|
if (!(drw = wlr_renderer_autocreate(backend)))
|
|
|
|
|
BARF("couldn't create renderer");
|
|
|
|
|
wlr_renderer_init_wl_display(drw, dpy);
|
|
|
|
|
|
|
|
|
|
/* Create a default allocator */
|
|
|
|
|
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
|
|
|
|
|
BARF("couldn't create allocator");
|
|
|
|
|
|
|
|
|
|
/* This creates some hands-off wlroots interfaces. The compositor is
|
|
|
|
|
* necessary for clients to allocate surfaces and the data device manager
|
|
|
|
|
* handles the clipboard. Each of these wlroots interfaces has room for you
|
|
|
|
@@ -2021,6 +2030,10 @@ setup(void)
|
|
|
|
|
wlr_primary_selection_v1_device_manager_create(dpy);
|
|
|
|
|
wlr_viewporter_create(dpy);
|
|
|
|
|
|
|
|
|
|
/* Initializes the interface used to implement urgency hints */
|
|
|
|
|
activation = wlr_xdg_activation_v1_create(dpy);
|
|
|
|
|
wl_signal_add(&activation->events.request_activate, &request_activate);
|
|
|
|
|
|
|
|
|
|
/* Creates an output layout, which a wlroots utility for working with an
|
|
|
|
|
* arrangement of screens in a physical layout. */
|
|
|
|
|
output_layout = wlr_output_layout_create();
|
|
|
|
@@ -2051,9 +2064,11 @@ setup(void)
|
|
|
|
|
xdg_shell = wlr_xdg_shell_create(dpy);
|
|
|
|
|
wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);
|
|
|
|
|
|
|
|
|
|
/* Use xdg_decoration protocol to negotiate server-side decorations */
|
|
|
|
|
xdeco_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
|
|
|
|
|
wl_signal_add(&xdeco_mgr->events.new_toplevel_decoration, &new_xdeco);
|
|
|
|
|
/* Use decoration protocols to negotiate server-side decorations */
|
|
|
|
|
wlr_server_decoration_manager_set_default_mode(
|
|
|
|
|
wlr_server_decoration_manager_create(dpy),
|
|
|
|
|
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
|
|
|
|
wlr_xdg_decoration_manager_v1_create(dpy);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Creates a cursor, which is a wlroots utility for tracking the cursor
|
|
|
|
@@ -2109,6 +2124,8 @@ setup(void)
|
|
|
|
|
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
|
|
|
|
|
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
|
|
|
|
|
|
|
|
|
|
presentation = wlr_presentation_create(dpy, backend);
|
|
|
|
|
|
|
|
|
|
#ifdef XWAYLAND
|
|
|
|
|
/*
|
|
|
|
|
* Initialise the XWayland X server.
|
|
|
|
@@ -2119,18 +2136,6 @@ setup(void)
|
|
|
|
|
wl_signal_add(&xwayland->events.ready, &xwayland_ready);
|
|
|
|
|
wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create the XWayland cursor manager at scale 1, setting its default
|
|
|
|
|
* pointer to match the rest of dwl.
|
|
|
|
|
*/
|
|
|
|
|
xcursor_mgr = wlr_xcursor_manager_create(NULL, 24);
|
|
|
|
|
wlr_xcursor_manager_load(xcursor_mgr, 1);
|
|
|
|
|
if ((xcursor = wlr_xcursor_manager_get_xcursor(xcursor_mgr, "left_ptr", 1)))
|
|
|
|
|
wlr_xwayland_set_cursor(xwayland,
|
|
|
|
|
xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
|
|
|
|
|
xcursor->images[0]->width, xcursor->images[0]->height,
|
|
|
|
|
xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
|
|
|
|
|
|
|
|
|
|
setenv("DISPLAY", xwayland->display_name, 1);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
|
|
|
|
@@ -2324,6 +2329,29 @@ updatemons(struct wl_listener *listener, void *data)
|
|
|
|
|
wlr_output_manager_v1_set_configuration(output_mgr, config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
updatetitle(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
Client *c = wl_container_of(listener, c, set_title);
|
|
|
|
|
if (c == focustop(c->mon))
|
|
|
|
|
printstatus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
urgent(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_xdg_activation_v1_request_activate_event *event = data;
|
|
|
|
|
Client *c;
|
|
|
|
|
|
|
|
|
|
if (!wlr_surface_is_xdg_surface(event->surface))
|
|
|
|
|
return;
|
|
|
|
|
c = wlr_xdg_surface_from_wlr_surface(event->surface)->data;
|
|
|
|
|
if (c != selclient()) {
|
|
|
|
|
c->isurgent = 1;
|
|
|
|
|
printstatus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
view(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -2460,6 +2488,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
|
|
|
|
|
activatex11);
|
|
|
|
|
LISTEN(&xwayland_surface->events.request_configure, &c->configure,
|
|
|
|
|
configurex11);
|
|
|
|
|
LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle);
|
|
|
|
|
LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify);
|
|
|
|
|
LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen,
|
|
|
|
|
fullscreennotify);
|
|
|
|
|