Merge pull request #1 from djpohly/master

Pull Request
This commit is contained in:
Bonicgamer 2020-08-15 13:56:22 -04:00 committed by GitHub
commit a683ec501e
Failed to generate hash of commit
5 changed files with 216 additions and 137 deletions

View file

@ -1,9 +1,10 @@
include config.mk
CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -Werror=declaration-after-statement
WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols) WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner) WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-error=unused-function
CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -Werror=declaration-after-statement
PKGS = wlroots wayland-server xcb xkbcommon PKGS = wlroots wayland-server xcb xkbcommon
CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p))) CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p)))
LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p))) LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p)))

View file

@ -70,7 +70,6 @@ dwl is a work in progress, and it has not yet reached its feature goals in a num
- Urgent/attention/focus-request ([not yet supported](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/9) by xdg-shell protocol) - Urgent/attention/focus-request ([not yet supported](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/9) by xdg-shell protocol)
- Statusbar support (built-in or external) - Statusbar support (built-in or external)
- layer-shell - layer-shell
- export-dmabuf
- Damage tracking - Damage tracking
- Fullscreen/fixed windows (or whatever the Wayland analogues are) - Fullscreen/fixed windows (or whatever the Wayland analogues are)

View file

@ -10,8 +10,10 @@ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const Rule rules[] = { static const Rule rules[] = {
/* app_id title tags mask isfloating monitor */ /* app_id title tags mask isfloating monitor */
/* examples:
{ "Gimp", NULL, 0, 1, -1 }, { "Gimp", NULL, 0, 1, -1 },
{ "Firefox", NULL, 1 << 8, 0, -1 }, { "firefox", NULL, 1 << 8, 0, -1 },
*/
}; };
/* layout(s) */ /* layout(s) */
@ -19,6 +21,7 @@ static const Layout layouts[] = {
/* symbol arrange function */ /* symbol arrange function */
{ "[]=", tile }, { "[]=", tile },
{ "><>", NULL }, /* no layout function means floating behavior */ { "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
}; };
/* monitors */ /* monitors */
@ -52,6 +55,7 @@ static const int repeat_delay = 600;
static const char *termcmd[] = { "alacritty", NULL }; static const char *termcmd[] = { "alacritty", NULL };
static const Key keys[] = { static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
/* modifier key function argument */ /* modifier key function argument */
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
@ -62,9 +66,10 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} },
{ MODKEY, XKB_KEY_Return, zoom, {0} }, { MODKEY, XKB_KEY_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} }, { MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XKB_KEY_space, setlayout, {0} }, { MODKEY, XKB_KEY_space, setlayout, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} }, { MODKEY, XKB_KEY_0, view, {.ui = ~0} },

5
config.mk Normal file
View file

@ -0,0 +1,5 @@
# Default compile flags (overridable by environment)
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-error=unused-function
# Uncomment to build XWayland support
#CFLAGS += -DXWAYLAND

331
dwl.c
View file

