/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef LABWC_VIEW_H #define LABWC_VIEW_H #include #include #include #include #include #include "common/edge.h" #include "config.h" #include "config/types.h" /* * Default minimal window size. Clients can explicitly set smaller values via * e.g. xdg_toplevel::set_min_size. */ #define LAB_MIN_VIEW_WIDTH 100 #define LAB_MIN_VIEW_HEIGHT 60 /* * Fallback view geometry used in some cases where a better position * and/or size can't be determined. Try to avoid using these except as * a last resort. */ #define VIEW_FALLBACK_X 100 #define VIEW_FALLBACK_Y 100 #define VIEW_FALLBACK_WIDTH 640 #define VIEW_FALLBACK_HEIGHT 480 /* * In labwc, a view is a container for surfaces which can be moved around by * the user. In practice this means XDG toplevel and XWayland windows. */ enum view_type { LAB_XDG_SHELL_VIEW, #if HAVE_XWAYLAND LAB_XWAYLAND_VIEW, #endif }; enum ssd_preference { LAB_SSD_PREF_UNSPEC = 0, LAB_SSD_PREF_CLIENT, LAB_SSD_PREF_SERVER, }; /** * Directions in which a view can be maximized. "None" is used * internally to mean "not maximized" but is not valid in rc.xml. * Therefore when parsing rc.xml, "None" means "Invalid". */ enum view_axis { VIEW_AXIS_NONE = 0, VIEW_AXIS_HORIZONTAL = (1 << 0), VIEW_AXIS_VERTICAL = (1 << 1), VIEW_AXIS_BOTH = (VIEW_AXIS_HORIZONTAL | VIEW_AXIS_VERTICAL), /* * If view_axis is treated as a bitfield, INVALID should never * set the HORIZONTAL or VERTICAL bits. */ VIEW_AXIS_INVALID = (1 << 2), }; enum view_wants_focus { /* View does not want focus */ VIEW_WANTS_FOCUS_NEVER = 0, /* View wants focus */ VIEW_WANTS_FOCUS_ALWAYS, /* * The following values apply only to XWayland views using the * Globally Active input model per the ICCCM. These views are * offered focus and will voluntarily accept or decline it. * * In some cases, labwc needs to decide in advance whether to * focus the view. For this purpose, these views are classified * (by a heuristic) as likely or unlikely to want focus. However, * it is still ultimately up to the client whether the view gets * focus or not. */ VIEW_WANTS_FOCUS_LIKELY, VIEW_WANTS_FOCUS_UNLIKELY, }; struct view; struct wlr_surface; struct foreign_toplevel; /* Common to struct view and struct xwayland_unmanaged */ struct mappable { bool connected; struct wl_listener map; struct wl_listener unmap; }; /* Basic size hints (subset of XSizeHints from X11) */ struct view_size_hints { int min_width; int min_height; int width_inc; int height_inc; int base_width; int base_height; }; struct view_impl { void (*configure)(struct view *view, struct wlr_box geo); void (*close)(struct view *view); const char *(*get_string_prop)(struct view *view, const char *prop); void (*map)(struct view *view); void (*set_activated)(struct view *view, bool activated); void (*set_fullscreen)(struct view *view, bool fullscreen); void (*notify_tiled)(struct view *view); /* * client_request is true if the client unmapped its own * surface; false if we are just minimizing the view. The two * cases are similar but have subtle differences (e.g., when * minimizing we don't destroy the foreign toplevel handle). */ void (*unmap)(struct view *view, bool client_request); void (*maximize)(struct view *view, enum view_axis maximized); 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 (*offer_focus)(struct view *self); /* returns true if view reserves space at screen edge */ bool (*has_strut_partial)(struct view *self); /* returns true if view declared itself a window type */ bool (*contains_window_type)(struct view *view, enum lab_window_type window_type); /* returns the client pid that this view belongs to */ pid_t (*get_pid)(struct view *view); }; struct view { struct server *server; enum view_type type; const struct view_impl *impl; struct wl_list link; /* * The primary output that the view is displayed on. Specifically: * * - For floating views, this is the output nearest to the * center of the view. It is computed automatically when the * view is moved or the output layout changes. * * - For fullscreen/maximized/tiled views, this is the output * used to compute the view's geometry. The view remains on * the same output unless it is disabled or disconnected. * * Many view functions (e.g. view_center(), view_fullscreen(), * view_maximize(), etc.) allow specifying a particular output * by calling view_set_output() beforehand. */ struct output *output; /* * The outputs that the view is displayed on. * This is used to notify the foreign toplevel * implementation and to update the SSD invisible * resize area. * It is a bitset of output->scene_output->index. */ uint64_t outputs; struct workspace *workspace; struct wlr_surface *surface; struct wlr_scene_tree *scene_tree; struct wlr_scene_tree *content_tree; bool mapped; bool been_mapped; enum lab_ssd_mode ssd_mode; enum ssd_preference ssd_preference; bool shaded; bool minimized; enum view_axis maximized; bool fullscreen; bool tearing_hint; enum lab_tristate force_tearing; bool visible_on_all_workspaces; enum lab_edge tiled; enum lab_edge edges_visible; bool inhibits_keybinds; /* also inhibits mousebinds */ xkb_layout_index_t keyboard_layout; /* Pointer to an output owned struct region, may be NULL */ struct region *tiled_region; /* Set to region->name when tiled_region is free'd by a destroying output */ char *tiled_region_evacuate; /* * Geometry of the wlr_surface contained within the view, as * currently displayed. Should be kept in sync with the * scene-graph at all times. */ struct wlr_box current; /* * Expected geometry after any pending move/resize requests * have been processed. Should match current geometry when no * move/resize requests are pending. */ struct wlr_box pending; /* * Saved geometry which will be restored when the view returns * to normal/floating state after being maximized/fullscreen/ * tiled. Values are undefined/out-of-date when the view is not * maximized/fullscreen/tiled. */ struct wlr_box natural_geometry; /* * Whenever an output layout change triggers a view relocation, the * last pending position (or natural geometry) will be saved so the * view may be restored to its original location on a subsequent layout * change. */ struct wlr_box last_layout_geometry; /* used by xdg-shell views */ uint32_t pending_configure_serial; struct wl_event_source *pending_configure_timeout; struct ssd *ssd; struct resize_indicator { int width, height; struct wlr_scene_tree *tree; struct wlr_scene_rect *border; struct wlr_scene_rect *background; struct scaled_font_buffer *text; } resize_indicator; struct resize_outlines { struct wlr_box view_geo; struct lab_scene_rect *rect; } resize_outlines; struct mappable mappable; struct wl_listener destroy; struct wl_listener surface_destroy; struct wl_listener commit; struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_minimize; struct wl_listener request_maximize; struct wl_listener request_fullscreen; struct wl_listener set_title; struct foreign_toplevel *foreign_toplevel; /* used by scaled_icon_buffer */ struct { char *name; struct wl_array buffers; /* struct lab_data_buffer * */ } icon; struct { struct wl_signal new_app_id; struct wl_signal new_title; struct wl_signal new_outputs; struct wl_signal maximized; struct wl_signal minimized; struct wl_signal fullscreened; struct wl_signal activated; /* bool *activated */ /* * This is emitted when app_id, or icon set via xdg_toplevel_icon * is updated. This is listened by scaled_icon_buffer. */ struct wl_signal set_icon; struct wl_signal destroy; } events; }; struct view_query { struct wl_list link; char *identifier; char *title; enum lab_window_type window_type; char *sandbox_engine; char *sandbox_app_id; enum lab_tristate shaded; enum view_axis maximized; enum lab_tristate iconified; enum lab_tristate focused; enum lab_tristate omnipresent; enum lab_edge tiled; char *tiled_region; char *desktop; enum lab_ssd_mode decoration; char *monitor; }; struct xdg_toplevel_view { struct view base; struct wlr_xdg_surface *xdg_surface; /* Events unique to xdg-toplevel views */ struct wl_listener set_app_id; struct wl_listener request_show_window_menu; struct wl_listener new_popup; }; /** * view_from_wlr_surface() - returns the view associated with a * wlr_surface, or NULL if the surface has no associated view. */ struct view *view_from_wlr_surface(struct wlr_surface *surface); /** * view_query_create() - Create a new heap allocated view query with * all members initialized to their default values (window_type = -1, * NULL for strings) */ struct view_query *view_query_create(void); /** * view_query_free() - Free a given view query * @query: Query to be freed. */ void view_query_free(struct view_query *view); /** * view_matches_query() - Check if view matches the given criteria * @view: View to checked. * @query: Criteria to match against. * * Returns true if %view matches all of the criteria given in %query, false * otherwise. */ bool view_matches_query(struct view *view, struct view_query *query); /** * for_each_view() - iterate over all views which match criteria * @view: Iterator. * @head: Head of list to iterate over. * @criteria: Criteria to match against. * Example: * struct view *view; * for_each_view(view, &server->views, LAB_VIEW_CRITERIA_NONE) { * printf("%s\n", view_get_string_prop(view, "app_id")); * } */ #define for_each_view(view, head, criteria) \ for (view = view_next(head, NULL, criteria); \ view; \ view = view_next(head, view, criteria)) /** * for_each_view_reverse() - iterate over all views which match criteria * @view: Iterator. * @head: Head of list to iterate over. * @criteria: Criteria to match against. * Example: * struct view *view; * for_each_view_reverse(view, &server->views, LAB_VIEW_CRITERIA_NONE) { * printf("%s\n", view_get_string_prop(view, "app_id")); * } */ #define for_each_view_reverse(view, head, criteria) \ for (view = view_prev(head, NULL, criteria); \ view; \ view = view_prev(head, view, criteria)) /** * view_next() - Get next view which matches criteria. * @head: Head of list to iterate over. * @view: Current view from which to find the next one. If NULL is provided as * the view argument, the start of the list will be used. * @criteria: Criteria to match against. * * Returns NULL if there are no views matching the criteria. */ struct view *view_next(struct wl_list *head, struct view *view, enum lab_view_criteria criteria); /** * view_prev() - Get previous view which matches criteria. * @head: Head of list to iterate over. * @view: Current view from which to find the previous one. If NULL is provided * as the view argument, the end of the list will be used. * @criteria: Criteria to match against. * * Returns NULL if there are no views matching the criteria. */ struct view *view_prev(struct wl_list *head, struct view *view, enum lab_view_criteria criteria); /* * Same as `view_next()` except that they iterate one whole cycle rather than * stopping at the list-head */ struct view *view_next_no_head_stop(struct wl_list *head, struct view *from, enum lab_view_criteria criteria); struct view *view_prev_no_head_stop(struct wl_list *head, struct view *from, enum lab_view_criteria criteria); /** * view_array_append() - Append views that match criteria to array * @server: server context * @views: arrays to append to * @criteria: criteria to match against * * This function is useful in cases where the calling function may change the * stacking order or where it needs to iterate over the views multiple times, * for example to get the number of views before processing them. * * Note: This array has a very short shelf-life so it is intended to be used * with a single-use-throw-away approach. * * Example usage: * struct view **view; * struct wl_array views; * wl_array_init(&views); * view_array_append(server, &views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE); * wl_array_for_each(view, &views) { * // Do something with *view * } * wl_array_release(&views); */ void view_array_append(struct server *server, struct wl_array *views, enum lab_view_criteria criteria); enum view_wants_focus view_wants_focus(struct view *view); bool view_contains_window_type(struct view *view, enum lab_window_type window_type); /* If view is NULL, the size of SSD is not considered */ struct wlr_box view_get_edge_snap_box(struct view *view, struct output *output, enum lab_edge edge); struct wlr_box view_get_region_snap_box(struct view *view, struct region *region); /** * view_is_focusable() - Check whether or not a view can be focused * @view: view to be checked * * The purpose of this test is to filter out views (generally Xwayland) which * are not meant to be focused such as those with surfaces * a. that have been created but never mapped; * b. set to NULL after client minimize-request. * * The only views that are allowed to be focused are those that have a surface * and have been mapped at some point since creation. */ bool view_is_focusable(struct view *view); /* * For use by desktop_focus_view() only - please do not call directly. * See the description of VIEW_WANTS_FOCUS_OFFER for more information. */ void view_offer_focus(struct view *view); struct wlr_box view_get_edge_snap_box(struct view *view, struct output *output, enum lab_edge edge); void mappable_connect(struct mappable *mappable, struct wlr_surface *surface, wl_notify_func_t notify_map, wl_notify_func_t notify_unmap); void mappable_disconnect(struct mappable *mappable); void view_toggle_keybinds(struct view *view); bool view_inhibits_actions(struct view *view, struct wl_list *actions); void view_set_activated(struct view *view, bool activated); void view_set_output(struct view *view, struct output *output); void view_close(struct view *view); /** * view_move_resize - resize and move view * @view: view to be resized and moved * @geo: the new geometry * NOTE: Only use this when the view actually changes width and/or height * otherwise the serials might cause a delay in moving xdg-shell clients. * For move only, use view_move() */ void view_move_resize(struct view *view, struct wlr_box geo); void view_resize_relative(struct view *view, int left, int right, int top, int bottom); void view_move_relative(struct view *view, int x, int y); void view_move(struct view *view, int x, int y); void view_move_to_cursor(struct view *view); void view_moved(struct view *view); void view_minimize(struct view *view, bool minimized); bool view_compute_centered_position(struct view *view, const struct wlr_box *ref, int w, int h, int *x, int *y); struct wlr_box view_get_fallback_natural_geometry(struct view *view); void view_store_natural_geometry(struct view *view); /** * view_apply_natural_geometry - adjust view->natural_geometry if it doesn't * intersect with view->output and then apply it */ void view_apply_natural_geometry(struct view *view); /** * view_effective_height - effective height of view, with respect to shaded state * @view: view for which effective height is desired * @use_pending: if false, report current height; otherwise, report pending height */ int view_effective_height(struct view *view, bool use_pending); /** * view_center - center view within some region * @view: view to be centered * @ref: optional reference region (in layout coordinates) to center * within; if NULL, view is centered within usable area of its output */ void view_center(struct view *view, const struct wlr_box *ref); /** * view_place_by_policy - apply placement strategy to view * @view: view to be placed * @allow_cursor: set to false to ignore center-on-cursor policy * @policy: placement policy to apply */ void view_place_by_policy(struct view *view, bool allow_cursor, enum lab_placement_policy policy); void view_constrain_size_to_that_of_usable_area(struct view *view); void view_set_maximized(struct view *view, enum view_axis maximized); void view_set_untiled(struct view *view); void view_maximize(struct view *view, enum view_axis axis, bool store_natural_geometry); void view_set_fullscreen(struct view *view, bool fullscreen); void view_toggle_maximize(struct view *view, enum view_axis axis); bool view_wants_decorations(struct view *view); void view_toggle_decorations(struct view *view); bool view_is_always_on_top(struct view *view); bool view_is_always_on_bottom(struct view *view); bool view_is_omnipresent(struct view *view); void view_toggle_always_on_top(struct view *view); void view_toggle_always_on_bottom(struct view *view); void view_toggle_visible_on_all_workspaces(struct view *view); bool view_is_tiled(struct view *view); bool view_is_tiled_and_notify_tiled(struct view *view); bool view_is_floating(struct view *view); void view_move_to_workspace(struct view *view, struct workspace *workspace); bool view_titlebar_visible(struct view *view); void view_set_ssd_mode(struct view *view, enum lab_ssd_mode mode); void view_set_decorations(struct view *view, enum lab_ssd_mode mode, bool force_ssd); void view_toggle_fullscreen(struct view *view); void view_invalidate_last_layout_geometry(struct view *view); void view_adjust_for_layout_change(struct view *view); void view_move_to_edge(struct view *view, enum lab_edge direction, bool snap_to_windows); void view_grow_to_edge(struct view *view, enum lab_edge direction); void view_shrink_to_edge(struct view *view, enum lab_edge direction); void view_snap_to_edge(struct view *view, enum lab_edge direction, bool across_outputs, bool combine, bool store_natural_geometry); void view_snap_to_region(struct view *view, struct region *region, bool store_natural_geometry); void view_move_to_output(struct view *view, struct output *output); void view_move_to_front(struct view *view); 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); /** * view_has_strut_partial() - returns true for views that reserve space * at a screen edge (e.g. panels). These views are treated as if they * have the fixedPosition window rule: i.e. they are not restricted to * the usable area and cannot be moved/resized interactively. */ bool view_has_strut_partial(struct view *view); const char *view_get_string_prop(struct view *view, const char *prop); void view_update_title(struct view *view); void view_update_app_id(struct view *view); void view_reload_ssd(struct view *view); void view_set_shade(struct view *view, bool shaded); /* Icon buffers set with this function are dropped later */ void view_set_icon(struct view *view, const char *icon_name, struct wl_array *buffers); struct view_size_hints view_get_size_hints(struct view *view); void view_adjust_size(struct view *view, int *w, int *h); void view_evacuate_region(struct view *view); void view_on_output_destroy(struct view *view); void view_connect_map(struct view *view, struct wlr_surface *surface); void view_init(struct view *view); void view_destroy(struct view *view); enum view_axis view_axis_parse(const char *direction); enum lab_placement_policy view_placement_parse(const char *policy); /* xdg.c */ struct wlr_xdg_surface *xdg_surface_from_view(struct view *view); #endif /* LABWC_VIEW_H */