|
|
|
@@ -3,6 +3,7 @@
|
|
|
|
|
*/
|
|
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
|
#include <getopt.h>
|
|
|
|
|
#include <libinput.h>
|
|
|
|
|
#include <linux/input-event-codes.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
@@ -10,9 +11,9 @@
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <libinput.h>
|
|
|
|
|
#include <wayland-server-core.h>
|
|
|
|
|
#include <wlr/backend.h>
|
|
|
|
|
#include <wlr/backend/libinput.h>
|
|
|
|
|
#include <wlr/render/allocator.h>
|
|
|
|
|
#include <wlr/render/wlr_renderer.h>
|
|
|
|
|
#include <wlr/types/wlr_compositor.h>
|
|
|
|
@@ -21,11 +22,12 @@
|
|
|
|
|
#include <wlr/types/wlr_data_device.h>
|
|
|
|
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_input_device.h>
|
|
|
|
|
#include <wlr/types/wlr_idle.h>
|
|
|
|
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_input_device.h>
|
|
|
|
|
#include <wlr/types/wlr_input_inhibitor.h>
|
|
|
|
|
#include <wlr/types/wlr_keyboard.h>
|
|
|
|
|
#include <wlr/types/wlr_matrix.h>
|
|
|
|
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_output.h>
|
|
|
|
|
#include <wlr/types/wlr_output_layout.h>
|
|
|
|
|
#include <wlr/types/wlr_output_management_v1.h>
|
|
|
|
@@ -33,10 +35,10 @@
|
|
|
|
|
#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_scene.h>
|
|
|
|
|
#include <wlr/types/wlr_server_decoration.h>
|
|
|
|
|
#include <wlr/types/wlr_screencopy_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_seat.h>
|
|
|
|
|
#include <wlr/types/wlr_server_decoration.h>
|
|
|
|
|
#include <wlr/types/wlr_subcompositor.h>
|
|
|
|
|
#include <wlr/types/wlr_viewporter.h>
|
|
|
|
|
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
|
|
|
@@ -45,7 +47,6 @@
|
|
|
|
|
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_output_v1.h>
|
|
|
|
|
#include <wlr/types/wlr_xdg_shell.h>
|
|
|
|
|
#include <wlr/backend/libinput.h>
|
|
|
|
|
#include <wlr/util/log.h>
|
|
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
|
#ifdef XWAYLAND
|
|
|
|
@@ -53,9 +54,9 @@
|
|
|
|
|
#include <wlr/xwayland.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
/* macros */
|
|
|
|
|
#define BARF(fmt, ...) do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } while (0)
|
|
|
|
|
#define EBARF(fmt, ...) BARF(fmt ": %s", ##__VA_ARGS__, strerror(errno))
|
|
|
|
|
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
|
|
|
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
|
|
|
|
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
|
|
|
@@ -139,6 +140,7 @@ typedef struct {
|
|
|
|
|
typedef struct {
|
|
|
|
|
/* Must be first */
|
|
|
|
|
unsigned int type; /* LayerShell */
|
|
|
|
|
int mapped;
|
|
|
|
|
struct wlr_scene_node *scene;
|
|
|
|
|
struct wlr_scene_layer_surface_v1 *scene_layer;
|
|
|
|
|
struct wl_list link;
|
|
|
|
@@ -180,8 +182,6 @@ typedef struct {
|
|
|
|
|
float scale;
|
|
|
|
|
const Layout *lt;
|
|
|
|
|
enum wl_output_transform rr;
|
|
|
|
|
int x;
|
|
|
|
|
int y;
|
|
|
|
|
} MonitorRule;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
@@ -208,12 +208,14 @@ static void cleanupmon(struct wl_listener *listener, void *data);
|
|
|
|
|
static void closemon(Monitor *m);
|
|
|
|
|
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void commitnotify(struct wl_listener *listener, void *data);
|
|
|
|
|
static void createidleinhibitor(struct wl_listener *listener, void *data);
|
|
|
|
|
static void createkeyboard(struct wlr_keyboard *keyboard);
|
|
|
|
|
static void createlayersurface(struct wl_listener *listener, void *data);
|
|
|
|
|
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_pointer *pointer);
|
|
|
|
|
static void cursorframe(struct wl_listener *listener, void *data);
|
|
|
|
|
static void destroyidleinhibitor(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 Monitor *dirtomon(enum wlr_direction dir);
|
|
|
|
@@ -221,8 +223,8 @@ static void dragicondestroy(struct wl_listener *listener, void *data);
|
|
|
|
|
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 fullscreennotify(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);
|
|
|
|
@@ -250,13 +252,13 @@ static void resize(Client *c, int x, int y, int w, int h, int interact);
|
|
|
|
|
static void run(char *startup_cmd);
|
|
|
|
|
static Client *selclient(void);
|
|
|
|
|
static void setcursor(struct wl_listener *listener, void *data);
|
|
|
|
|
static void setpsel(struct wl_listener *listener, void *data);
|
|
|
|
|
static void setsel(struct wl_listener *listener, void *data);
|
|
|
|
|
static void setfloating(Client *c, int floating);
|
|
|
|
|
static void setfullscreen(Client *c, int fullscreen);
|
|
|
|
|
static void setlayout(const Arg *arg);
|
|
|
|
|
static void setmfact(const Arg *arg);
|
|
|
|
|
static void setmon(Client *c, Monitor *m, unsigned int newtags);
|
|
|
|
|
static void setpsel(struct wl_listener *listener, void *data);
|
|
|
|
|
static void setsel(struct wl_listener *listener, void *data);
|
|
|
|
|
static void setup(void);
|
|
|
|
|
static void spawn(const Arg *arg);
|
|
|
|
|
static void startdrag(struct wl_listener *listener, void *data);
|
|
|
|
@@ -275,9 +277,9 @@ 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 Monitor *xytomon(double x, double y);
|
|
|
|
|
static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,
|
|
|
|
|
Client **pc, LayerSurface **pl, double *nx, double *ny);
|
|
|
|
|
static Monitor *xytomon(double x, double y);
|
|
|
|
|
static void zoom(const Arg *arg);
|
|
|
|
|
|
|
|
|
|
/* variables */
|
|
|
|
@@ -295,6 +297,8 @@ static struct wlr_xdg_activation_v1 *activation;
|
|
|
|
|
static struct wl_list clients; /* tiling order */
|
|
|
|
|
static struct wl_list fstack; /* focus order */
|
|
|
|
|
static struct wlr_idle *idle;
|
|
|
|
|
static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
|
|
|
|
|
static struct wlr_input_inhibit_manager *input_inhibit_mgr;
|
|
|
|
|
static struct wlr_layer_shell_v1 *layer_shell;
|
|
|
|
|
static struct wlr_output_manager_v1 *output_mgr;
|
|
|
|
|
static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
|
|
|
|
@@ -319,6 +323,8 @@ static struct wl_listener cursor_button = {.notify = buttonpress};
|
|
|
|
|
static struct wl_listener cursor_frame = {.notify = cursorframe};
|
|
|
|
|
static struct wl_listener cursor_motion = {.notify = motionrelative};
|
|
|
|
|
static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
|
|
|
|
|
static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor};
|
|
|
|
|
static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor};
|
|
|
|
|
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};
|
|
|
|
@@ -620,9 +626,14 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)
|
|
|
|
|
wlr_scene_node_reparent(layersurface->scene,
|
|
|
|
|
layers[wlr_layer_surface->current.layer]);
|
|
|
|
|
|
|
|
|
|
if (!wlr_output)
|
|
|
|
|
if (!wlr_output || !(m = wlr_output->data))
|
|
|
|
|
return;
|
|
|
|
|
m = wlr_output->data;
|
|
|
|
|
|
|
|
|
|
if (wlr_layer_surface->current.committed == 0
|
|
|
|
|
&& layersurface->mapped == wlr_layer_surface->mapped)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
layersurface->mapped = wlr_layer_surface->mapped;
|
|
|
|
|
|
|
|
|
|
if (layers[wlr_layer_surface->current.layer] != layersurface->scene) {
|
|
|
|
|
wl_list_remove(&layersurface->link);
|
|
|
|
@@ -642,14 +653,21 @@ commitnotify(struct wl_listener *listener, void *data)
|
|
|
|
|
c->resize = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createidleinhibitor(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
|
|
|
|
|
wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy);
|
|
|
|
|
|
|
|
|
|
wlr_idle_set_enabled(idle, seat, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createkeyboard(struct wlr_keyboard *keyboard)
|
|
|
|
|
{
|
|
|
|
|
struct xkb_context *context;
|
|
|
|
|
struct xkb_keymap *keymap;
|
|
|
|
|
Keyboard *kb = keyboard->data = calloc(1, sizeof(*kb));
|
|
|
|
|
if (!kb)
|
|
|
|
|
EBARF("createkeyboard: calloc");
|
|
|
|
|
Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb));
|
|
|
|
|
kb->wlr_keyboard = keyboard;
|
|
|
|
|
|
|
|
|
|
/* Prepare an XKB keymap and assign it to the keyboard. */
|
|
|
|
@@ -673,6 +691,52 @@ createkeyboard(struct wlr_keyboard *keyboard)
|
|
|
|
|
wl_list_insert(&keyboards, &kb->link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createlayersurface(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_layer_surface_v1 *wlr_layer_surface = data;
|
|
|
|
|
LayerSurface *layersurface;
|
|
|
|
|
Monitor *m;
|
|
|
|
|
struct wlr_layer_surface_v1_state old_state;
|
|
|
|
|
|
|
|
|
|
if (!wlr_layer_surface->output) {
|
|
|
|
|
wlr_layer_surface->output = selmon->wlr_output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layersurface = ecalloc(1, sizeof(LayerSurface));
|
|
|
|
|
layersurface->type = LayerShell;
|
|
|
|
|
LISTEN(&wlr_layer_surface->surface->events.commit,
|
|
|
|
|
&layersurface->surface_commit, commitlayersurfacenotify);
|
|
|
|
|
LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy,
|
|
|
|
|
destroylayersurfacenotify);
|
|
|
|
|
LISTEN(&wlr_layer_surface->events.map, &layersurface->map,
|
|
|
|
|
maplayersurfacenotify);
|
|
|
|
|
LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap,
|
|
|
|
|
unmaplayersurfacenotify);
|
|
|
|
|
|
|
|
|
|
layersurface->layer_surface = wlr_layer_surface;
|
|
|
|
|
wlr_layer_surface->data = layersurface;
|
|
|
|
|
m = wlr_layer_surface->output->data;
|
|
|
|
|
|
|
|
|
|
layersurface->scene_layer = wlr_scene_layer_surface_v1_create(
|
|
|
|
|
layers[wlr_layer_surface->pending.layer], wlr_layer_surface);
|
|
|
|
|
layersurface->scene = wlr_layer_surface->surface->data =
|
|
|
|
|
layersurface->scene_layer->node;
|
|
|
|
|
|
|
|
|
|
layersurface->scene->data = layersurface;
|
|
|
|
|
|
|
|
|
|
wl_list_insert(&m->layers[wlr_layer_surface->pending.layer],
|
|
|
|
|
&layersurface->link);
|
|
|
|
|
|
|
|
|
|
/* 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->pending;
|
|
|
|
|
arrangelayers(m);
|
|
|
|
|
wlr_layer_surface->current = old_state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createmon(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
@@ -680,9 +744,7 @@ createmon(struct wl_listener *listener, void *data)
|
|
|
|
|
* monitor) becomes available. */
|
|
|
|
|
struct wlr_output *wlr_output = data;
|
|
|
|
|
const MonitorRule *r;
|
|
|
|
|
Monitor *m = wlr_output->data = calloc(1, sizeof(*m));
|
|
|
|
|
if (!m)
|
|
|
|
|
EBARF("createmon: calloc");
|
|
|
|
|
Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m));
|
|
|
|
|
m->wlr_output = wlr_output;
|
|
|
|
|
|
|
|
|
|
wlr_output_init_render(wlr_output, alloc, drw);
|
|
|
|
@@ -767,9 +829,7 @@ createnotify(struct wl_listener *listener, void *data)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Allocate a Client for this surface */
|
|
|
|
|
c = xdg_surface->data = calloc(1, sizeof(*c));
|
|
|
|
|
if (!c)
|
|
|
|
|
EBARF("createnotify: calloc");
|
|
|
|
|
c = xdg_surface->data = ecalloc(1, sizeof(*c));
|
|
|
|
|
c->surface.xdg = xdg_surface;
|
|
|
|
|
c->bw = borderpx;
|
|
|
|
|
|
|
|
|
@@ -783,53 +843,6 @@ createnotify(struct wl_listener *listener, void *data)
|
|
|
|
|
c->isfullscreen = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createlayersurface(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_layer_surface_v1 *wlr_layer_surface = data;
|
|
|
|
|
LayerSurface *layersurface;
|
|
|
|
|
Monitor *m;
|
|
|
|
|
struct wlr_layer_surface_v1_state old_state;
|
|
|
|
|
|
|
|
|
|
if (!wlr_layer_surface->output) {
|
|
|
|
|
wlr_layer_surface->output = selmon->wlr_output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layersurface = calloc(1, sizeof(LayerSurface));
|
|
|
|
|
if (!layersurface)
|
|
|
|
|
EBARF("layersurface: calloc");
|
|
|
|
|
layersurface->type = LayerShell;
|
|
|
|
|
LISTEN(&wlr_layer_surface->surface->events.commit,
|
|
|
|
|
&layersurface->surface_commit, commitlayersurfacenotify);
|
|
|
|
|
LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy,
|
|
|
|
|
destroylayersurfacenotify);
|
|
|
|
|
LISTEN(&wlr_layer_surface->events.map, &layersurface->map,
|
|
|
|
|
maplayersurfacenotify);
|
|
|
|
|
LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap,
|
|
|
|
|
unmaplayersurfacenotify);
|
|
|
|
|
|
|
|
|
|
layersurface->layer_surface = wlr_layer_surface;
|
|
|
|
|
wlr_layer_surface->data = layersurface;
|
|
|
|
|
m = wlr_layer_surface->output->data;
|
|
|
|
|
|
|
|
|
|
layersurface->scene_layer = wlr_scene_layer_surface_v1_create(
|
|
|
|
|
layers[wlr_layer_surface->pending.layer], wlr_layer_surface);
|
|
|
|
|
layersurface->scene = wlr_layer_surface->surface->data =
|
|
|
|
|
layersurface->scene_layer->node;
|
|
|
|
|
layersurface->scene->data = layersurface;
|
|
|
|
|
|
|
|
|
|
wl_list_insert(&m->layers[wlr_layer_surface->pending.layer],
|
|
|
|
|
&layersurface->link);
|
|
|
|
|
|
|
|
|
|
/* 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->pending;
|
|
|
|
|
arrangelayers(m);
|
|
|
|
|
wlr_layer_surface->current = old_state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
createpointer(struct wlr_pointer *pointer)
|
|
|
|
|
{
|
|
|
|
@@ -862,6 +875,14 @@ cursorframe(struct wl_listener *listener, void *data)
|
|
|
|
|
wlr_seat_pointer_notify_frame(seat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
destroyidleinhibitor(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
/* I've been testing and at this point the inhibitor has not yet been
|
|
|
|
|
* removed from the list, checking if it has at least one item. */
|
|
|
|
|
wlr_idle_set_enabled(idle, seat, wl_list_length(&idle_inhibit_mgr->inhibitors) <= 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
destroylayersurfacenotify(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
@@ -903,57 +924,6 @@ destroynotify(struct wl_listener *listener, void *data)
|
|
|
|
|
free(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dragicondestroy(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_drag_icon *icon = data;
|
|
|
|
|
wlr_scene_node_destroy(icon->data);
|
|
|
|
|
// Focus enter isn't sent during drag, so refocus the focused node.
|
|
|
|
|
focusclient(selclient(), 1);
|
|
|
|
|
motionnotify(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
togglefullscreen(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
|
Client *sel = selclient();
|
|
|
|
|
if (sel)
|
|
|
|
|
setfullscreen(sel, !sel->isfullscreen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
setfullscreen(Client *c, int fullscreen)
|
|
|
|
|
{
|
|
|
|
|
c->isfullscreen = fullscreen;
|
|
|
|
|
c->bw = fullscreen ? 0 : borderpx;
|
|
|
|
|
client_set_fullscreen(c, fullscreen);
|
|
|
|
|
|
|
|
|
|
if (fullscreen) {
|
|
|
|
|
c->prev = c->geom;
|
|
|
|
|
resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0);
|
|
|
|
|
} else {
|
|
|
|
|
/* restore previous size instead of arrange for floating windows since
|
|
|
|
|
* client positions are set by the user and cannot be recalculated */
|
|
|
|
|
resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0);
|
|
|
|
|
}
|
|
|
|
|
arrange(c->mon);
|
|
|
|
|
printstatus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fullscreennotify(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
Client *c = wl_container_of(listener, c, fullscreen);
|
|
|
|
|
int fullscreen = client_wants_fullscreen(c);
|
|
|
|
|
|
|
|
|
|
if (!c->mon) {
|
|
|
|
|
/* if the client is not mapped yet, let mapnotify() call setfullscreen() */
|
|
|
|
|
c->isfullscreen = fullscreen;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setfullscreen(c, fullscreen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Monitor *
|
|
|
|
|
dirtomon(enum wlr_direction dir)
|
|
|
|
|
{
|
|
|
|
@@ -968,6 +938,16 @@ dirtomon(enum wlr_direction dir)
|
|
|
|
|
return selmon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dragicondestroy(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_drag_icon *icon = data;
|
|
|
|
|
wlr_scene_node_destroy(icon->data);
|
|
|
|
|
// Focus enter isn't sent during drag, so refocus the focused node.
|
|
|
|
|
focusclient(selclient(), 1);
|
|
|
|
|
motionnotify(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
focusclient(Client *c, int lift)
|
|
|
|
|
{
|
|
|
|
@@ -1021,6 +1001,7 @@ focusclient(Client *c, int lift)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printstatus();
|
|
|
|
|
wlr_idle_set_enabled(idle, seat, wl_list_empty(&idle_inhibit_mgr->inhibitors));
|
|
|
|
|
|
|
|
|
|
if (!c) {
|
|
|
|
|
/* With no client, all we have left is to clear focus */
|
|
|
|
@@ -1082,6 +1063,20 @@ focustop(Monitor *m)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fullscreennotify(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
Client *c = wl_container_of(listener, c, fullscreen);
|
|
|
|
|
int fullscreen = client_wants_fullscreen(c);
|
|
|
|
|
|
|
|
|
|
if (!c->mon) {
|
|
|
|
|
/* if the client is not mapped yet, let mapnotify() call setfullscreen() */
|
|
|
|
|
c->isfullscreen = fullscreen;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setfullscreen(c, fullscreen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
incnmaster(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -1159,8 +1154,10 @@ keypress(struct wl_listener *listener, void *data)
|
|
|
|
|
|
|
|
|
|
wlr_idle_notify_activity(idle, seat);
|
|
|
|
|
|
|
|
|
|
/* On _press_, attempt to process a compositor keybinding. */
|
|
|
|
|
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
|
|
|
|
|
/* On _press_ if there is no active screen locker,
|
|
|
|
|
* attempt to process a compositor keybinding. */
|
|
|
|
|
if (!input_inhibit_mgr->active_inhibitor
|
|
|
|
|
&& event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
|
|
|
|
|
for (i = 0; i < nsyms; i++)
|
|
|
|
|
handled = keybinding(mods, syms[i]) || handled;
|
|
|
|
|
|
|
|
|
@@ -1591,22 +1588,22 @@ run(char *startup_cmd)
|
|
|
|
|
/* Add a Unix socket to the Wayland display. */
|
|
|
|
|
const char *socket = wl_display_add_socket_auto(dpy);
|
|
|
|
|
if (!socket)
|
|
|
|
|
BARF("startup: display_add_socket_auto");
|
|
|
|
|
die("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 (pipe(piperw) < 0)
|
|
|
|
|
die("startup: pipe:");
|
|
|
|
|
if ((startup_pid = fork()) < 0)
|
|
|
|
|
die("startup: fork:");
|
|
|
|
|
if (startup_pid == 0) {
|
|
|
|
|
dup2(piperw[0], STDIN_FILENO);
|
|
|
|
|
close(piperw[0]);
|
|
|
|
|
close(piperw[1]);
|
|
|
|
|
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
|
|
|
|
|
EBARF("startup: execl");
|
|
|
|
|
die("startup: execl:");
|
|
|
|
|
}
|
|
|
|
|
dup2(piperw[1], STDOUT_FILENO);
|
|
|
|
|
close(piperw[1]);
|
|
|
|
@@ -1619,7 +1616,7 @@ run(char *startup_cmd)
|
|
|
|
|
/* Start the backend. This will enumerate outputs and inputs, become the DRM
|
|
|
|
|
* master, etc */
|
|
|
|
|
if (!wlr_backend_start(backend))
|
|
|
|
|
BARF("startup: backend_start");
|
|
|
|
|
die("startup: backend_start");
|
|
|
|
|
|
|
|
|
|
/* Now that outputs are initialized, choose initial selmon based on
|
|
|
|
|
* cursor position, and set default cursor image */
|
|
|
|
@@ -1681,6 +1678,25 @@ setfloating(Client *c, int floating)
|
|
|
|
|
printstatus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
setfullscreen(Client *c, int fullscreen)
|
|
|
|
|
{
|
|
|
|
|
c->isfullscreen = fullscreen;
|
|
|
|
|
c->bw = fullscreen ? 0 : borderpx;
|
|
|
|
|
client_set_fullscreen(c, fullscreen);
|
|
|
|
|
|
|
|
|
|
if (fullscreen) {
|
|
|
|
|
c->prev = c->geom;
|
|
|
|
|
resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0);
|
|
|
|
|
} else {
|
|
|
|
|
/* restore previous size instead of arrange for floating windows since
|
|
|
|
|
* client positions are set by the user and cannot be recalculated */
|
|
|
|
|
resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0);
|
|
|
|
|
}
|
|
|
|
|
arrange(c->mon);
|
|
|
|
|
printstatus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
setlayout(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -1779,7 +1795,7 @@ setup(void)
|
|
|
|
|
* if the backend does not support hardware cursors (some older GPUs
|
|
|
|
|
* don't). */
|
|
|
|
|
if (!(backend = wlr_backend_autocreate(dpy)))
|
|
|
|
|
BARF("couldn't create backend");
|
|
|
|
|
die("couldn't create backend");
|
|
|
|
|
|
|
|
|
|
/* Initialize the scene graph used to lay out windows */
|
|
|
|
|
scene = wlr_scene_create();
|
|
|
|
@@ -1793,12 +1809,12 @@ setup(void)
|
|
|
|
|
|
|
|
|
|
/* Create a renderer with the default implementation */
|
|
|
|
|
if (!(drw = wlr_renderer_autocreate(backend)))
|
|
|
|
|
BARF("couldn't create renderer");
|
|
|
|
|
die("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");
|
|
|
|
|
die("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
|
|
|
|
@@ -1842,12 +1858,17 @@ setup(void)
|
|
|
|
|
|
|
|
|
|
idle = wlr_idle_create(dpy);
|
|
|
|
|
|
|
|
|
|
idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
|
|
|
|
|
wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create);
|
|
|
|
|
|
|
|
|
|
layer_shell = wlr_layer_shell_v1_create(dpy);
|
|
|
|
|
wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface);
|
|
|
|
|
|
|
|
|
|
xdg_shell = wlr_xdg_shell_create(dpy);
|
|
|
|
|
wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);
|
|
|
|
|
|
|
|
|
|
input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy);
|
|
|
|
|
|
|
|
|
|
/* Use decoration protocols to negotiate server-side decorations */
|
|
|
|
|
wlr_server_decoration_manager_set_default_mode(
|
|
|
|
|
wlr_server_decoration_manager_create(dpy),
|
|
|
|
@@ -1933,7 +1954,7 @@ spawn(const Arg *arg)
|
|
|
|
|
dup2(STDERR_FILENO, STDOUT_FILENO);
|
|
|
|
|
setsid();
|
|
|
|
|
execvp(((char **)arg->v)[0], (char **)arg->v);
|
|
|
|
|
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]);
|
|
|
|
|
die("dwl: execvp %s failed:", ((char **)arg->v)[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2013,6 +2034,14 @@ togglefloating(const Arg *arg)
|
|
|
|
|
setfloating(sel, !sel->isfloating);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
togglefullscreen(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
|
Client *sel = selclient();
|
|
|
|
|
if (sel)
|
|
|
|
|
setfullscreen(sel, !sel->isfullscreen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
toggletag(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -2167,6 +2196,13 @@ virtualkeyboard(struct wl_listener *listener, void *data)
|
|
|
|
|
createkeyboard(device->keyboard);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Monitor *
|
|
|
|
|
xytomon(double x, double y)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
|
|
|
|
|
return o ? o->data : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct wlr_scene_node *
|
|
|
|
|
xytonode(double x, double y, struct wlr_surface **psurface,
|
|
|
|
|
Client **pc, LayerSurface **pl, double *nx, double *ny)
|
|
|
|
@@ -2200,13 +2236,6 @@ xytonode(double x, double y, struct wlr_surface **psurface,
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Monitor *
|
|
|
|
|
xytomon(double x, double y)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
|
|
|
|
|
return o ? o->data : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
zoom(const Arg *arg)
|
|
|
|
|
{
|
|
|
|
@@ -2269,9 +2298,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
|
|
|
|
|
setfullscreen(c, 0);
|
|
|
|
|
|
|
|
|
|
/* Allocate a Client for this surface */
|
|
|
|
|
c = xwayland_surface->data = calloc(1, sizeof(*c));
|
|
|
|
|
if (!c)
|
|
|
|
|
EBARF("createnotifyx11: calloc");
|
|
|
|
|
c = xwayland_surface->data = ecalloc(1, sizeof(*c));
|
|
|
|
|
c->surface.xwayland = xwayland_surface;
|
|
|
|
|
c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;
|
|
|
|
|
c->bw = borderpx;
|
|
|
|
@@ -2370,12 +2397,12 @@ main(int argc, char *argv[])
|
|
|
|
|
|
|
|
|
|
/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
|
|
|
|
|
if (!getenv("XDG_RUNTIME_DIR"))
|
|
|
|
|
BARF("XDG_RUNTIME_DIR must be set");
|
|
|
|
|
die("XDG_RUNTIME_DIR must be set");
|
|
|
|
|
setup();
|
|
|
|
|
run(startup_cmd);
|
|
|
|
|
cleanup();
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
|
|
|
|
|
usage:
|
|
|
|
|
BARF("Usage: %s [-s startup command]", argv[0]);
|
|
|
|
|
die("Usage: %s [-s startup command]", argv[0]);
|
|
|
|
|
}
|
|
|
|
|