@ -16,6 +16,7 @@
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h> #include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_matrix.h>
@ -26,14 +27,17 @@
#include <wlr/types/wlr_primary_selection_v1.h> #include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_screencopy_v1.h> #include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_seat.h> #include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_decoration_v1.h> #include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h> #include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <wlr/xwayland.h>
#include <X11/Xlib.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#ifdef XWAYLAND
#include <X11/Xlib.h>
#include <wlr/xwayland.h>
#endif
/* macros */ /* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B))
@ -43,13 +47,19 @@
#define LENGTH(X) (sizeof X / sizeof X[0]) #define LENGTH(X) (sizeof X / sizeof X[0])
#define END(A) ((A) + LENGTH(A)) #define END(A) ((A) + LENGTH(A))
#define TAGMASK ((1 << LENGTH(tags)) - 1) #define TAGMASK ((1 << LENGTH(tags)) - 1)
#ifdef XWAYLAND
#define WLR_SURFACE(C) ((C)->type != XDGShell ? (C)->surface.xwayland->surface : (C)->surface.xdg->surface) #define WLR_SURFACE(C) ((C)->type != XDGShell ? (C)->surface.xwayland->surface : (C)->surface.xdg->surface)
#else
#define WLR_SURFACE(C) ((C)->surface.xdg->surface)
#endif
/* enums */ /* enums */
enum { CurNormal, CurMove, CurResize }; /* cursor */ enum { CurNormal, CurMove, CurResize }; /* cursor */
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
#ifdef XWAYLAND
enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */ enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */
#endif
typedef union { typedef union {
int i; int i;
@ -72,16 +82,22 @@ typedef struct {
struct wl_list slink; struct wl_list slink;
union { union {
struct wlr_xdg_surface *xdg; struct wlr_xdg_surface *xdg;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xwayland; struct wlr_xwayland_surface *xwayland;
#endif
} surface; } surface;
#ifdef XWAYLAND
struct wl_listener activate; struct wl_listener activate;
#endif
struct wl_listener commit; struct wl_listener commit;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
struct wl_listener destroy; struct wl_listener destroy;
struct wlr_box geom; /* layout-relative, includes border */ struct wlr_box geom; /* layout-relative, includes border */
Monitor *mon; Monitor *mon;
#ifdef XWAYLAND
unsigned int type; unsigned int type;
#endif
int bw; int bw;
unsigned int tags; unsigned int tags;
int isfloating; int isfloating;
@ -155,7 +171,6 @@ struct render_data {
}; };
/* function declarations */ /* function declarations */
static void activatex11(struct wl_listener *listener, void *data);
static void applybounds(Client *c, struct wlr_box *bbox); static void applybounds(Client *c, struct wlr_box *bbox);
static void applyrules(Client *c); static void applyrules(Client *c);
static void arrange(Monitor *m); static void arrange(Monitor *m);
@ -164,10 +179,10 @@ static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg); static void chvt(const Arg *arg);
static void cleanupkeyboard(struct wl_listener *listener, void *data); static void cleanupkeyboard(struct wl_listener *listener, void *data);
static void cleanupmon(struct wl_listener *listener, void *data); static void cleanupmon(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_input_device *device); static void createkeyboard(struct wlr_input_device *device);
static void createmon(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 createnotify(struct wl_listener *listener, void *data);
static void createnotifyx11(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_input_device *device); static void createpointer(struct wlr_input_device *device);
static void createxdeco(struct wl_listener *listener, void *data); static void createxdeco(struct wl_listener *listener, void *data);
static void cursorframe(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data);
@ -178,7 +193,6 @@ static void focusclient(Client *old, Client *c, int lift);
static void focusmon(const Arg *arg); static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg); static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m); static Client *focustop(Monitor *m);
static Atom getatom(xcb_connection_t *xc, const char *name);
static void getxdecomode(struct wl_listener *listener, void *data); static void getxdecomode(struct wl_listener *listener, void *data);
static void incnmaster(const Arg *arg); static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data); static void inputdevice(struct wl_listener *listener, void *data);
@ -187,6 +201,7 @@ 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);
static void killclient(const Arg *arg); static void killclient(const Arg *arg);
static void maprequest(struct wl_listener *listener, void *data); static void maprequest(struct wl_listener *listener, void *data);
static void monocle(Monitor *m);
static void motionabsolute(struct wl_listener *listener, void *data); static void motionabsolute(struct wl_listener *listener, void *data);
static void motionnotify(uint32_t time); static void motionnotify(uint32_t time);
static void motionrelative(struct wl_listener *listener, void *data); static void motionrelative(struct wl_listener *listener, void *data);
@ -216,9 +231,7 @@ static void tile(Monitor *m);
static void togglefloating(const Arg *arg); static void togglefloating(const Arg *arg);
static void toggletag(const Arg *arg); static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg); static void toggleview(const Arg *arg);
static void updatewindowtype(Client *c);
static void unmapnotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data);
static void xwaylandready(struct wl_listener *listener, void *data);
static void view(const Arg *arg); static void view(const Arg *arg);
static Client *xytoclient(double x, double y); static Client *xytoclient(double x, double y);
static Monitor *xytomon(double x, double y); static Monitor *xytomon(double x, double y);
@ -230,7 +243,6 @@ static struct wl_display *dpy;
static struct wlr_backend *backend; static struct wlr_backend *backend;
static struct wlr_renderer *drw; static struct wlr_renderer *drw;
static struct wlr_compositor *compositor; static struct wlr_compositor *compositor;
static struct wlr_xwayland *xwayland;
static struct wlr_xdg_shell *xdg_shell; static struct wlr_xdg_shell *xdg_shell;
static struct wl_list clients; /* tiling order */ static struct wl_list clients; /* tiling order */
@ -253,8 +265,6 @@ static struct wlr_box sgeom;
static struct wl_list mons; static struct wl_list mons;
static Monitor *selmon; static Monitor *selmon;
static Atom netatom[NetLast];
/* global event handlers */ /* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify}; static struct wl_listener cursor_axis = {.notify = axisnotify};
static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_button = {.notify = buttonpress};
@ -265,11 +275,22 @@ static struct wl_listener new_input = {.notify = inputdevice};
static struct wl_listener new_output = {.notify = createmon}; static struct wl_listener new_output = {.notify = createmon};
static struct wl_listener new_xdeco = {.notify = createxdeco}; static struct wl_listener new_xdeco = {.notify = createxdeco};
static struct wl_listener new_xdg_surface = {.notify = createnotify}; static struct wl_listener new_xdg_surface = {.notify = createnotify};
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_cursor = {.notify = setcursor};
static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_psel = {.notify = setpsel};
static struct wl_listener request_set_sel = {.notify = setsel}; static struct wl_listener request_set_sel = {.notify = setsel};
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void createnotifyx11(struct wl_listener *listener, void *data);
static Atom getatom(xcb_connection_t *xc, const char *name);
static void renderindependents(struct wlr_output *output, struct timespec *now);
static void updatewindowtype(Client *c);
static void xwaylandready(struct wl_listener *listener, void *data);
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wl_listener xwayland_ready = {.notify = xwaylandready};
static struct wlr_xwayland *xwayland;
static Atom netatom[NetLast];
#endif
/* configuration, allows nested code to access above variables */ /* configuration, allows nested code to access above variables */
#include "config.h" #include "config.h"
@ -278,16 +299,6 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready};
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
/* function implementations */ /* function implementations */
void
activatex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, activate);
/* Only "managed" windows can be activated */
if (c->type == X11Managed)
wlr_xwayland_surface_activate(c->surface.xwayland, 1);
}
void void
applybounds(Client *c, struct wlr_box *bbox) applybounds(Client *c, struct wlr_box *bbox)
{ {
@ -315,10 +326,17 @@ applyrules(Client *c)
/* rule matching */ /* rule matching */
c->isfloating = 0; c->isfloating = 0;
appid = c->type != XDGShell ? c->surface.xwayland->class : #ifdef XWAYLAND
c->surface.xdg->toplevel->app_id; updatewindowtype(c);
title = c->type != XDGShell ? c->surface.xwayland->title : if (c->type != XDGShell) {
c->surface.xdg->toplevel->title; appid = c->surface.xwayland->class;
title = c->surface.xwayland->title;
} else
#endif
{
appid = c->surface.xdg->toplevel->app_id;
title = c->surface.xdg->toplevel->title;
}
if (!appid) if (!appid)
appid = broken; appid = broken;
if (!title) if (!title)
@ -335,7 +353,6 @@ applyrules(Client *c)
mon = m; mon = m;
} }
} }
updatewindowtype(c);
setmon(c, mon, newtags); setmon(c, mon, newtags);
} }
@ -549,7 +566,6 @@ createnotify(struct wl_listener *listener, void *data)
/* Allocate a Client for this surface */ /* Allocate a Client for this surface */
c = xdg_surface->data = calloc(1, sizeof(*c)); c = xdg_surface->data = calloc(1, sizeof(*c));
c->surface.xdg = xdg_surface; c->surface.xdg = xdg_surface;
c->type = XDGShell;
c->bw = borderpx; c->bw = borderpx;
/* Tell the client not to try anything fancy */ /* Tell the client not to try anything fancy */
@ -567,29 +583,6 @@ createnotify(struct wl_listener *listener, void *data)
wl_signal_add(&xdg_surface->events.destroy, &c->destroy); wl_signal_add(&xdg_surface->events.destroy, &c->destroy);
} }
void
createnotifyx11(struct wl_listener *listener, void *data)
{
struct wlr_xwayland_surface *xwayland_surface = data;
Client *c;
/* Allocate a Client for this surface */
c = xwayland_surface->data = calloc(1, sizeof(*c));
c->surface.xwayland = xwayland_surface;
c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;
c->bw = borderpx;
/* Listen to the various events it can emit */
c->map.notify = maprequest;
wl_signal_add(&xwayland_surface->events.map, &c->map);
c->unmap.notify = unmapnotify;
wl_signal_add(&xwayland_surface->events.unmap, &c->unmap);
c->activate.notify = activatex11;
wl_signal_add(&xwayland_surface->events.request_activate, &c->activate);
c->destroy.notify = destroynotify;
wl_signal_add(&xwayland_surface->events.destroy, &c->destroy);
}
void void
createpointer(struct wlr_input_device *device) createpointer(struct wlr_input_device *device)
{ {
@ -634,10 +627,12 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->map.link); wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link); wl_list_remove(&c->unmap.link);
wl_list_remove(&c->destroy.link); wl_list_remove(&c->destroy.link);
if (c->type == XDGShell) #ifdef XWAYLAND
wl_list_remove(&c->commit.link);
if (c->type == X11Managed) if (c->type == X11Managed)
wl_list_remove(&c->activate.link); wl_list_remove(&c->activate.link);
else if (c->type == XDGShell)
#endif
wl_list_remove(&c->commit.link);
free(c); free(c);
} }
@ -685,9 +680,11 @@ focusclient(Client *old, Client *c, int lift)
/* Deactivate old client if focus is changing */ /* Deactivate old client if focus is changing */
if (c != old && old) { if (c != old && old) {
#ifdef XWAYLAND
if (old->type != XDGShell) if (old->type != XDGShell)
wlr_xwayland_surface_activate(old->surface.xwayland, 0); wlr_xwayland_surface_activate(old->surface.xwayland, 0);
else else
#endif
wlr_xdg_toplevel_set_activated(old->surface.xdg, 0); wlr_xdg_toplevel_set_activated(old->surface.xdg, 0);
} }
@ -708,9 +705,11 @@ focusclient(Client *old, Client *c, int lift)
selmon = c->mon; selmon = c->mon;
/* Activate the new client */ /* Activate the new client */
#ifdef XWAYLAND
if (c->type != XDGShell) if (c->type != XDGShell)
wlr_xwayland_surface_activate(c->surface.xwayland, 1); wlr_xwayland_surface_activate(c->surface.xwayland, 1);
else else
#endif
wlr_xdg_toplevel_set_activated(c->surface.xdg, 1); wlr_xdg_toplevel_set_activated(c->surface.xdg, 1);
} }
@ -759,23 +758,6 @@ focustop(Monitor *m)
return NULL; return NULL;
} }
Atom
getatom(xcb_connection_t *xc, const char *name)
{
Atom atom;
xcb_generic_error_t *error;
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom(xc, 0, strlen(name), name);
reply = xcb_intern_atom_reply(xc, cookie, &error);
if (reply != NULL && error == NULL)
atom = reply->atom;
free(reply);
return atom;
}
void void
getxdecomode(struct wl_listener *listener, void *data) getxdecomode(struct wl_listener *listener, void *data)
{ {
@ -894,9 +876,11 @@ killclient(const Arg *arg)
if (!sel) if (!sel)
return; return;
#ifdef XWAYLAND
if (sel->type != XDGShell) if (sel->type != XDGShell)
wlr_xwayland_surface_close(sel->surface.xwayland); wlr_xwayland_surface_close(sel->surface.xwayland);
else else
#endif
wlr_xdg_toplevel_send_close(sel->surface.xdg); wlr_xdg_toplevel_send_close(sel->surface.xdg);
} }
@ -906,23 +890,28 @@ maprequest(struct wl_listener *listener, void *data)
/* Called when the surface is mapped, or ready to display on-screen. */ /* Called when the surface is mapped, or ready to display on-screen. */
Client *c = wl_container_of(listener, c, map); Client *c = wl_container_of(listener, c, map);
#ifdef XWAYLAND
if (c->type == X11Unmanaged) { if (c->type == X11Unmanaged) {
/* Insert this independent into independents lists. */ /* Insert this independent into independents lists. */
wl_list_insert(&independents, &c->link); wl_list_insert(&independents, &c->link);
return; return;
} }
#endif
/* Insert this client into client lists. */ /* Insert this client into client lists. */
wl_list_insert(&clients, &c->link); wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink); wl_list_insert(&fstack, &c->flink);
wl_list_insert(&stack, &c->slink); wl_list_insert(&stack, &c->slink);
#ifdef XWAYLAND
if (c->type != XDGShell) { if (c->type != XDGShell) {
c->geom.x = c->surface.xwayland->x; c->geom.x = c->surface.xwayland->x;
c->geom.y = c->surface.xwayland->y; c->geom.y = c->surface.xwayland->y;
c->geom.width = c->surface.xwayland->width + 2 * c->bw; c->geom.width = c->surface.xwayland->width + 2 * c->bw;
c->geom.height = c->surface.xwayland->height + 2 * c->bw; c->geom.height = c->surface.xwayland->height + 2 * c->bw;
} else { } else
#endif
{
wlr_xdg_surface_get_geometry(c->surface.xdg, &c->geom); wlr_xdg_surface_get_geometry(c->surface.xdg, &c->geom);
c->geom.width += 2 * c->bw; c->geom.width += 2 * c->bw;
c->geom.height += 2 * c->bw; c->geom.height += 2 * c->bw;
@ -932,6 +921,18 @@ maprequest(struct wl_listener *listener, void *data)
applyrules(c); applyrules(c);
} }
void
monocle(Monitor *m)
{
Client *c;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating)
continue;
resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0);
}
}
void void
motionabsolute(struct wl_listener *listener, void *data) motionabsolute(struct wl_listener *listener, void *data)
{ {
@ -972,11 +973,13 @@ motionnotify(uint32_t time)
/* Otherwise, find the client under the pointer and send the event along. */ /* Otherwise, find the client under the pointer and send the event along. */
if ((c = xytoclient(cursor->x, cursor->y))) { if ((c = xytoclient(cursor->x, cursor->y))) {
#ifdef XWAYLAND
if (c->type != XDGShell) if (c->type != XDGShell)
surface = wlr_surface_surface_at(c->surface.xwayland->surface, surface = wlr_surface_surface_at(c->surface.xwayland->surface,
cursor->x - c->geom.x - c->bw, cursor->x - c->geom.x - c->bw,
cursor->y - c->geom.y - c->bw, &sx, &sy); cursor->y - c->geom.y - c->bw, &sx, &sy);
else else
#endif
surface = wlr_xdg_surface_surface_at(c->surface.xdg, surface = wlr_xdg_surface_surface_at(c->surface.xdg,
cursor->x - c->geom.x - c->bw, cursor->x - c->geom.x - c->bw,
cursor->y - c->geom.y - c->bw, &sx, &sy); cursor->y - c->geom.y - c->bw, &sx, &sy);
@ -1170,39 +1173,15 @@ renderclients(Monitor *m, struct timespec *now)
rdata.when = now; rdata.when = now;
rdata.x = c->geom.x + c->bw; rdata.x = c->geom.x + c->bw;
rdata.y = c->geom.y + c->bw; rdata.y = c->geom.y + c->bw;
#ifdef XWAYLAND
if (c->type != XDGShell) if (c->type != XDGShell)
wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata); wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata);
else else
#endif
wlr_xdg_surface_for_each_surface(c->surface.xdg, render, &rdata); wlr_xdg_surface_for_each_surface(c->surface.xdg, render, &rdata);
} }
} }
void
renderindependents(struct wlr_output *output, struct timespec *now)
{
Client *c;
struct render_data rdata;
struct wlr_box geom;
wl_list_for_each_reverse(c, &independents, link) {
geom.x = c->surface.xwayland->x;
geom.y = c->surface.xwayland->y;
geom.width = c->surface.xwayland->width;
geom.height = c->surface.xwayland->height;
/* Only render visible clients which show on this output */
if (!wlr_output_layout_intersects(output_layout, output, &geom))
continue;
rdata.output = output;
rdata.when = now;
rdata.x = c->surface.xwayland->x;
rdata.y = c->surface.xwayland->y;
wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata);
}
}
void void
rendermon(struct wl_listener *listener, void *data) rendermon(struct wl_listener *listener, void *data)
{ {
@ -1234,7 +1213,9 @@ rendermon(struct wl_listener *listener, void *data)
wlr_renderer_clear(drw, rootcolor); wlr_renderer_clear(drw, rootcolor);
renderclients(m, &now); renderclients(m, &now);
#ifdef XWAYLAND
renderindependents(m->wlr_output, &now); renderindependents(m->wlr_output, &now);
#endif
/* Hardware cursors are rendered by the GPU on a separate plane, and can be /* Hardware cursors are rendered by the GPU on a separate plane, and can be
* moved around without re-rendering what's beneath them - which is more * moved around without re-rendering what's beneath them - which is more
@ -1267,11 +1248,13 @@ resize(Client *c, int x, int y, int w, int h, int interact)
c->geom.height = h; c->geom.height = h;
applybounds(c, bbox); applybounds(c, bbox);
/* wlroots makes this a no-op if size hasn't changed */ /* wlroots makes this a no-op if size hasn't changed */
#ifdef XWAYLAND
if (c->type != XDGShell) if (c->type != XDGShell)
wlr_xwayland_surface_configure(c->surface.xwayland, wlr_xwayland_surface_configure(c->surface.xwayland,
c->geom.x, c->geom.y, c->geom.x, c->geom.y,
c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
else else
#endif
c->resize = wlr_xdg_toplevel_set_size(c->surface.xdg, c->resize = wlr_xdg_toplevel_set_size(c->surface.xdg,
c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
} }
@ -1485,9 +1468,11 @@ setup(void)
* the clients cannot set the selection directly without compositor approval, * the clients cannot set the selection directly without compositor approval,
* see the setsel() function. */ * see the setsel() function. */
compositor = wlr_compositor_create(dpy, drw); compositor = wlr_compositor_create(dpy, drw);
wlr_export_dmabuf_manager_v1_create(dpy);
wlr_screencopy_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy);
wlr_data_device_manager_create(dpy); wlr_data_device_manager_create(dpy);
wlr_primary_selection_v1_device_manager_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy);
wlr_viewporter_create(dpy);
/* Creates an output layout, which a wlroots utility for working with an /* Creates an output layout, which a wlroots utility for working with an
* arrangement of screens in a physical layout. */ * arrangement of screens in a physical layout. */
@ -1564,6 +1549,7 @@ setup(void)
wl_signal_add(&seat->events.request_set_primary_selection, wl_signal_add(&seat->events.request_set_primary_selection,
&request_set_psel); &request_set_psel);
#ifdef XWAYLAND
/* /*
* Initialise the XWayland X server. * Initialise the XWayland X server.
* It will be started when the first X client is started. * It will be started when the first X client is started.
@ -1577,6 +1563,7 @@ setup(void)
} else { } else {
fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
} }
#endif
} }
void void
@ -1688,48 +1675,15 @@ unmapnotify(struct wl_listener *listener, void *data)
/* Called when the surface is unmapped, and should no longer be shown. */ /* Called when the surface is unmapped, and should no longer be shown. */
Client *c = wl_container_of(listener, c, unmap); Client *c = wl_container_of(listener, c, unmap);
wl_list_remove(&c->link); wl_list_remove(&c->link);
#ifdef XWAYLAND
if (c->type == X11Unmanaged) if (c->type == X11Unmanaged)
return; return;
#endif
setmon(c, NULL, 0); setmon(c, NULL, 0);
wl_list_remove(&c->flink); wl_list_remove(&c->flink);
wl_list_remove(&c->slink); wl_list_remove(&c->slink);
} }
void
updatewindowtype(Client *c)
{
size_t i;
if (c->type != XDGShell)
for (i = 0; i < c->surface.xwayland->window_type_len; i++)
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility])
c->isfloating = 1;
}
void
xwaylandready(struct wl_listener *listener, void *data) {
xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);
int err = xcb_connection_has_error(xc);
if (err) {
fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);
return;
}
/* collect atoms we are interested in */
netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");
netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");
netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");
netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");
/* assign the one and only seat */
wlr_xwayland_set_seat(xwayland, seat);
xcb_disconnect(xc);
}
void void
view(const Arg *arg) view(const Arg *arg)
{ {
@ -1794,6 +1748,119 @@ zoom(const Arg *arg)
arrange(selmon); arrange(selmon);
} }
#ifdef XWAYLAND
void
activatex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, activate);
/* Only "managed" windows can be activated */
if (c->type == X11Managed)
wlr_xwayland_surface_activate(c->surface.xwayland, 1);
}
void
createnotifyx11(struct wl_listener *listener, void *data)
{
struct wlr_xwayland_surface *xwayland_surface = data;
Client *c;
/* Allocate a Client for this surface */
c = xwayland_surface->data = calloc(1, sizeof(*c));
c->surface.xwayland = xwayland_surface;
c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;
c->bw = borderpx;
/* Listen to the various events it can emit */
c->map.notify = maprequest;
wl_signal_add(&xwayland_surface->events.map, &c->map);
c->unmap.notify = unmapnotify;
wl_signal_add(&xwayland_surface->events.unmap, &c->unmap);
c->activate.notify = activatex11;
wl_signal_add(&xwayland_surface->events.request_activate, &c->activate);
c->destroy.notify = destroynotify;
wl_signal_add(&xwayland_surface->events.destroy, &c->destroy);
}
Atom
getatom(xcb_connection_t *xc, const char *name)
{
Atom atom = 0;
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom(xc, 0, strlen(name), name);
if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))
atom = reply->atom;
free(reply);
return atom;
}
void
renderindependents(struct wlr_output *output, struct timespec *now)
{
Client *c;
struct render_data rdata;
struct wlr_box geom;
wl_list_for_each_reverse(c, &independents, link) {
geom.x = c->surface.xwayland->x;
geom.y = c->surface.xwayland->y;
geom.width = c->surface.xwayland->width;
geom.height = c->surface.xwayland->height;
/* Only render visible clients which show on this output */
if (!wlr_output_layout_intersects(output_layout, output, &geom))
continue;
rdata.output = output;
rdata.when = now;
rdata.x = c->surface.xwayland->x;
rdata.y = c->surface.xwayland->y;
wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata);
}
}
void
updatewindowtype(Client *c)
{
size_t i;
if (c->type != XDGShell)
for (i = 0; i < c->surface.xwayland->window_type_len; i++)
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility])
c->isfloating = 1;
}
void
xwaylandready(struct wl_listener *listener, void *data)
{
xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);
int err = xcb_connection_has_error(xc);
if (err) {
fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);
return;
}
/* Collect atoms we are interested in. If getatom returns 0, we will
* not detect that window type. */
netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");
netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");
netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");
netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");
/* assign the one and only seat */
wlr_xwayland_set_seat(xwayland, seat);
xcb_disconnect(xc);
}
#endif
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -1838,7 +1905,9 @@ main(int argc, char *argv[])
run(startup_cmd); run(startup_cmd);
/* Once wl_display_run returns, we shut down the server. */ /* Once wl_display_run returns, we shut down the server. */
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland); wlr_xwayland_destroy(xwayland);
#endif
wl_display_destroy_clients(dpy); wl_display_destroy_clients(dpy);
wl_display_destroy(dpy); wl_display_destroy(dpy);