Harden output lifecycle state handling
fa8cd67132e8c89565d8b0526f9022820a53d8dc
1 parent
273d34f6
swm.c
+42 -15
| 315 | 315 | int layout_x; /* Last configured layout position. */ |
|
| 316 | 316 | int layout_y; |
|
| 317 | 317 | struct wl_list layers[4]; /* Layer surfaces on this display. */ |
|
| 318 | 318 | workspace_t *ws; /* Workspace shown on this display. */ |
|
| 319 | 319 | workspace_t *previous_workspace; /* Workspace shown before the current one. */ |
|
| 320 | + | workspace_t *disabled_workspace; /* Workspace hidden while the output is disabled. */ |
|
| 320 | 321 | int gamma_lut_changed; |
|
| 321 | 322 | int asleep; |
|
| 322 | 323 | }; |
|
| 323 | 324 | ||
| 324 | 325 | /* Each workspace keeps separate settings for vertical and horizontal layouts. */ |
| 2157 | 2158 | selmon = candidate; |
|
| 2158 | 2159 | break; |
|
| 2159 | 2160 | } |
|
| 2160 | 2161 | } |
|
| 2161 | 2162 | } |
|
| 2162 | - | if (m->ws) |
|
| 2163 | - | m->ws->mon = nullptr; |
|
| 2163 | + | if (m->ws) { |
|
| 2164 | + | m->disabled_workspace = m->ws; |
|
| 2165 | + | m->ws->mon = nullptr; |
|
| 2166 | + | } |
|
| 2164 | 2167 | m->ws = m->previous_workspace = nullptr; |
|
| 2165 | 2168 | ||
| 2166 | 2169 | for (ws = workspaces; ws < END(workspaces); ws++) { |
|
| 2167 | 2170 | if (ws->mon == m) |
|
| 2168 | 2171 | ws->mon = nullptr; |
| 2586 | 2589 | * monitor supports only a specific set of modes. We just pick the |
|
| 2587 | 2590 | * monitor's preferred mode; a more sophisticated compositor would let |
|
| 2588 | 2591 | * the user configure it. */ |
|
| 2589 | 2592 | wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); |
|
| 2590 | 2593 | ||
| 2591 | - | /* Listen for display events. */ |
|
| 2594 | + | wlr_output_state_set_enabled(&state, 1); |
|
| 2595 | + | ||
| 2596 | + | if (!wlr_output_commit_state(wlr_output, &state)) { |
|
| 2597 | + | wlr_output_state_finish(&state); |
|
| 2598 | + | ||
| 2599 | + | if (m->ws) |
|
| 2600 | + | m->ws->mon = nullptr; |
|
| 2601 | + | wlr_output->data = nullptr; |
|
| 2602 | + | pool_release(&monitor_pool, m); |
|
| 2603 | + | fprintf(stderr, "swm: failed to enable output %s\n", wlr_output->name); |
|
| 2604 | + | return; |
|
| 2605 | + | } |
|
| 2606 | + | wlr_output_state_finish(&state); |
|
| 2607 | + | ||
| 2608 | + | /* Listen for display events after its initial state has committed. */ |
|
| 2592 | 2609 | LISTEN(&wlr_output->events.frame, &m->frame, render_monitor); |
|
| 2593 | 2610 | LISTEN(&wlr_output->events.destroy, &m->destroy, cleanup_monitor); |
|
| 2594 | 2611 | LISTEN(&wlr_output->events.request_state, &m->request_state, request_monitor_state); |
|
| 2595 | 2612 | LISTEN(&wlr_output->events.bind, &m->output_bind, workspace_output_bind); |
|
| 2596 | 2613 | ||
| 2597 | - | wlr_output_state_set_enabled(&state, 1); |
|
| 2598 | - | wlr_output_commit_state(wlr_output, &state); |
|
| 2599 | - | wlr_output_state_finish(&state); |
|
| 2600 | - | ||
| 2601 | 2614 | wl_list_insert(&mons, &m->link); |
|
| 2602 | 2615 | print_status(); |
|
| 2603 | 2616 | ||
| 2604 | 2617 | /* Hide unrelated content behind a transparent fullscreen window, as the |
|
| 2605 | 2618 | * XDG shell protocol requires. */ |
| 4808 | 4821 | } |
|
| 4809 | 4822 | ||
| 4810 | 4823 | /* Turn a display on or off at an external client's request. */ |
|
| 4811 | 4824 | void power_manager_set_mode(struct wl_listener *listener, void *data) { |
|
| 4812 | 4825 | struct wlr_output_power_v1_set_mode_event *event = data; |
|
| 4813 | - | struct wlr_output_state state = {}; |
|
| 4814 | - | monitor_t *m = event->output->data; |
|
| 4826 | + | struct wlr_output_state state; |
|
| 4827 | + | monitor_t *m = event->output->data; |
|
| 4815 | 4828 | ||
| 4816 | 4829 | if (!m) |
|
| 4817 | 4830 | return; |
|
| 4818 | 4831 | ||
| 4819 | - | m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */ |
|
| 4832 | + | wlr_output_state_init(&state); |
|
| 4820 | 4833 | wlr_output_state_set_enabled(&state, event->mode); |
|
| 4821 | - | wlr_output_commit_state(m->wlr_output, &state); |
|
| 4822 | 4834 | ||
| 4823 | - | m->asleep = !event->mode; |
|
| 4824 | - | update_monitors(nullptr, nullptr); |
|
| 4835 | + | if (wlr_output_commit_state(m->wlr_output, &state)) { |
|
| 4836 | + | m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */ |
|
| 4837 | + | m->asleep = !event->mode; |
|
| 4838 | + | update_monitors(nullptr, nullptr); |
|
| 4839 | + | } |
|
| 4840 | + | wlr_output_state_finish(&state); |
|
| 4825 | 4841 | } |
|
| 4826 | 4842 | ||
| 4827 | 4843 | /* Stop the Wayland event loop and begin shutdown. */ |
|
| 4828 | 4844 | void quit(const arg_t *arg) { |
|
| 4829 | 4845 | wl_display_terminate(dpy); |
| 4886 | 4902 | ||
| 4887 | 4903 | /* Commit a display-state change requested by the backend. */ |
|
| 4888 | 4904 | void request_monitor_state(struct wl_listener *listener, void *data) { |
|
| 4889 | 4905 | struct wlr_output_event_request_state *event = data; |
|
| 4890 | 4906 | ||
| 4891 | - | wlr_output_commit_state(event->output, event->state); |
|
| 4892 | - | update_monitors(nullptr, nullptr); |
|
| 4907 | + | if (wlr_output_commit_state(event->output, event->state)) |
|
| 4908 | + | update_monitors(nullptr, nullptr); |
|
| 4893 | 4909 | } |
|
| 4894 | 4910 | ||
| 4895 | 4911 | /* Request a new window geometry and apply it when the application is ready. */ |
|
| 4896 | 4912 | void resize(client_t *c, struct wlr_box geo, bool interact) { |
|
| 4897 | 4913 | struct wlr_box *bbox; |
| 6389 | 6405 | if (m->lock_surface) { |
|
| 6390 | 6406 | struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; |
|
| 6391 | 6407 | wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); |
|
| 6392 | 6408 | wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height); |
|
| 6393 | 6409 | } |
|
| 6410 | + | if (!m->ws) { |
|
| 6411 | + | workspace_t *ws = m->disabled_workspace; |
|
| 6412 | + | ||
| 6413 | + | if (!ws || ws->mon) |
|
| 6414 | + | ws = free_workspace(); |
|
| 6415 | + | m->disabled_workspace = nullptr; |
|
| 6416 | + | m->ws = m->previous_workspace = ws; |
|
| 6417 | + | ||
| 6418 | + | if (ws) |
|
| 6419 | + | ws->mon = m; |
|
| 6420 | + | } |
|
| 6394 | 6421 | /* Reserve panel space before arranging regular windows. */ |
|
| 6395 | 6422 | arrange_layers(m); |
|
| 6396 | 6423 | /* Sync clients of this output's workspace (it may have been |
|
| 6397 | 6424 | * hidden or shown elsewhere before this display appeared). */ |
|
| 6398 | 6425 | if (m->ws) |
test/run.py
+4 -0
| 688 | 688 | protocol("output-management", "configure-second") |
|
| 689 | 689 | protocol("output-management", "disable-second") |
|
| 690 | 690 | wait_title("multi") |
|
| 691 | 691 | protocol("output-management", "enable-second") |
|
| 692 | 692 | wait_title("multi") |
|
| 693 | + | virtual_keyboard(106, 4) |
|
| 694 | + | wait_title("") |
|
| 695 | + | virtual_keyboard(106, 1) |
|
| 696 | + | wait_title("multi") |
|
| 693 | 697 | ||
| 694 | 698 | test("multiple outputs", multioutput) |
|
| 695 | 699 | terminate(client) |
|
| 696 | 700 | ||
| 697 | 701 |