void (*minimize)(struct view *view, bool minimize);
struct view *(*get_root)(struct view *self);
void (*append_children)(struct view *self, struct wl_array *children);
+ bool (*is_modal_dialog)(struct view *self);
struct view_size_hints (*get_size_hints)(struct view *self);
/* if not implemented, VIEW_WANTS_FOCUS_ALWAYS is assumed */
enum view_wants_focus (*wants_focus)(struct view *self);
void view_move_to_back(struct view *view);
struct view *view_get_root(struct view *view);
void view_append_children(struct view *view, struct wl_array *children);
+
+/**
+ * view_get_modal_dialog() - returns any modal dialog found among this
+ * view's children or siblings (or possibly this view itself). Applies
+ * only to xwayland views and always returns NULL for xdg-shell views.
+ */
+struct view *view_get_modal_dialog(struct view *view);
+
bool view_on_output(struct view *view, struct output *output);
/**
}
}
+static void
+set_or_offer_focus(struct view *view)
+{
+ struct seat *seat = &view->server->seat;
+ switch (view_wants_focus(view)) {
+ case VIEW_WANTS_FOCUS_ALWAYS:
+ if (view->surface != seat->seat->keyboard_state.focused_surface) {
+ seat_focus_surface(seat, view->surface);
+ }
+ break;
+ case VIEW_WANTS_FOCUS_LIKELY:
+ case VIEW_WANTS_FOCUS_UNLIKELY:
+ view_offer_focus(view);
+ break;
+ case VIEW_WANTS_FOCUS_NEVER:
+ break;
+ }
+}
+
void
desktop_focus_view(struct view *view, bool raise)
{
workspaces_switch_to(view->workspace, /*update_focus*/ false);
}
- struct seat *seat = &view->server->seat;
- switch (view_wants_focus(view)) {
- case VIEW_WANTS_FOCUS_ALWAYS:
- if (view->surface != seat->seat->keyboard_state.focused_surface) {
- seat_focus_surface(seat, view->surface);
- }
- break;
- case VIEW_WANTS_FOCUS_LIKELY:
- case VIEW_WANTS_FOCUS_UNLIKELY:
- view_offer_focus(view);
- break;
- case VIEW_WANTS_FOCUS_NEVER:
- break;
- }
-
if (raise) {
view_move_to_front(view);
}
+
+ /*
+ * If any child/sibling of the view is a modal dialog, focus
+ * the dialog instead. It does not need to be raised separately
+ * since view_move_to_front() raises all sibling views together.
+ */
+ struct view *dialog = view_get_modal_dialog(view);
+ set_or_offer_focus(dialog ? dialog : view);
}
/* TODO: focus layer-shell surfaces also? */
}
}
+struct view *
+view_get_modal_dialog(struct view *view)
+{
+ assert(view);
+ if (!view->impl->is_modal_dialog) {
+ return NULL;
+ }
+ /* check view itself first */
+ if (view->impl->is_modal_dialog(view)) {
+ return view;
+ }
+
+ /* check sibling views */
+ struct view *dialog = NULL;
+ struct view *root = view_get_root(view);
+ struct wl_array children;
+ struct view **child;
+
+ wl_array_init(&children);
+ view_append_children(root, &children);
+ wl_array_for_each(child, &children) {
+ if (view->impl->is_modal_dialog(*child)) {
+ dialog = *child;
+ break;
+ }
+ }
+ wl_array_release(&children);
+ return dialog;
+}
+
bool
view_has_strut_partial(struct view *view)
{
}
}
+static bool
+xwayland_view_is_modal_dialog(struct view *self)
+{
+ return xwayland_surface_from_view(self)->modal;
+}
+
static void
xwayland_view_set_activated(struct view *view, bool activated)
{
.minimize = xwayland_view_minimize,
.get_root = xwayland_view_get_root,
.append_children = xwayland_view_append_children,
+ .is_modal_dialog = xwayland_view_is_modal_dialog,
.get_size_hints = xwayland_view_get_size_hints,
.wants_focus = xwayland_view_wants_focus,
.offer_focus = xwayland_view_offer_focus,