diff options
Diffstat (limited to 'dwl.c')
-rw-r--r-- | dwl.c | 675 |
1 files changed, 435 insertions, 240 deletions
@@ -16,21 +16,25 @@ #include <wlr/render/wlr_renderer.h> #include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_data_control_v1.h> #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_keyboard.h> #include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_output.h> #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_primary_selection.h> #include <wlr/types/wlr_primary_selection_v1.h> #include <wlr/types/wlr_screencopy_v1.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_decoration_v1.h> #include <wlr/types/wlr_xdg_output_v1.h> @@ -95,6 +99,7 @@ typedef struct { } surface; #ifdef XWAYLAND struct wl_listener activate; + struct wl_listener configure; #endif struct wl_listener commit; struct wl_listener map; @@ -171,6 +176,7 @@ struct Monitor { double mfact; int nmaster; Client *fullscreenclient; + int position; }; typedef struct { @@ -206,7 +212,7 @@ static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usable_area, bool exclusive); + struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); @@ -214,6 +220,7 @@ static void chvt(const Arg *arg); static void cleanup(void); static void cleanupkeyboard(struct wl_listener *listener, void *data); 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 createkeyboard(struct wlr_input_device *device); @@ -227,7 +234,7 @@ 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(int dir); -static void focusclient(Client *old, Client *c, int lift); +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); @@ -240,13 +247,16 @@ static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); static void maplayersurfacenotify(struct wl_listener *listener, void *data); -static void maprequest(struct wl_listener *listener, void *data); +static void mapnotify(struct wl_listener *listener, void *data); static void maximizeclient(Client *c); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); static void motionnotify(uint32_t time); static void motionrelative(struct wl_listener *listener, void *data); static void moveresize(const Arg *arg); +static void outputmgrapply(struct wl_listener *listener, void *data); +static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); +static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void quit(const Arg *arg); @@ -268,7 +278,6 @@ static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, unsigned int newtags); static void setup(void); static void sigchld(int unused); -static bool shouldfocusclients(); static void spawn(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -282,6 +291,7 @@ static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); static void updatemons(); static void view(const Arg *arg); +static void virtualkeyboard(struct wl_listener *listener, void *data); static Client *xytoclient(double x, double y); static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, double x, double y, double *sx, double *sy); @@ -300,8 +310,11 @@ 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_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -328,16 +341,20 @@ 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 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_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); +static void configurex11(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); @@ -379,53 +396,61 @@ applyexclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, int32_t margin_bottom, int32_t margin_left) { + if (exclusive <= 0) + return; + struct { uint32_t singular_anchor; uint32_t anchor_triplet; int *positive_axis; int *negative_axis; int margin; - } edges[4]; - - if (exclusive <= 0) - return; - - // Top - edges[0].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; - edges[0].anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; - edges[0].positive_axis = &usable_area->y; - edges[0].negative_axis = &usable_area->height; - edges[0].margin = margin_top; - // Bottom - edges[1].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - edges[1].anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - edges[1].positive_axis = NULL; - edges[1].negative_axis = &usable_area->height; - edges[1].margin = margin_bottom; - // Left - edges[2].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; - edges[2].anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - edges[2].positive_axis = &usable_area->x; - edges[2].negative_axis = &usable_area->width; - edges[2].margin = margin_left; - // Right - edges[3].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - edges[3].anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - edges[3].positive_axis = NULL; - edges[3].negative_axis = &usable_area->width; - edges[3].margin = margin_right; + } edges[] = { + // Top + { + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + .anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + .positive_axis = &usable_area->y, + .negative_axis = &usable_area->height, + .margin = margin_top, + }, + // Bottom + { + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = NULL, + .negative_axis = &usable_area->height, + .margin = margin_bottom, + }, + // Left + { + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, + .anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = &usable_area->x, + .negative_axis = &usable_area->width, + .margin = margin_left, + }, + // Right + { + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + .anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = NULL, + .negative_axis = &usable_area->width, + .margin = margin_right, + }, + }; for (size_t i = 0; i < LENGTH(edges); ++i) { if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) @@ -442,13 +467,8 @@ applyexclusive(struct wlr_box *usable_area, void applyrules(Client *c) { - const char *appid, *title; - unsigned int i, newtags = 0; - const Rule *r; - Monitor *mon = selmon, *m; - /* rule matching */ - c->isfloating = 0; + const char *appid, *title; #ifdef XWAYLAND if (c->type != XDGShell) { updatewindowtype(c); @@ -465,6 +485,9 @@ applyrules(Client *c) if (!title) title = broken; + unsigned int i, newtags = 0; + const Rule *r; + Monitor *mon = selmon, *m; for (r = rules; r < END(rules); r++) { if ((!r->title || strstr(title, r->title)) && (!r->id || strstr(appid, r->id))) { @@ -486,11 +509,11 @@ arrange(Monitor *m) m->lt[m->sellt]->arrange(m); else if (m->fullscreenclient) maximizeclient(m->fullscreenclient); - /* XXX recheck pointer focus here... or in resize()? */ + /* TODO recheck pointer focus here... or in resize()? */ } void -arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) { LayerSurface *layersurface; struct wlr_box full_area = m->m; @@ -498,22 +521,20 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool wl_list_for_each(layersurface, list, link) { struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; - struct wlr_box bounds; struct wlr_box box = { .width = state->desired_width, .height = state->desired_height }; - const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; if (exclusive != (state->exclusive_zone > 0)) continue; - bounds = state->exclusive_zone == -1 ? full_area : *usable_area; + struct wlr_box bounds = state->exclusive_zone == -1 ? + full_area : *usable_area; // Horizontal axis + const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; if ((state->anchor & both_horiz) && box.width == 0) { box.x = bounds.x; box.width = bounds.width; @@ -525,6 +546,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); } // Vertical axis + const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP + | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; if ((state->anchor & both_vert) && box.height == 0) { box.y = bounds.y; box.height = bounds.height; @@ -569,23 +592,16 @@ void arrangelayers(Monitor *m) { struct wlr_box usable_area = m->m; - uint32_t layers_above_shell[] = { - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, - }; - size_t nlayers = LENGTH(layers_above_shell); - LayerSurface *layersurface; - struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); // Arrange exclusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, true); + &usable_area, 1); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, true); + &usable_area, 1); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, true); + &usable_area, 1); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, true); + &usable_area, 1); if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { m->w = usable_area; @@ -594,20 +610,29 @@ arrangelayers(Monitor *m) // Arrange non-exlusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, false); + &usable_area, 0); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, false); + &usable_area, 0); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, false); + &usable_area, 0); arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, false); + &usable_area, 0); // Find topmost keyboard interactive layer, if such a layer exists + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + size_t nlayers = LENGTH(layers_above_shell); + LayerSurface *layersurface; + struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); for (size_t i = 0; i < nlayers; ++i) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && layersurface->layer_surface->mapped) { + // Deactivate the focused client. + focusclient(NULL, 0); wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); return; @@ -622,6 +647,7 @@ axisnotify(struct wl_listener *listener, void *data) /* This event is forwarded by the cursor when a pointer emits an axis event, * for example when you move the scroll wheel. */ struct wlr_event_pointer_axis *event = data; + wlr_idle_notify_activity(idle, seat); /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, event->delta, @@ -632,19 +658,19 @@ void buttonpress(struct wl_listener *listener, void *data) { struct wlr_event_pointer_button *event = data; - struct wlr_keyboard *keyboard; - uint32_t mods; - Client *c; - const Button *b; + + wlr_idle_notify_activity(idle, seat); switch (event->state) { case WLR_BUTTON_PRESSED:; /* Change focus if the button was _pressed_ over a client */ + Client *c; if ((c = xytoclient(cursor->x, cursor->y))) - focusclient(selclient(), c, 1); + focusclient(c, 1); - keyboard = wlr_seat_get_keyboard(seat); - mods = wlr_keyboard_get_modifiers(keyboard); + struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(seat); + uint32_t mods = wlr_keyboard_get_modifiers(keyboard); + const Button *b; for (b = buttons; b < END(buttons); b++) { if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && b->func) { @@ -655,7 +681,7 @@ buttonpress(struct wl_listener *listener, void *data) break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ - /* XXX should reset to the pointer focus's current setcursor */ + /* TODO should reset to the pointer focus's current setcursor */ if (cursor_mode != CurNormal) { wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); @@ -699,6 +725,9 @@ cleanupkeyboard(struct wl_listener *listener, void *data) struct wlr_input_device *device = data; Keyboard *kb = device->data; + wl_list_remove(&kb->link); + wl_list_remove(&kb->modifiers.link); + wl_list_remove(&kb->key.link); wl_list_remove(&kb->destroy.link); free(kb); } @@ -710,9 +739,33 @@ cleanupmon(struct wl_listener *listener, void *data) Monitor *m = wlr_output->data; wl_list_remove(&m->destroy.link); + wl_list_remove(&m->frame.link); + wl_list_remove(&m->link); + wlr_output_layout_remove(output_layout, m->wlr_output); + updatemons(); + + int nmons = wl_list_length(&mons), i = 0; + do // don't switch to disabled mons + selmon = wl_container_of(mons.prev, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + focusclient(focustop(selmon), 1); + closemon(m); free(m); +} - updatemons(); +void +closemon(Monitor *m) +{ + // move closed monitor's clients to the focused one + Client *c; + + wl_list_for_each(c, &clients, link) { + if (c->isfloating && c->geom.x > m->m.width) + resize(c, c->geom.x - m->w.width, c->geom.y, + c->geom.width, c->geom.height, 0); + if (c->mon == m) + setmon(c, selmon, c->tags); + } } void @@ -721,12 +774,11 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_output *wlr_output = wlr_layer_surface->output; - Monitor *m; if (!wlr_output) return; - m = wlr_output->data; + Monitor *m = wlr_output->data; arrangelayers(m); if (layersurface->layer != wlr_layer_surface->current.layer) { @@ -750,16 +802,12 @@ commitnotify(struct wl_listener *listener, void *data) void createkeyboard(struct wlr_input_device *device) { - struct xkb_context *context; - struct xkb_keymap *keymap; - Keyboard *kb; - - kb = device->data = calloc(1, sizeof(*kb)); + Keyboard *kb = device->data = calloc(1, sizeof(*kb)); kb->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, + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + struct xkb_keymap *keymap = xkb_map_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); wlr_keyboard_set_keymap(device->keyboard, keymap); @@ -787,9 +835,6 @@ createmon(struct wl_listener *listener, void *data) /* This event is raised by the backend when a new output (aka a display or * monitor) becomes available. */ struct wlr_output *wlr_output = data; - Monitor *m; - const MonitorRule *r; - size_t nlayers = LENGTH(m->layers); /* The mode is a tuple of (width, height, refresh rate), and each * monitor supports only a specific set of modes. We just pick the @@ -798,49 +843,77 @@ createmon(struct wl_listener *listener, void *data) wlr_output_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output)); /* Allocates and configures monitor state using configured rules */ - m = wlr_output->data = calloc(1, sizeof(*m)); + Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); m->wlr_output = wlr_output; m->tagset[0] = m->tagset[1] = 1; - for (r = monrules; r < END(monrules); r++) { + m->position = -1; + for (const MonitorRule *r = monrules; r < END(monrules); r++) { if (!r->name || strstr(wlr_output->name, r->name)) { m->mfact = r->mfact; m->nmaster = r->nmaster; wlr_output_set_scale(wlr_output, r->scale); wlr_xcursor_manager_load(cursor_mgr, r->scale); - m->lt[0] = m->lt[1] = r->lt; + m->lt[0] = r->lt; + m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; wlr_output_set_transform(wlr_output, r->rr); + m->position = r - monrules; break; } } + wlr_output_enable_adaptive_sync(wlr_output, 1); /* Set up event listeners */ m->frame.notify = rendermon; wl_signal_add(&wlr_output->events.frame, &m->frame); m->destroy.notify = cleanupmon; wl_signal_add(&wlr_output->events.destroy, &m->destroy); - wl_list_insert(&mons, &m->link); + Monitor *moni, *insertmon = NULL; + int x = 0; + wl_list_for_each(moni, &mons, link) + if (m->position > moni->position) + insertmon = moni; + if (insertmon) { + x = insertmon->w.x + insertmon->w.width; + wl_list_insert(&insertmon->link, &m->link); + } else { + wl_list_insert(&mons, &m->link); + } wlr_output_enable(wlr_output, 1); if (!wlr_output_commit(wlr_output)) return; - /* Adds this to the output layout. The add_auto function arranges outputs - * from left-to-right in the order they appear. A more sophisticated - * compositor would let the user configure the arrangement of outputs in the - * layout. + /* 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 * display, which Wayland clients can see to find out information about the * output (such as DPI, scale factor, manufacturer, etc). */ - wlr_output_layout_add_auto(output_layout, wlr_output); + wlr_output_layout_add(output_layout, wlr_output, x, 0); + wl_list_for_each_reverse(moni, &mons, link) { + /* All monitors to the right of the new one must be moved */ + if (moni == m) + break; + wlr_output_layout_move(output_layout, moni->wlr_output, moni->w.x + m->wlr_output->width, 0); + } sgeom = *wlr_output_layout_get_box(output_layout, NULL); + size_t nlayers = LENGTH(m->layers); for (size_t i = 0; i < nlayers; ++i) wl_list_init(&m->layers[i]); /* When adding monitors, the geometries of all monitors must be updated */ updatemons(); + wl_list_for_each(m, &mons, link) { + /* The first monitor in the list is the most recently added */ + Client *c; + wl_list_for_each(c, &clients, link) { + if (c->isfloating) + resize(c, c->geom.x + m->w.width, c->geom.y, + c->geom.width, c->geom.height, 0); + } + return; + } } void @@ -853,6 +926,9 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; + wl_list_for_each(c, &clients, link) + if (c->isfullscreen && VISIBLEON(c, c->mon)) + setfullscreen(c, 0); /* Allocate a Client for this surface */ c = xdg_surface->data = calloc(1, sizeof(*c)); @@ -866,7 +942,7 @@ createnotify(struct wl_listener *listener, void *data) /* Listen to the various events it can emit */ c->commit.notify = commitnotify; wl_signal_add(&xdg_surface->surface->events.commit, &c->commit); - c->map.notify = maprequest; + c->map.notify = mapnotify; wl_signal_add(&xdg_surface->events.map, &c->map); c->unmap.notify = unmapnotify; wl_signal_add(&xdg_surface->events.unmap, &c->unmap); @@ -882,15 +958,12 @@ 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)); + LayerSurface *layersurface = calloc(1, sizeof(LayerSurface)); layersurface->surface_commit.notify = commitlayersurfacenotify; wl_signal_add(&wlr_layer_surface->surface->events.commit, @@ -905,14 +978,14 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->layer_surface = wlr_layer_surface; wlr_layer_surface->data = layersurface; - m = wlr_layer_surface->output->data; + Monitor *m = wlr_layer_surface->output->data; wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer], &layersurface->link); // Temporarily set the layer's current state to client_pending // so that we can easily arrange it - old_state = wlr_layer_surface->current; + struct wlr_layer_surface_v1_state old_state = wlr_layer_surface->current; wlr_layer_surface->current = wlr_layer_surface->client_pending; arrangelayers(m); wlr_layer_surface->current = old_state; @@ -968,7 +1041,6 @@ void destroylayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); - Monitor *m; if (layersurface->layer_surface->mapped) unmaplayersurface(layersurface); @@ -978,7 +1050,7 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); if (layersurface->layer_surface->output) { - m = layersurface->layer_surface->output->data; + Monitor *m = layersurface->layer_surface->output->data; if (m) arrangelayers(m); layersurface->layer_surface->output = NULL; @@ -1082,31 +1154,53 @@ dirtomon(int dir) } void -focusclient(Client *old, Client *c, int lift) +focusclient(Client *c, int lift) { - struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); - /* Raise client in stacking order if requested */ if (c && lift) { wl_list_remove(&c->slink); wl_list_insert(&stack, &c->slink); } - /* Nothing else to do? */ - if (c == old) + struct wlr_surface *old = seat->keyboard_state.focused_surface; + + if (c && WLR_SURFACE(c) == old) return; + /* Put the new client atop the focus stack and select its monitor */ + if (c) { + wl_list_remove(&c->flink); + wl_list_insert(&fstack, &c->flink); + selmon = c->mon; + } + /* Deactivate old client if focus is changing */ - if (c != old && old) { + if (old && (!c || WLR_SURFACE(c) != old)) { + if (wlr_surface_is_xdg_surface(old)) + wlr_xdg_toplevel_set_activated( + wlr_xdg_surface_from_wlr_surface(old), 0); #ifdef XWAYLAND - if (old->type != XDGShell) - wlr_xwayland_surface_activate(old->surface.xwayland, 0); - else + else if (wlr_surface_is_xwayland_surface(old)) + wlr_xwayland_surface_activate( + wlr_xwayland_surface_from_wlr_surface(old), 0); #endif - wlr_xdg_toplevel_set_activated(old->surface.xdg, 0); + /* If an overlay is focused, don't focus or activate the client, + * but only update its position in fstack to render its border with focuscolor + * and focus it after the overlay is closed. + * It's probably pointless to check if old is a layer surface + * since it can't be anything else at this point. */ + else if (wlr_surface_is_layer_surface(old)) { + struct wlr_layer_surface_v1 *wlr_layer_surface = + wlr_layer_surface_v1_from_wlr_surface(old); + + if (wlr_layer_surface->mapped && ( + wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || + wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY + )) + return; + } } - /* Update wlroots' keyboard focus */ if (!c) { /* With no client, all we have left is to clear focus */ wlr_seat_keyboard_notify_clear_focus(seat); @@ -1114,14 +1208,9 @@ focusclient(Client *old, Client *c, int lift) } /* Have a client, so focus its top-level wlr_surface */ - if (shouldfocusclients(c->mon)) - wlr_seat_keyboard_notify_enter(seat, WLR_SURFACE(c), - kb->keycodes, kb->num_keycodes, &kb->modifiers); - - /* Put the new client atop the focus stack and select its monitor */ - wl_list_remove(&c->flink); - wl_list_insert(&fstack, &c->flink); - selmon = c->mon; + struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); + wlr_seat_keyboard_notify_enter(seat, WLR_SURFACE(c), + kb->keycodes, kb->num_keycodes, &kb->modifiers); /* Activate the new client */ #ifdef XWAYLAND @@ -1135,10 +1224,10 @@ focusclient(Client *old, Client *c, int lift) void focusmon(const Arg *arg) { - Client *sel = selclient(); - - selmon = dirtomon(arg->i); - focusclient(sel, focustop(selmon), 1); + do + selmon = dirtomon(arg->i); + while (!selmon->wlr_output->enabled); + focusclient(focustop(selmon), 1); } void @@ -1164,7 +1253,7 @@ focusstack(const Arg *arg) } } /* If only one client is visible on selmon, then c == sel */ - focusclient(sel, c, 1); + focusclient(c, 1); } Client * @@ -1198,7 +1287,6 @@ inputdevice(struct wl_listener *listener, void *data) /* This event is raised by the backend when a new input device becomes * available. */ struct wlr_input_device *device = data; - uint32_t caps; switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: createkeyboard(device); @@ -1207,14 +1295,14 @@ inputdevice(struct wl_listener *listener, void *data) createpointer(device); break; default: - /* XXX handle other input device types */ + /* TODO handle other input device types */ break; } /* We need to let the wlr_seat know what our capabilities are, which is * communiciated to the client. In dwl we always have a cursor, even if * there are no pointer devices, so we always include that capability. */ - /* XXX do we actually require a cursor? */ - caps = WL_SEAT_CAPABILITY_POINTER; + /* TODO do we actually require a cursor? */ + uint32_t caps = WL_SEAT_CAPABILITY_POINTER; if (!wl_list_empty(&keyboards)) caps |= WL_SEAT_CAPABILITY_KEYBOARD; wlr_seat_set_capabilities(seat, caps); @@ -1243,10 +1331,10 @@ keybinding(uint32_t mods, xkb_keysym_t sym) void keypress(struct wl_listener *listener, void *data) { + int i; /* This event is raised when a key is pressed or released. */ Keyboard *kb = wl_container_of(listener, kb, key); struct wlr_event_keyboard_key *event = data; - int i; /* Translate libinput keycode -> xkbcommon */ uint32_t keycode = event->keycode + 8; @@ -1257,6 +1345,9 @@ keypress(struct wl_listener *listener, void *data) int handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); + + wlr_idle_notify_activity(idle, seat); + /* On _press_, attempt to process a compositor keybinding. */ if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) for (i = 0; i < nsyms; i++) @@ -1312,7 +1403,7 @@ maplayersurfacenotify(struct wl_listener *listener, void *data) } void -maprequest(struct wl_listener *listener, void *data) +mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ Client *c = wl_container_of(listener, c, map), *oldfocus = selclient(); @@ -1350,7 +1441,7 @@ maprequest(struct wl_listener *listener, void *data) if (c->mon->fullscreenclient && c->mon->fullscreenclient == oldfocus && !c->isfloating && c->mon->lt[c->mon->sellt]->arrange) { maximizeclient(c->mon->fullscreenclient); - focusclient(c, c->mon->fullscreenclient, 1); + focusclient(c->mon->fullscreenclient, 1); /* give the focus back the fullscreen client on that monitor if exists, * is focused and the new client isn't floating */ } @@ -1388,18 +1479,14 @@ motionabsolute(struct wl_listener *listener, void *data) void motionnotify(uint32_t time) { - double sx = 0, sy = 0; - struct wlr_surface *surface = NULL; - Client *c = NULL; - struct timespec now; - if (!time) { - clock_gettime(CLOCK_MONOTONIC, &now); - time = now.tv_sec * 1000 + now.tv_nsec / 1000000; - } + // time is 0 in internal calls meant to restore pointer focus. + if (time) { + wlr_idle_notify_activity(idle, seat); - /* Update selmon (even while dragging a window) */ - if (sloppyfocus) - selmon = xytomon(cursor->x, cursor->y); + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) + selmon = xytomon(cursor->x, cursor->y); + } /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { @@ -1414,6 +1501,9 @@ motionnotify(uint32_t time) return; } + struct wlr_surface *surface = NULL; + double sx = 0, sy = 0; + Client *c = NULL; if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], cursor->x, cursor->y, &sx, &sy))) ; @@ -1452,7 +1542,7 @@ motionnotify(uint32_t time) /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ - if (!surface) + if (!surface && time) wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); @@ -1503,6 +1593,72 @@ moveresize(const Arg *arg) } void +outputmgrapply(struct wl_listener *listener, void *data) +{ + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 0); +} + +void +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) +{ + struct wlr_output_configuration_head_v1 *config_head; + int ok = 1; + + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + + wlr_output_enable(wlr_output, config_head->state.enabled); + if (config_head->state.enabled) { + if (config_head->state.mode) + wlr_output_set_mode(wlr_output, config_head->state.mode); + else + wlr_output_set_custom_mode(wlr_output, + config_head->state.custom_mode.width, + config_head->state.custom_mode.height, + config_head->state.custom_mode.refresh); + + wlr_output_layout_move(output_layout, wlr_output, + config_head->state.x, config_head->state.y); + wlr_output_set_transform(wlr_output, config_head->state.transform); + wlr_output_set_scale(wlr_output, config_head->state.scale); + } else if (wl_list_length(&mons) > 1) { + Monitor *m; + wl_list_for_each(m, &mons, link) { + if (m->wlr_output->name == wlr_output->name) { + // focus the left monitor (relative to the current focus) + m->wlr_output->enabled = !m->wlr_output->enabled; + Arg ar = {.i = -1}; + focusmon(&ar); + closemon(m); + m->wlr_output->enabled = !m->wlr_output->enabled; + } + } + } + + if (test) { + ok &= wlr_output_test(wlr_output); + wlr_output_rollback(wlr_output); + } else + ok &= wlr_output_commit(wlr_output); + } + if (ok) { + wlr_output_configuration_v1_send_succeeded(config); + if (!test) + updatemons(); + } else + wlr_output_configuration_v1_send_failed(config); + wlr_output_configuration_v1_destroy(config); +} + +void +outputmgrtest(struct wl_listener *listener, void *data) +{ + struct wlr_output_configuration_v1 *config = data; + outputmgrapplyortest(config, 1); +} + +void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { @@ -1516,6 +1672,13 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, return; } + int internal_call = !time; + if (!time) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } + /* If surface is already focused, only notify of motion */ if (surface == seat->pointer_state.focused_surface) { wlr_seat_pointer_notify_motion(seat, time, sx, sy); @@ -1534,8 +1697,8 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, return; #endif - if (sloppyfocus) - focusclient(selclient(), c, 0); + if (sloppyfocus && !internal_call) + focusclient(c, 0); } void @@ -1550,10 +1713,6 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) /* This function is called for every surface that needs to be rendered. */ struct render_data *rdata = data; struct wlr_output *output = rdata->output; - double ox = 0, oy = 0; - struct wlr_box obox; - float matrix[9]; - enum wl_output_transform transform; /* We first obtain a wlr_texture, which is a GPU resource. wlroots * automatically handles negotiating these with the client. The underlying @@ -1568,14 +1727,17 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) * one next to the other, both 1080p, a client on the rightmost display might * have layout coordinates of 2000,100. We need to translate that to * output-local coordinates, or (2000 - 1920). */ + double ox = 0, oy = 0; wlr_output_layout_output_coords(output_layout, output, &ox, &oy); /* We also have to apply the scale factor for HiDPI outputs. This is only * part of the puzzle, dwl does not fully support HiDPI. */ - obox.x = ox + rdata->x + sx; - obox.y = oy + rdata->y + sy; - obox.width = surface->current.width; - obox.height = surface->current.height; + struct wlr_box obox = { + .x = ox + rdata->x + sx, + .y = oy + rdata->y + sy, + .width = surface->current.width, + .height = surface->current.height, + }; scalebox(&obox, output->scale); /* @@ -1589,7 +1751,9 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) * Naturally you can do this any way you like, for example to make a 3D * compositor. */ - transform = wlr_output_transform_invert(surface->current.transform); + float matrix[9]; + enum wl_output_transform transform = wlr_output_transform_invert( + surface->current.transform); wlr_matrix_project_box(matrix, &obox, transform, 0, output->transform_matrix); @@ -1662,13 +1826,14 @@ renderclients(Monitor *m, struct timespec *now) void renderlayer(struct wl_list *layer_surfaces, struct timespec *now) { - struct render_data rdata; LayerSurface *layersurface; wl_list_for_each(layersurface, layer_surfaces, link) { - rdata.output = layersurface->layer_surface->output; - rdata.when = now; - rdata.x = layersurface->geo.x; - rdata.y = layersurface->geo.y; + struct render_data rdata = { + .output = layersurface->layer_surface->output, + .when = now, + .x = layersurface->geo.x, + .y = layersurface->geo.y, + }; wlr_surface_for_each_surface(layersurface->layer_surface->surface, render, &rdata); @@ -1678,9 +1843,6 @@ renderlayer(struct wl_list *layer_surfaces, struct timespec *now) void rendermon(struct wl_listener *listener, void *data) { - Client *c; - int render = 1; - /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); @@ -1689,6 +1851,8 @@ rendermon(struct wl_listener *listener, void *data) clock_gettime(CLOCK_MONOTONIC, &now); /* Do not render if any XDG clients have an outstanding resize. */ + Client *c; + int render = 1; wl_list_for_each(c, &stack, slink) { if (c->resize) { wlr_surface_send_frame_done(WLR_SURFACE(c), &now); @@ -1738,11 +1902,11 @@ resize(Client *c, int x, int y, int w, int h, int interact) * compositor, you'd wait for the client to prepare a buffer at * the new size, then commit any movement that was prepared. */ - struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; c->geom.x = x; c->geom.y = y; c->geom.width = w; c->geom.height = h; + struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; applybounds(c, bbox); /* wlroots makes this a no-op if size hasn't changed */ #ifdef XWAYLAND @@ -1759,8 +1923,6 @@ resize(Client *c, int x, int y, int w, int h, int interact) void run(char *startup_cmd) { - pid_t startup_pid = -1; - /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); if (!socket) @@ -1775,7 +1937,7 @@ run(char *startup_cmd) * cursor position, and set default cursor image */ selmon = xytomon(cursor->x, cursor->y); - /* XXX hack to get cursor to display in its initial location (100, 100) + /* TODO hack to get cursor to display in its initial location (100, 100) * instead of (0, 0) and then jumping. still may not be fully * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ @@ -1785,8 +1947,10 @@ run(char *startup_cmd) /* Set the WAYLAND_DISPLAY environment variable to our socket and run the * startup command if requested. */ setenv("WAYLAND_DISPLAY", socket, 1); + + pid_t startup_pid = -1; if (startup_cmd) { - startup_pid = fork(); + pid_t startup_pid = fork(); if (startup_pid < 0) EBARF("startup: fork"); if (startup_pid == 0) { @@ -1794,6 +1958,7 @@ run(char *startup_cmd) 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 @@ -1830,7 +1995,7 @@ setcursor(struct wl_listener *listener, void *data) /* This event is raised by the seat when a client provides a cursor image */ struct wlr_seat_pointer_request_set_cursor_event *event = data; /* If we're "grabbing" the cursor, don't use the client's image */ - /* XXX still need to save the provided surface to restore later */ + /* TODO still need to save the provided surface to restore later */ if (cursor_mode != CurNormal) return; /* This can be sent by any client, so we check to make sure this one is @@ -1857,7 +2022,7 @@ setlayout(const Arg *arg) selmon->sellt ^= 1; if (arg && arg->v) selmon->lt[selmon->sellt] = (Layout *)arg->v; - /* XXX change layout symbol? */ + /* TODO change layout symbol? */ arrange(selmon); } @@ -1865,11 +2030,9 @@ setlayout(const Arg *arg) void setmfact(const Arg *arg) { - float f; - if (!arg || !selmon->lt[selmon->sellt]->arrange) return; - f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + float f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.1 || f > 0.9) return; selmon->mfact = f; @@ -1880,13 +2043,12 @@ void setmon(Client *c, Monitor *m, unsigned int newtags) { Monitor *oldmon = c->mon; - Client *oldsel = selclient(); if (oldmon == m) return; c->mon = m; - /* XXX leave/enter is not optimal but works */ + /* TODO leave/enter is not optimal but works */ if (oldmon) { wlr_surface_send_leave(WLR_SURFACE(c), oldmon->wlr_output); arrange(oldmon); @@ -1898,7 +2060,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ arrange(m); } - focusclient(oldsel, focustop(selmon), 1); + focusclient(focustop(selmon), 1); } void @@ -1959,6 +2121,7 @@ setup(void) compositor = wlr_compositor_create(dpy, drw); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); + wlr_data_control_manager_v1_create(dpy); wlr_data_device_manager_create(dpy); wlr_gamma_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); @@ -1985,6 +2148,8 @@ setup(void) wl_list_init(&stack); wl_list_init(&independents); + idle = wlr_idle_create(dpy); + layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); @@ -2035,6 +2200,9 @@ setup(void) */ wl_list_init(&keyboards); wl_signal_add(&backend->events.new_input, &new_input); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); + wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, + &new_virtual_keyboard); seat = wlr_seat_create(dpy, "seat0"); wl_signal_add(&seat->events.request_set_cursor, &request_cursor); @@ -2043,12 +2211,16 @@ setup(void) wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); + output_mgr = wlr_output_manager_v1_create(dpy); + wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); + wl_signal_add(&output_mgr->events.test, &output_mgr_test); + #ifdef XWAYLAND /* * Initialise the XWayland X server. * It will be started when the first X client is started. */ - xwayland = wlr_xwayland_create(dpy, compositor, true); + xwayland = wlr_xwayland_create(dpy, compositor, 1); if (xwayland) { wl_signal_add(&xwayland->events.ready, &xwayland_ready); wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); @@ -2067,7 +2239,7 @@ setup(void) xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); } - setenv("DISPLAY", xwayland->display_name, true); + setenv("DISPLAY", xwayland->display_name, 1); } else { fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); } @@ -2083,22 +2255,6 @@ sigchld(int unused) ; } -bool -shouldfocusclients(Monitor *m) -{ - LayerSurface *layersurface; - uint32_t layers_above_shell[] = { - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, - }; - for (size_t i = 0; i < LENGTH(layers_above_shell); ++i) - wl_list_for_each(layersurface, &m->layers[layers_above_shell[i]], link) - if (layersurface->layer_surface->current.keyboard_interactive && - layersurface->layer_surface->mapped) - return false; - return true; -} - void spawn(const Arg *arg) { @@ -2115,7 +2271,7 @@ tag(const Arg *arg) Client *sel = selclient(); if (sel && arg->ui & TAGMASK) { sel->tags = arg->ui & TAGMASK; - focusclient(sel, focustop(selmon), 1); + focusclient(focustop(selmon), 1); arrange(selmon); } } @@ -2177,14 +2333,13 @@ togglefloating(const Arg *arg) void toggletag(const Arg *arg) { - unsigned int newtags; Client *sel = selclient(); if (!sel) return; - newtags = sel->tags ^ (arg->ui & TAGMASK); + unsigned int newtags = sel->tags ^ (arg->ui & TAGMASK); if (newtags) { sel->tags = newtags; - focusclient(sel, focustop(selmon), 1); + focusclient(focustop(selmon), 1); arrange(selmon); } } @@ -2192,12 +2347,11 @@ toggletag(const Arg *arg) void toggleview(const Arg *arg) { - Client *sel = selclient(); unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; - focusclient(sel, focustop(selmon), 1); + focusclient(focustop(selmon), 1); arrange(selmon); } } @@ -2205,10 +2359,10 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { - layersurface->layer_surface->mapped = false; + layersurface->layer_surface->mapped = 0; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) - focusclient(NULL, selclient(), 1); + focusclient(selclient(), 1); motionnotify(0); } @@ -2237,30 +2391,50 @@ unmapnotify(struct wl_listener *listener, void *data) void updatemons() { + struct wlr_output_configuration_v1 *config = + wlr_output_configuration_v1_create(); Monitor *m; + sgeom = *wlr_output_layout_get_box(output_layout, NULL); wl_list_for_each(m, &mons, link) { + struct wlr_output_configuration_head_v1 *config_head = + wlr_output_configuration_head_v1_create(config, m->wlr_output); + /* Get the effective monitor geometry to use for surfaces */ m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ arrange(m); + + config_head->state.enabled = m->wlr_output->enabled; + config_head->state.mode = m->wlr_output->current_mode; + config_head->state.x = m->m.x; + config_head->state.y = m->m.y; } + + wlr_output_manager_v1_set_configuration(output_mgr, config); } void view(const Arg *arg) { - Client *sel = selclient(); if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; - focusclient(sel, focustop(selmon), 1); + focusclient(focustop(selmon), 1); arrange(selmon); } +void +virtualkeyboard(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_keyboard_v1 *keyboard = data; + struct wlr_input_device *device = &keyboard->input_device; + createkeyboard(device); +} + Client * xytoclient(double x, double y) { @@ -2304,7 +2478,7 @@ xytomon(double x, double y) void zoom(const Arg *arg) { - Client *c, *sel = selclient(), *oldsel = sel; + Client *c, *sel = selclient(); if (!sel || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) return; @@ -2329,7 +2503,7 @@ zoom(const Arg *arg) wl_list_remove(&sel->link); wl_list_insert(&clients, &sel->link); - focusclient(oldsel, sel, 1); + focusclient(sel, 1); arrange(selmon); } @@ -2345,24 +2519,38 @@ activatex11(struct wl_listener *listener, void *data) } void +configurex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, configure); + struct wlr_xwayland_surface_configure_event *event = data; + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); +} + +void createnotifyx11(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xwayland_surface = data; Client *c; + wl_list_for_each(c, &clients, link) + if (c->isfullscreen && VISIBLEON(c, c->mon)) + setfullscreen(c, 0); /* Allocate a Client for this surface */ + struct wlr_xwayland_surface *xwayland_surface = data; 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; + c->map.notify = mapnotify; 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->configure.notify = configurex11; + wl_signal_add(&xwayland_surface->events.request_configure, &c->configure); c->destroy.notify = destroynotify; wl_signal_add(&xwayland_surface->events.destroy, &c->destroy); @@ -2375,10 +2563,8 @@ 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); + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) atom = reply->atom; free(reply); @@ -2390,23 +2576,25 @@ 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; + struct wlr_box geom = { + .x = c->surface.xwayland->x, + .y = c->surface.xwayland->y, + .width = c->surface.xwayland->width, + .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; + struct render_data rdata = { + .output = output, + .when = now, + .x = c->surface.xwayland->x, + .y = c->surface.xwayland->y, + }; wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata); } @@ -2415,8 +2603,7 @@ renderindependents(struct wlr_output *output, struct timespec *now) void updatewindowtype(Client *c) { - size_t i; - for (i = 0; i < c->surface.xwayland->window_type_len; i++) + for (size_t 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] || @@ -2444,6 +2631,13 @@ xwaylandready(struct wl_listener *listener, void *data) /* assign the one and only seat */ wlr_xwayland_set_seat(xwayland, seat); + /* Set the default XWayland cursor to match the rest of dwl. */ + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(cursor_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); + xcb_disconnect(xc); } @@ -2456,12 +2650,13 @@ xytoindependent(double x, double y) * client loses focus, which ensures that unmanaged are only visible on * the current tag. */ Client *c; - 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; + struct wlr_box geom = { + .x = c->surface.xwayland->x, + .y = c->surface.xwayland->y, + .width = c->surface.xwayland->width, + .height = c->surface.xwayland->height, + }; if (wlr_box_contains_point(&geom, x, y)) return c; } |