diff --git a/Makefile b/Makefile index 578194f..ab521b7 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ - wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h + wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h wlr-foreign-toplevel-management-unstable-v1-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -45,6 +45,9 @@ wlr-output-power-management-unstable-v1-protocol.h: xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +wlr-foreign-toplevel-management-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@ config.h: cp config.def.h $@ diff --git a/dwl.c b/dwl.c index 4816159..2a2a1c3 100644 --- a/dwl.c +++ b/dwl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,11 @@ typedef struct { struct wl_listener fullscreen; struct wl_listener set_decoration_mode; struct wl_listener destroy_decoration; + struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; + struct wl_listener factivate; + struct wl_listener fclose; + struct wl_listener ffullscreen; + struct wl_listener fdestroy; #ifdef XWAYLAND struct wl_listener activate; struct wl_listener associate; @@ -351,6 +357,11 @@ static Monitor *xytomon(double x, double y); static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void zoom(const Arg *arg); +static void createforeigntoplevel(Client *c); +static void factivatenotify(struct wl_listener *listener, void *data); +static void fclosenotify(struct wl_listener *listener, void *data); +static void fdestroynotify(struct wl_listener *listener, void *data); +static void ffullscreennotify(struct wl_listener *listener, void *data); /* variables */ static pid_t child_pid = -1; @@ -395,6 +406,8 @@ static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; +static struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_mgr; + static struct wlr_seat *seat; static KeyboardGroup *kb_group; static unsigned int cursor_mode; @@ -487,6 +500,11 @@ applyrules(Client *c) appid = client_get_appid(c); title = client_get_title(c); + if (c->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_set_app_id(c->foreign_toplevel, appid); + wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); + } + for (r = rules; r < END(rules); r++) { if ((!r->title || strstr(title, r->title)) && (!r->id || strstr(appid, r->id))) { @@ -1450,6 +1468,8 @@ focusclient(Client *c, int lift) client_set_border_color(old_c, bordercolor); client_activate_surface(old, 0); + if (old_c->foreign_toplevel) + wlr_foreign_toplevel_handle_v1_set_activated(old_c->foreign_toplevel, 0); } } printstatus(); @@ -1468,6 +1488,8 @@ focusclient(Client *c, int lift) /* Activate the new client */ client_activate_surface(client_surface(c), 1); + if (c->foreign_toplevel) + wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, 1); } void @@ -1769,6 +1791,8 @@ mapnotify(struct wl_listener *listener, void *data) c->border[i]->node.data = c; } + createforeigntoplevel(c); + /* Initialize client geometry with room for border */ client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); c->geom.width += 2 * c->bw; @@ -2403,12 +2427,17 @@ setmon(Client *c, Monitor *m, uint32_t newtags) c->prev = c->geom; /* Scene graph sends surface leave/enter events on move and resize */ - if (oldmon) + if (oldmon) { + if (c->foreign_toplevel) + wlr_foreign_toplevel_handle_v1_output_leave(c->foreign_toplevel, oldmon->wlr_output); arrange(oldmon); + } if (m) { /* Make sure window actually overlaps with the monitor */ resize(c, c->geom, 0); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ + if (c->foreign_toplevel) + wlr_foreign_toplevel_handle_v1_output_enter(c->foreign_toplevel, m->wlr_output); setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ setfloating(c, c->isfloating); } @@ -2529,6 +2558,9 @@ setup(void) power_mgr = wlr_output_power_manager_v1_create(dpy); wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); + /* Initializes foreign toplevel management */ + foreign_toplevel_mgr = wlr_foreign_toplevel_manager_v1_create(dpy); + /* 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(dpy); @@ -2826,6 +2858,11 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->flink); } + if (c->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel); + c->foreign_toplevel = NULL; + } + wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0, NULL, 0, 0, 0, 0); @@ -2941,6 +2978,12 @@ void updatetitle(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_title); + if (c->foreign_toplevel) { + const char *title; + if (!(title = client_get_title(c))) + title = broken; + wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); + } if (c == focustop(c->mon)) printstatus(); } @@ -3070,6 +3113,54 @@ zoom(const Arg *arg) arrange(selmon); } +void +createforeigntoplevel(Client *c) +{ + c->foreign_toplevel = wlr_foreign_toplevel_handle_v1_create(foreign_toplevel_mgr); + + LISTEN(&c->foreign_toplevel->events.request_activate, &c->factivate, factivatenotify); + LISTEN(&c->foreign_toplevel->events.request_close, &c->fclose, fclosenotify); + LISTEN(&c->foreign_toplevel->events.request_fullscreen, &c->ffullscreen, ffullscreennotify); + LISTEN(&c->foreign_toplevel->events.destroy, &c->fdestroy, fdestroynotify); +} + +void +factivatenotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, factivate); + if (c->mon == selmon) { + c->tags = c->mon->tagset[c->mon->seltags]; + } else { + setmon(c, selmon, 0); + } + focusclient(c, 1); + arrange(c->mon); +} + +void +fclosenotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fclose); + client_send_close(c); +} + +void +ffullscreennotify(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, ffullscreen); + struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data; + setfullscreen(c, event->fullscreen); +} + +void +fdestroynotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fdestroy); + wl_list_remove(&c->factivate.link); + wl_list_remove(&c->fclose.link); + wl_list_remove(&c->ffullscreen.link); + wl_list_remove(&c->fdestroy.link); +} + #ifdef XWAYLAND void activatex11(struct wl_listener *listener, void *data)