Add xdg-dialog-v1 support
488f4e61ef58be1d7ff9dbab49dcdb5e1b6d79da
1 parent
7e066161
swm.c
+85 -6
| 68 | 68 | #include <wlr/types/wlr_virtual_keyboard_v1.h> |
|
| 69 | 69 | #include <wlr/types/wlr_virtual_pointer_v1.h> |
|
| 70 | 70 | #include <wlr/types/wlr_xcursor_manager.h> |
|
| 71 | 71 | #include <wlr/types/wlr_xdg_activation_v1.h> |
|
| 72 | 72 | #include <wlr/types/wlr_xdg_decoration_v1.h> |
|
| 73 | + | #include <wlr/types/wlr_xdg_dialog_v1.h> |
|
| 73 | 74 | #include <wlr/types/wlr_xdg_output_v1.h> |
|
| 74 | 75 | #include <wlr/types/wlr_xdg_shell.h> |
|
| 75 | 76 | #include <wlr/util/log.h> |
|
| 76 | 77 | #include <wlr/util/region.h> |
|
| 77 | 78 | #include <wlr/xwayland.h> |
| 207 | 208 | struct wl_listener set_title; |
|
| 208 | 209 | struct wl_listener set_appid; |
|
| 209 | 210 | struct wl_listener fullscreen; |
|
| 210 | 211 | struct wl_listener set_decoration_mode; |
|
| 211 | 212 | struct wl_listener destroy_decoration; |
|
| 213 | + | struct wlr_xdg_dialog_v1 *dialog; |
|
| 214 | + | struct wl_listener dialog_destroy; |
|
| 215 | + | struct wl_listener dialog_modal; |
|
| 216 | + | struct wl_listener set_parent; |
|
| 212 | 217 | struct wl_listener activate; |
|
| 213 | 218 | struct wl_listener associate; |
|
| 214 | 219 | struct wl_listener dissociate; |
|
| 215 | 220 | struct wl_listener configure; |
|
| 216 | 221 | struct wl_listener set_hints; |
| 487 | 492 | static void text_input_disable_notify(struct wl_listener *listener, void *data); |
|
| 488 | 493 | static void text_input_enable_notify(struct wl_listener *listener, void *data); |
|
| 489 | 494 | static void focus_monitor(const arg_t *arg); |
|
| 490 | 495 | static void focus_stack(const arg_t *arg); |
|
| 491 | 496 | static client_t *focus_top(monitor_t *m); |
|
| 497 | + | static bool client_is_blocked(client_t *c); |
|
| 492 | 498 | static void fullscreen_notify(struct wl_listener *listener, void *data); |
|
| 493 | 499 | static void gpu_reset(struct wl_listener *listener, void *data); |
|
| 494 | 500 | static int handle_signal(int signo, void *data); |
|
| 495 | 501 | static void master_bottom(monitor_t *m); |
|
| 496 | 502 | static void master_left(monitor_t *m); |
| 584 | 590 | static void unmap_notify(struct wl_listener *listener, void *data); |
|
| 585 | 591 | static void update_monitors(struct wl_listener *listener, void *data); |
|
| 586 | 592 | static void update_app_id(struct wl_listener *listener, void *data); |
|
| 587 | 593 | static void update_title(struct wl_listener *listener, void *data); |
|
| 588 | 594 | static void urgent(struct wl_listener *listener, void *data); |
|
| 595 | + | static void create_dialog(struct wl_listener *listener, void *data); |
|
| 596 | + | static void dialog_changed(struct wl_listener *listener, void *data); |
|
| 597 | + | static void dialog_destroyed(struct wl_listener *listener, void *data); |
|
| 589 | 598 | static void view(const arg_t *arg); |
|
| 590 | 599 | static void virtual_keyboard(struct wl_listener *listener, void *data); |
|
| 591 | 600 | static void virtual_pointer(struct wl_listener *listener, void *data); |
|
| 592 | 601 | static monitor_t *point_to_monitor(double x, double y); |
|
| 593 | 602 | static void point_to_node( |
| 620 | 629 | static struct wlr_allocator *alloc; |
|
| 621 | 630 | static struct wlr_compositor *compositor; |
|
| 622 | 631 | static struct wlr_session *session; |
|
| 623 | 632 | ||
| 624 | 633 | static struct wlr_xdg_shell *xdg_shell; |
|
| 634 | + | static struct wlr_xdg_wm_dialog_v1 *xdg_dialog_mgr; |
|
| 625 | 635 | static struct wlr_xdg_activation_v1 *activation; |
|
| 626 | 636 | static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; |
|
| 627 | 637 | static struct wl_list clients; /* tiling order */ |
|
| 628 | 638 | static struct wl_list fstack; /* focus order */ |
|
| 629 | 639 | static struct wlr_idle_notifier_v1 *idle_notifier; |
| 697 | 707 | static struct wl_listener new_output = { .notify = create_monitor }; |
|
| 698 | 708 | static struct wl_listener new_xdg_toplevel = { .notify = create_notify }; |
|
| 699 | 709 | static struct wl_listener new_text_input = { .notify = text_input_create_notify }; |
|
| 700 | 710 | static struct wl_listener new_xdg_popup = { .notify = create_popup }; |
|
| 701 | 711 | static struct wl_listener new_xdg_decoration = { .notify = create_decoration }; |
|
| 712 | + | static struct wl_listener new_xdg_dialog = { .notify = create_dialog }; |
|
| 702 | 713 | static struct wl_listener new_layer_surface = { .notify = create_layer_surface }; |
|
| 703 | 714 | static struct wl_listener output_mgr_apply = { .notify = output_manager_apply }; |
|
| 704 | 715 | static struct wl_listener output_mgr_test = { .notify = output_manager_test }; |
|
| 705 | 716 | static struct wl_listener output_power_mgr_set_mode = { .notify = power_manager_set_mode }; |
|
| 706 | 717 | static struct wl_listener request_activate = { .notify = urgent }; |
| 1986 | 1997 | wl_list_remove(&new_shortcuts_inhibitor_listener.link); |
|
| 1987 | 1998 | wl_list_remove(&new_output.link); |
|
| 1988 | 1999 | wl_list_remove(&new_xdg_toplevel.link); |
|
| 1989 | 2000 | wl_list_remove(&new_text_input.link); |
|
| 1990 | 2001 | wl_list_remove(&new_xdg_decoration.link); |
|
| 2002 | + | wl_list_remove(&new_xdg_dialog.link); |
|
| 1991 | 2003 | wl_list_remove(&new_xdg_popup.link); |
|
| 1992 | 2004 | wl_list_remove(&new_layer_surface.link); |
|
| 1993 | 2005 | wl_list_remove(&ext_ftl_capture_request.link); |
|
| 1994 | 2006 | wl_list_remove(&output_mgr_apply.link); |
|
| 1995 | 2007 | wl_list_remove(&output_mgr_test.link); |
| 2492 | 2504 | LISTEN(&toplevel->events.destroy, &c->destroy, destroy_notify); |
|
| 2493 | 2505 | LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreen_notify); |
|
| 2494 | 2506 | LISTEN(&toplevel->events.request_maximize, &c->maximize, maximize_notify); |
|
| 2495 | 2507 | LISTEN(&toplevel->events.set_title, &c->set_title, update_title); |
|
| 2496 | 2508 | LISTEN(&toplevel->events.set_app_id, &c->set_appid, update_app_id); |
|
| 2509 | + | LISTEN(&toplevel->events.set_parent, &c->set_parent, dialog_changed); |
|
| 2510 | + | } |
|
| 2511 | + | ||
| 2512 | + | /* Track modal state for a newly created XDG dialog. */ |
|
| 2513 | + | void create_dialog(struct wl_listener *listener, void *data) { |
|
| 2514 | + | struct wlr_xdg_dialog_v1 *dialog = data; |
|
| 2515 | + | client_t *c = dialog->xdg_toplevel->base->data; |
|
| 2516 | + | ||
| 2517 | + | if (!c) |
|
| 2518 | + | return; |
|
| 2519 | + | c->dialog = dialog; |
|
| 2520 | + | LISTEN(&dialog->events.set_modal, &c->dialog_modal, dialog_changed); |
|
| 2521 | + | LISTEN(&dialog->events.destroy, &c->dialog_destroy, dialog_destroyed); |
|
| 2522 | + | dialog_changed(&c->dialog_modal, nullptr); |
|
| 2523 | + | } |
|
| 2524 | + | ||
| 2525 | + | /* Re-evaluate focus and pointer targets after dialog relationship changes. */ |
|
| 2526 | + | void dialog_changed(struct wl_listener *listener, void *data) { |
|
| 2527 | + | client_t *focused = nullptr; |
|
| 2528 | + | ||
| 2529 | + | toplevel_from_wlr_surface(seat->keyboard_state.focused_surface, &focused, nullptr); |
|
| 2530 | + | if (focused && client_is_blocked(focused)) |
|
| 2531 | + | focus_client(focus_top(focused->mon), 1); |
|
| 2532 | + | motion_notify(0, nullptr, 0, 0, 0, 0, 1); |
|
| 2533 | + | } |
|
| 2534 | + | ||
| 2535 | + | /* Stop tracking a destroyed dialog and immediately restore parent interaction. */ |
|
| 2536 | + | void dialog_destroyed(struct wl_listener *listener, void *data) { |
|
| 2537 | + | client_t *c = wl_container_of(listener, c, dialog_destroy); |
|
| 2538 | + | ||
| 2539 | + | wl_list_remove(&c->dialog_modal.link); |
|
| 2540 | + | wl_list_remove(&c->dialog_destroy.link); |
|
| 2541 | + | c->dialog = nullptr; |
|
| 2542 | + | dialog_changed(nullptr, nullptr); |
|
| 2497 | 2543 | } |
|
| 2498 | 2544 | ||
| 2499 | 2545 | /* Attach a pointer device and apply its configured input settings. */ |
|
| 2500 | 2546 | void create_pointer(struct wlr_pointer *pointer) { |
|
| 2501 | 2547 | struct libinput_device *device; |
| 2709 | 2755 | } else { |
|
| 2710 | 2756 | wl_list_remove(&c->commit.link); |
|
| 2711 | 2757 | wl_list_remove(&c->map.link); |
|
| 2712 | 2758 | wl_list_remove(&c->unmap.link); |
|
| 2713 | 2759 | wl_list_remove(&c->maximize.link); |
|
| 2760 | + | wl_list_remove(&c->set_parent.link); |
|
| 2761 | + | ||
| 2762 | + | if (c->dialog) { |
|
| 2763 | + | wl_list_remove(&c->dialog_modal.link); |
|
| 2764 | + | wl_list_remove(&c->dialog_destroy.link); |
|
| 2765 | + | c->dialog = nullptr; |
|
| 2766 | + | } |
|
| 2714 | 2767 | ||
| 2715 | 2768 | if (c->decoration) { |
|
| 2716 | 2769 | wl_list_remove(&c->destroy_decoration.link); |
|
| 2717 | 2770 | wl_list_remove(&c->set_decoration_mode.link); |
|
| 2718 | 2771 | c->decoration = nullptr; |
| 2805 | 2858 | layer_surface_t *old_l = nullptr; |
|
| 2806 | 2859 | ||
| 2807 | 2860 | if (locked) |
|
| 2808 | 2861 | return; |
|
| 2809 | 2862 | ||
| 2863 | + | if (c && client_is_blocked(c)) |
|
| 2864 | + | c = focus_top(c->mon); |
|
| 2865 | + | ||
| 2810 | 2866 | /* Raise the window when requested. */ |
|
| 2811 | 2867 | if (c && lift) |
|
| 2812 | 2868 | wlr_scene_node_raise_to_top(&c->scene->node); |
|
| 2813 | 2869 | ||
| 2814 | 2870 | if (c && client_surface(c) == old) |
| 2875 | 2931 | while (c && (p = client_get_parent(c)) && p != c) |
|
| 2876 | 2932 | c = p; |
|
| 2877 | 2933 | return c; |
|
| 2878 | 2934 | } |
|
| 2879 | 2935 | ||
| 2936 | + | /* Return whether a mapped modal XDG child blocks this direct parent. */ |
|
| 2937 | + | bool client_is_blocked(client_t *c) { |
|
| 2938 | + | client_t *child; |
|
| 2939 | + | ||
| 2940 | + | if (!c || client_is_x11(c)) |
|
| 2941 | + | return false; |
|
| 2942 | + | ||
| 2943 | + | wl_list_for_each(child, &clients, link) { |
|
| 2944 | + | if (!client_is_x11(child) && child->dialog && child->dialog->modal && |
|
| 2945 | + | client_surface(child)->mapped && |
|
| 2946 | + | child->surface.xdg->toplevel->parent == c->surface.xdg->toplevel) |
|
| 2947 | + | return true; |
|
| 2948 | + | } |
|
| 2949 | + | return false; |
|
| 2950 | + | } |
|
| 2951 | + | ||
| 2880 | 2952 | /* Return whether two clients belong to one group. */ |
|
| 2881 | 2953 | bool clients_related(client_t *a, client_t *b) { |
|
| 2882 | 2954 | return a && b && client_main(a) == client_main(b); |
|
| 2883 | 2955 | } |
|
| 2884 | 2956 |
| 2888 | 2960 | struct wl_list *node; |
|
| 2889 | 2961 | ||
| 2890 | 2962 | if (!c || !c->mon) |
|
| 2891 | 2963 | return nullptr; |
|
| 2892 | 2964 | ||
| 2893 | - | if ((p = client_get_parent(c)) && VISIBLEON(p, c->mon)) |
|
| 2965 | + | if ((p = client_get_parent(c)) && VISIBLEON(p, c->mon) && !client_is_blocked(p)) |
|
| 2894 | 2966 | return p; |
|
| 2895 | 2967 | ||
| 2896 | 2968 | for (node = c->link.prev; node != &c->link; node = node->prev) { |
|
| 2897 | 2969 | if (node == &clients) |
|
| 2898 | 2970 | continue; |
|
| 2899 | 2971 | p = wl_container_of(node, p, link); |
|
| 2900 | 2972 | ||
| 2901 | - | if (VISIBLEON(p, c->mon) && !clients_related(p, c)) |
|
| 2973 | + | if (VISIBLEON(p, c->mon) && !client_is_blocked(p) && !clients_related(p, c)) |
|
| 2902 | 2974 | return p; |
|
| 2903 | 2975 | } |
|
| 2904 | 2976 | return nullptr; |
|
| 2905 | 2977 | } |
|
| 2906 | 2978 |
| 2929 | 3001 | node = arg->i > 0 ? node->next : node->prev) { |
|
| 2930 | 3002 | if (node == &clients) |
|
| 2931 | 3003 | continue; |
|
| 2932 | 3004 | c = wl_container_of(node, c, link); |
|
| 2933 | 3005 | ||
| 2934 | - | if (VISIBLEON(c, selmon) && !client_get_parent(c)) { |
|
| 3006 | + | if (VISIBLEON(c, selmon) && !client_is_blocked(c) && !client_get_parent(c)) { |
|
| 2935 | 3007 | bool fullscreen = sel->is_fullscreen; |
|
| 2936 | 3008 | ||
| 2937 | 3009 | if (fullscreen) |
|
| 2938 | 3010 | set_fullscreen(sel, 0); |
|
| 2939 | 3011 | focus_client(c, 1); |
| 2950 | 3022 | /* focus the main (first tiled) window; if it |
|
| 2951 | 3023 | * already has focus, return focus to the previously focused window. */ |
|
| 2952 | 3024 | client_t *c, *sel = focus_top(selmon); |
|
| 2953 | 3025 | ||
| 2954 | 3026 | wl_list_for_each(c, &clients, link) { |
|
| 2955 | - | if (VISIBLEON(c, selmon) && !c->is_floating) { |
|
| 3027 | + | if (VISIBLEON(c, selmon) && !client_is_blocked(c) && !c->is_floating) { |
|
| 2956 | 3028 | if (c != sel) { |
|
| 2957 | 3029 | focus_client(c, 1); |
|
| 2958 | 3030 | } else { |
|
| 2959 | 3031 | client_t *p; |
|
| 2960 | 3032 | wl_list_for_each(p, &fstack, flink) { |
|
| 2961 | - | if (p != sel && VISIBLEON(p, selmon)) { |
|
| 3033 | + | if (p != sel && VISIBLEON(p, selmon) && !client_is_blocked(p)) { |
|
| 2962 | 3034 | focus_client(p, 1); |
|
| 2963 | 3035 | break; |
|
| 2964 | 3036 | } |
|
| 2965 | 3037 | } |
|
| 2966 | 3038 | } |
| 2987 | 3059 | ||
| 2988 | 3060 | /* Return the most recently focused visible window. */ |
|
| 2989 | 3061 | client_t *focus_top(monitor_t *m) { |
|
| 2990 | 3062 | client_t *c; |
|
| 2991 | 3063 | wl_list_for_each(c, &fstack, flink) { |
|
| 2992 | - | if (VISIBLEON(c, m)) |
|
| 3064 | + | if (VISIBLEON(c, m) && !client_is_blocked(c)) |
|
| 2993 | 3065 | return c; |
|
| 2994 | 3066 | } |
|
| 2995 | 3067 | return nullptr; |
|
| 2996 | 3068 | } |
|
| 2997 | 3069 |
| 5269 | 5341 | ||
| 5270 | 5342 | xdg_shell = wlr_xdg_shell_create(dpy, 6); |
|
| 5271 | 5343 | wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel); |
|
| 5272 | 5344 | wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup); |
|
| 5273 | 5345 | ||
| 5346 | + | xdg_dialog_mgr = wlr_xdg_wm_dialog_v1_create(dpy, 1); |
|
| 5347 | + | wl_signal_add(&xdg_dialog_mgr->events.new_dialog, &new_xdg_dialog); |
|
| 5348 | + | ||
| 5274 | 5349 | layer_shell = wlr_layer_shell_v1_create(dpy, 3); |
|
| 5275 | 5350 | wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface); |
|
| 5276 | 5351 | ||
| 5277 | 5352 | idle_notifier = wlr_idle_notifier_v1_create(dpy); |
|
| 5278 | 5353 |
| 5900 | 5975 | } |
|
| 5901 | 5976 | if (c && c->type == LAYER_SHELL) { |
|
| 5902 | 5977 | c = nullptr; |
|
| 5903 | 5978 | l = pnode->data; |
|
| 5904 | 5979 | } |
|
| 5980 | + | if (c && client_is_blocked(c)) { |
|
| 5981 | + | c = nullptr; |
|
| 5982 | + | surface = nullptr; |
|
| 5983 | + | } |
|
| 5905 | 5984 | } |
|
| 5906 | 5985 | if (psurface) |
|
| 5907 | 5986 | *psurface = surface; |
|
| 5908 | 5987 | if (pc) |
|
| 5909 | 5988 | *pc = c; |