diff --git a/dwl.c b/dwl.c index 1e6c423..d5f2f98 100644 --- a/dwl.c +++ b/dwl.c @@ -328,6 +328,7 @@ static void mapnotify(struct wl_listener *listener, void *data); static void maximizenotify(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); +static char **monoff(struct wlr_output *wlr_output); static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, double sy, double sx_unaccel, double sy_unaccel); static void motionrelative(struct wl_listener *listener, void *data); @@ -353,6 +354,7 @@ 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, uint32_t newtags); +static void setmonoff(struct wlr_output *wlr_output, int off); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); @@ -450,6 +452,7 @@ static struct wl_event_source *transaction_idle; static struct wl_event_source *transaction_timer; static int transaction_waiting; static struct wl_array ghosts; /* struct wlr_scene_node *, unmapped clients */ +static struct wl_array offmons; /* char *, names of outputs turned off by clients */ /* global event handlers */ static struct wl_listener cursor_axis = {.notify = axisnotify}; @@ -824,6 +827,8 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { + char **name; + cleanuplisteners(); #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); @@ -849,6 +854,9 @@ cleanup(void) wl_event_source_remove(transaction_idle); wl_event_source_remove(transaction_timer); wl_array_release(&ghosts); + wl_array_for_each(name, &offmons) + free(*name); + wl_array_release(&offmons); wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) @@ -1229,14 +1237,17 @@ createmon(struct wl_listener *listener, void *data) * monitor supports only a specific set of modes. We just pick the * monitor's preferred mode; a more sophisticated compositor would let * the user configure it. */ - wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); - /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); - wlr_output_state_set_enabled(&state, 1); + /* Some monitors disconnect when they are turned off and reconnect shortly + * after, so keep outputs that were turned off disabled. */ + if (!monoff(wlr_output)) { + wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); + wlr_output_state_set_enabled(&state, 1); + } wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); @@ -2068,6 +2079,17 @@ motionabsolute(struct wl_listener *listener, void *data) motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } +char ** +monoff(struct wlr_output *wlr_output) +{ + char **name; + wl_array_for_each(name, &offmons) { + if (!strcmp(*name, wlr_output->name)) + return name; + } + return NULL; +} + void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, double dx_unaccel, double dy_unaccel) @@ -2254,6 +2276,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) /* Ensure displays previously disabled by wlr-output-power-management-v1 * are properly handled*/ m->asleep = 0; + setmonoff(wlr_output, !config_head->state.enabled); /* Don't move monitors if position wouldn't change. This avoids * wlroots marking the output as manually configured. @@ -2372,6 +2395,10 @@ powermgrsetmode(struct wl_listener *listener, void *data) m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */ wlr_output_state_set_enabled(&state, event->mode); + /* The output was reconnected while off and was never modeset */ + if (event->mode && !m->wlr_output->current_mode) + wlr_output_state_set_mode(&state, wlr_output_preferred_mode(m->wlr_output)); + setmonoff(m->wlr_output, !event->mode); wlr_output_commit_state(m->wlr_output, &state); m->asleep = !event->mode; @@ -2647,6 +2674,22 @@ setmon(Client *c, Monitor *m, uint32_t newtags) focusclient(focustop(selmon), NULL, 1); } +void +setmonoff(struct wlr_output *wlr_output, int off) +{ + char **name = monoff(wlr_output), **last; + + if (off && !name && (name = wl_array_add(&offmons, sizeof(*name)))) { + if (!(*name = strdup(wlr_output->name))) + offmons.size -= sizeof(*name); + } else if (!off && name) { + free(*name); + last = (char **)((char *)offmons.data + offmons.size) - 1; + *name = *last; + offmons.size -= sizeof(*name); + } +} + void setpsel(struct wl_listener *listener, void *data) { @@ -2787,6 +2830,7 @@ setup(void) transaction_timer = wl_event_loop_add_timer(event_loop, transactiontimeout, NULL); wl_array_init(&ghosts); + wl_array_init(&offmons); xdg_shell = wlr_xdg_shell_create(dpy, 6); wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);