Add xdg-dialog-v1 support

488f4e61ef58be1d7ff9dbab49dcdb5e1b6d79da
Alexis Sellier committed ago 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;