mirror of
https://github.com/swaywm/sway.git
synced 2024-11-28 02:41:28 +00:00
Merge branch 'master' of github.com:swaywm/sway into feature/swap-workspace
This commit is contained in:
commit
1b4d5ba2f2
|
@ -31,7 +31,7 @@ Install dependencies:
|
|||
* json-c
|
||||
* pango
|
||||
* cairo
|
||||
* gdk-pixbuf2 (optional: system tray)
|
||||
* gdk-pixbuf2 (optional: additional image formats for system tray)
|
||||
* [swaybg] (optional: wallpaper)
|
||||
* [scdoc] (optional: man pages) \*
|
||||
* git (optional: version info) \*
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#include <wlr/types/wlr_compositor.h>
|
||||
|
||||
struct sway_container;
|
||||
struct sway_view;
|
||||
|
||||
void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
|
||||
bool whole);
|
||||
|
||||
void desktop_damage_whole_container(struct sway_container *con);
|
||||
|
||||
void desktop_damage_box(struct wlr_box *box);
|
||||
|
||||
void desktop_damage_view(struct sway_view *view);
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _SWAY_TRANSACTION_H
|
||||
#define _SWAY_TRANSACTION_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Transactions enable us to perform atomic layout updates.
|
||||
|
@ -38,8 +39,11 @@ void transaction_commit_dirty_client(void);
|
|||
* Notify the transaction system that a view is ready for the new layout.
|
||||
*
|
||||
* When all views in the transaction are ready, the layout will be applied.
|
||||
*
|
||||
* A success boolean is returned denoting that this part of the transaction is
|
||||
* ready.
|
||||
*/
|
||||
void transaction_notify_view_ready_by_serial(struct sway_view *view,
|
||||
bool transaction_notify_view_ready_by_serial(struct sway_view *view,
|
||||
uint32_t serial);
|
||||
|
||||
/**
|
||||
|
@ -47,8 +51,11 @@ void transaction_notify_view_ready_by_serial(struct sway_view *view,
|
|||
* identifying the instruction by geometry rather than by serial.
|
||||
*
|
||||
* This is used by xwayland views, as they don't have serials.
|
||||
*
|
||||
* A success boolean is returned denoting that this part of the transaction is
|
||||
* ready.
|
||||
*/
|
||||
void transaction_notify_view_ready_by_geometry(struct sway_view *view,
|
||||
bool transaction_notify_view_ready_by_geometry(struct sway_view *view,
|
||||
double x, double y, int width, int height);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/util/edges.h>
|
||||
|
@ -12,7 +13,6 @@
|
|||
#include "sway/input/text_input.h"
|
||||
|
||||
struct sway_seat;
|
||||
struct render_context;
|
||||
|
||||
struct sway_seatop_impl {
|
||||
void (*button)(struct sway_seat *seat, uint32_t time_msec,
|
||||
|
@ -52,7 +52,6 @@ struct sway_seatop_impl {
|
|||
uint32_t time_msec, enum wlr_tablet_tool_tip_state state);
|
||||
void (*end)(struct sway_seat *seat);
|
||||
void (*unref)(struct sway_seat *seat, struct sway_container *con);
|
||||
void (*render)(struct sway_seat *seat, struct render_context *ctx);
|
||||
bool allow_set_cursor;
|
||||
};
|
||||
|
||||
|
@ -75,20 +74,6 @@ struct sway_seat_node {
|
|||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct sway_drag_icon {
|
||||
struct sway_seat *seat;
|
||||
struct wlr_drag_icon *wlr_drag_icon;
|
||||
struct wl_list link; // sway_root::drag_icons
|
||||
|
||||
double x, y; // in layout-local coordinates
|
||||
int dx, dy; // offset in surface-local coordinates
|
||||
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct sway_drag {
|
||||
struct sway_seat *seat;
|
||||
struct wlr_drag *wlr_drag;
|
||||
|
@ -99,6 +84,15 @@ struct sway_seat {
|
|||
struct wlr_seat *wlr_seat;
|
||||
struct sway_cursor *cursor;
|
||||
|
||||
// Seat scene tree structure
|
||||
// - scene_tree
|
||||
// - drag icons
|
||||
// - drag icon 1
|
||||
// - drag icon 2
|
||||
// - seatop specific stuff
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
struct wlr_scene_tree *drag_icons;
|
||||
|
||||
bool has_focus;
|
||||
struct wl_list focus_stack; // list of containers in focus order
|
||||
struct sway_workspace *workspace;
|
||||
|
@ -257,7 +251,7 @@ void seat_idle_notify_activity(struct sway_seat *seat,
|
|||
|
||||
bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
|
||||
|
||||
void drag_icon_update_position(struct sway_drag_icon *icon);
|
||||
void drag_icons_update_position(struct sway_seat *seat);
|
||||
|
||||
enum wlr_edges find_resize_edge(struct sway_container *cont,
|
||||
struct wlr_surface *surface, struct sway_cursor *cursor);
|
||||
|
@ -357,12 +351,6 @@ void seatop_end(struct sway_seat *seat);
|
|||
*/
|
||||
void seatop_unref(struct sway_seat *seat, struct sway_container *con);
|
||||
|
||||
/**
|
||||
* Instructs a seatop to render anything that it needs to render
|
||||
* (eg. dropzone for move-tiling)
|
||||
*/
|
||||
void seatop_render(struct sway_seat *seat, struct render_context *ctx);
|
||||
|
||||
bool seatop_allows_set_cursor(struct sway_seat *seat);
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,53 +4,30 @@
|
|||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
|
||||
enum layer_parent {
|
||||
LAYER_PARENT_LAYER,
|
||||
LAYER_PARENT_POPUP,
|
||||
};
|
||||
|
||||
struct sway_layer_surface {
|
||||
struct wlr_layer_surface_v1 *layer_surface;
|
||||
struct wl_list link;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener output_destroy;
|
||||
struct wl_listener node_destroy;
|
||||
struct wl_listener new_popup;
|
||||
struct wl_listener new_subsurface;
|
||||
|
||||
struct wlr_box geo;
|
||||
bool mapped;
|
||||
struct wlr_box extent;
|
||||
enum zwlr_layer_shell_v1_layer layer;
|
||||
|
||||
struct wl_list subsurfaces;
|
||||
struct sway_output *output;
|
||||
struct wlr_scene_layer_surface_v1 *scene;
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wlr_scene_tree *popups;
|
||||
struct wlr_layer_surface_v1 *layer_surface;
|
||||
};
|
||||
|
||||
struct sway_layer_popup {
|
||||
struct wlr_xdg_popup *wlr_popup;
|
||||
enum layer_parent parent_type;
|
||||
union {
|
||||
struct sway_layer_surface *parent_layer;
|
||||
struct sway_layer_popup *parent_popup;
|
||||
};
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wlr_scene_tree *scene;
|
||||
struct sway_layer_surface *toplevel;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener new_popup;
|
||||
};
|
||||
|
||||
struct sway_layer_subsurface {
|
||||
struct wlr_subsurface *wlr_subsurface;
|
||||
struct sway_layer_surface *layer_surface;
|
||||
struct wl_list link;
|
||||
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
};
|
||||
|
||||
|
@ -61,7 +38,4 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
|||
|
||||
void arrange_layers(struct sway_output *output);
|
||||
|
||||
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
||||
struct wlr_layer_surface_v1 *layer_surface);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "config.h"
|
||||
#include "sway/tree/node.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
@ -19,16 +20,31 @@ struct sway_output_state {
|
|||
|
||||
struct sway_output {
|
||||
struct sway_node node;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *shell_background;
|
||||
struct wlr_scene_tree *shell_bottom;
|
||||
struct wlr_scene_tree *tiling;
|
||||
struct wlr_scene_tree *fullscreen;
|
||||
struct wlr_scene_tree *shell_top;
|
||||
struct wlr_scene_tree *shell_overlay;
|
||||
struct wlr_scene_tree *session_lock;
|
||||
} layers;
|
||||
|
||||
// when a container is fullscreen, in case the fullscreen surface is
|
||||
// translucent (can see behind) we must make sure that the background is a
|
||||
// solid color in order to conform to the wayland protocol. This rect
|
||||
// ensures that when looking through a surface, all that will be seen
|
||||
// is black.
|
||||
struct wlr_scene_rect *fullscreen_background;
|
||||
|
||||
struct wlr_output *wlr_output;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct sway_server *server;
|
||||
struct wl_list link;
|
||||
|
||||
struct wl_list layers[4]; // sway_layer_surface::link
|
||||
struct wlr_box usable_area;
|
||||
|
||||
struct timespec last_frame;
|
||||
struct wlr_damage_ring damage_ring;
|
||||
|
||||
int lx, ly; // layout coords
|
||||
int width, height; // transformed buffer size
|
||||
enum wl_output_subpixel detected_subpixel;
|
||||
|
@ -43,9 +59,7 @@ struct sway_output {
|
|||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener present;
|
||||
struct wl_listener damage;
|
||||
struct wl_listener frame;
|
||||
struct wl_listener needs_frame;
|
||||
struct wl_listener request_state;
|
||||
|
||||
struct {
|
||||
|
@ -65,14 +79,6 @@ struct sway_output_non_desktop {
|
|||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct render_context {
|
||||
struct sway_output *output;
|
||||
struct wlr_renderer *renderer;
|
||||
const pixman_region32_t *output_damage;
|
||||
|
||||
struct wlr_render_pass *pass;
|
||||
};
|
||||
|
||||
struct sway_output *output_create(struct wlr_output *wlr_output);
|
||||
|
||||
void output_destroy(struct sway_output *output);
|
||||
|
@ -91,19 +97,6 @@ typedef void (*sway_surface_iterator_func_t)(struct sway_output *output,
|
|||
struct sway_view *view, struct wlr_surface *surface, struct wlr_box *box,
|
||||
void *user_data);
|
||||
|
||||
void output_damage_whole(struct sway_output *output);
|
||||
|
||||
void output_damage_surface(struct sway_output *output, double ox, double oy,
|
||||
struct wlr_surface *surface, bool whole);
|
||||
|
||||
void output_damage_from_view(struct sway_output *output,
|
||||
struct sway_view *view);
|
||||
|
||||
void output_damage_box(struct sway_output *output, struct wlr_box *box);
|
||||
|
||||
void output_damage_whole_container(struct sway_output *output,
|
||||
struct sway_container *con);
|
||||
|
||||
bool output_match_name_or_id(struct sway_output *output,
|
||||
const char *name_or_id);
|
||||
|
||||
|
@ -119,46 +112,8 @@ void output_enable(struct sway_output *output);
|
|||
|
||||
void output_disable(struct sway_output *output);
|
||||
|
||||
bool output_has_opaque_overlay_layer_surface(struct sway_output *output);
|
||||
|
||||
struct sway_workspace *output_get_active_workspace(struct sway_output *output);
|
||||
|
||||
void output_render(struct render_context *ctx);
|
||||
|
||||
void output_surface_for_each_surface(struct sway_output *output,
|
||||
struct wlr_surface *surface, double ox, double oy,
|
||||
sway_surface_iterator_func_t iterator, void *user_data);
|
||||
|
||||
void output_view_for_each_surface(struct sway_output *output,
|
||||
struct sway_view *view, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
|
||||
void output_view_for_each_popup_surface(struct sway_output *output,
|
||||
struct sway_view *view, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
|
||||
void output_layer_for_each_surface(struct sway_output *output,
|
||||
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
|
||||
void output_layer_for_each_toplevel_surface(struct sway_output *output,
|
||||
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
|
||||
void output_layer_for_each_popup_surface(struct sway_output *output,
|
||||
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
void output_unmanaged_for_each_surface(struct sway_output *output,
|
||||
struct wl_list *unmanaged, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
#endif
|
||||
|
||||
void output_drag_icons_for_each_surface(struct sway_output *output,
|
||||
struct wl_list *drag_icons, sway_surface_iterator_func_t iterator,
|
||||
void *user_data);
|
||||
|
||||
void output_for_each_workspace(struct sway_output *output,
|
||||
void (*f)(struct sway_workspace *ws, void *data), void *data);
|
||||
|
||||
|
@ -176,13 +131,6 @@ void output_get_box(struct sway_output *output, struct wlr_box *box);
|
|||
enum sway_container_layout output_get_default_layout(
|
||||
struct sway_output *output);
|
||||
|
||||
void render_rect(struct render_context *ctx, const struct wlr_box *_box,
|
||||
float color[static 4]);
|
||||
|
||||
void premultiply_alpha(float color[4], float opacity);
|
||||
|
||||
void scale_box(struct wlr_box *box, float scale);
|
||||
|
||||
enum wlr_direction opposite_direction(enum wlr_direction d);
|
||||
|
||||
void handle_output_layout_change(struct wl_listener *listener, void *data);
|
||||
|
|
33
include/sway/scene_descriptor.h
Normal file
33
include/sway/scene_descriptor.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Across a wayland compositor, there are multiple shells: It can be
|
||||
* a toplevel, or a layer_shell, or even something more meta like a drag
|
||||
* icon or highlight indicators when dragging windows around.
|
||||
*
|
||||
* This object lets us store values that represent these modes of operation
|
||||
* and keep track of what object is being represented.
|
||||
*/
|
||||
#ifndef _SWAY_SCENE_DESCRIPTOR_H
|
||||
#define _SWAY_SCENE_DESCRIPTOR_H
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
enum sway_scene_descriptor_type {
|
||||
SWAY_SCENE_DESC_BUFFER_TIMER,
|
||||
SWAY_SCENE_DESC_NON_INTERACTIVE,
|
||||
SWAY_SCENE_DESC_CONTAINER,
|
||||
SWAY_SCENE_DESC_VIEW,
|
||||
SWAY_SCENE_DESC_LAYER_SHELL,
|
||||
SWAY_SCENE_DESC_XWAYLAND_UNMANAGED,
|
||||
SWAY_SCENE_DESC_POPUP,
|
||||
SWAY_SCENE_DESC_DRAG_ICON,
|
||||
};
|
||||
|
||||
bool scene_descriptor_assign(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type, void *data);
|
||||
|
||||
void *scene_descriptor_try_get(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type);
|
||||
|
||||
void scene_descriptor_destroy(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type);
|
||||
|
||||
#endif
|
|
@ -28,6 +28,19 @@
|
|||
|
||||
struct sway_transaction;
|
||||
|
||||
struct sway_session_lock {
|
||||
struct wlr_session_lock_v1 *lock;
|
||||
struct wlr_surface *focused;
|
||||
bool abandoned;
|
||||
|
||||
struct wl_list outputs; // struct sway_session_lock_output
|
||||
|
||||
// invalid if the session is abandoned
|
||||
struct wl_listener new_surface;
|
||||
struct wl_listener unlock;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct sway_server {
|
||||
struct wl_display *wl_display;
|
||||
struct wl_event_loop *wl_event_loop;
|
||||
|
@ -41,7 +54,6 @@ struct sway_server {
|
|||
struct wlr_allocator *allocator;
|
||||
|
||||
struct wlr_compositor *compositor;
|
||||
struct wl_listener compositor_new_surface;
|
||||
|
||||
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
|
||||
|
||||
|
@ -93,15 +105,9 @@ struct sway_server {
|
|||
struct wl_listener gamma_control_set_gamma;
|
||||
|
||||
struct {
|
||||
bool locked;
|
||||
struct sway_session_lock *lock;
|
||||
struct wlr_session_lock_manager_v1 *manager;
|
||||
|
||||
struct wlr_session_lock_v1 *lock;
|
||||
struct wlr_surface *focused;
|
||||
struct wl_listener lock_new_surface;
|
||||
struct wl_listener lock_unlock;
|
||||
struct wl_listener lock_destroy;
|
||||
|
||||
struct wl_listener new_lock;
|
||||
struct wl_listener manager_destroy;
|
||||
} session_lock;
|
||||
|
@ -150,13 +156,7 @@ struct sway_debug {
|
|||
bool noatomic; // Ignore atomic layout updates
|
||||
bool txn_timings; // Log verbose messages about transactions
|
||||
bool txn_wait; // Always wait for the timeout before applying
|
||||
bool noscanout; // Disable direct scan-out
|
||||
|
||||
enum {
|
||||
DAMAGE_DEFAULT, // Default behaviour
|
||||
DAMAGE_HIGHLIGHT, // Highlight regions of the screen being damaged
|
||||
DAMAGE_RERENDER, // Render the full output when any damage occurs
|
||||
} damage;
|
||||
bool legacy_wl_drm; // Enable the legacy wl_drm interface
|
||||
};
|
||||
|
||||
extern struct sway_debug debug;
|
||||
|
@ -170,12 +170,15 @@ void server_run(struct sway_server *server);
|
|||
|
||||
void restore_nofile_limit(void);
|
||||
|
||||
void handle_compositor_new_surface(struct wl_listener *listener, void *data);
|
||||
void handle_new_output(struct wl_listener *listener, void *data);
|
||||
|
||||
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
|
||||
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
|
||||
void sway_session_lock_init(void);
|
||||
void sway_session_lock_add_output(struct sway_session_lock *lock,
|
||||
struct sway_output *output);
|
||||
bool sway_session_lock_has_surface(struct sway_session_lock *lock,
|
||||
struct wlr_surface *surface);
|
||||
void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data);
|
||||
#if HAVE_XWAYLAND
|
||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef _SWAY_SURFACE_H
|
||||
#define _SWAY_SURFACE_H
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
|
||||
struct sway_surface {
|
||||
struct wlr_surface *wlr_surface;
|
||||
|
||||
struct wl_listener destroy;
|
||||
|
||||
/**
|
||||
* This timer can be used for issuing delayed frame done callbacks (for
|
||||
* example, to improve presentation latency). Its handler is set to a
|
||||
* function that issues a frame done callback to this surface.
|
||||
*/
|
||||
struct wl_event_source *frame_done_timer;
|
||||
};
|
||||
|
||||
void surface_update_outputs(struct wlr_surface *surface);
|
||||
void surface_enter_output(struct wlr_surface *surface,
|
||||
struct sway_output *output);
|
||||
void surface_leave_output(struct wlr_surface *surface,
|
||||
struct sway_output *output);
|
||||
|
||||
#endif
|
28
include/sway/sway_text_node.h
Normal file
28
include/sway/sway_text_node.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef _SWAY_BUFFER_H
|
||||
#define _SWAY_BUFFER_H
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct sway_text_node {
|
||||
int width;
|
||||
int max_width;
|
||||
int height;
|
||||
int baseline;
|
||||
bool pango_markup;
|
||||
float color[4];
|
||||
float background[4];
|
||||
|
||||
struct wlr_scene_node *node;
|
||||
};
|
||||
|
||||
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
|
||||
char *text, float color[4], bool pango_markup);
|
||||
|
||||
void sway_text_node_set_color(struct sway_text_node *node, float color[4]);
|
||||
|
||||
void sway_text_node_set_text(struct sway_text_node *node, char *text);
|
||||
|
||||
void sway_text_node_set_max_width(struct sway_text_node *node, int max_width);
|
||||
|
||||
void sway_text_node_set_background(struct sway_text_node *node, float background[4]);
|
||||
|
||||
#endif
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "list.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
||||
|
@ -68,11 +69,39 @@ struct sway_container {
|
|||
struct sway_node node;
|
||||
struct sway_view *view;
|
||||
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tree;
|
||||
|
||||
struct wlr_scene_tree *border;
|
||||
struct wlr_scene_tree *background;
|
||||
|
||||
struct sway_text_node *title_text;
|
||||
struct sway_text_node *marks_text;
|
||||
} title_bar;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tree;
|
||||
|
||||
struct wlr_scene_rect *top;
|
||||
struct wlr_scene_rect *bottom;
|
||||
struct wlr_scene_rect *left;
|
||||
struct wlr_scene_rect *right;
|
||||
} border;
|
||||
|
||||
struct wlr_scene_tree *content_tree;
|
||||
struct wlr_scene_buffer *output_handler;
|
||||
|
||||
struct wl_listener output_enter;
|
||||
struct wl_listener output_leave;
|
||||
|
||||
struct sway_container_state current;
|
||||
struct sway_container_state pending;
|
||||
|
||||
char *title; // The view's title (unformatted)
|
||||
char *formatted_title; // The title displayed in the title bar
|
||||
int title_width;
|
||||
|
||||
enum sway_container_layout prev_split_layout;
|
||||
|
||||
|
@ -100,14 +129,6 @@ struct sway_container {
|
|||
double child_total_width;
|
||||
double child_total_height;
|
||||
|
||||
// In most cases this is the same as the content x and y, but if the view
|
||||
// refuses to resize to the content dimensions then it can be smaller.
|
||||
// These are in layout coordinates.
|
||||
double surface_x, surface_y;
|
||||
|
||||
// Outputs currently being intersected
|
||||
list_t *outputs; // struct sway_output
|
||||
|
||||
// Indicates that the container is a scratchpad container.
|
||||
// Both hidden and visible scratchpad containers have scratchpad=true.
|
||||
// Hidden scratchpad containers have a NULL parent.
|
||||
|
@ -120,18 +141,7 @@ struct sway_container {
|
|||
|
||||
float alpha;
|
||||
|
||||
struct wlr_texture *title_focused;
|
||||
struct wlr_texture *title_focused_inactive;
|
||||
struct wlr_texture *title_focused_tab_title;
|
||||
struct wlr_texture *title_unfocused;
|
||||
struct wlr_texture *title_urgent;
|
||||
|
||||
list_t *marks; // char *
|
||||
struct wlr_texture *marks_focused;
|
||||
struct wlr_texture *marks_focused_inactive;
|
||||
struct wlr_texture *marks_focused_tab_title;
|
||||
struct wlr_texture *marks_unfocused;
|
||||
struct wlr_texture *marks_urgent;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
|
@ -151,19 +161,6 @@ void container_begin_destroy(struct sway_container *con);
|
|||
struct sway_container *container_find_child(struct sway_container *container,
|
||||
bool (*test)(struct sway_container *view, void *data), void *data);
|
||||
|
||||
/**
|
||||
* Find a container at the given coordinates. Returns the surface and
|
||||
* surface-local coordinates of the given layout coordinates if the container
|
||||
* is a view and the view contains a surface at those coordinates.
|
||||
*/
|
||||
struct sway_container *container_at(struct sway_workspace *workspace,
|
||||
double lx, double ly, struct wlr_surface **surface,
|
||||
double *sx, double *sy);
|
||||
|
||||
struct sway_container *tiling_container_at(
|
||||
struct sway_node *parent, double lx, double ly,
|
||||
struct wlr_surface **surface, double *sx, double *sy);
|
||||
|
||||
struct sway_container *container_get_first_view(struct sway_container *container);
|
||||
|
||||
void container_for_each_child(struct sway_container *container,
|
||||
|
@ -182,13 +179,13 @@ bool container_has_ancestor(struct sway_container *container,
|
|||
|
||||
void container_update_textures_recursive(struct sway_container *con);
|
||||
|
||||
void container_damage_whole(struct sway_container *container);
|
||||
|
||||
void container_reap_empty(struct sway_container *con);
|
||||
|
||||
struct sway_container *container_flatten(struct sway_container *container);
|
||||
|
||||
void container_update_title_textures(struct sway_container *container);
|
||||
void container_update_title_bar(struct sway_container *container);
|
||||
|
||||
void container_update_marks(struct sway_container *container);
|
||||
|
||||
size_t container_build_representation(enum sway_container_layout layout,
|
||||
list_t *children, char *buffer);
|
||||
|
@ -224,11 +221,6 @@ void container_set_geometry_from_content(struct sway_container *con);
|
|||
*/
|
||||
bool container_is_floating(struct sway_container *container);
|
||||
|
||||
/**
|
||||
* Same as above, but for current container state.
|
||||
*/
|
||||
bool container_is_current_floating(struct sway_container *container);
|
||||
|
||||
/**
|
||||
* Get a container's box in layout coordinates.
|
||||
*/
|
||||
|
@ -291,26 +283,12 @@ bool container_is_floating_or_child(struct sway_container *container);
|
|||
*/
|
||||
bool container_is_fullscreen_or_child(struct sway_container *container);
|
||||
|
||||
/**
|
||||
* Return the output which will be used for scale purposes.
|
||||
* This is the most recently entered output.
|
||||
* If the container is not on any output, return NULL.
|
||||
*/
|
||||
struct sway_output *container_get_effective_output(struct sway_container *con);
|
||||
|
||||
void container_discover_outputs(struct sway_container *con);
|
||||
|
||||
enum sway_container_layout container_parent_layout(struct sway_container *con);
|
||||
|
||||
enum sway_container_layout container_current_parent_layout(
|
||||
struct sway_container *con);
|
||||
|
||||
list_t *container_get_siblings(struct sway_container *container);
|
||||
|
||||
int container_sibling_index(struct sway_container *child);
|
||||
|
||||
list_t *container_get_current_siblings(struct sway_container *container);
|
||||
|
||||
void container_handle_fullscreen_reparent(struct sway_container *con);
|
||||
|
||||
void container_add_child(struct sway_container *parent,
|
||||
|
@ -358,8 +336,6 @@ bool container_has_mark(struct sway_container *container, char *mark);
|
|||
|
||||
void container_add_mark(struct sway_container *container, char *mark);
|
||||
|
||||
void container_update_marks_textures(struct sway_container *container);
|
||||
|
||||
void container_raise_floating(struct sway_container *con);
|
||||
|
||||
bool container_is_scratchpad_hidden(struct sway_container *con);
|
||||
|
@ -383,4 +359,10 @@ bool container_is_sticky_or_child(struct sway_container *con);
|
|||
*/
|
||||
int container_squash(struct sway_container *con);
|
||||
|
||||
void container_arrange_title_bar(struct sway_container *con);
|
||||
|
||||
void container_update(struct sway_container *con);
|
||||
|
||||
void container_update_itself_and_parents(struct sway_container *con);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_NODE_H
|
||||
#include <wayland-server-core.h>
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "list.h"
|
||||
|
||||
#define MIN_SANE_W 100
|
||||
|
@ -75,4 +76,15 @@ list_t *node_get_children(struct sway_node *node);
|
|||
|
||||
bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor);
|
||||
|
||||
// when destroying a sway tree, it's not known which order the tree will be
|
||||
// destroyed. To prevent freeing of scene_nodes recursing up the tree,
|
||||
// let's use this helper function to disown them to the staging node.
|
||||
void scene_node_disown_children(struct wlr_scene_tree *tree);
|
||||
|
||||
// a helper function used to allocate tree nodes. If an allocation failure
|
||||
// occurs a flag is flipped that can be checked later to destroy a parent
|
||||
// of this scene node preventing memory leaks.
|
||||
struct wlr_scene_tree *alloc_scene_tree(struct wlr_scene_tree *parent,
|
||||
bool *failed);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
@ -16,10 +17,44 @@ struct sway_root {
|
|||
struct wlr_output_layout *output_layout;
|
||||
|
||||
struct wl_listener output_layout_change;
|
||||
|
||||
// scene node layout:
|
||||
// - root
|
||||
// - staging
|
||||
// - layer shell stuff
|
||||
// - tiling
|
||||
// - floating
|
||||
// - fullscreen stuff
|
||||
// - seat stuff
|
||||
// - ext_session_lock
|
||||
struct wlr_scene *root_scene;
|
||||
|
||||
// since wlr_scene nodes can't be orphaned and must always
|
||||
// have a parent, use this staging scene_tree so that a
|
||||
// node always have a valid parent. Nothing in this
|
||||
// staging node will be visible.
|
||||
struct wlr_scene_tree *staging;
|
||||
|
||||
// tree containing all layers the compositor will render. Cursor handling
|
||||
// will end up iterating this tree.
|
||||
struct wlr_scene_tree *layer_tree;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *shell_background;
|
||||
struct wlr_scene_tree *shell_bottom;
|
||||
struct wlr_scene_tree *tiling;
|
||||
struct wlr_scene_tree *floating;
|
||||
struct wlr_scene_tree *shell_top;
|
||||
struct wlr_scene_tree *fullscreen;
|
||||
struct wlr_scene_tree *fullscreen_global;
|
||||
#if HAVE_XWAYLAND
|
||||
struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
|
||||
struct wlr_scene_tree *unmanaged;
|
||||
#endif
|
||||
struct wl_list drag_icons; // sway_drag_icon::link
|
||||
struct wlr_scene_tree *shell_overlay;
|
||||
struct wlr_scene_tree *popup;
|
||||
struct wlr_scene_tree *seat;
|
||||
struct wlr_scene_tree *session_lock;
|
||||
} layers;
|
||||
|
||||
// Includes disabled outputs
|
||||
struct wl_list all_outputs; // sway_output::link
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_VIEW_H
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "sway/config.h"
|
||||
#if HAVE_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
|
@ -45,10 +46,6 @@ struct sway_view_impl {
|
|||
void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
|
||||
void (*set_resizing)(struct sway_view *view, bool resizing);
|
||||
bool (*wants_floating)(struct sway_view *view);
|
||||
void (*for_each_surface)(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||
void (*for_each_popup_surface)(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||
bool (*is_transient_for)(struct sway_view *child,
|
||||
struct sway_view *ancestor);
|
||||
void (*close)(struct sway_view *view);
|
||||
|
@ -56,19 +53,14 @@ struct sway_view_impl {
|
|||
void (*destroy)(struct sway_view *view);
|
||||
};
|
||||
|
||||
struct sway_saved_buffer {
|
||||
struct wlr_client_buffer *buffer;
|
||||
int x, y;
|
||||
int width, height;
|
||||
enum wl_output_transform transform;
|
||||
struct wlr_fbox source_box;
|
||||
struct wl_list link; // sway_view::saved_buffers
|
||||
};
|
||||
|
||||
struct sway_view {
|
||||
enum sway_view_type type;
|
||||
const struct sway_view_impl *impl;
|
||||
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
struct wlr_scene_tree *content_tree;
|
||||
struct wlr_scene_tree *saved_surface_tree;
|
||||
|
||||
struct sway_container *container; // NULL if unmapped and transactions finished
|
||||
struct wlr_surface *surface; // NULL for unmapped views
|
||||
struct sway_xdg_decoration *xdg_decoration;
|
||||
|
@ -88,16 +80,10 @@ struct sway_view {
|
|||
bool allow_request_urgent;
|
||||
struct wl_event_source *urgent_timer;
|
||||
|
||||
struct wl_list saved_buffers; // sway_saved_buffer::link
|
||||
|
||||
// The geometry for whatever the client is committing, regardless of
|
||||
// transaction state. Updated on every commit.
|
||||
struct wlr_box geometry;
|
||||
|
||||
// The "old" geometry during a transaction. Used to damage the old location
|
||||
// when a transaction is applied.
|
||||
struct wlr_box saved_geometry;
|
||||
|
||||
struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
|
||||
struct wl_listener foreign_activate_request;
|
||||
struct wl_listener foreign_fullscreen_request;
|
||||
|
@ -119,8 +105,6 @@ struct sway_view {
|
|||
struct wl_signal unmap;
|
||||
} events;
|
||||
|
||||
struct wl_listener surface_new_subsurface;
|
||||
|
||||
int max_render_time; // In milliseconds
|
||||
|
||||
enum seat_config_shortcuts_inhibit shortcuts_inhibit;
|
||||
|
@ -145,6 +129,8 @@ struct sway_xdg_shell_view {
|
|||
struct sway_xwayland_view {
|
||||
struct sway_view view;
|
||||
|
||||
struct wlr_scene_tree *surface_tree;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener request_move;
|
||||
struct wl_listener request_resize;
|
||||
|
@ -166,18 +152,18 @@ struct sway_xwayland_view {
|
|||
struct wl_listener unmap;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener override_redirect;
|
||||
|
||||
struct wl_listener surface_tree_destroy;
|
||||
};
|
||||
|
||||
struct sway_xwayland_unmanaged {
|
||||
struct wlr_xwayland_surface *wlr_xwayland_surface;
|
||||
struct wl_list link;
|
||||
|
||||
int lx, ly;
|
||||
struct wlr_scene_surface *surface_scene;
|
||||
|
||||
struct wl_listener request_activate;
|
||||
struct wl_listener request_configure;
|
||||
struct wl_listener request_fullscreen;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener set_geometry;
|
||||
struct wl_listener associate;
|
||||
struct wl_listener dissociate;
|
||||
|
@ -187,43 +173,12 @@ struct sway_xwayland_unmanaged {
|
|||
struct wl_listener override_redirect;
|
||||
};
|
||||
#endif
|
||||
struct sway_view_child;
|
||||
|
||||
struct sway_view_child_impl {
|
||||
void (*get_view_coords)(struct sway_view_child *child, int *sx, int *sy);
|
||||
void (*destroy)(struct sway_view_child *child);
|
||||
};
|
||||
|
||||
/**
|
||||
* A view child is a surface in the view tree, such as a subsurface or a popup.
|
||||
*/
|
||||
struct sway_view_child {
|
||||
const struct sway_view_child_impl *impl;
|
||||
struct wl_list link;
|
||||
|
||||
struct sway_view *view;
|
||||
struct sway_view_child *parent;
|
||||
struct wl_list children; // sway_view_child::link
|
||||
struct wlr_surface *surface;
|
||||
bool mapped;
|
||||
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener surface_new_subsurface;
|
||||
struct wl_listener surface_map;
|
||||
struct wl_listener surface_unmap;
|
||||
struct wl_listener surface_destroy;
|
||||
struct wl_listener view_unmap;
|
||||
};
|
||||
|
||||
struct sway_subsurface {
|
||||
struct sway_view_child child;
|
||||
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct sway_xdg_popup {
|
||||
struct sway_view_child child;
|
||||
struct sway_view *view;
|
||||
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
struct wlr_scene_tree *xdg_surface_tree;
|
||||
struct wlr_xdg_popup *wlr_xdg_popup;
|
||||
|
||||
struct wl_listener surface_commit;
|
||||
|
@ -295,23 +250,9 @@ void view_close(struct sway_view *view);
|
|||
|
||||
void view_close_popups(struct sway_view *view);
|
||||
|
||||
void view_damage_from(struct sway_view *view);
|
||||
|
||||
/**
|
||||
* Iterate all surfaces of a view (toplevels + popups).
|
||||
*/
|
||||
void view_for_each_surface(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||
|
||||
/**
|
||||
* Iterate all popup surfaces of a view.
|
||||
*/
|
||||
void view_for_each_popup_surface(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||
|
||||
// view implementation
|
||||
|
||||
void view_init(struct sway_view *view, enum sway_view_type type,
|
||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||
const struct sway_view_impl *impl);
|
||||
|
||||
void view_destroy(struct sway_view *view);
|
||||
|
@ -333,14 +274,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
|
|||
void view_unmap(struct sway_view *view);
|
||||
|
||||
void view_update_size(struct sway_view *view);
|
||||
void view_center_surface(struct sway_view *view);
|
||||
|
||||
void view_child_init(struct sway_view_child *child,
|
||||
const struct sway_view_child_impl *impl, struct sway_view *view,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
void view_child_destroy(struct sway_view_child *child);
|
||||
|
||||
void view_center_and_clip_surface(struct sway_view *view);
|
||||
|
||||
struct sway_view *view_from_wlr_xdg_surface(
|
||||
struct wlr_xdg_surface *xdg_surface);
|
||||
|
@ -381,4 +315,6 @@ bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
|
|||
|
||||
void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
|
||||
|
||||
void view_send_frame_done(struct sway_view *view);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_WORKSPACE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
@ -23,6 +24,12 @@ struct sway_workspace_state {
|
|||
|
||||
struct sway_workspace {
|
||||
struct sway_node node;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tiling;
|
||||
struct wlr_scene_tree *fullscreen;
|
||||
} layers;
|
||||
|
||||
struct sway_container *fullscreen;
|
||||
|
||||
char *name;
|
||||
|
|
|
@ -6,6 +6,6 @@ option('swaybar', type: 'boolean', value: true, description: 'Enable support for
|
|||
option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag')
|
||||
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
|
||||
option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray')
|
||||
option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybg')
|
||||
option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybar tray')
|
||||
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
|
||||
option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library')
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
#include "sway/tree/container.h"
|
||||
#include "util.h"
|
||||
|
||||
static void rebuild_textures_iterator(struct sway_container *con, void *data) {
|
||||
container_update_marks_textures(con);
|
||||
container_update_title_textures(con);
|
||||
static void container_update_iterator(struct sway_container *con, void *data) {
|
||||
container_update(con);
|
||||
}
|
||||
|
||||
static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
|
||||
|
@ -51,12 +50,7 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
|
|||
memcpy(class, &colors, sizeof(struct border_colors));
|
||||
|
||||
if (config->active) {
|
||||
root_for_each_container(rebuild_textures_iterator, NULL);
|
||||
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole(output);
|
||||
}
|
||||
root_for_each_container(container_update_iterator, NULL);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -59,7 +59,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
|
|||
}
|
||||
|
||||
free(mark);
|
||||
container_update_marks_textures(container);
|
||||
container_update_marks(container);
|
||||
if (container->view) {
|
||||
view_execute_criteria(container->view);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
|
|||
}
|
||||
|
||||
con->alpha = val;
|
||||
container_damage_whole(con);
|
||||
container_update(con);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,8 @@
|
|||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
static void rebuild_textures_iterator(struct sway_container *con, void *data) {
|
||||
container_update_marks_textures(con);
|
||||
container_update_title_textures(con);
|
||||
static void title_bar_update_iterator(struct sway_container *con, void *data) {
|
||||
container_update_title_bar(con);
|
||||
}
|
||||
|
||||
static void do_reload(void *data) {
|
||||
|
@ -48,7 +47,7 @@ static void do_reload(void *data) {
|
|||
}
|
||||
list_free_items_and_destroy(bar_ids);
|
||||
|
||||
root_for_each_container(rebuild_textures_iterator, NULL);
|
||||
root_for_each_container(title_bar_update_iterator, NULL);
|
||||
|
||||
arrange_root();
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include "stringop.h"
|
||||
#include "util.h"
|
||||
|
||||
static void rebuild_marks_iterator(struct sway_container *con, void *data) {
|
||||
container_update_marks_textures(con);
|
||||
static void title_bar_update_iterator(struct sway_container *con, void *data) {
|
||||
container_update_marks(con);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_show_marks(int argc, char **argv) {
|
||||
|
@ -23,12 +23,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) {
|
|||
config->show_marks = parse_boolean(argv[0], config->show_marks);
|
||||
|
||||
if (config->show_marks) {
|
||||
root_for_each_container(rebuild_marks_iterator, NULL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole(output);
|
||||
root_for_each_container(title_bar_update_iterator, NULL);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
|
||||
static void arrange_title_bar_iterator(struct sway_container *con, void *data) {
|
||||
container_arrange_title_bar(con);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_title_align(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) {
|
||||
|
@ -21,10 +25,7 @@ struct cmd_results *cmd_title_align(int argc, char **argv) {
|
|||
"Expected 'title_align left|center|right'");
|
||||
}
|
||||
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole(output);
|
||||
}
|
||||
root_for_each_container(arrange_title_bar_iterator, NULL);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ struct cmd_results *cmd_titlebar_border_thickness(int argc, char **argv) {
|
|||
"Expected output to have a workspace");
|
||||
}
|
||||
arrange_workspace(ws);
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -33,7 +33,6 @@ struct cmd_results *cmd_titlebar_padding(int argc, char **argv) {
|
|||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
arrange_workspace(output_get_active_workspace(output));
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
|
||||
static void remove_all_marks_iterator(struct sway_container *con, void *data) {
|
||||
static void remove_mark(struct sway_container *con) {
|
||||
container_clear_marks(con);
|
||||
container_update_marks_textures(con);
|
||||
container_update_marks(con);
|
||||
}
|
||||
|
||||
static void remove_all_marks_iterator(struct sway_container *con, void *data) {
|
||||
remove_mark(con);
|
||||
}
|
||||
|
||||
// unmark Remove all marks from all views
|
||||
|
@ -38,8 +42,7 @@ struct cmd_results *cmd_unmark(int argc, char **argv) {
|
|||
}
|
||||
} else if (con && !mark) {
|
||||
// Clear all marks from the given container
|
||||
container_clear_marks(con);
|
||||
container_update_marks_textures(con);
|
||||
remove_mark(con);
|
||||
} else if (!con && mark) {
|
||||
// Remove mark from whichever container has it
|
||||
container_find_and_unmark(mark);
|
||||
|
|
|
@ -538,10 +538,6 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (config->reloading) {
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
if (oc) {
|
||||
enum scale_filter_mode scale_filter_old = output->scale_filter;
|
||||
switch (oc->scale_filter) {
|
||||
|
@ -558,6 +554,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
|
|||
if (scale_filter_old != output->scale_filter) {
|
||||
sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name,
|
||||
sway_output_scale_filter_to_string(output->scale_filter));
|
||||
wlr_damage_ring_add_whole(&output->scene_output->damage_ring);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
#include "sway/tree/container.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/output.h"
|
||||
|
||||
void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
|
||||
bool whole) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
struct wlr_box output_box;
|
||||
wlr_output_layout_get_box(root->output_layout,
|
||||
output->wlr_output, &output_box);
|
||||
output_damage_surface(output, lx - output_box.x,
|
||||
ly - output_box.y, surface, whole);
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_damage_whole_container(struct sway_container *con) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole_container(output, con);
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_damage_box(struct wlr_box *box) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_box(output, box);
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_damage_view(struct sway_view *view) {
|
||||
desktop_damage_whole_container(view->container);
|
||||
struct wlr_box box = {
|
||||
.x = view->container->current.content_x - view->geometry.x,
|
||||
.y = view->container->current.content_y - view->geometry.y,
|
||||
.width = view->surface->current.width,
|
||||
.height = view->surface->current.height,
|
||||
};
|
||||
desktop_damage_box(&box);
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_subcompositor.h>
|
||||
#include "log.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
|
@ -13,9 +14,9 @@
|
|||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/surface.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
||||
struct wlr_surface *surface) {
|
||||
|
@ -50,162 +51,22 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
|||
} while (true);
|
||||
}
|
||||
|
||||
static void apply_exclusive(struct wlr_box *usable_area,
|
||||
uint32_t anchor, int32_t exclusive,
|
||||
int32_t margin_top, int32_t margin_right,
|
||||
int32_t margin_bottom, int32_t margin_left) {
|
||||
if (exclusive <= 0) {
|
||||
return;
|
||||
}
|
||||
struct {
|
||||
uint32_t singular_anchor;
|
||||
uint32_t anchor_triplet;
|
||||
int *positive_axis;
|
||||
int *negative_axis;
|
||||
int margin;
|
||||
} edges[] = {
|
||||
// Top
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
||||
.anchor_triplet =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
||||
.positive_axis = &usable_area->y,
|
||||
.negative_axis = &usable_area->height,
|
||||
.margin = margin_top,
|
||||
},
|
||||
// Bottom
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.anchor_triplet =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.positive_axis = NULL,
|
||||
.negative_axis = &usable_area->height,
|
||||
.margin = margin_bottom,
|
||||
},
|
||||
// Left
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
|
||||
.anchor_triplet =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.positive_axis = &usable_area->x,
|
||||
.negative_axis = &usable_area->width,
|
||||
.margin = margin_left,
|
||||
},
|
||||
// Right
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
|
||||
.anchor_triplet =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.positive_axis = NULL,
|
||||
.negative_axis = &usable_area->width,
|
||||
.margin = margin_right,
|
||||
},
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
|
||||
if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet)
|
||||
&& exclusive + edges[i].margin > 0) {
|
||||
if (edges[i].positive_axis) {
|
||||
*edges[i].positive_axis += exclusive + edges[i].margin;
|
||||
}
|
||||
if (edges[i].negative_axis) {
|
||||
*edges[i].negative_axis -= exclusive + edges[i].margin;
|
||||
}
|
||||
break;
|
||||
static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
|
||||
struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &tree->children, link) {
|
||||
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
||||
SWAY_SCENE_DESC_LAYER_SHELL);
|
||||
// surface could be null during destruction
|
||||
if (!surface) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_layer(struct sway_output *output, struct wl_list *list,
|
||||
struct wlr_box *usable_area, bool exclusive) {
|
||||
struct sway_layer_surface *sway_layer;
|
||||
struct wlr_box full_area = { 0 };
|
||||
wlr_output_effective_resolution(output->wlr_output,
|
||||
&full_area.width, &full_area.height);
|
||||
wl_list_for_each(sway_layer, list, link) {
|
||||
struct wlr_layer_surface_v1 *layer = sway_layer->layer_surface;
|
||||
struct wlr_layer_surface_v1_state *state = &layer->current;
|
||||
if (exclusive != (state->exclusive_zone > 0)) {
|
||||
if (!surface->scene->layer_surface->initialized) {
|
||||
continue;
|
||||
}
|
||||
struct wlr_box bounds;
|
||||
if (state->exclusive_zone == -1) {
|
||||
bounds = full_area;
|
||||
} else {
|
||||
bounds = *usable_area;
|
||||
}
|
||||
struct wlr_box box = {
|
||||
.width = state->desired_width,
|
||||
.height = state->desired_height
|
||||
};
|
||||
// Horizontal axis
|
||||
const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
|
||||
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
if (box.width == 0) {
|
||||
box.x = bounds.x;
|
||||
} else if ((state->anchor & both_horiz) == both_horiz) {
|
||||
box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
|
||||
box.x = bounds.x;
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
|
||||
box.x = bounds.x + (bounds.width - box.width);
|
||||
} else {
|
||||
box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
|
||||
}
|
||||
// Vertical axis
|
||||
const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
|
||||
| ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
if (box.height == 0) {
|
||||
box.y = bounds.y;
|
||||
} else if ((state->anchor & both_vert) == both_vert) {
|
||||
box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
|
||||
box.y = bounds.y;
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
|
||||
box.y = bounds.y + (bounds.height - box.height);
|
||||
} else {
|
||||
box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
|
||||
}
|
||||
// Margin
|
||||
if (box.width == 0) {
|
||||
box.x += state->margin.left;
|
||||
box.width = bounds.width -
|
||||
(state->margin.left + state->margin.right);
|
||||
} else if ((state->anchor & both_horiz) == both_horiz) {
|
||||
// don't apply margins
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
|
||||
box.x += state->margin.left;
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
|
||||
box.x -= state->margin.right;
|
||||
}
|
||||
if (box.height == 0) {
|
||||
box.y += state->margin.top;
|
||||
box.height = bounds.height -
|
||||
(state->margin.top + state->margin.bottom);
|
||||
} else if ((state->anchor & both_vert) == both_vert) {
|
||||
// don't apply margins
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
|
||||
box.y += state->margin.top;
|
||||
} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
|
||||
box.y -= state->margin.bottom;
|
||||
}
|
||||
if (!sway_assert(box.width >= 0 && box.height >= 0,
|
||||
"Expected layer surface to have positive size")) {
|
||||
continue;
|
||||
}
|
||||
// Apply
|
||||
sway_layer->geo = box;
|
||||
apply_exclusive(usable_area, state->anchor, state->exclusive_zone,
|
||||
state->margin.top, state->margin.right,
|
||||
state->margin.bottom, state->margin.left);
|
||||
wlr_layer_surface_v1_configure(layer, box.width, box.height);
|
||||
|
||||
wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,84 +74,81 @@ void arrange_layers(struct sway_output *output) {
|
|||
struct wlr_box usable_area = { 0 };
|
||||
wlr_output_effective_resolution(output->wlr_output,
|
||||
&usable_area.width, &usable_area.height);
|
||||
const struct wlr_box full_area = usable_area;
|
||||
|
||||
// Arrange exclusive surfaces from top->bottom
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&usable_area, true);
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&usable_area, true);
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
&usable_area, true);
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
&usable_area, true);
|
||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background);
|
||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom);
|
||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top);
|
||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay);
|
||||
|
||||
if (memcmp(&usable_area, &output->usable_area,
|
||||
sizeof(struct wlr_box)) != 0) {
|
||||
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
|
||||
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
|
||||
memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
|
||||
output->usable_area = usable_area;
|
||||
arrange_output(output);
|
||||
}
|
||||
|
||||
// Arrange non-exclusive surfaces from top->bottom
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&usable_area, false);
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&usable_area, false);
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
&usable_area, false);
|
||||
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
&usable_area, false);
|
||||
|
||||
// Find topmost keyboard interactive layer, if such a layer exists
|
||||
uint32_t layers_above_shell[] = {
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_TOP,
|
||||
};
|
||||
size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
|
||||
struct sway_layer_surface *layer, *topmost = NULL;
|
||||
for (size_t i = 0; i < nlayers; ++i) {
|
||||
wl_list_for_each_reverse(layer,
|
||||
&output->layers[layers_above_shell[i]], link) {
|
||||
if (layer->layer_surface->current.keyboard_interactive
|
||||
== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
|
||||
layer->layer_surface->surface->mapped) {
|
||||
topmost = layer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (topmost != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
seat->has_exclusive_layer = false;
|
||||
if (topmost != NULL) {
|
||||
seat_set_focus_layer(seat, topmost->layer_surface);
|
||||
} else if (seat->focused_layer &&
|
||||
seat->focused_layer->current.keyboard_interactive
|
||||
!= ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
|
||||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
|
||||
enum zwlr_layer_shell_v1_layer type) {
|
||||
switch (type) {
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
|
||||
return output->layers.shell_background;
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
|
||||
return output->layers.shell_bottom;
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
|
||||
return output->layers.shell_top;
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
|
||||
return output->layers.shell_overlay;
|
||||
}
|
||||
|
||||
sway_assert(false, "unreachable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sway_layer_surface *sway_layer_surface_create(
|
||||
struct wlr_scene_layer_surface_v1 *scene) {
|
||||
struct sway_layer_surface *surface = calloc(1, sizeof(*surface));
|
||||
if (!surface) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a scene_layer surface");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *popups = wlr_scene_tree_create(root->layers.popup);
|
||||
if (!popups) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a scene_layer popup node");
|
||||
free(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface->tree = scene->tree;
|
||||
surface->scene = scene;
|
||||
surface->layer_surface = scene->layer_surface;
|
||||
surface->popups = popups;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static struct sway_layer_surface *find_mapped_layer_by_client(
|
||||
struct wl_client *client, struct wlr_output *ignore_output) {
|
||||
struct wl_client *client, struct sway_output *ignore_output) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
if (output->wlr_output == ignore_output) {
|
||||
if (output == ignore_output) {
|
||||
continue;
|
||||
}
|
||||
// For now we'll only check the overlay layer
|
||||
struct sway_layer_surface *lsurface;
|
||||
wl_list_for_each(lsurface,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) {
|
||||
struct wl_resource *resource = lsurface->layer_surface->resource;
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each (node, &output->layers.shell_overlay->children, link) {
|
||||
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
||||
SWAY_SCENE_DESC_LAYER_SHELL);
|
||||
if (!surface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
|
||||
struct wl_resource *resource = layer_surface->resource;
|
||||
if (wl_resource_get_client(resource) == client
|
||||
&& lsurface->layer_surface->surface->mapped) {
|
||||
return lsurface;
|
||||
&& layer_surface->surface->mapped) {
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,262 +156,144 @@ static struct sway_layer_surface *find_mapped_layer_by_client(
|
|||
}
|
||||
|
||||
static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer =
|
||||
wl_container_of(listener, sway_layer, output_destroy);
|
||||
struct sway_layer_surface *layer =
|
||||
wl_container_of(listener, layer, output_destroy);
|
||||
|
||||
layer->output = NULL;
|
||||
wlr_scene_node_destroy(&layer->scene->tree->node);
|
||||
}
|
||||
|
||||
static void handle_node_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *layer =
|
||||
wl_container_of(listener, layer, node_destroy);
|
||||
|
||||
// destroy the scene descriptor straight away if it exists, otherwise
|
||||
// we will try to reflow still considering the destroyed node.
|
||||
scene_descriptor_destroy(&layer->tree->node, SWAY_SCENE_DESC_LAYER_SHELL);
|
||||
|
||||
// Determine if this layer is being used by an exclusive client. If it is,
|
||||
// try and find another layer owned by this client to pass focus to.
|
||||
struct sway_seat *seat = input_manager_get_default_seat();
|
||||
struct wl_client *client =
|
||||
wl_resource_get_client(sway_layer->layer_surface->resource);
|
||||
|
||||
if (!server.session_lock.locked) {
|
||||
struct sway_layer_surface *layer =
|
||||
find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
|
||||
if (layer) {
|
||||
seat_set_focus_layer(seat, layer->layer_surface);
|
||||
wl_resource_get_client(layer->layer_surface->resource);
|
||||
if (!server.session_lock.lock) {
|
||||
struct sway_layer_surface *consider_layer =
|
||||
find_mapped_layer_by_client(client, layer->output);
|
||||
if (consider_layer) {
|
||||
seat_set_focus_layer(seat, consider_layer->layer_surface);
|
||||
}
|
||||
}
|
||||
|
||||
wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
|
||||
if (layer->output) {
|
||||
arrange_layers(layer->output);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
wlr_scene_node_destroy(&layer->popups->node);
|
||||
|
||||
wl_list_remove(&layer->map.link);
|
||||
wl_list_remove(&layer->unmap.link);
|
||||
wl_list_remove(&layer->surface_commit.link);
|
||||
wl_list_remove(&layer->node_destroy.link);
|
||||
wl_list_remove(&layer->output_destroy.link);
|
||||
|
||||
free(layer);
|
||||
}
|
||||
|
||||
static void handle_surface_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *layer =
|
||||
wl_container_of(listener, layer, surface_commit);
|
||||
struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
|
||||
struct wlr_output *wlr_output = layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
struct wlr_box old_extent = layer->extent;
|
||||
struct sway_layer_surface *surface =
|
||||
wl_container_of(listener, surface, surface_commit);
|
||||
|
||||
bool layer_changed = false;
|
||||
if (layer_surface->current.committed != 0
|
||||
|| layer->mapped != layer_surface->surface->mapped) {
|
||||
layer->mapped = layer_surface->surface->mapped;
|
||||
layer_changed = layer->layer != layer_surface->current.layer;
|
||||
if (layer_changed) {
|
||||
wl_list_remove(&layer->link);
|
||||
wl_list_insert(&output->layers[layer_surface->current.layer],
|
||||
&layer->link);
|
||||
layer->layer = layer_surface->current.layer;
|
||||
}
|
||||
arrange_layers(output);
|
||||
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
|
||||
if (!layer_surface->initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_surface_get_extends(layer_surface->surface, &layer->extent);
|
||||
layer->extent.x += layer->geo.x;
|
||||
layer->extent.y += layer->geo.y;
|
||||
|
||||
bool extent_changed =
|
||||
memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0;
|
||||
if (extent_changed || layer_changed) {
|
||||
old_extent.x += output->lx;
|
||||
old_extent.y += output->ly;
|
||||
output_damage_box(output, &old_extent);
|
||||
output_damage_surface(output, layer->geo.x, layer->geo.y,
|
||||
layer_surface->surface, true);
|
||||
} else {
|
||||
output_damage_surface(output, layer->geo.x, layer->geo.y,
|
||||
layer_surface->surface, false);
|
||||
uint32_t committed = layer_surface->current.committed;
|
||||
if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
|
||||
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer;
|
||||
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
|
||||
surface->output, layer_type);
|
||||
wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);
|
||||
}
|
||||
|
||||
transaction_commit_dirty();
|
||||
if (layer_surface->initial_commit || committed || layer_surface->surface->mapped != surface->mapped) {
|
||||
surface->mapped = layer_surface->surface->mapped;
|
||||
arrange_layers(surface->output);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(&surface->scene->tree->node, &lx, &ly);
|
||||
wlr_scene_node_set_position(&surface->popups->node, lx, ly);
|
||||
}
|
||||
|
||||
static void unmap(struct sway_layer_surface *sway_layer) {
|
||||
static void handle_map(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *surface = wl_container_of(listener,
|
||||
surface, map);
|
||||
|
||||
struct wlr_layer_surface_v1 *layer_surface =
|
||||
surface->scene->layer_surface;
|
||||
|
||||
// focus on new surface
|
||||
if (layer_surface->current.keyboard_interactive &&
|
||||
(layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ||
|
||||
layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP)) {
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
// but only if the currently focused layer has a lower precedence
|
||||
if (!seat->focused_layer ||
|
||||
seat->focused_layer->current.layer >= layer_surface->current.layer) {
|
||||
seat_set_focus_layer(seat, layer_surface);
|
||||
}
|
||||
}
|
||||
arrange_layers(surface->output);
|
||||
}
|
||||
|
||||
cursor_rebase_all();
|
||||
}
|
||||
|
||||
static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *surface = wl_container_of(
|
||||
listener, surface, unmap);
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
if (seat->focused_layer == sway_layer->layer_surface) {
|
||||
if (seat->focused_layer == surface->layer_surface) {
|
||||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
cursor_rebase_all();
|
||||
|
||||
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
||||
sway_layer->layer_surface->surface, true);
|
||||
}
|
||||
|
||||
static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
|
||||
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_popup *popup =
|
||||
wl_container_of(listener, popup, destroy);
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer =
|
||||
wl_container_of(listener, sway_layer, destroy);
|
||||
sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)",
|
||||
sway_layer->layer_surface->namespace);
|
||||
if (sway_layer->layer_surface->surface->mapped) {
|
||||
unmap(sway_layer);
|
||||
}
|
||||
|
||||
struct sway_layer_subsurface *subsurface, *subsurface_tmp;
|
||||
wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) {
|
||||
layer_subsurface_destroy(subsurface);
|
||||
}
|
||||
|
||||
wl_list_remove(&sway_layer->link);
|
||||
wl_list_remove(&sway_layer->destroy.link);
|
||||
wl_list_remove(&sway_layer->map.link);
|
||||
wl_list_remove(&sway_layer->unmap.link);
|
||||
wl_list_remove(&sway_layer->surface_commit.link);
|
||||
wl_list_remove(&sway_layer->new_popup.link);
|
||||
wl_list_remove(&sway_layer->new_subsurface.link);
|
||||
|
||||
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
arrange_layers(output);
|
||||
transaction_commit_dirty();
|
||||
wl_list_remove(&sway_layer->output_destroy.link);
|
||||
sway_layer->layer_surface->output = NULL;
|
||||
|
||||
free(sway_layer);
|
||||
}
|
||||
|
||||
static void handle_map(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer = wl_container_of(listener,
|
||||
sway_layer, map);
|
||||
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
||||
sway_layer->layer_surface->surface, true);
|
||||
cursor_rebase_all();
|
||||
}
|
||||
|
||||
static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer = wl_container_of(
|
||||
listener, sway_layer, unmap);
|
||||
unmap(sway_layer);
|
||||
}
|
||||
|
||||
static void subsurface_damage(struct sway_layer_subsurface *subsurface,
|
||||
bool whole) {
|
||||
struct sway_layer_surface *layer = subsurface->layer_surface;
|
||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
|
||||
int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
|
||||
output_damage_surface(
|
||||
output, ox, oy, subsurface->wlr_subsurface->surface, whole);
|
||||
}
|
||||
|
||||
static void subsurface_handle_unmap(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, unmap);
|
||||
subsurface_damage(subsurface, true);
|
||||
}
|
||||
|
||||
static void subsurface_handle_map(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, map);
|
||||
subsurface_damage(subsurface, true);
|
||||
}
|
||||
|
||||
static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, commit);
|
||||
subsurface_damage(subsurface, false);
|
||||
}
|
||||
|
||||
static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
|
||||
wl_list_remove(&subsurface->link);
|
||||
wl_list_remove(&subsurface->map.link);
|
||||
wl_list_remove(&subsurface->unmap.link);
|
||||
wl_list_remove(&subsurface->destroy.link);
|
||||
wl_list_remove(&subsurface->commit.link);
|
||||
free(subsurface);
|
||||
}
|
||||
|
||||
static void subsurface_handle_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, destroy);
|
||||
layer_subsurface_destroy(subsurface);
|
||||
}
|
||||
|
||||
static struct sway_layer_subsurface *create_subsurface(
|
||||
struct wlr_subsurface *wlr_subsurface,
|
||||
struct sway_layer_surface *layer_surface) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
calloc(1, sizeof(struct sway_layer_subsurface));
|
||||
if (subsurface == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subsurface->wlr_subsurface = wlr_subsurface;
|
||||
subsurface->layer_surface = layer_surface;
|
||||
wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
|
||||
|
||||
subsurface->map.notify = subsurface_handle_map;
|
||||
wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map);
|
||||
subsurface->unmap.notify = subsurface_handle_unmap;
|
||||
wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap);
|
||||
subsurface->destroy.notify = subsurface_handle_destroy;
|
||||
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
|
||||
subsurface->commit.notify = subsurface_handle_commit;
|
||||
wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit);
|
||||
|
||||
return subsurface;
|
||||
}
|
||||
|
||||
static void handle_new_subsurface(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer_surface =
|
||||
wl_container_of(listener, sway_layer_surface, new_subsurface);
|
||||
struct wlr_subsurface *wlr_subsurface = data;
|
||||
create_subsurface(wlr_subsurface, sway_layer_surface);
|
||||
}
|
||||
|
||||
|
||||
static struct sway_layer_surface *popup_get_layer(
|
||||
struct sway_layer_popup *popup) {
|
||||
while (popup->parent_type == LAYER_PARENT_POPUP) {
|
||||
popup = popup->parent_popup;
|
||||
}
|
||||
return popup->parent_layer;
|
||||
}
|
||||
|
||||
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
|
||||
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
|
||||
struct wlr_surface *surface = popup->base->surface;
|
||||
int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x;
|
||||
int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y;
|
||||
int ox = popup_sx, oy = popup_sy;
|
||||
struct sway_layer_surface *layer;
|
||||
while (true) {
|
||||
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
|
||||
layer_popup = layer_popup->parent_popup;
|
||||
ox += layer_popup->wlr_popup->current.geometry.x;
|
||||
oy += layer_popup->wlr_popup->current.geometry.y;
|
||||
} else {
|
||||
layer = layer_popup->parent_layer;
|
||||
ox += layer->geo.x;
|
||||
oy += layer->geo.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
output_damage_surface(output, ox, oy, surface, whole);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
wl_list_remove(&popup->commit.link);
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static void popup_unconstrain(struct sway_layer_popup *popup) {
|
||||
struct sway_layer_surface *layer = popup_get_layer(popup);
|
||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
|
||||
struct sway_output *output = popup->toplevel->output;
|
||||
|
||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
struct sway_output *output = wlr_output->data;
|
||||
// if a client tries to create a popup while we are in the process of destroying
|
||||
// its output, don't crash.
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(&popup->toplevel->scene->tree->node, &lx, &ly);
|
||||
|
||||
// the output box expressed in the coordinate system of the toplevel parent
|
||||
// of the popup
|
||||
struct wlr_box output_toplevel_sx_box = {
|
||||
.x = -layer->geo.x,
|
||||
.y = -layer->geo.y,
|
||||
.x = output->lx - lx,
|
||||
.y = output->ly - ly,
|
||||
.width = output->width,
|
||||
.height = output->height,
|
||||
};
|
||||
|
@ -561,63 +301,38 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
|
|||
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
|
||||
}
|
||||
|
||||
static void popup_handle_map(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
|
||||
struct sway_layer_surface *layer = popup_get_layer(popup);
|
||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||
surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data);
|
||||
popup_damage(popup, true);
|
||||
}
|
||||
|
||||
static void popup_handle_unmap(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap);
|
||||
popup_damage(popup, true);
|
||||
}
|
||||
|
||||
static void popup_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
|
||||
if (popup->wlr_popup->base->initial_commit) {
|
||||
popup_unconstrain(popup);
|
||||
}
|
||||
popup_damage(popup, false);
|
||||
}
|
||||
|
||||
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_popup *popup =
|
||||
wl_container_of(listener, popup, destroy);
|
||||
|
||||
wl_list_remove(&popup->map.link);
|
||||
wl_list_remove(&popup->unmap.link);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->commit.link);
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||
|
||||
static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
|
||||
enum layer_parent parent_type, void *parent) {
|
||||
struct sway_layer_popup *popup =
|
||||
calloc(1, sizeof(struct sway_layer_popup));
|
||||
struct sway_layer_surface *toplevel, struct wlr_scene_tree *parent) {
|
||||
struct sway_layer_popup *popup = calloc(1, sizeof(*popup));
|
||||
if (popup == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
popup->toplevel = toplevel;
|
||||
popup->wlr_popup = wlr_popup;
|
||||
popup->parent_type = parent_type;
|
||||
popup->parent_layer = parent;
|
||||
popup->scene = wlr_scene_xdg_surface_create(parent,
|
||||
wlr_popup->base);
|
||||
|
||||
if (!popup->scene) {
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
popup->map.notify = popup_handle_map;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map);
|
||||
popup->unmap.notify = popup_handle_unmap;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap);
|
||||
popup->destroy.notify = popup_handle_destroy;
|
||||
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||
popup->commit.notify = popup_handle_commit;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||
popup->new_popup.notify = popup_handle_new_popup;
|
||||
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||
popup->commit.notify = popup_handle_commit;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
@ -626,19 +341,14 @@ static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
|
|||
struct sway_layer_popup *sway_layer_popup =
|
||||
wl_container_of(listener, sway_layer_popup, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup);
|
||||
create_popup(wlr_popup, sway_layer_popup->toplevel, sway_layer_popup->scene);
|
||||
}
|
||||
|
||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer_surface =
|
||||
wl_container_of(listener, sway_layer_surface, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface);
|
||||
}
|
||||
|
||||
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
||||
struct wlr_layer_surface_v1 *layer_surface) {
|
||||
return layer_surface->data;
|
||||
create_popup(wlr_popup, sway_layer_surface, sway_layer_surface->popups);
|
||||
}
|
||||
|
||||
void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
||||
|
@ -670,10 +380,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
|||
sway_log(SWAY_ERROR,
|
||||
"no output to auto-assign layer surface '%s' to",
|
||||
layer_surface->namespace);
|
||||
// Note that layer_surface->output can be NULL
|
||||
// here, but none of our destroy callbacks are
|
||||
// registered yet so we don't have to make them
|
||||
// handle that case.
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
return;
|
||||
}
|
||||
|
@ -682,46 +388,51 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
|||
layer_surface->output = output->wlr_output;
|
||||
}
|
||||
|
||||
struct sway_layer_surface *sway_layer =
|
||||
calloc(1, sizeof(struct sway_layer_surface));
|
||||
if (!sway_layer) {
|
||||
struct sway_output *output = layer_surface->output->data;
|
||||
|
||||
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer;
|
||||
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
|
||||
output, layer_type);
|
||||
struct wlr_scene_layer_surface_v1 *scene_surface =
|
||||
wlr_scene_layer_surface_v1_create(output_layer, layer_surface);
|
||||
if (!scene_surface) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_init(&sway_layer->subsurfaces);
|
||||
struct sway_layer_surface *surface =
|
||||
sway_layer_surface_create(scene_surface);
|
||||
if (!surface) {
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
|
||||
sway_layer->surface_commit.notify = handle_surface_commit;
|
||||
sway_log(SWAY_ERROR, "Could not allocate a sway_layer_surface");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scene_descriptor_assign(&scene_surface->tree->node,
|
||||
SWAY_SCENE_DESC_LAYER_SHELL, surface)) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a layer surface descriptor");
|
||||
// destroying the layer_surface will also destroy its corresponding
|
||||
// scene node
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
return;
|
||||
}
|
||||
|
||||
surface->output = output;
|
||||
|
||||
surface->surface_commit.notify = handle_surface_commit;
|
||||
wl_signal_add(&layer_surface->surface->events.commit,
|
||||
&sway_layer->surface_commit);
|
||||
&surface->surface_commit);
|
||||
surface->map.notify = handle_map;
|
||||
wl_signal_add(&layer_surface->surface->events.map, &surface->map);
|
||||
surface->unmap.notify = handle_unmap;
|
||||
wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
|
||||
surface->new_popup.notify = handle_new_popup;
|
||||
wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
|
||||
|
||||
sway_layer->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy);
|
||||
sway_layer->map.notify = handle_map;
|
||||
wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map);
|
||||
sway_layer->unmap.notify = handle_unmap;
|
||||
wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap);
|
||||
sway_layer->new_popup.notify = handle_new_popup;
|
||||
wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);
|
||||
sway_layer->new_subsurface.notify = handle_new_subsurface;
|
||||
wl_signal_add(&layer_surface->surface->events.new_subsurface,
|
||||
&sway_layer->new_subsurface);
|
||||
surface->output_destroy.notify = handle_output_destroy;
|
||||
wl_signal_add(&output->events.disable, &surface->output_destroy);
|
||||
|
||||
sway_layer->layer_surface = layer_surface;
|
||||
layer_surface->data = sway_layer;
|
||||
|
||||
struct sway_output *output = layer_surface->output->data;
|
||||
sway_layer->output_destroy.notify = handle_output_destroy;
|
||||
wl_signal_add(&output->events.disable, &sway_layer->output_destroy);
|
||||
|
||||
wl_list_insert(&output->layers[layer_surface->pending.layer],
|
||||
&sway_layer->link);
|
||||
|
||||
surface_enter_output(layer_surface->surface, output);
|
||||
|
||||
// Temporarily set the layer's current state to pending
|
||||
// So that we can easily arrange it
|
||||
struct wlr_layer_surface_v1_state old_state = layer_surface->current;
|
||||
layer_surface->current = layer_surface->pending;
|
||||
arrange_layers(output);
|
||||
layer_surface->current = old_state;
|
||||
surface->node_destroy.notify = handle_node_destroy;
|
||||
wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
#include "sway/ipc-server.h"
|
||||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/surface.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
|
@ -71,318 +71,6 @@ struct sway_output *all_output_by_name_or_id(const char *name_or_id) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct surface_iterator_data {
|
||||
sway_surface_iterator_func_t user_iterator;
|
||||
void *user_data;
|
||||
|
||||
struct sway_output *output;
|
||||
struct sway_view *view;
|
||||
double ox, oy;
|
||||
int width, height;
|
||||
};
|
||||
|
||||
static bool get_surface_box(struct surface_iterator_data *data,
|
||||
struct wlr_surface *surface, int sx, int sy,
|
||||
struct wlr_box *surface_box) {
|
||||
struct sway_output *output = data->output;
|
||||
|
||||
if (!wlr_surface_has_buffer(surface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sw = surface->current.width;
|
||||
int sh = surface->current.height;
|
||||
|
||||
struct wlr_box box = {
|
||||
.x = floor(data->ox + sx),
|
||||
.y = floor(data->oy + sy),
|
||||
.width = sw,
|
||||
.height = sh,
|
||||
};
|
||||
if (surface_box != NULL) {
|
||||
memcpy(surface_box, &box, sizeof(struct wlr_box));
|
||||
}
|
||||
|
||||
struct wlr_box output_box = {
|
||||
.width = output->width,
|
||||
.height = output->height,
|
||||
};
|
||||
|
||||
struct wlr_box intersection;
|
||||
return wlr_box_intersection(&intersection, &output_box, &box);
|
||||
}
|
||||
|
||||
static void output_for_each_surface_iterator(struct wlr_surface *surface,
|
||||
int sx, int sy, void *_data) {
|
||||
struct surface_iterator_data *data = _data;
|
||||
|
||||
struct wlr_box box;
|
||||
bool intersects = get_surface_box(data, surface, sx, sy, &box);
|
||||
if (!intersects) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->user_iterator(data->output, data->view, surface, &box,
|
||||
data->user_data);
|
||||
}
|
||||
|
||||
void output_surface_for_each_surface(struct sway_output *output,
|
||||
struct wlr_surface *surface, double ox, double oy,
|
||||
sway_surface_iterator_func_t iterator, void *user_data) {
|
||||
struct surface_iterator_data data = {
|
||||
.user_iterator = iterator,
|
||||
.user_data = user_data,
|
||||
.output = output,
|
||||
.view = NULL,
|
||||
.ox = ox,
|
||||
.oy = oy,
|
||||
.width = surface->current.width,
|
||||
.height = surface->current.height,
|
||||
};
|
||||
|
||||
wlr_surface_for_each_surface(surface,
|
||||
output_for_each_surface_iterator, &data);
|
||||
}
|
||||
|
||||
void output_view_for_each_surface(struct sway_output *output,
|
||||
struct sway_view *view, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct surface_iterator_data data = {
|
||||
.user_iterator = iterator,
|
||||
.user_data = user_data,
|
||||
.output = output,
|
||||
.view = view,
|
||||
.ox = view->container->surface_x - output->lx
|
||||
- view->geometry.x,
|
||||
.oy = view->container->surface_y - output->ly
|
||||
- view->geometry.y,
|
||||
.width = view->container->current.content_width,
|
||||
.height = view->container->current.content_height,
|
||||
};
|
||||
|
||||
view_for_each_surface(view, output_for_each_surface_iterator, &data);
|
||||
}
|
||||
|
||||
void output_view_for_each_popup_surface(struct sway_output *output,
|
||||
struct sway_view *view, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct surface_iterator_data data = {
|
||||
.user_iterator = iterator,
|
||||
.user_data = user_data,
|
||||
.output = output,
|
||||
.view = view,
|
||||
.ox = view->container->surface_x - output->lx
|
||||
- view->geometry.x,
|
||||
.oy = view->container->surface_y - output->ly
|
||||
- view->geometry.y,
|
||||
.width = view->container->current.content_width,
|
||||
.height = view->container->current.content_height,
|
||||
};
|
||||
|
||||
view_for_each_popup_surface(view, output_for_each_surface_iterator, &data);
|
||||
}
|
||||
|
||||
void output_layer_for_each_surface(struct sway_output *output,
|
||||
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct sway_layer_surface *layer_surface;
|
||||
wl_list_for_each(layer_surface, layer_surfaces, link) {
|
||||
struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
|
||||
layer_surface->layer_surface;
|
||||
struct wlr_surface *surface = wlr_layer_surface_v1->surface;
|
||||
struct surface_iterator_data data = {
|
||||
.user_iterator = iterator,
|
||||
.user_data = user_data,
|
||||
.output = output,
|
||||
.view = NULL,
|
||||
.ox = layer_surface->geo.x,
|
||||
.oy = layer_surface->geo.y,
|
||||
.width = surface->current.width,
|
||||
.height = surface->current.height,
|
||||
};
|
||||
wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1,
|
||||
output_for_each_surface_iterator, &data);
|
||||
}
|
||||
}
|
||||
|
||||
void output_layer_for_each_toplevel_surface(struct sway_output *output,
|
||||
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct sway_layer_surface *layer_surface;
|
||||
wl_list_for_each(layer_surface, layer_surfaces, link) {
|
||||
struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
|
||||
layer_surface->layer_surface;
|
||||
output_surface_for_each_surface(output, wlr_layer_surface_v1->surface,
|
||||
layer_surface->geo.x, layer_surface->geo.y, iterator,
|
||||
user_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void output_layer_for_each_popup_surface(struct sway_output *output,
|
||||
struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct sway_layer_surface *layer_surface;
|
||||
wl_list_for_each(layer_surface, layer_surfaces, link) {
|
||||
struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
|
||||
layer_surface->layer_surface;
|
||||
struct wlr_surface *surface = wlr_layer_surface_v1->surface;
|
||||
struct surface_iterator_data data = {
|
||||
.user_iterator = iterator,
|
||||
.user_data = user_data,
|
||||
.output = output,
|
||||
.view = NULL,
|
||||
.ox = layer_surface->geo.x,
|
||||
.oy = layer_surface->geo.y,
|
||||
.width = surface->current.width,
|
||||
.height = surface->current.height,
|
||||
};
|
||||
wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1,
|
||||
output_for_each_surface_iterator, &data);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
void output_unmanaged_for_each_surface(struct sway_output *output,
|
||||
struct wl_list *unmanaged, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct sway_xwayland_unmanaged *unmanaged_surface;
|
||||
wl_list_for_each(unmanaged_surface, unmanaged, link) {
|
||||
struct wlr_xwayland_surface *xsurface =
|
||||
unmanaged_surface->wlr_xwayland_surface;
|
||||
double ox = unmanaged_surface->lx - output->lx;
|
||||
double oy = unmanaged_surface->ly - output->ly;
|
||||
|
||||
output_surface_for_each_surface(output, xsurface->surface, ox, oy,
|
||||
iterator, user_data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void output_drag_icons_for_each_surface(struct sway_output *output,
|
||||
struct wl_list *drag_icons, sway_surface_iterator_func_t iterator,
|
||||
void *user_data) {
|
||||
struct sway_drag_icon *drag_icon;
|
||||
wl_list_for_each(drag_icon, drag_icons, link) {
|
||||
double ox = drag_icon->x - output->lx;
|
||||
double oy = drag_icon->y - output->ly;
|
||||
|
||||
if (drag_icon->wlr_drag_icon->surface->mapped) {
|
||||
output_surface_for_each_surface(output,
|
||||
drag_icon->wlr_drag_icon->surface, ox, oy,
|
||||
iterator, user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void for_each_surface_container_iterator(struct sway_container *con,
|
||||
void *_data) {
|
||||
if (!con->view || !view_is_visible(con->view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct surface_iterator_data *data = _data;
|
||||
output_view_for_each_surface(data->output, con->view,
|
||||
data->user_iterator, data->user_data);
|
||||
}
|
||||
|
||||
static void output_for_each_surface(struct sway_output *output,
|
||||
sway_surface_iterator_func_t iterator, void *user_data) {
|
||||
if (server.session_lock.locked) {
|
||||
if (server.session_lock.lock == NULL) {
|
||||
return;
|
||||
}
|
||||
struct wlr_session_lock_surface_v1 *lock_surface;
|
||||
wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
|
||||
if (lock_surface->output != output->wlr_output) {
|
||||
continue;
|
||||
}
|
||||
if (!lock_surface->surface->mapped) {
|
||||
continue;
|
||||
}
|
||||
|
||||
output_surface_for_each_surface(output, lock_surface->surface,
|
||||
0.0, 0.0, iterator, user_data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (output_has_opaque_overlay_layer_surface(output)) {
|
||||
goto overlay;
|
||||
}
|
||||
|
||||
struct surface_iterator_data data = {
|
||||
.user_iterator = iterator,
|
||||
.user_data = user_data,
|
||||
.output = output,
|
||||
.view = NULL,
|
||||
};
|
||||
|
||||
struct sway_workspace *workspace = output_get_active_workspace(output);
|
||||
struct sway_container *fullscreen_con = root->fullscreen_global;
|
||||
if (!fullscreen_con) {
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
fullscreen_con = workspace->current.fullscreen;
|
||||
}
|
||||
if (fullscreen_con) {
|
||||
for_each_surface_container_iterator(fullscreen_con, &data);
|
||||
container_for_each_child(fullscreen_con,
|
||||
for_each_surface_container_iterator, &data);
|
||||
|
||||
// TODO: Show transient containers for fullscreen global
|
||||
if (fullscreen_con == workspace->current.fullscreen) {
|
||||
for (int i = 0; i < workspace->current.floating->length; ++i) {
|
||||
struct sway_container *floater =
|
||||
workspace->current.floating->items[i];
|
||||
if (container_is_transient_for(floater, fullscreen_con)) {
|
||||
for_each_surface_container_iterator(floater, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if HAVE_XWAYLAND
|
||||
output_unmanaged_for_each_surface(output, &root->xwayland_unmanaged,
|
||||
iterator, user_data);
|
||||
#endif
|
||||
} else {
|
||||
output_layer_for_each_surface(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
iterator, user_data);
|
||||
output_layer_for_each_surface(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
iterator, user_data);
|
||||
|
||||
workspace_for_each_container(workspace,
|
||||
for_each_surface_container_iterator, &data);
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
output_unmanaged_for_each_surface(output, &root->xwayland_unmanaged,
|
||||
iterator, user_data);
|
||||
#endif
|
||||
output_layer_for_each_surface(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
iterator, user_data);
|
||||
}
|
||||
|
||||
overlay:
|
||||
output_layer_for_each_surface(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
iterator, user_data);
|
||||
output_drag_icons_for_each_surface(output, &root->drag_icons,
|
||||
iterator, user_data);
|
||||
}
|
||||
|
||||
static int scale_length(int length, int offset, float scale) {
|
||||
return roundf((offset + length) * scale) - roundf(offset * scale);
|
||||
}
|
||||
|
||||
void scale_box(struct wlr_box *box, float scale) {
|
||||
box->width = scale_length(box->width, box->x, scale);
|
||||
box->height = scale_length(box->height, box->y, scale);
|
||||
box->x = roundf(box->x * scale);
|
||||
box->y = roundf(box->y * scale);
|
||||
}
|
||||
|
||||
struct sway_workspace *output_get_active_workspace(struct sway_output *output) {
|
||||
struct sway_seat *seat = input_manager_current_seat();
|
||||
|
@ -396,304 +84,186 @@ struct sway_workspace *output_get_active_workspace(struct sway_output *output) {
|
|||
return focus->sway_workspace;
|
||||
}
|
||||
|
||||
bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
|
||||
struct sway_layer_surface *sway_layer_surface;
|
||||
wl_list_for_each(sway_layer_surface,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) {
|
||||
struct wlr_surface *wlr_surface = sway_layer_surface->layer_surface->surface;
|
||||
pixman_box32_t output_box = {
|
||||
.x2 = output->width,
|
||||
.y2 = output->height,
|
||||
};
|
||||
pixman_region32_t surface_opaque_box;
|
||||
pixman_region32_init(&surface_opaque_box);
|
||||
pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region);
|
||||
pixman_region32_translate(&surface_opaque_box,
|
||||
sway_layer_surface->geo.x, sway_layer_surface->geo.y);
|
||||
pixman_region_overlap_t contains =
|
||||
pixman_region32_contains_rectangle(&surface_opaque_box, &output_box);
|
||||
pixman_region32_fini(&surface_opaque_box);
|
||||
|
||||
if (contains == PIXMAN_REGION_IN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct send_frame_done_data {
|
||||
struct timespec when;
|
||||
int msec_until_refresh;
|
||||
struct sway_output *output;
|
||||
};
|
||||
|
||||
static void send_frame_done_iterator(struct sway_output *output,
|
||||
struct sway_view *view, struct wlr_surface *surface,
|
||||
struct wlr_box *box, void *user_data) {
|
||||
int view_max_render_time = 0;
|
||||
if (view != NULL) {
|
||||
view_max_render_time = view->max_render_time;
|
||||
struct buffer_timer {
|
||||
struct wl_listener destroy;
|
||||
struct wl_event_source *frame_done_timer;
|
||||
};
|
||||
|
||||
static int handle_buffer_timer(void *data) {
|
||||
struct wlr_scene_buffer *buffer = data;
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_buffer_send_frame_done(buffer, &now);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_buffer_timer_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct buffer_timer *timer = wl_container_of(listener, timer, destroy);
|
||||
|
||||
wl_list_remove(&timer->destroy.link);
|
||||
wl_event_source_remove(timer->frame_done_timer);
|
||||
free(timer);
|
||||
}
|
||||
|
||||
static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_buffer *buffer) {
|
||||
struct buffer_timer *timer =
|
||||
scene_descriptor_try_get(&buffer->node, SWAY_SCENE_DESC_BUFFER_TIMER);
|
||||
if (timer) {
|
||||
return timer;
|
||||
}
|
||||
|
||||
timer = calloc(1, sizeof(struct buffer_timer));
|
||||
if (!timer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timer->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop,
|
||||
handle_buffer_timer, buffer);
|
||||
if (!timer->frame_done_timer) {
|
||||
free(timer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene_descriptor_assign(&buffer->node, SWAY_SCENE_DESC_BUFFER_TIMER, timer);
|
||||
|
||||
timer->destroy.notify = handle_buffer_timer_destroy;
|
||||
wl_signal_add(&buffer->node.events.destroy, &timer->destroy);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
static void send_frame_done_iterator(struct wlr_scene_buffer *buffer,
|
||||
int x, int y, void *user_data) {
|
||||
struct send_frame_done_data *data = user_data;
|
||||
struct sway_output *output = data->output;
|
||||
int view_max_render_time = 0;
|
||||
|
||||
if (buffer->primary_output != data->output->scene_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_node *current = &buffer->node;
|
||||
while (true) {
|
||||
struct sway_view *view = scene_descriptor_try_get(current,
|
||||
SWAY_SCENE_DESC_VIEW);
|
||||
if (view) {
|
||||
view_max_render_time = view->max_render_time;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!current->parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
current = ¤t->parent->node;
|
||||
}
|
||||
|
||||
int delay = data->msec_until_refresh - output->max_render_time
|
||||
- view_max_render_time;
|
||||
|
||||
if (output->max_render_time == 0 || view_max_render_time == 0 || delay < 1) {
|
||||
wlr_surface_send_frame_done(surface, &data->when);
|
||||
struct buffer_timer *timer = NULL;
|
||||
|
||||
if (output->max_render_time != 0 && view_max_render_time != 0 && delay > 0) {
|
||||
timer = buffer_timer_get_or_create(buffer);
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
wl_event_source_timer_update(timer->frame_done_timer, delay);
|
||||
} else {
|
||||
struct sway_surface *sway_surface = surface->data;
|
||||
wl_event_source_timer_update(sway_surface->frame_done_timer, delay);
|
||||
wlr_scene_buffer_send_frame_done(buffer, &data->when);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_frame_done(struct sway_output *output, struct send_frame_done_data *data) {
|
||||
output_for_each_surface(output, send_frame_done_iterator, data);
|
||||
static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) {
|
||||
switch (output->scale_filter) {
|
||||
case SCALE_FILTER_LINEAR:
|
||||
return WLR_SCALE_FILTER_BILINEAR;
|
||||
case SCALE_FILTER_NEAREST:
|
||||
return WLR_SCALE_FILTER_NEAREST;
|
||||
default:
|
||||
abort(); // unreachable
|
||||
}
|
||||
}
|
||||
|
||||
static void count_surface_iterator(struct sway_output *output,
|
||||
struct sway_view *view, struct wlr_surface *surface,
|
||||
struct wlr_box *box, void *data) {
|
||||
size_t *n = data;
|
||||
(*n)++;
|
||||
}
|
||||
|
||||
static bool scan_out_fullscreen_view(struct sway_output *output,
|
||||
struct wlr_output_state *pending, struct sway_view *view) {
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
struct sway_workspace *workspace = output->current.active_workspace;
|
||||
if (!sway_assert(workspace, "Expected an active workspace")) {
|
||||
return false;
|
||||
static void output_configure_scene(struct sway_output *output,
|
||||
struct wlr_scene_node *node, float opacity) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.session_lock.locked) {
|
||||
return false;
|
||||
struct sway_container *con =
|
||||
scene_descriptor_try_get(node, SWAY_SCENE_DESC_CONTAINER);
|
||||
if (con) {
|
||||
opacity = con->alpha;
|
||||
}
|
||||
|
||||
if (!wl_list_empty(&view->saved_buffers)) {
|
||||
return false;
|
||||
}
|
||||
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
|
||||
|
||||
for (int i = 0; i < workspace->current.floating->length; ++i) {
|
||||
struct sway_container *floater =
|
||||
workspace->current.floating->items[i];
|
||||
if (container_is_transient_for(floater, view->container)) {
|
||||
return false;
|
||||
// hack: don't call the scene setter because that will damage all outputs
|
||||
// We don't want to damage outputs that aren't our current output that
|
||||
// we're configuring
|
||||
buffer->filter_mode = get_scale_filter(output);
|
||||
|
||||
wlr_scene_buffer_set_opacity(buffer, opacity);
|
||||
} else if (node->type == WLR_SCENE_NODE_TREE) {
|
||||
struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &tree->children, link) {
|
||||
output_configure_scene(output, node, opacity);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
if (!wl_list_empty(&root->xwayland_unmanaged)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!wl_list_empty(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) {
|
||||
return false;
|
||||
}
|
||||
if (!wl_list_empty(&root->drag_icons)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_surface *surface = view->surface;
|
||||
if (surface == NULL) {
|
||||
return false;
|
||||
}
|
||||
size_t n_surfaces = 0;
|
||||
output_view_for_each_surface(output, view,
|
||||
count_surface_iterator, &n_surfaces);
|
||||
if (n_surfaces != 1) {
|
||||
return false;
|
||||
}
|
||||
size_t n_popups = 0;
|
||||
output_view_for_each_popup_surface(output, view,
|
||||
count_surface_iterator, &n_popups);
|
||||
if (n_popups > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (surface->buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((float)surface->current.scale != wlr_output->scale ||
|
||||
surface->current.transform != wlr_output->transform) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wlr_output_is_direct_scanout_allowed(wlr_output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_output_state_set_buffer(pending, &surface->buffer->base);
|
||||
|
||||
if (!wlr_output_test_state(wlr_output, pending)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_presentation_surface_scanned_out_on_output(surface,
|
||||
wlr_output);
|
||||
|
||||
return wlr_output_commit_state(wlr_output, pending);
|
||||
}
|
||||
|
||||
static void get_frame_damage(struct sway_output *output,
|
||||
pixman_region32_t *frame_damage) {
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(wlr_output, &width, &height);
|
||||
|
||||
pixman_region32_init(frame_damage);
|
||||
|
||||
enum wl_output_transform transform =
|
||||
wlr_output_transform_invert(wlr_output->transform);
|
||||
wlr_region_transform(frame_damage, &output->damage_ring.current,
|
||||
transform, width, height);
|
||||
|
||||
if (debug.damage != DAMAGE_DEFAULT) {
|
||||
pixman_region32_union_rect(frame_damage, frame_damage,
|
||||
0, 0, wlr_output->width, wlr_output->height);
|
||||
}
|
||||
}
|
||||
|
||||
static int output_repaint_timer_handler(void *data) {
|
||||
struct sway_output *output = data;
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
if (wlr_output == NULL) {
|
||||
|
||||
if (!output->enabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
wlr_output->frame_pending = false;
|
||||
output->wlr_output->frame_pending = false;
|
||||
|
||||
if (!wlr_output->needs_frame &&
|
||||
!output->gamma_lut_changed &&
|
||||
!pixman_region32_not_empty(&output->damage_ring.current)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sway_workspace *workspace = output->current.active_workspace;
|
||||
if (workspace == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sway_container *fullscreen_con = root->fullscreen_global;
|
||||
if (!fullscreen_con) {
|
||||
fullscreen_con = workspace->current.fullscreen;
|
||||
}
|
||||
|
||||
struct wlr_output_state pending = {0};
|
||||
output_configure_scene(output, &root->root_scene->tree.node, 1.0f);
|
||||
|
||||
if (output->gamma_lut_changed) {
|
||||
struct wlr_output_state pending;
|
||||
wlr_output_state_init(&pending);
|
||||
if (!wlr_scene_output_build_state(output->scene_output, &pending, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
output->gamma_lut_changed = false;
|
||||
struct wlr_gamma_control_v1 *gamma_control =
|
||||
wlr_gamma_control_manager_v1_get_control(
|
||||
server.gamma_control_manager_v1, wlr_output);
|
||||
server.gamma_control_manager_v1, output->wlr_output);
|
||||
if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
|
||||
goto out;
|
||||
}
|
||||
if (!wlr_output_test_state(wlr_output, &pending)) {
|
||||
wlr_output_state_finish(&pending);
|
||||
pending = (struct wlr_output_state){0};
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!wlr_output_commit_state(output->wlr_output, &pending)) {
|
||||
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
|
||||
wlr_output_state_finish(&pending);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wlr_output_state_finish(&pending);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pending.committed |= WLR_OUTPUT_STATE_DAMAGE;
|
||||
get_frame_damage(output, &pending.damage);
|
||||
|
||||
if (fullscreen_con && fullscreen_con->view && !debug.noscanout) {
|
||||
// Try to scan-out the fullscreen view
|
||||
static bool last_scanned_out = false;
|
||||
bool scanned_out =
|
||||
scan_out_fullscreen_view(output, &pending, fullscreen_con->view);
|
||||
|
||||
if (scanned_out && !last_scanned_out) {
|
||||
sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s",
|
||||
output->wlr_output->name);
|
||||
}
|
||||
if (last_scanned_out && !scanned_out) {
|
||||
sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s",
|
||||
output->wlr_output->name);
|
||||
output_damage_whole(output);
|
||||
}
|
||||
last_scanned_out = scanned_out;
|
||||
|
||||
if (scanned_out) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wlr_output_configure_primary_swapchain(wlr_output, &pending, &wlr_output->swapchain)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
int buffer_age;
|
||||
struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age);
|
||||
if (buffer == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(
|
||||
wlr_output->renderer, buffer, NULL);
|
||||
if (render_pass == NULL) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
|
||||
|
||||
if (debug.damage == DAMAGE_RERENDER) {
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(wlr_output, &width, &height);
|
||||
pixman_region32_union_rect(&damage, &damage, 0, 0, width, height);
|
||||
}
|
||||
|
||||
struct render_context ctx = {
|
||||
.output_damage = &damage,
|
||||
.renderer = wlr_output->renderer,
|
||||
.output = output,
|
||||
.pass = render_pass,
|
||||
};
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
output_render(&ctx);
|
||||
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
if (!wlr_render_pass_submit(render_pass)) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wlr_output_state_set_buffer(&pending, buffer);
|
||||
wlr_buffer_unlock(buffer);
|
||||
|
||||
if (!wlr_output_commit_state(wlr_output, &pending)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
wlr_damage_ring_rotate(&output->damage_ring);
|
||||
output->last_frame = now;
|
||||
|
||||
out:
|
||||
wlr_output_state_finish(&pending);
|
||||
wlr_scene_output_commit(output->scene_output, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_damage(struct wl_listener *listener, void *user_data) {
|
||||
struct sway_output *output =
|
||||
wl_container_of(listener, output, damage);
|
||||
struct wlr_output_event_damage *event = user_data;
|
||||
if (wlr_damage_ring_add(&output->damage_ring, event->damage)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_frame(struct wl_listener *listener, void *user_data) {
|
||||
struct sway_output *output =
|
||||
wl_container_of(listener, output, frame);
|
||||
|
@ -754,117 +324,8 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
|
|||
struct send_frame_done_data data = {0};
|
||||
clock_gettime(CLOCK_MONOTONIC, &data.when);
|
||||
data.msec_until_refresh = msec_until_refresh;
|
||||
send_frame_done(output, &data);
|
||||
}
|
||||
|
||||
static void handle_needs_frame(struct wl_listener *listener, void *user_data) {
|
||||
struct sway_output *output =
|
||||
wl_container_of(listener, output, needs_frame);
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
|
||||
void output_damage_whole(struct sway_output *output) {
|
||||
// The output can exist with no wlr_output if it's just been disconnected
|
||||
// and the transaction to evacuate it has't completed yet.
|
||||
if (output != NULL && output->wlr_output != NULL) {
|
||||
wlr_damage_ring_add_whole(&output->damage_ring);
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
static void damage_surface_iterator(struct sway_output *output,
|
||||
struct sway_view *view, struct wlr_surface *surface,
|
||||
struct wlr_box *_box, void *_data) {
|
||||
bool *data = _data;
|
||||
bool whole = *data;
|
||||
|
||||
struct wlr_box box = *_box;
|
||||
scale_box(&box, output->wlr_output->scale);
|
||||
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
wlr_surface_get_effective_damage(surface, &damage);
|
||||
wlr_region_scale(&damage, &damage, output->wlr_output->scale);
|
||||
if (ceilf(output->wlr_output->scale) > surface->current.scale) {
|
||||
// When scaling up a surface, it'll become blurry so we need to
|
||||
// expand the damage region
|
||||
wlr_region_expand(&damage, &damage,
|
||||
ceilf(output->wlr_output->scale) - surface->current.scale);
|
||||
}
|
||||
pixman_region32_translate(&damage, box.x, box.y);
|
||||
if (wlr_damage_ring_add(&output->damage_ring, &damage)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
if (whole) {
|
||||
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wl_list_empty(&surface->current.frame_callback_list)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
void output_damage_surface(struct sway_output *output, double ox, double oy,
|
||||
struct wlr_surface *surface, bool whole) {
|
||||
output_surface_for_each_surface(output, surface, ox, oy,
|
||||
damage_surface_iterator, &whole);
|
||||
}
|
||||
|
||||
void output_damage_from_view(struct sway_output *output,
|
||||
struct sway_view *view) {
|
||||
if (!view_is_visible(view)) {
|
||||
return;
|
||||
}
|
||||
bool whole = false;
|
||||
output_view_for_each_surface(output, view, damage_surface_iterator, &whole);
|
||||
}
|
||||
|
||||
// Expecting an unscaled box in layout coordinates
|
||||
void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
|
||||
struct wlr_box box;
|
||||
memcpy(&box, _box, sizeof(struct wlr_box));
|
||||
box.x -= output->lx;
|
||||
box.y -= output->ly;
|
||||
scale_box(&box, output->wlr_output->scale);
|
||||
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
static void damage_child_views_iterator(struct sway_container *con,
|
||||
void *data) {
|
||||
if (!con->view || !view_is_visible(con->view)) {
|
||||
return;
|
||||
}
|
||||
struct sway_output *output = data;
|
||||
bool whole = true;
|
||||
output_view_for_each_surface(output, con->view, damage_surface_iterator,
|
||||
&whole);
|
||||
}
|
||||
|
||||
void output_damage_whole_container(struct sway_output *output,
|
||||
struct sway_container *con) {
|
||||
// Pad the box by 1px, because the width is a double and might be a fraction
|
||||
struct wlr_box box = {
|
||||
.x = con->current.x - output->lx - 1,
|
||||
.y = con->current.y - output->ly - 1,
|
||||
.width = con->current.width + 2,
|
||||
.height = con->current.height + 2,
|
||||
};
|
||||
scale_box(&box, output->wlr_output->scale);
|
||||
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
// Damage subsurfaces as well, which may extend outside the box
|
||||
if (con->view) {
|
||||
damage_child_views_iterator(con, output);
|
||||
} else {
|
||||
container_for_each_child(con, damage_child_views_iterator, output);
|
||||
}
|
||||
data.output = output;
|
||||
wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
|
||||
}
|
||||
|
||||
static void update_output_manager_config(struct sway_server *server) {
|
||||
|
@ -907,13 +368,11 @@ static void begin_destroy(struct sway_output *output) {
|
|||
wl_list_remove(&output->destroy.link);
|
||||
wl_list_remove(&output->commit.link);
|
||||
wl_list_remove(&output->present.link);
|
||||
wl_list_remove(&output->damage.link);
|
||||
wl_list_remove(&output->frame.link);
|
||||
wl_list_remove(&output->needs_frame.link);
|
||||
wl_list_remove(&output->request_state.link);
|
||||
|
||||
wlr_damage_ring_finish(&output->damage_ring);
|
||||
|
||||
wlr_scene_output_destroy(output->scene_output);
|
||||
output->scene_output = NULL;
|
||||
output->wlr_output->data = NULL;
|
||||
output->wlr_output = NULL;
|
||||
|
||||
|
@ -932,17 +391,6 @@ static void handle_layout_destroy(struct wl_listener *listener, void *data) {
|
|||
begin_destroy(output);
|
||||
}
|
||||
|
||||
static void update_textures(struct sway_container *con, void *data) {
|
||||
container_update_title_textures(con);
|
||||
container_update_marks_textures(con);
|
||||
}
|
||||
|
||||
static void update_output_scale_iterator(struct sway_output *output,
|
||||
struct sway_view *view, struct wlr_surface *surface,
|
||||
struct wlr_box *box, void *user_data) {
|
||||
surface_update_outputs(surface);
|
||||
}
|
||||
|
||||
static void handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_output *output = wl_container_of(listener, output, commit);
|
||||
struct wlr_output_event_commit *event = data;
|
||||
|
@ -951,11 +399,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (event->state->committed & WLR_OUTPUT_STATE_SCALE) {
|
||||
output_for_each_container(output, update_textures, NULL);
|
||||
output_for_each_surface(output, update_output_scale_iterator, NULL);
|
||||
}
|
||||
|
||||
if (event->state->committed & (
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_TRANSFORM |
|
||||
|
@ -967,15 +410,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
update_output_manager_config(output->server);
|
||||
}
|
||||
|
||||
if (event->state->committed & (
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_TRANSFORM)) {
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
|
||||
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
|
||||
// Next time the output is enabled, try to re-apply the gamma LUT
|
||||
if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) {
|
||||
output->gamma_lut_changed = true;
|
||||
|
@ -1039,12 +473,24 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct sway_output *output = output_create(wlr_output);
|
||||
if (!output) {
|
||||
// Create the scene output here so we're not accidentally creating one for
|
||||
// the fallback output
|
||||
struct wlr_scene_output *scene_output =
|
||||
wlr_scene_output_create(root->root_scene, wlr_output);
|
||||
if (!scene_output) {
|
||||
sway_log(SWAY_ERROR, "Failed to create a scene output");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sway_output *output = output_create(wlr_output);
|
||||
if (!output) {
|
||||
sway_log(SWAY_ERROR, "Failed to create a sway output");
|
||||
wlr_scene_output_destroy(scene_output);
|
||||
return;
|
||||
}
|
||||
|
||||
output->server = server;
|
||||
wlr_damage_ring_init(&output->damage_ring);
|
||||
output->scene_output = scene_output;
|
||||
|
||||
wl_signal_add(&root->output_layout->events.destroy, &output->layout_destroy);
|
||||
output->layout_destroy.notify = handle_layout_destroy;
|
||||
|
@ -1054,27 +500,24 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
output->commit.notify = handle_commit;
|
||||
wl_signal_add(&wlr_output->events.present, &output->present);
|
||||
output->present.notify = handle_present;
|
||||
wl_signal_add(&wlr_output->events.damage, &output->damage);
|
||||
output->damage.notify = handle_damage;
|
||||
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||
output->frame.notify = handle_frame;
|
||||
wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame);
|
||||
output->needs_frame.notify = handle_needs_frame;
|
||||
wl_signal_add(&wlr_output->events.request_state, &output->request_state);
|
||||
output->request_state.notify = handle_request_state;
|
||||
|
||||
output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop,
|
||||
output_repaint_timer_handler, output);
|
||||
|
||||
if (server->session_lock.lock) {
|
||||
sway_session_lock_add_output(server->session_lock.lock, output);
|
||||
}
|
||||
|
||||
struct output_config *oc = find_output_config(output);
|
||||
apply_output_config(oc, output);
|
||||
free_output_config(oc);
|
||||
|
||||
transaction_commit_dirty();
|
||||
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
|
||||
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
|
||||
update_output_manager_config(server);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,72 +0,0 @@
|
|||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include "sway/server.h"
|
||||
#include "sway/surface.h"
|
||||
#include "sway/output.h"
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_surface *surface = wl_container_of(listener, surface, destroy);
|
||||
|
||||
surface->wlr_surface->data = NULL;
|
||||
wl_list_remove(&surface->destroy.link);
|
||||
|
||||
if (surface->frame_done_timer) {
|
||||
wl_event_source_remove(surface->frame_done_timer);
|
||||
}
|
||||
|
||||
free(surface);
|
||||
}
|
||||
|
||||
static int surface_frame_done_timer_handler(void *data) {
|
||||
struct sway_surface *surface = data;
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_surface_send_frame_done(surface->wlr_surface, &now);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handle_compositor_new_surface(struct wl_listener *listener, void *data) {
|
||||
struct wlr_surface *wlr_surface = data;
|
||||
|
||||
struct sway_surface *surface = calloc(1, sizeof(struct sway_surface));
|
||||
surface->wlr_surface = wlr_surface;
|
||||
wlr_surface->data = surface;
|
||||
|
||||
surface->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
|
||||
|
||||
surface->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop,
|
||||
surface_frame_done_timer_handler, surface);
|
||||
if (!surface->frame_done_timer) {
|
||||
wl_resource_post_no_memory(wlr_surface->resource);
|
||||
}
|
||||
}
|
||||
|
||||
void surface_update_outputs(struct wlr_surface *surface) {
|
||||
float scale = 1;
|
||||
struct wlr_surface_output *surface_output;
|
||||
wl_list_for_each(surface_output, &surface->current_outputs, link) {
|
||||
if (surface_output->output->scale > scale) {
|
||||
scale = surface_output->output->scale;
|
||||
}
|
||||
}
|
||||
wlr_fractional_scale_v1_notify_scale(surface, scale);
|
||||
wlr_surface_set_preferred_buffer_scale(surface, ceil(scale));
|
||||
}
|
||||
|
||||
void surface_enter_output(struct wlr_surface *surface,
|
||||
struct sway_output *output) {
|
||||
wlr_surface_send_enter(surface, output->wlr_output);
|
||||
surface_update_outputs(surface);
|
||||
}
|
||||
|
||||
void surface_leave_output(struct wlr_surface *surface,
|
||||
struct sway_output *output) {
|
||||
wlr_surface_send_leave(surface, output->wlr_output);
|
||||
surface_update_outputs(surface);
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
#include <time.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
|
@ -214,39 +214,20 @@ static void transaction_add_node(struct sway_transaction *transaction,
|
|||
|
||||
static void apply_output_state(struct sway_output *output,
|
||||
struct sway_output_state *state) {
|
||||
output_damage_whole(output);
|
||||
list_free(output->current.workspaces);
|
||||
memcpy(&output->current, state, sizeof(struct sway_output_state));
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
static void apply_workspace_state(struct sway_workspace *ws,
|
||||
struct sway_workspace_state *state) {
|
||||
output_damage_whole(ws->current.output);
|
||||
list_free(ws->current.floating);
|
||||
list_free(ws->current.tiling);
|
||||
memcpy(&ws->current, state, sizeof(struct sway_workspace_state));
|
||||
output_damage_whole(ws->current.output);
|
||||
}
|
||||
|
||||
static void apply_container_state(struct sway_container *container,
|
||||
struct sway_container_state *state) {
|
||||
struct sway_view *view = container->view;
|
||||
// Damage the old location
|
||||
desktop_damage_whole_container(container);
|
||||
if (view && !wl_list_empty(&view->saved_buffers)) {
|
||||
struct sway_saved_buffer *saved_buf;
|
||||
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
|
||||
struct wlr_box box = {
|
||||
.x = saved_buf->x - view->saved_geometry.x,
|
||||
.y = saved_buf->y - view->saved_geometry.y,
|
||||
.width = saved_buf->width,
|
||||
.height = saved_buf->height,
|
||||
};
|
||||
desktop_damage_box(&box);
|
||||
}
|
||||
}
|
||||
|
||||
// There are separate children lists for each instruction state, the
|
||||
// container's current state and the container's pending state
|
||||
// (ie. con->children). The list itself needs to be freed here.
|
||||
|
@ -256,35 +237,449 @@ static void apply_container_state(struct sway_container *container,
|
|||
|
||||
memcpy(&container->current, state, sizeof(struct sway_container_state));
|
||||
|
||||
if (view && !wl_list_empty(&view->saved_buffers)) {
|
||||
if (!container->node.destroying || container->node.ntxnrefs == 1) {
|
||||
view_remove_saved_buffer(view);
|
||||
if (view) {
|
||||
if (view->saved_surface_tree) {
|
||||
if (!container->node.destroying || container->node.ntxnrefs == 1) {
|
||||
view_remove_saved_buffer(view);
|
||||
}
|
||||
}
|
||||
|
||||
// If the view hasn't responded to the configure, center it within
|
||||
// the container. This is important for fullscreen views which
|
||||
// refuse to resize to the size of the output.
|
||||
if (view->surface) {
|
||||
view_center_and_clip_surface(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_title_bar(struct sway_container *con,
|
||||
int x, int y, int width, int height) {
|
||||
container_update(con);
|
||||
|
||||
bool has_title_bar = height > 0;
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, has_title_bar);
|
||||
if (!has_title_bar) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_position(&con->title_bar.tree->node, x, y);
|
||||
|
||||
con->title_width = width;
|
||||
container_arrange_title_bar(con);
|
||||
}
|
||||
|
||||
static void disable_container(struct sway_container *con) {
|
||||
if (con->view) {
|
||||
wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
|
||||
} else {
|
||||
for (int i = 0; i < con->current.children->length; i++) {
|
||||
struct sway_container *child = con->current.children->items[i];
|
||||
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
|
||||
|
||||
disable_container(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_container(struct sway_container *con,
|
||||
int width, int height, bool title_bar, int gaps);
|
||||
|
||||
static void arrange_children(enum sway_container_layout layout, list_t *children,
|
||||
struct sway_container *active, struct wlr_scene_tree *content,
|
||||
int width, int height, int gaps) {
|
||||
int title_bar_height = container_titlebar_height();
|
||||
|
||||
if (layout == L_TABBED) {
|
||||
struct sway_container *first = children->length == 1 ?
|
||||
((struct sway_container *)children->items[0]) : NULL;
|
||||
if (config->hide_lone_tab && first && first->view &&
|
||||
first->current.border != B_NORMAL) {
|
||||
title_bar_height = 0;
|
||||
}
|
||||
|
||||
double w = (double) width / children->length;
|
||||
int title_offset = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
bool activated = child == active;
|
||||
int next_title_offset = round(w * i + w);
|
||||
|
||||
arrange_title_bar(child, title_offset, -title_bar_height,
|
||||
next_title_offset - title_offset, title_bar_height);
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, activated);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
|
||||
if (activated) {
|
||||
arrange_container(child, width, height - title_bar_height,
|
||||
false, 0);
|
||||
} else {
|
||||
disable_container(child);
|
||||
}
|
||||
|
||||
title_offset = next_title_offset;
|
||||
}
|
||||
} else if (layout == L_STACKED) {
|
||||
struct sway_container *first = children->length == 1 ?
|
||||
((struct sway_container *)children->items[0]) : NULL;
|
||||
if (config->hide_lone_tab && first && first->view &&
|
||||
first->current.border != B_NORMAL) {
|
||||
title_bar_height = 0;
|
||||
}
|
||||
|
||||
int title_height = title_bar_height * children->length;
|
||||
|
||||
int y = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
bool activated = child == active;
|
||||
|
||||
arrange_title_bar(child, 0, y - title_height, width, title_bar_height);
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, activated);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
|
||||
if (activated) {
|
||||
arrange_container(child, width, height - title_height,
|
||||
false, 0);
|
||||
} else {
|
||||
disable_container(child);
|
||||
}
|
||||
|
||||
y += title_bar_height;
|
||||
}
|
||||
} else if (layout == L_VERT) {
|
||||
int off = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
int cheight = child->current.height;
|
||||
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, true);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
arrange_container(child, width, cheight, true, gaps);
|
||||
off += cheight + gaps;
|
||||
}
|
||||
} else if (layout == L_HORIZ) {
|
||||
int off = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
int cwidth = child->current.width;
|
||||
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, true);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
arrange_container(child, cwidth, height, true, gaps);
|
||||
off += cwidth + gaps;
|
||||
}
|
||||
} else {
|
||||
sway_assert(false, "unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_container(struct sway_container *con,
|
||||
int width, int height, bool title_bar, int gaps) {
|
||||
// this container might have previously been in the scratchpad,
|
||||
// make sure it's enabled for viewing
|
||||
wlr_scene_node_set_enabled(&con->scene_tree->node, true);
|
||||
|
||||
if (con->output_handler) {
|
||||
wlr_scene_buffer_set_dest_size(con->output_handler, width, height);
|
||||
}
|
||||
|
||||
if (con->view) {
|
||||
int border_top = container_titlebar_height();
|
||||
int border_width = con->current.border_thickness;
|
||||
|
||||
if (title_bar && con->current.border != B_NORMAL) {
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, false);
|
||||
wlr_scene_node_set_enabled(&con->border.top->node, true);
|
||||
} else {
|
||||
wlr_scene_node_set_enabled(&con->border.top->node, false);
|
||||
}
|
||||
|
||||
if (con->current.border == B_NORMAL) {
|
||||
if (title_bar) {
|
||||
arrange_title_bar(con, 0, 0, width, border_top);
|
||||
} else {
|
||||
border_top = 0;
|
||||
// should be handled by the parent container
|
||||
}
|
||||
} else if (con->current.border == B_PIXEL) {
|
||||
container_update(con);
|
||||
border_top = title_bar && con->current.border_top ? border_width : 0;
|
||||
} else if (con->current.border == B_NONE) {
|
||||
container_update(con);
|
||||
border_top = 0;
|
||||
border_width = 0;
|
||||
} else if (con->current.border == B_CSD) {
|
||||
border_top = 0;
|
||||
border_width = 0;
|
||||
} else {
|
||||
sway_assert(false, "unreachable");
|
||||
}
|
||||
|
||||
int border_bottom = con->current.border_bottom ? border_width : 0;
|
||||
int border_left = con->current.border_left ? border_width : 0;
|
||||
int border_right = con->current.border_right ? border_width : 0;
|
||||
|
||||
wlr_scene_rect_set_size(con->border.top, width, border_top);
|
||||
wlr_scene_rect_set_size(con->border.bottom, width, border_bottom);
|
||||
wlr_scene_rect_set_size(con->border.left,
|
||||
border_left, height - border_top - border_bottom);
|
||||
wlr_scene_rect_set_size(con->border.right,
|
||||
border_right, height - border_top - border_bottom);
|
||||
|
||||
wlr_scene_node_set_position(&con->border.top->node, 0, 0);
|
||||
wlr_scene_node_set_position(&con->border.bottom->node,
|
||||
0, height - border_bottom);
|
||||
wlr_scene_node_set_position(&con->border.left->node,
|
||||
0, border_top);
|
||||
wlr_scene_node_set_position(&con->border.right->node,
|
||||
width - border_right, border_top);
|
||||
|
||||
// make sure to reparent, it's possible that the client just came out of
|
||||
// fullscreen mode where the parent of the surface is not the container
|
||||
wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
|
||||
wlr_scene_node_set_position(&con->view->scene_tree->node,
|
||||
border_left, border_top);
|
||||
} else {
|
||||
// make sure to disable the title bar if the parent is not managing it
|
||||
if (title_bar) {
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, false);
|
||||
}
|
||||
|
||||
arrange_children(con->current.layout, con->current.children,
|
||||
con->current.focused_inactive_child, con->content_tree,
|
||||
width, height, gaps);
|
||||
}
|
||||
}
|
||||
|
||||
static int container_get_gaps(struct sway_container *con) {
|
||||
struct sway_workspace *ws = con->current.workspace;
|
||||
struct sway_container *temp = con;
|
||||
while (temp) {
|
||||
enum sway_container_layout layout;
|
||||
if (temp->current.parent) {
|
||||
layout = temp->current.parent->current.layout;
|
||||
} else {
|
||||
layout = ws->current.layout;
|
||||
}
|
||||
if (layout == L_TABBED || layout == L_STACKED) {
|
||||
return 0;
|
||||
}
|
||||
temp = temp->pending.parent;
|
||||
}
|
||||
return ws->gaps_inner;
|
||||
}
|
||||
|
||||
static void arrange_fullscreen(struct wlr_scene_tree *tree,
|
||||
struct sway_container *fs, struct sway_workspace *ws,
|
||||
int width, int height) {
|
||||
struct wlr_scene_node *fs_node;
|
||||
if (fs->view) {
|
||||
fs_node = &fs->view->scene_tree->node;
|
||||
|
||||
// if we only care about the view, disable any decorations
|
||||
wlr_scene_node_set_enabled(&fs->scene_tree->node, false);
|
||||
} else {
|
||||
fs_node = &fs->scene_tree->node;
|
||||
arrange_container(fs, width, height, true, container_get_gaps(fs));
|
||||
}
|
||||
|
||||
wlr_scene_node_reparent(fs_node, tree);
|
||||
wlr_scene_node_lower_to_bottom(fs_node);
|
||||
wlr_scene_node_set_position(fs_node, 0, 0);
|
||||
}
|
||||
|
||||
static void arrange_workspace_floating(struct sway_workspace *ws) {
|
||||
for (int i = 0; i < ws->current.floating->length; i++) {
|
||||
struct sway_container *floater = ws->current.floating->items[i];
|
||||
struct wlr_scene_tree *layer = root->layers.floating;
|
||||
|
||||
if (floater->current.fullscreen_mode != FULLSCREEN_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (root->fullscreen_global) {
|
||||
if (container_is_transient_for(floater, root->fullscreen_global)) {
|
||||
layer = root->layers.fullscreen_global;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < root->outputs->length; i++) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
struct sway_workspace *active = output->current.active_workspace;
|
||||
|
||||
if (active && active->fullscreen &&
|
||||
container_is_transient_for(floater, active->fullscreen)) {
|
||||
layer = root->layers.fullscreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_scene_node_reparent(&floater->scene_tree->node, layer);
|
||||
wlr_scene_node_set_position(&floater->scene_tree->node,
|
||||
floater->current.x, floater->current.y);
|
||||
wlr_scene_node_set_enabled(&floater->scene_tree->node, true);
|
||||
|
||||
arrange_container(floater, floater->current.width, floater->current.height,
|
||||
true, ws->gaps_inner);
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_workspace_tiling(struct sway_workspace *ws,
|
||||
int width, int height) {
|
||||
arrange_children(ws->current.layout, ws->current.tiling,
|
||||
ws->current.focused_inactive_child, ws->layers.tiling,
|
||||
width, height, ws->gaps_inner);
|
||||
}
|
||||
|
||||
static void disable_workspace(struct sway_workspace *ws) {
|
||||
// if any containers were just moved to a disabled workspace it will
|
||||
// have the parent of the old workspace. Move the workspace so that it won't
|
||||
// be shown.
|
||||
for (int i = 0; i < ws->current.tiling->length; i++) {
|
||||
struct sway_container *child = ws->current.tiling->items[i];
|
||||
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, ws->layers.tiling);
|
||||
disable_container(child);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ws->current.floating->length; i++) {
|
||||
struct sway_container *floater = ws->current.floating->items[i];
|
||||
wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating);
|
||||
disable_container(floater);
|
||||
wlr_scene_node_set_enabled(&floater->scene_tree->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_output(struct sway_output *output, int width, int height) {
|
||||
for (int i = 0; i < output->current.workspaces->length; i++) {
|
||||
struct sway_workspace *child = output->current.workspaces->items[i];
|
||||
|
||||
bool activated = output->current.active_workspace == child;
|
||||
|
||||
wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
|
||||
wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
|
||||
|
||||
for (int i = 0; i < child->current.floating->length; i++) {
|
||||
struct sway_container *floater = child->current.floating->items[i];
|
||||
wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating);
|
||||
wlr_scene_node_set_enabled(&floater->scene_tree->node, activated);
|
||||
}
|
||||
|
||||
if (activated) {
|
||||
struct sway_container *fs = child->current.fullscreen;
|
||||
wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs);
|
||||
wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs);
|
||||
|
||||
arrange_workspace_floating(child);
|
||||
|
||||
wlr_scene_node_set_enabled(&output->layers.shell_background->node, !fs);
|
||||
wlr_scene_node_set_enabled(&output->layers.shell_bottom->node, !fs);
|
||||
wlr_scene_node_set_enabled(&output->layers.fullscreen->node, fs);
|
||||
|
||||
if (fs) {
|
||||
wlr_scene_rect_set_size(output->fullscreen_background, width, height);
|
||||
|
||||
arrange_fullscreen(child->layers.fullscreen, fs, child,
|
||||
width, height);
|
||||
} else {
|
||||
struct wlr_box *area = &output->usable_area;
|
||||
struct side_gaps *gaps = &child->current_gaps;
|
||||
|
||||
wlr_scene_node_set_position(&child->layers.tiling->node,
|
||||
gaps->left + area->x, gaps->top + area->y);
|
||||
|
||||
arrange_workspace_tiling(child,
|
||||
area->width - gaps->left - gaps->right,
|
||||
area->height - gaps->top - gaps->bottom);
|
||||
}
|
||||
} else {
|
||||
wlr_scene_node_set_enabled(&child->layers.tiling->node, false);
|
||||
wlr_scene_node_set_enabled(&child->layers.fullscreen->node, false);
|
||||
|
||||
disable_workspace(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_popup(struct wlr_scene_tree *popup) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &popup->children, link) {
|
||||
struct sway_xdg_popup *popup = scene_descriptor_try_get(node,
|
||||
SWAY_SCENE_DESC_POPUP);
|
||||
|
||||
// the popup layer may have popups from layer_shell surfaces, in this
|
||||
// case those don't have a scene descriptor, so lets skip those here.
|
||||
if (popup) {
|
||||
struct wlr_scene_tree *tree = popup->view->content_tree;
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(&tree->node, &lx, &ly);
|
||||
wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_root(struct sway_root *root) {
|
||||
struct sway_container *fs = root->fullscreen_global;
|
||||
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_background->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_bottom->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.tiling->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.floating->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_top->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.fullscreen->node, !fs);
|
||||
|
||||
// hide all contents in the scratchpad
|
||||
for (int i = 0; i < root->scratchpad->length; i++) {
|
||||
struct sway_container *con = root->scratchpad->items[i];
|
||||
|
||||
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
||||
}
|
||||
|
||||
if (fs) {
|
||||
for (int i = 0; i < root->outputs->length; i++) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
struct sway_workspace *ws = output->current.active_workspace;
|
||||
|
||||
if (ws) {
|
||||
arrange_workspace_floating(ws);
|
||||
}
|
||||
}
|
||||
|
||||
arrange_fullscreen(root->layers.fullscreen_global, fs, NULL,
|
||||
root->width, root->height);
|
||||
} else {
|
||||
for (int i = 0; i < root->outputs->length; i++) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
|
||||
wlr_scene_output_set_position(output->scene_output, output->lx, output->ly);
|
||||
|
||||
wlr_scene_node_reparent(&output->layers.shell_background->node, root->layers.shell_background);
|
||||
wlr_scene_node_reparent(&output->layers.shell_bottom->node, root->layers.shell_bottom);
|
||||
wlr_scene_node_reparent(&output->layers.tiling->node, root->layers.tiling);
|
||||
wlr_scene_node_reparent(&output->layers.shell_top->node, root->layers.shell_top);
|
||||
wlr_scene_node_reparent(&output->layers.shell_overlay->node, root->layers.shell_overlay);
|
||||
wlr_scene_node_reparent(&output->layers.fullscreen->node, root->layers.fullscreen);
|
||||
wlr_scene_node_reparent(&output->layers.session_lock->node, root->layers.session_lock);
|
||||
|
||||
wlr_scene_node_set_position(&output->layers.shell_background->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.shell_bottom->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.tiling->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.fullscreen->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.shell_top->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.shell_overlay->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.session_lock->node, output->lx, output->ly);
|
||||
|
||||
arrange_output(output, output->width, output->height);
|
||||
}
|
||||
}
|
||||
|
||||
// If the view hasn't responded to the configure, center it within
|
||||
// the container. This is important for fullscreen views which
|
||||
// refuse to resize to the size of the output.
|
||||
if (view && view->surface) {
|
||||
view_center_surface(view);
|
||||
}
|
||||
|
||||
// Damage the new location
|
||||
desktop_damage_whole_container(container);
|
||||
if (view && view->surface) {
|
||||
struct wlr_surface *surface = view->surface;
|
||||
struct wlr_box box = {
|
||||
.x = container->current.content_x - view->geometry.x,
|
||||
.y = container->current.content_y - view->geometry.y,
|
||||
.width = surface->current.width,
|
||||
.height = surface->current.height,
|
||||
};
|
||||
desktop_damage_box(&box);
|
||||
}
|
||||
|
||||
if (!container->node.destroying) {
|
||||
container_discover_outputs(container);
|
||||
}
|
||||
arrange_popup(root->layers.popup);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,8 +721,6 @@ static void transaction_apply(struct sway_transaction *transaction) {
|
|||
|
||||
node->instruction = NULL;
|
||||
}
|
||||
|
||||
cursor_rebase_all();
|
||||
}
|
||||
|
||||
static void transaction_commit_pending(void);
|
||||
|
@ -340,6 +733,8 @@ static void transaction_progress(void) {
|
|||
return;
|
||||
}
|
||||
transaction_apply(server.queued_transaction);
|
||||
arrange_root(root);
|
||||
cursor_rebase_all();
|
||||
transaction_destroy(server.queued_transaction);
|
||||
server.queued_transaction = NULL;
|
||||
|
||||
|
@ -415,21 +810,11 @@ static void transaction_commit(struct sway_transaction *transaction) {
|
|||
++transaction->num_waiting;
|
||||
}
|
||||
|
||||
// From here on we are rendering a saved buffer of the view, which
|
||||
// means we can send a frame done event to make the client redraw it
|
||||
// as soon as possible. Additionally, this is required if a view is
|
||||
// mapping and its default geometry doesn't intersect an output.
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_surface_send_frame_done(
|
||||
node->sway_container->view->surface, &now);
|
||||
view_send_frame_done(node->sway_container->view);
|
||||
}
|
||||
if (!hidden && node_is_view(node) &&
|
||||
wl_list_empty(&node->sway_container->view->saved_buffers)) {
|
||||
!node->sway_container->view->saved_surface_tree) {
|
||||
view_save_buffer(node->sway_container->view);
|
||||
memcpy(&node->sway_container->view->saved_geometry,
|
||||
&node->sway_container->view->geometry,
|
||||
sizeof(struct wlr_box));
|
||||
}
|
||||
node->instruction = instruction;
|
||||
}
|
||||
|
@ -499,16 +884,18 @@ static void set_instruction_ready(
|
|||
transaction_progress();
|
||||
}
|
||||
|
||||
void transaction_notify_view_ready_by_serial(struct sway_view *view,
|
||||
bool transaction_notify_view_ready_by_serial(struct sway_view *view,
|
||||
uint32_t serial) {
|
||||
struct sway_transaction_instruction *instruction =
|
||||
view->container->node.instruction;
|
||||
if (instruction != NULL && instruction->serial == serial) {
|
||||
set_instruction_ready(instruction);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void transaction_notify_view_ready_by_geometry(struct sway_view *view,
|
||||
bool transaction_notify_view_ready_by_geometry(struct sway_view *view,
|
||||
double x, double y, int width, int height) {
|
||||
struct sway_transaction_instruction *instruction =
|
||||
view->container->node.instruction;
|
||||
|
@ -518,7 +905,9 @@ void transaction_notify_view_ready_by_geometry(struct sway_view *view,
|
|||
instruction->container_state.content_width == width &&
|
||||
instruction->container_state.content_height == height) {
|
||||
set_instruction_ready(instruction);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _transaction_commit_dirty(bool server_request) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <wlr/util/edges.h>
|
||||
#include "log.h"
|
||||
#include "sway/decoration.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
|
@ -19,41 +19,29 @@
|
|||
#include "sway/tree/workspace.h"
|
||||
#include "sway/xdg_decoration.h"
|
||||
|
||||
static const struct sway_view_child_impl popup_impl;
|
||||
static struct sway_xdg_popup *popup_create(
|
||||
struct wlr_xdg_popup *wlr_popup, struct sway_view *view,
|
||||
struct wlr_scene_tree *parent);
|
||||
|
||||
static void popup_get_view_coords(struct sway_view_child *child,
|
||||
int *sx, int *sy) {
|
||||
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
|
||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
|
||||
|
||||
wlr_xdg_popup_get_toplevel_coords(wlr_popup,
|
||||
wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x,
|
||||
wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y,
|
||||
sx, sy);
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_popup *popup =
|
||||
wl_container_of(listener, popup, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
popup_create(wlr_popup, popup->view, popup->xdg_surface_tree);
|
||||
}
|
||||
|
||||
static void popup_destroy(struct sway_view_child *child) {
|
||||
if (!sway_assert(child->impl == &popup_impl,
|
||||
"Expected an xdg_shell popup")) {
|
||||
return;
|
||||
}
|
||||
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
|
||||
wl_list_remove(&popup->surface_commit.link);
|
||||
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->surface_commit.link);
|
||||
wlr_scene_node_destroy(&popup->scene_tree->node);
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static const struct sway_view_child_impl popup_impl = {
|
||||
.get_view_coords = popup_get_view_coords,
|
||||
.destroy = popup_destroy,
|
||||
};
|
||||
|
||||
static struct sway_xdg_popup *popup_create(
|
||||
struct wlr_xdg_popup *wlr_popup, struct sway_view *view);
|
||||
|
||||
static void popup_unconstrain(struct sway_xdg_popup *popup) {
|
||||
struct sway_view *view = popup->child.view;
|
||||
struct sway_view *view = popup->view;
|
||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
|
||||
|
||||
struct sway_workspace *workspace = view->container->pending.workspace;
|
||||
|
@ -83,29 +71,44 @@ static void popup_handle_surface_commit(struct wl_listener *listener, void *data
|
|||
}
|
||||
}
|
||||
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_popup *popup =
|
||||
wl_container_of(listener, popup, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
popup_create(wlr_popup, popup->child.view);
|
||||
}
|
||||
|
||||
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
view_child_destroy(&popup->child);
|
||||
}
|
||||
|
||||
static struct sway_xdg_popup *popup_create(
|
||||
struct wlr_xdg_popup *wlr_popup, struct sway_view *view) {
|
||||
static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
|
||||
struct sway_view *view, struct wlr_scene_tree *parent) {
|
||||
struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
|
||||
|
||||
struct sway_xdg_popup *popup =
|
||||
calloc(1, sizeof(struct sway_xdg_popup));
|
||||
if (popup == NULL) {
|
||||
struct sway_xdg_popup *popup = calloc(1, sizeof(struct sway_xdg_popup));
|
||||
if (!popup) {
|
||||
return NULL;
|
||||
}
|
||||
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
|
||||
|
||||
popup->wlr_xdg_popup = wlr_popup;
|
||||
popup->view = view;
|
||||
|
||||
popup->scene_tree = wlr_scene_tree_create(parent);
|
||||
if (!popup->scene_tree) {
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
popup->xdg_surface_tree = wlr_scene_xdg_surface_create(
|
||||
popup->scene_tree, xdg_surface);
|
||||
if (!popup->xdg_surface_tree) {
|
||||
wlr_scene_node_destroy(&popup->scene_tree->node);
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!scene_descriptor_assign(&popup->scene_tree->node,
|
||||
SWAY_SCENE_DESC_POPUP, popup)) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor");
|
||||
wlr_scene_node_destroy(&popup->scene_tree->node);
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
popup->wlr_xdg_popup = xdg_surface->popup;
|
||||
struct sway_xdg_shell_view *shell_view =
|
||||
wl_container_of(view, shell_view, view);
|
||||
xdg_surface->data = shell_view;
|
||||
|
||||
wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit);
|
||||
popup->surface_commit.notify = popup_handle_surface_commit;
|
||||
|
@ -114,9 +117,6 @@ static struct sway_xdg_popup *popup_create(
|
|||
wl_signal_add(&wlr_popup->events.destroy, &popup->destroy);
|
||||
popup->destroy.notify = popup_handle_destroy;
|
||||
|
||||
wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map);
|
||||
wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
|
@ -214,24 +214,6 @@ static bool wants_floating(struct sway_view *view) {
|
|||
|| toplevel->parent;
|
||||
}
|
||||
|
||||
static void for_each_surface(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data) {
|
||||
if (xdg_shell_view_from_view(view) == NULL) {
|
||||
return;
|
||||
}
|
||||
wlr_xdg_surface_for_each_surface(view->wlr_xdg_toplevel->base, iterator,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void for_each_popup_surface(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data) {
|
||||
if (xdg_shell_view_from_view(view) == NULL) {
|
||||
return;
|
||||
}
|
||||
wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_toplevel->base,
|
||||
iterator, user_data);
|
||||
}
|
||||
|
||||
static bool is_transient_for(struct sway_view *child,
|
||||
struct sway_view *ancestor) {
|
||||
if (xdg_shell_view_from_view(child) == NULL) {
|
||||
|
@ -279,8 +261,6 @@ static const struct sway_view_impl view_impl = {
|
|||
.set_fullscreen = set_fullscreen,
|
||||
.set_resizing = set_resizing,
|
||||
.wants_floating = wants_floating,
|
||||
.for_each_surface = for_each_surface,
|
||||
.for_each_popup_surface = for_each_popup_surface,
|
||||
.is_transient_for = is_transient_for,
|
||||
.close = _close,
|
||||
.close_popups = close_popups,
|
||||
|
@ -317,7 +297,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
// The client changed its surface size in this commit. For floating
|
||||
// containers, we resize the container to match. For tiling containers,
|
||||
// we only recenter the surface.
|
||||
desktop_damage_view(view);
|
||||
memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
|
||||
if (container_is_floating(view->container)) {
|
||||
view_update_size(view);
|
||||
|
@ -327,18 +306,23 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
view->geometry.height);
|
||||
}
|
||||
transaction_commit_dirty_client();
|
||||
} else {
|
||||
view_center_surface(view);
|
||||
}
|
||||
desktop_damage_view(view);
|
||||
|
||||
view_center_and_clip_surface(view);
|
||||
}
|
||||
|
||||
if (view->container->node.instruction) {
|
||||
transaction_notify_view_ready_by_serial(view,
|
||||
bool successful = transaction_notify_view_ready_by_serial(view,
|
||||
xdg_surface->current.configure_serial);
|
||||
}
|
||||
|
||||
view_damage_from(view);
|
||||
// If we saved the view and this commit isn't what we're looking for
|
||||
// that means the user will never actually see the buffers submitted to
|
||||
// us here. Just send frame done events to these surfaces so they can
|
||||
// commit another time for us.
|
||||
if (view->saved_surface_tree && !successful) {
|
||||
view_send_frame_done(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_set_title(struct wl_listener *listener, void *data) {
|
||||
|
@ -360,7 +344,16 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
|
|||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
wl_container_of(listener, xdg_shell_view, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
popup_create(wlr_popup, &xdg_shell_view->view);
|
||||
|
||||
struct sway_xdg_popup *popup = popup_create(wlr_popup,
|
||||
&xdg_shell_view->view, root->layers.popup);
|
||||
if (!popup) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(&popup->view->content_tree->node, &lx, &ly);
|
||||
wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly);
|
||||
}
|
||||
|
||||
static void handle_request_maximize(struct wl_listener *listener, void *data) {
|
||||
|
@ -548,7 +541,10 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
|
||||
if (!view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl)) {
|
||||
free(xdg_shell_view);
|
||||
return;
|
||||
}
|
||||
xdg_shell_view->view.wlr_xdg_toplevel = xdg_toplevel;
|
||||
|
||||
xdg_shell_view->map.notify = handle_map;
|
||||
|
@ -564,5 +560,7 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
|
|||
xdg_shell_view->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy);
|
||||
|
||||
wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base);
|
||||
|
||||
xdg_toplevel->base->data = xdg_shell_view;
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_xdg_activation_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include "log.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/server.h"
|
||||
|
@ -45,29 +46,12 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener,
|
|||
ev->width, ev->height);
|
||||
}
|
||||
|
||||
static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_unmanaged *surface =
|
||||
wl_container_of(listener, surface, commit);
|
||||
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
|
||||
|
||||
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
|
||||
false);
|
||||
}
|
||||
|
||||
static void unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_unmanaged *surface =
|
||||
wl_container_of(listener, surface, set_geometry);
|
||||
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
|
||||
|
||||
if (xsurface->x != surface->lx || xsurface->y != surface->ly) {
|
||||
// Surface has moved
|
||||
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
|
||||
true);
|
||||
surface->lx = xsurface->x;
|
||||
surface->ly = xsurface->y;
|
||||
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
|
||||
true);
|
||||
}
|
||||
wlr_scene_node_set_position(&surface->surface_scene->buffer->node, xsurface->x, xsurface->y);
|
||||
}
|
||||
|
||||
static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
|
||||
|
@ -75,17 +59,18 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
|
|||
wl_container_of(listener, surface, map);
|
||||
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
|
||||
|
||||
wl_list_insert(root->xwayland_unmanaged.prev, &surface->link);
|
||||
surface->surface_scene = wlr_scene_surface_create(root->layers.unmanaged,
|
||||
xsurface->surface);
|
||||
|
||||
wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry);
|
||||
surface->set_geometry.notify = unmanaged_handle_set_geometry;
|
||||
if (surface->surface_scene) {
|
||||
scene_descriptor_assign(&surface->surface_scene->buffer->node,
|
||||
SWAY_SCENE_DESC_XWAYLAND_UNMANAGED, surface);
|
||||
wlr_scene_node_set_position(&surface->surface_scene->buffer->node,
|
||||
xsurface->x, xsurface->y);
|
||||
|
||||
wl_signal_add(&xsurface->surface->events.commit, &surface->commit);
|
||||
surface->commit.notify = unmanaged_handle_commit;
|
||||
|
||||
surface->lx = xsurface->x;
|
||||
surface->ly = xsurface->y;
|
||||
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
|
||||
wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry);
|
||||
surface->set_geometry.notify = unmanaged_handle_set_geometry;
|
||||
}
|
||||
|
||||
if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
|
||||
struct sway_seat *seat = input_manager_current_seat();
|
||||
|
@ -99,10 +84,13 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
|
|||
struct sway_xwayland_unmanaged *surface =
|
||||
wl_container_of(listener, surface, unmap);
|
||||
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
|
||||
desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
|
||||
wl_list_remove(&surface->link);
|
||||
wl_list_remove(&surface->set_geometry.link);
|
||||
wl_list_remove(&surface->commit.link);
|
||||
|
||||
if (surface->surface_scene) {
|
||||
wl_list_remove(&surface->set_geometry.link);
|
||||
|
||||
wlr_scene_node_destroy(&surface->surface_scene->buffer->node);
|
||||
surface->surface_scene = NULL;
|
||||
}
|
||||
|
||||
struct sway_seat *seat = input_manager_current_seat();
|
||||
if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) {
|
||||
|
@ -426,17 +414,6 @@ static const struct sway_view_impl view_impl = {
|
|||
.destroy = destroy,
|
||||
};
|
||||
|
||||
static void get_geometry(struct sway_view *view, struct wlr_box *box) {
|
||||
box->x = box->y = 0;
|
||||
if (view->surface) {
|
||||
box->width = view->surface->current.width;
|
||||
box->height = view->surface->current.height;
|
||||
} else {
|
||||
box->width = 0;
|
||||
box->height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, commit);
|
||||
|
@ -444,34 +421,38 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
|
||||
struct wlr_surface_state *state = &xsurface->surface->current;
|
||||
|
||||
struct wlr_box new_geo;
|
||||
get_geometry(view, &new_geo);
|
||||
struct wlr_box new_geo = {0};
|
||||
new_geo.width = state->width;
|
||||
new_geo.height = state->height;
|
||||
|
||||
bool new_size = new_geo.width != view->geometry.width ||
|
||||
new_geo.height != view->geometry.height ||
|
||||
new_geo.x != view->geometry.x ||
|
||||
new_geo.y != view->geometry.y;
|
||||
new_geo.height != view->geometry.height;
|
||||
|
||||
if (new_size) {
|
||||
// The client changed its surface size in this commit. For floating
|
||||
// containers, we resize the container to match. For tiling containers,
|
||||
// we only recenter the surface.
|
||||
desktop_damage_view(view);
|
||||
memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
|
||||
if (container_is_floating(view->container)) {
|
||||
view_update_size(view);
|
||||
transaction_commit_dirty_client();
|
||||
} else {
|
||||
view_center_surface(view);
|
||||
}
|
||||
desktop_damage_view(view);
|
||||
|
||||
view_center_and_clip_surface(view);
|
||||
}
|
||||
|
||||
if (view->container->node.instruction) {
|
||||
transaction_notify_view_ready_by_geometry(view,
|
||||
bool successful = transaction_notify_view_ready_by_geometry(view,
|
||||
xsurface->x, xsurface->y, state->width, state->height);
|
||||
}
|
||||
|
||||
view_damage_from(view);
|
||||
// If we saved the view and this commit isn't what we're looking for
|
||||
// that means the user will never actually see the buffers submitted to
|
||||
// us here. Just send frame done events to these surfaces so they can
|
||||
// commit another time for us.
|
||||
if (view->saved_surface_tree && !successful) {
|
||||
view_send_frame_done(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
|
@ -515,9 +496,21 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
view_unmap(view);
|
||||
|
||||
wl_list_remove(&xwayland_view->commit.link);
|
||||
wl_list_remove(&xwayland_view->surface_tree_destroy.link);
|
||||
|
||||
if (xwayland_view->surface_tree) {
|
||||
wlr_scene_node_destroy(&xwayland_view->surface_tree->node);
|
||||
xwayland_view->surface_tree = NULL;
|
||||
}
|
||||
|
||||
view_unmap(view);
|
||||
}
|
||||
|
||||
static void handle_surface_tree_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view,
|
||||
surface_tree_destroy);
|
||||
xwayland_view->surface_tree = NULL;
|
||||
}
|
||||
|
||||
static void handle_map(struct wl_listener *listener, void *data) {
|
||||
|
@ -537,6 +530,15 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
|||
// Put it back into the tree
|
||||
view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false);
|
||||
|
||||
xwayland_view->surface_tree = wlr_scene_subsurface_tree_create(
|
||||
xwayland_view->view.content_tree, xsurface->surface);
|
||||
|
||||
if (xwayland_view->surface_tree) {
|
||||
xwayland_view->surface_tree_destroy.notify = handle_surface_tree_destroy;
|
||||
wl_signal_add(&xwayland_view->surface_tree->node.events.destroy,
|
||||
&xwayland_view->surface_tree_destroy);
|
||||
}
|
||||
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
|
@ -796,7 +798,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu
|
|||
return NULL;
|
||||
}
|
||||
|
||||
view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
|
||||
if (!view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl)) {
|
||||
free(xwayland_view);
|
||||
return NULL;
|
||||
}
|
||||
xwayland_view->view.wlr_xwayland_surface = xsurface;
|
||||
|
||||
wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
#include "sway/input/tablet.h"
|
||||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
@ -37,43 +37,6 @@ static uint32_t get_current_time_msec(void) {
|
|||
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
static struct wlr_surface *layer_surface_at(struct sway_output *output,
|
||||
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
|
||||
struct sway_layer_surface *sway_layer;
|
||||
wl_list_for_each_reverse(sway_layer, layer, link) {
|
||||
double _sx = ox - sway_layer->geo.x;
|
||||
double _sy = oy - sway_layer->geo.y;
|
||||
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
|
||||
sway_layer->layer_surface, _sx, _sy, sx, sy);
|
||||
if (sub) {
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool surface_is_xdg_popup(struct wlr_surface *surface) {
|
||||
struct wlr_xdg_surface *xdg_surface =
|
||||
wlr_xdg_surface_try_from_wlr_surface(surface);
|
||||
return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP &&
|
||||
xdg_surface->popup != NULL;
|
||||
}
|
||||
|
||||
static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
|
||||
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
|
||||
struct sway_layer_surface *sway_layer;
|
||||
wl_list_for_each_reverse(sway_layer, layer, link) {
|
||||
double _sx = ox - sway_layer->geo.x;
|
||||
double _sy = oy - sway_layer->geo.y;
|
||||
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
|
||||
sway_layer->layer_surface, _sx, _sy, sx, sy);
|
||||
if (sub && surface_is_xdg_popup(sub)) {
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node at the cursor's position. If there is a surface at that
|
||||
* location, it is stored in **surface (it may not be a view).
|
||||
|
@ -81,137 +44,101 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
|
|||
struct sway_node *node_at_coords(
|
||||
struct sway_seat *seat, double lx, double ly,
|
||||
struct wlr_surface **surface, double *sx, double *sy) {
|
||||
// find the output the cursor is on
|
||||
struct wlr_scene_node *scene_node = NULL;
|
||||
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each_reverse(node, &root->layer_tree->children, link) {
|
||||
struct wlr_scene_tree *layer = wlr_scene_tree_from_node(node);
|
||||
|
||||
bool non_interactive = scene_descriptor_try_get(&layer->node,
|
||||
SWAY_SCENE_DESC_NON_INTERACTIVE);
|
||||
if (non_interactive) {
|
||||
continue;
|
||||
}
|
||||
|
||||
scene_node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy);
|
||||
if (scene_node) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (scene_node) {
|
||||
// determine what wlr_surface we clicked on
|
||||
if (scene_node->type == WLR_SCENE_NODE_BUFFER) {
|
||||
struct wlr_scene_buffer *scene_buffer =
|
||||
wlr_scene_buffer_from_node(scene_node);
|
||||
struct wlr_scene_surface *scene_surface =
|
||||
wlr_scene_surface_try_from_buffer(scene_buffer);
|
||||
|
||||
if (scene_surface) {
|
||||
*surface = scene_surface->surface;
|
||||
}
|
||||
}
|
||||
|
||||
// determine what container we clicked on
|
||||
struct wlr_scene_node *current = scene_node;
|
||||
while (true) {
|
||||
struct sway_container *con = scene_descriptor_try_get(current,
|
||||
SWAY_SCENE_DESC_CONTAINER);
|
||||
|
||||
if (!con) {
|
||||
struct sway_view *view = scene_descriptor_try_get(current,
|
||||
SWAY_SCENE_DESC_VIEW);
|
||||
if (view) {
|
||||
con = view->container;
|
||||
}
|
||||
}
|
||||
|
||||
if (!con) {
|
||||
struct sway_xdg_popup *popup =
|
||||
scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP);
|
||||
if (popup) {
|
||||
con = popup->view->container;
|
||||
}
|
||||
}
|
||||
|
||||
if (con && (!con->view || con->view->surface)) {
|
||||
return &con->node;
|
||||
}
|
||||
|
||||
if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) {
|
||||
// We don't want to feed through the current workspace on
|
||||
// layer shells
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!current->parent) {
|
||||
break;
|
||||
}
|
||||
|
||||
current = ¤t->parent->node;
|
||||
}
|
||||
}
|
||||
|
||||
// if we aren't on a container, determine what workspace we are on
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
root->output_layout, lx, ly);
|
||||
if (wlr_output == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_output *output = wlr_output->data;
|
||||
if (!output || !output->enabled) {
|
||||
// output is being destroyed or is being enabled
|
||||
return NULL;
|
||||
}
|
||||
double ox = lx, oy = ly;
|
||||
wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
|
||||
|
||||
if (server.session_lock.locked) {
|
||||
if (server.session_lock.lock == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_session_lock_surface_v1 *lock_surf;
|
||||
wl_list_for_each(lock_surf, &server.session_lock.lock->surfaces, link) {
|
||||
if (lock_surf->output != wlr_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*surface = wlr_surface_surface_at(lock_surf->surface, ox, oy, sx, sy);
|
||||
if (*surface != NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// layer surfaces on the overlay layer are rendered on top
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check for unmanaged views
|
||||
#if HAVE_XWAYLAND
|
||||
struct wl_list *unmanaged = &root->xwayland_unmanaged;
|
||||
struct sway_xwayland_unmanaged *unmanaged_surface;
|
||||
wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
|
||||
struct wlr_xwayland_surface *xsurface =
|
||||
unmanaged_surface->wlr_xwayland_surface;
|
||||
|
||||
double _sx = lx - unmanaged_surface->lx;
|
||||
double _sy = ly - unmanaged_surface->ly;
|
||||
if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) {
|
||||
*surface = xsurface->surface;
|
||||
*sx = _sx;
|
||||
*sy = _sy;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (root->fullscreen_global) {
|
||||
// Try fullscreen container
|
||||
struct sway_container *con = tiling_container_at(
|
||||
&root->fullscreen_global->node, lx, ly, surface, sx, sy);
|
||||
if (con) {
|
||||
return &con->node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find the focused workspace on the output for this seat
|
||||
struct sway_workspace *ws = output_get_active_workspace(output);
|
||||
if (!ws) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ws->fullscreen) {
|
||||
// Try transient containers
|
||||
for (int i = 0; i < ws->floating->length; ++i) {
|
||||
struct sway_container *floater = ws->floating->items[i];
|
||||
if (container_is_transient_for(floater, ws->fullscreen)) {
|
||||
struct sway_container *con = tiling_container_at(
|
||||
&floater->node, lx, ly, surface, sx, sy);
|
||||
if (con) {
|
||||
return &con->node;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try fullscreen container
|
||||
struct sway_container *con =
|
||||
tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy);
|
||||
if (con) {
|
||||
return &con->node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if ((*surface = layer_surface_popup_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
if ((*surface = layer_surface_popup_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
if ((*surface = layer_surface_popup_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *c;
|
||||
if ((c = container_at(ws, lx, ly, surface, sx, sy))) {
|
||||
return &c->node;
|
||||
}
|
||||
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &ws->node;
|
||||
}
|
||||
|
||||
|
@ -543,12 +470,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
|
|||
if (seat->touch_id == event->touch_id) {
|
||||
seat->touch_x = lx;
|
||||
seat->touch_y = ly;
|
||||
struct sway_drag_icon *drag_icon;
|
||||
wl_list_for_each(drag_icon, &root->drag_icons, link) {
|
||||
if (drag_icon->seat == seat) {
|
||||
drag_icon_update_position(drag_icon);
|
||||
}
|
||||
}
|
||||
|
||||
drag_icons_update_position(seat);
|
||||
}
|
||||
|
||||
if (cursor->simulating_pointer_from_touch) {
|
||||
|
|
|
@ -405,7 +405,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
|||
char *device_identifier = input_device_get_identifier(wlr_device);
|
||||
bool exact_identifier = keyboard->wlr->group != NULL;
|
||||
seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
|
||||
bool locked = server.session_lock.locked;
|
||||
bool locked = server.session_lock.lock;
|
||||
struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
|
||||
keyboard_shortcuts_inhibitor_get_for_focused_surface(seat);
|
||||
bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
|
@ -92,6 +92,7 @@ void seat_destroy(struct sway_seat *seat) {
|
|||
for (int i = 0; i < seat->deferred_bindings->length; i++) {
|
||||
free_sway_binding(seat->deferred_bindings->items[i]);
|
||||
}
|
||||
wlr_scene_node_destroy(&seat->scene_tree->node);
|
||||
list_free(seat->deferred_bindings);
|
||||
free(seat->prev_workspace_name);
|
||||
free(seat);
|
||||
|
@ -353,25 +354,15 @@ static void handle_new_node(struct wl_listener *listener, void *data) {
|
|||
seat_node_from_node(seat, node);
|
||||
}
|
||||
|
||||
static void drag_icon_damage_whole(struct sway_drag_icon *icon) {
|
||||
if (!icon->wlr_drag_icon->surface->mapped) {
|
||||
return;
|
||||
}
|
||||
desktop_damage_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, true);
|
||||
}
|
||||
|
||||
void drag_icon_update_position(struct sway_drag_icon *icon) {
|
||||
drag_icon_damage_whole(icon);
|
||||
|
||||
struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon;
|
||||
struct sway_seat *seat = icon->seat;
|
||||
static void drag_icon_update_position(struct sway_seat *seat, struct wlr_scene_node *node) {
|
||||
struct wlr_drag_icon *wlr_icon = scene_descriptor_try_get(node, SWAY_SCENE_DESC_DRAG_ICON);
|
||||
struct wlr_cursor *cursor = seat->cursor->cursor;
|
||||
|
||||
switch (wlr_icon->drag->grab_type) {
|
||||
case WLR_DRAG_GRAB_KEYBOARD:
|
||||
return;
|
||||
case WLR_DRAG_GRAB_KEYBOARD_POINTER:
|
||||
icon->x = cursor->x + icon->dx;
|
||||
icon->y = cursor->y + icon->dy;
|
||||
wlr_scene_node_set_position(node, cursor->x, cursor->y);
|
||||
break;
|
||||
case WLR_DRAG_GRAB_KEYBOARD_TOUCH:;
|
||||
struct wlr_touch_point *point =
|
||||
|
@ -379,42 +370,15 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
|
|||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
icon->x = seat->touch_x + icon->dx;
|
||||
icon->y = seat->touch_y + icon->dy;
|
||||
wlr_scene_node_set_position(node, seat->touch_x, seat->touch_y);
|
||||
}
|
||||
|
||||
drag_icon_damage_whole(icon);
|
||||
}
|
||||
|
||||
static void drag_icon_handle_surface_commit(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_drag_icon *icon =
|
||||
wl_container_of(listener, icon, surface_commit);
|
||||
struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon;
|
||||
icon->dx += wlr_icon->surface->current.dx;
|
||||
icon->dy += wlr_icon->surface->current.dy;
|
||||
drag_icon_update_position(icon);
|
||||
}
|
||||
|
||||
static void drag_icon_handle_map(struct wl_listener *listener, void *data) {
|
||||
struct sway_drag_icon *icon = wl_container_of(listener, icon, map);
|
||||
drag_icon_damage_whole(icon);
|
||||
}
|
||||
|
||||
static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) {
|
||||
struct sway_drag_icon *icon = wl_container_of(listener, icon, unmap);
|
||||
drag_icon_damage_whole(icon);
|
||||
}
|
||||
|
||||
static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy);
|
||||
icon->wlr_drag_icon->data = NULL;
|
||||
wl_list_remove(&icon->link);
|
||||
wl_list_remove(&icon->surface_commit.link);
|
||||
wl_list_remove(&icon->unmap.link);
|
||||
wl_list_remove(&icon->map.link);
|
||||
wl_list_remove(&icon->destroy.link);
|
||||
free(icon);
|
||||
void drag_icons_update_position(struct sway_seat *seat) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &seat->drag_icons->children, link) {
|
||||
drag_icon_update_position(seat, node);
|
||||
}
|
||||
}
|
||||
|
||||
static void drag_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
|
@ -486,27 +450,20 @@ static void handle_start_drag(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_drag_icon *wlr_drag_icon = wlr_drag->icon;
|
||||
if (wlr_drag_icon != NULL) {
|
||||
struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon));
|
||||
if (icon == NULL) {
|
||||
sway_log(SWAY_ERROR, "Allocation failed");
|
||||
struct wlr_scene_tree *tree = wlr_scene_drag_icon_create(seat->drag_icons, wlr_drag_icon);
|
||||
if (!tree) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a drag icon scene tree");
|
||||
return;
|
||||
}
|
||||
icon->seat = seat;
|
||||
icon->wlr_drag_icon = wlr_drag_icon;
|
||||
wlr_drag_icon->data = icon;
|
||||
|
||||
icon->surface_commit.notify = drag_icon_handle_surface_commit;
|
||||
wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit);
|
||||
icon->unmap.notify = drag_icon_handle_unmap;
|
||||
wl_signal_add(&wlr_drag_icon->surface->events.unmap, &icon->unmap);
|
||||
icon->map.notify = drag_icon_handle_map;
|
||||
wl_signal_add(&wlr_drag_icon->surface->events.map, &icon->map);
|
||||
icon->destroy.notify = drag_icon_handle_destroy;
|
||||
wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy);
|
||||
if (!scene_descriptor_assign(&tree->node, SWAY_SCENE_DESC_DRAG_ICON,
|
||||
wlr_drag_icon)) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a drag icon scene descriptor");
|
||||
wlr_scene_node_destroy(&tree->node);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_insert(&root->drag_icons, &icon->link);
|
||||
|
||||
drag_icon_update_position(icon);
|
||||
drag_icon_update_position(seat, &tree->node);
|
||||
}
|
||||
seatop_begin_default(seat);
|
||||
}
|
||||
|
@ -553,8 +510,18 @@ struct sway_seat *seat_create(const char *seat_name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
seat->scene_tree = alloc_scene_tree(root->layers.seat, &failed);
|
||||
seat->drag_icons = alloc_scene_tree(seat->scene_tree, &failed);
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&seat->scene_tree->node);
|
||||
free(seat);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seat->wlr_seat = wlr_seat_create(server.wl_display, seat_name);
|
||||
if (!sway_assert(seat->wlr_seat, "could not allocate seat")) {
|
||||
wlr_scene_node_destroy(&seat->scene_tree->node);
|
||||
free(seat);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -562,6 +529,7 @@ struct sway_seat *seat_create(const char *seat_name) {
|
|||
|
||||
seat->cursor = sway_cursor_create(seat);
|
||||
if (!seat->cursor) {
|
||||
wlr_scene_node_destroy(&seat->scene_tree->node);
|
||||
wlr_seat_destroy(seat->wlr_seat);
|
||||
free(seat);
|
||||
return NULL;
|
||||
|
@ -1092,19 +1060,10 @@ void seat_configure_xcursor(struct sway_seat *seat) {
|
|||
|
||||
bool seat_is_input_allowed(struct sway_seat *seat,
|
||||
struct wlr_surface *surface) {
|
||||
if (!server.session_lock.locked) {
|
||||
return true;
|
||||
if (server.session_lock.lock) {
|
||||
return sway_session_lock_has_surface(server.session_lock.lock, surface);
|
||||
}
|
||||
if (server.session_lock.lock == NULL) {
|
||||
return false;
|
||||
}
|
||||
struct wlr_session_lock_surface_v1 *lock_surf;
|
||||
wl_list_for_each(lock_surf, &server.session_lock.lock->surfaces, link) {
|
||||
if (lock_surf->surface == surface) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void send_unfocus(struct sway_container *con, void *data) {
|
||||
|
@ -1309,8 +1268,8 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
|
|||
} else {
|
||||
seat_set_workspace_focus(seat, node);
|
||||
}
|
||||
if (server.session_lock.locked) {
|
||||
seat_set_focus_surface(seat, server.session_lock.focused, false);
|
||||
if (server.session_lock.lock) {
|
||||
seat_set_focus_surface(seat, server.session_lock.lock->focused, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1732,12 +1691,6 @@ void seatop_end(struct sway_seat *seat) {
|
|||
seat->seatop_impl = NULL;
|
||||
}
|
||||
|
||||
void seatop_render(struct sway_seat *seat, struct render_context *ctx) {
|
||||
if (seat->seatop_impl->render) {
|
||||
seat->seatop_impl->render(seat, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
bool seatop_allows_set_cursor(struct sway_seat *seat) {
|
||||
return seat->seatop_impl->allow_set_cursor;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "sway/input/tablet.h"
|
||||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "log.h"
|
||||
|
@ -55,6 +56,9 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
|
|||
while (cont) {
|
||||
if (container_parent_layout(cont) == layout) {
|
||||
list_t *siblings = container_get_siblings(cont);
|
||||
if (!siblings) {
|
||||
return false;
|
||||
}
|
||||
int index = list_find(siblings, cont);
|
||||
if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {
|
||||
return false;
|
||||
|
@ -620,12 +624,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
|
|||
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
|
||||
}
|
||||
|
||||
struct sway_drag_icon *drag_icon;
|
||||
wl_list_for_each(drag_icon, &root->drag_icons, link) {
|
||||
if (drag_icon->seat == seat) {
|
||||
drag_icon_update_position(drag_icon);
|
||||
}
|
||||
}
|
||||
drag_icons_update_position(seat);
|
||||
|
||||
e->previous_node = node;
|
||||
}
|
||||
|
@ -655,12 +654,7 @@ static void handle_tablet_tool_motion(struct sway_seat *seat,
|
|||
wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool);
|
||||
}
|
||||
|
||||
struct sway_drag_icon *drag_icon;
|
||||
wl_list_for_each(drag_icon, &root->drag_icons, link) {
|
||||
if (drag_icon->seat == seat) {
|
||||
drag_icon_update_position(drag_icon);
|
||||
}
|
||||
}
|
||||
drag_icons_update_position(seat);
|
||||
|
||||
e->previous_node = node;
|
||||
}
|
||||
|
@ -802,8 +796,9 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
|||
|
||||
if (!handled) {
|
||||
wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
|
||||
event->orientation, scroll_factor * event->delta,
|
||||
roundf(scroll_factor * event->delta_discrete), event->source);
|
||||
event->orientation, scroll_factor * event->delta,
|
||||
roundf(scroll_factor * event->delta_discrete), event->source,
|
||||
event->relative_direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,8 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
|||
|
||||
wlr_seat_pointer_notify_axis(seat->wlr_seat, event->time_msec,
|
||||
event->orientation, scroll_factor * event->delta,
|
||||
roundf(scroll_factor * event->delta_discrete), event->source);
|
||||
roundf(scroll_factor * event->delta_discrete), event->source,
|
||||
event->relative_direction);
|
||||
}
|
||||
|
||||
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/seat.h"
|
||||
|
@ -39,9 +38,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
|
|||
static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
|
||||
struct seatop_move_floating_event *e = seat->seatop_data;
|
||||
struct wlr_cursor *cursor = seat->cursor->cursor;
|
||||
desktop_damage_whole_container(e->con);
|
||||
container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy);
|
||||
desktop_damage_whole_container(e->con);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <limits.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/util/edges.h>
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/seat.h"
|
||||
|
@ -24,28 +23,17 @@ struct seatop_move_tiling_event {
|
|||
struct sway_container *con;
|
||||
struct sway_node *target_node;
|
||||
enum wlr_edges target_edge;
|
||||
struct wlr_box drop_box;
|
||||
double ref_lx, ref_ly; // cursor's x/y at start of op
|
||||
bool threshold_reached;
|
||||
bool split_target;
|
||||
bool insert_after_target;
|
||||
struct wlr_scene_rect *indicator_rect;
|
||||
};
|
||||
|
||||
static void handle_render(struct sway_seat *seat, struct render_context *ctx) {
|
||||
static void handle_end(struct sway_seat *seat) {
|
||||
struct seatop_move_tiling_event *e = seat->seatop_data;
|
||||
if (!e->threshold_reached) {
|
||||
return;
|
||||
}
|
||||
if (e->target_node && node_get_output(e->target_node) == ctx->output) {
|
||||
float color[4];
|
||||
memcpy(&color, config->border_colors.focused.indicator,
|
||||
sizeof(float) * 4);
|
||||
premultiply_alpha(color, 0.5);
|
||||
struct wlr_box box;
|
||||
memcpy(&box, &e->drop_box, sizeof(struct wlr_box));
|
||||
scale_box(&box, ctx->output->wlr_output->scale);
|
||||
render_rect(ctx, &box, color);
|
||||
}
|
||||
wlr_scene_node_destroy(&e->indicator_rect->node);
|
||||
e->indicator_rect = NULL;
|
||||
}
|
||||
|
||||
static void handle_motion_prethreshold(struct sway_seat *seat) {
|
||||
|
@ -66,6 +54,7 @@ static void handle_motion_prethreshold(struct sway_seat *seat) {
|
|||
|
||||
// If the threshold has been exceeded, start the actual drag
|
||||
if ((cx - sx) * (cx - sx) + (cy - sy) * (cy - sy) > threshold) {
|
||||
wlr_scene_node_set_enabled(&e->indicator_rect->node, true);
|
||||
e->threshold_reached = true;
|
||||
cursor_set_image(seat->cursor, "grab", NULL);
|
||||
}
|
||||
|
@ -164,6 +153,11 @@ static bool split_titlebar(struct sway_node *node, struct sway_container *avoid,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void update_indicator(struct seatop_move_tiling_event *e, struct wlr_box *box) {
|
||||
wlr_scene_node_set_position(&e->indicator_rect->node, box->x, box->y);
|
||||
wlr_scene_rect_set_size(e->indicator_rect, box->width, box->height);
|
||||
}
|
||||
|
||||
static void handle_motion_postthreshold(struct sway_seat *seat) {
|
||||
struct seatop_move_tiling_event *e = seat->seatop_data;
|
||||
e->split_target = false;
|
||||
|
@ -172,8 +166,6 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
|
|||
struct sway_cursor *cursor = seat->cursor;
|
||||
struct sway_node *node = node_at_coords(seat,
|
||||
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
|
||||
// Damage the old location
|
||||
desktop_damage_box(&e->drop_box);
|
||||
|
||||
if (!node) {
|
||||
// Eg. hovered over a layer surface such as swaybar
|
||||
|
@ -186,8 +178,10 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
|
|||
// Empty workspace
|
||||
e->target_node = node;
|
||||
e->target_edge = WLR_EDGE_NONE;
|
||||
workspace_get_box(node->sway_workspace, &e->drop_box);
|
||||
desktop_damage_box(&e->drop_box);
|
||||
|
||||
struct wlr_box drop_box;
|
||||
workspace_get_box(node->sway_workspace, &drop_box);
|
||||
update_indicator(e, &drop_box);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -200,11 +194,18 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct wlr_box drop_box = {
|
||||
.x = con->pending.content_x,
|
||||
.y = con->pending.content_y,
|
||||
.width = con->pending.content_width,
|
||||
.height = con->pending.content_height,
|
||||
};
|
||||
|
||||
// Check if the cursor is over a tilebar only if the destination
|
||||
// container is not a descendant of the source container.
|
||||
if (!surface && !container_has_ancestor(con, e->con) &&
|
||||
split_titlebar(node, e->con, cursor->cursor,
|
||||
&e->drop_box, &e->insert_after_target)) {
|
||||
&drop_box, &e->insert_after_target)) {
|
||||
// Don't allow dropping over the source container's titlebar
|
||||
// to give users a chance to cancel a drag operation.
|
||||
if (con == e->con) {
|
||||
|
@ -214,6 +215,7 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
|
|||
e->split_target = true;
|
||||
}
|
||||
e->target_edge = WLR_EDGE_NONE;
|
||||
update_indicator(e, &drop_box);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -255,8 +257,7 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
|
|||
e->target_node = node_get_parent(e->target_node);
|
||||
}
|
||||
e->target_edge = edge;
|
||||
e->drop_box = box;
|
||||
desktop_damage_box(&e->drop_box);
|
||||
update_indicator(e, &box);
|
||||
return;
|
||||
}
|
||||
con = con->pending.parent;
|
||||
|
@ -298,12 +299,8 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
|
|||
}
|
||||
|
||||
e->target_node = node;
|
||||
e->drop_box.x = con->pending.content_x;
|
||||
e->drop_box.y = con->pending.content_y;
|
||||
e->drop_box.width = con->pending.content_width;
|
||||
e->drop_box.height = con->pending.content_height;
|
||||
resize_box(&e->drop_box, e->target_edge, thickness);
|
||||
desktop_damage_box(&e->drop_box);
|
||||
resize_box(&drop_box, e->target_edge, thickness);
|
||||
update_indicator(e, &drop_box);
|
||||
}
|
||||
|
||||
static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
|
||||
|
@ -438,7 +435,7 @@ static const struct sway_seatop_impl seatop_impl = {
|
|||
.pointer_motion = handle_pointer_motion,
|
||||
.tablet_tool_tip = handle_tablet_tool_tip,
|
||||
.unref = handle_unref,
|
||||
.render = handle_render,
|
||||
.end = handle_end,
|
||||
};
|
||||
|
||||
void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
|
||||
|
@ -450,6 +447,20 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
|
|||
if (!e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float *indicator = config->border_colors.focused.indicator;
|
||||
float color[4] = {
|
||||
indicator[0] * .5,
|
||||
indicator[1] * .5,
|
||||
indicator[2] * .5,
|
||||
indicator[3] * .5,
|
||||
};
|
||||
e->indicator_rect = wlr_scene_rect_create(seat->scene_tree, 0, 0, color);
|
||||
if (!e->indicator_rect) {
|
||||
free(e);
|
||||
return;
|
||||
}
|
||||
|
||||
e->con = con;
|
||||
e->ref_lx = seat->cursor->cursor->x;
|
||||
e->ref_ly = seat->cursor->cursor->y;
|
||||
|
|
|
@ -34,7 +34,7 @@ static bool sway_switch_trigger_test(enum sway_switch_trigger trigger,
|
|||
|
||||
static void execute_binding(struct sway_switch *sway_switch) {
|
||||
struct sway_seat *seat = sway_switch->seat_device->sway_seat;
|
||||
bool locked = server.session_lock.locked;
|
||||
bool locked = server.session_lock.lock;
|
||||
|
||||
list_t *bindings = config->current_mode->switch_bindings;
|
||||
struct sway_switch_binding *matched_binding = NULL;
|
||||
|
|
359
sway/lock.c
359
sway/lock.c
|
@ -1,5 +1,6 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "log.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
|
@ -7,21 +8,29 @@
|
|||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/surface.h"
|
||||
|
||||
struct sway_session_lock_surface {
|
||||
struct wlr_session_lock_surface_v1 *lock_surface;
|
||||
struct sway_session_lock_output {
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wlr_scene_rect *background;
|
||||
struct sway_session_lock *lock;
|
||||
|
||||
struct sway_output *output;
|
||||
struct wlr_surface *surface;
|
||||
struct wl_listener map;
|
||||
|
||||
struct wl_list link; // sway_session_lock::outputs
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener output_destroy;
|
||||
struct wl_listener commit;
|
||||
|
||||
struct wlr_session_lock_surface_v1 *surface;
|
||||
|
||||
// invalid if surface is NULL
|
||||
struct wl_listener surface_destroy;
|
||||
struct wl_listener surface_map;
|
||||
};
|
||||
|
||||
static void set_lock_focused_surface(struct wlr_surface *focused) {
|
||||
server.session_lock.focused = focused;
|
||||
static void focus_surface(struct sway_session_lock *lock,
|
||||
struct wlr_surface *focused) {
|
||||
lock->focused = focused;
|
||||
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
|
@ -29,104 +38,189 @@ static void set_lock_focused_surface(struct wlr_surface *focused) {
|
|||
}
|
||||
}
|
||||
|
||||
static void refocus_output(struct sway_session_lock_output *output) {
|
||||
// Move the seat focus to another surface if one is available
|
||||
if (output->lock->focused == output->surface->surface) {
|
||||
struct wlr_surface *next_focus = NULL;
|
||||
|
||||
struct sway_session_lock_output *candidate;
|
||||
wl_list_for_each(candidate, &output->lock->outputs, link) {
|
||||
if (candidate == output || !candidate->surface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (candidate->surface->surface->mapped) {
|
||||
next_focus = candidate->surface->surface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
focus_surface(output->lock, next_focus);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_surface_map(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, map);
|
||||
if (server.session_lock.focused == NULL) {
|
||||
set_lock_focused_surface(surf->surface);
|
||||
struct sway_session_lock_output *surf = wl_container_of(listener, surf, surface_map);
|
||||
if (surf->lock->focused == NULL) {
|
||||
focus_surface(surf->lock, surf->surface->surface);
|
||||
}
|
||||
cursor_rebase_all();
|
||||
surface_enter_output(surf->surface, surf->output);
|
||||
output_damage_whole(surf->output);
|
||||
}
|
||||
|
||||
static void handle_surface_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, surface_commit);
|
||||
output_damage_surface(surf->output, 0, 0, surf->surface, false);
|
||||
static void handle_surface_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_output *output =
|
||||
wl_container_of(listener, output, surface_destroy);
|
||||
refocus_output(output);
|
||||
|
||||
sway_assert(output->surface, "Trying to destroy a surface that the lock doesn't think exists");
|
||||
output->surface = NULL;
|
||||
wl_list_remove(&output->surface_destroy.link);
|
||||
wl_list_remove(&output->surface_map.link);
|
||||
}
|
||||
|
||||
static void handle_output_commit(struct wl_listener *listener, void *data) {
|
||||
static void lock_output_reconfigure(struct sway_session_lock_output *output) {
|
||||
int width = output->output->width;
|
||||
int height = output->output->height;
|
||||
|
||||
wlr_scene_rect_set_size(output->background, width, height);
|
||||
|
||||
if (output->surface) {
|
||||
wlr_session_lock_surface_v1_configure(output->surface, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_new_surface(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock *lock = wl_container_of(listener, lock, new_surface);
|
||||
struct wlr_session_lock_surface_v1 *lock_surface = data;
|
||||
struct sway_output *output = lock_surface->output->data;
|
||||
|
||||
sway_log(SWAY_DEBUG, "new lock layer surface");
|
||||
|
||||
struct sway_session_lock_output *current_lock_output, *lock_output = NULL;
|
||||
wl_list_for_each(current_lock_output, &lock->outputs, link) {
|
||||
if (current_lock_output->output == output) {
|
||||
lock_output = current_lock_output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sway_assert(lock_output, "Couldn't find output to lock");
|
||||
sway_assert(!lock_output->surface, "Tried to reassign a surface to an existing output");
|
||||
|
||||
lock_output->surface = lock_surface;
|
||||
|
||||
wlr_scene_subsurface_tree_create(lock_output->tree, lock_surface->surface);
|
||||
|
||||
lock_output->surface_destroy.notify = handle_surface_destroy;
|
||||
wl_signal_add(&lock_surface->events.destroy, &lock_output->surface_destroy);
|
||||
lock_output->surface_map.notify = handle_surface_map;
|
||||
wl_signal_add(&lock_surface->surface->events.map, &lock_output->surface_map);
|
||||
|
||||
lock_output_reconfigure(lock_output);
|
||||
}
|
||||
|
||||
static void sway_session_lock_output_destroy(struct sway_session_lock_output *output) {
|
||||
if (output->surface) {
|
||||
refocus_output(output);
|
||||
wl_list_remove(&output->surface_destroy.link);
|
||||
wl_list_remove(&output->surface_map.link);
|
||||
}
|
||||
|
||||
wl_list_remove(&output->commit.link);
|
||||
wl_list_remove(&output->destroy.link);
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
free(output);
|
||||
}
|
||||
|
||||
static void lock_node_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_output *output =
|
||||
wl_container_of(listener, output, destroy);
|
||||
sway_session_lock_output_destroy(output);
|
||||
}
|
||||
|
||||
static void lock_output_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output_event_commit *event = data;
|
||||
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_commit);
|
||||
struct sway_session_lock_output *output =
|
||||
wl_container_of(listener, output, commit);
|
||||
if (event->state->committed & (
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_SCALE |
|
||||
WLR_OUTPUT_STATE_TRANSFORM)) {
|
||||
wlr_session_lock_surface_v1_configure(surf->lock_surface,
|
||||
surf->output->width, surf->output->height);
|
||||
lock_output_reconfigure(output);
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_lock_surface(struct sway_session_lock_surface *surf) {
|
||||
// Move the seat focus to another surface if one is available
|
||||
if (server.session_lock.focused == surf->surface) {
|
||||
struct wlr_surface *next_focus = NULL;
|
||||
|
||||
struct wlr_session_lock_surface_v1 *other;
|
||||
wl_list_for_each(other, &server.session_lock.lock->surfaces, link) {
|
||||
if (other != surf->lock_surface && other->surface->mapped) {
|
||||
next_focus = other->surface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_lock_focused_surface(next_focus);
|
||||
static struct sway_session_lock_output *session_lock_output_create(
|
||||
struct sway_session_lock *lock, struct sway_output *output) {
|
||||
struct sway_session_lock_output *lock_output = calloc(1, sizeof(*lock_output));
|
||||
if (!lock_output) {
|
||||
sway_log(SWAY_ERROR, "failed to allocate a session lock output");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_list_remove(&surf->map.link);
|
||||
wl_list_remove(&surf->destroy.link);
|
||||
wl_list_remove(&surf->surface_commit.link);
|
||||
wl_list_remove(&surf->output_commit.link);
|
||||
wl_list_remove(&surf->output_destroy.link);
|
||||
output_damage_whole(surf->output);
|
||||
free(surf);
|
||||
}
|
||||
|
||||
static void handle_surface_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, destroy);
|
||||
destroy_lock_surface(surf);
|
||||
}
|
||||
|
||||
static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_surface *surf =
|
||||
wl_container_of(listener, surf, output_destroy);
|
||||
destroy_lock_surface(surf);
|
||||
}
|
||||
|
||||
static void handle_new_surface(struct wl_listener *listener, void *data) {
|
||||
struct wlr_session_lock_surface_v1 *lock_surface = data;
|
||||
struct sway_session_lock_surface *surf = calloc(1, sizeof(*surf));
|
||||
if (surf == NULL) {
|
||||
return;
|
||||
struct wlr_scene_tree *tree = wlr_scene_tree_create(output->layers.session_lock);
|
||||
if (!tree) {
|
||||
sway_log(SWAY_ERROR, "failed to allocate a session lock output scene tree");
|
||||
free(lock_output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sway_log(SWAY_DEBUG, "new lock layer surface");
|
||||
struct wlr_scene_rect *background = wlr_scene_rect_create(tree, 0, 0, (float[4]){
|
||||
lock->abandoned ? 1.f : 0.f,
|
||||
0.f,
|
||||
0.f,
|
||||
1.f,
|
||||
});
|
||||
if (!background) {
|
||||
sway_log(SWAY_ERROR, "failed to allocate a session lock output scene background");
|
||||
wlr_scene_node_destroy(&tree->node);
|
||||
free(lock_output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_output *output = lock_surface->output->data;
|
||||
wlr_session_lock_surface_v1_configure(lock_surface, output->width, output->height);
|
||||
lock_output->output = output;
|
||||
lock_output->tree = tree;
|
||||
lock_output->background = background;
|
||||
lock_output->lock = lock;
|
||||
|
||||
surf->lock_surface = lock_surface;
|
||||
surf->surface = lock_surface->surface;
|
||||
surf->output = output;
|
||||
surf->map.notify = handle_surface_map;
|
||||
wl_signal_add(&lock_surface->surface->events.map, &surf->map);
|
||||
surf->destroy.notify = handle_surface_destroy;
|
||||
wl_signal_add(&lock_surface->events.destroy, &surf->destroy);
|
||||
surf->surface_commit.notify = handle_surface_commit;
|
||||
wl_signal_add(&surf->surface->events.commit, &surf->surface_commit);
|
||||
surf->output_commit.notify = handle_output_commit;
|
||||
wl_signal_add(&output->wlr_output->events.commit, &surf->output_commit);
|
||||
surf->output_destroy.notify = handle_output_destroy;
|
||||
wl_signal_add(&output->node.events.destroy, &surf->output_destroy);
|
||||
lock_output->destroy.notify = lock_node_handle_destroy;
|
||||
wl_signal_add(&tree->node.events.destroy, &lock_output->destroy);
|
||||
|
||||
lock_output->commit.notify = lock_output_handle_commit;
|
||||
wl_signal_add(&output->wlr_output->events.commit, &lock_output->commit);
|
||||
|
||||
lock_output_reconfigure(lock_output);
|
||||
|
||||
wl_list_insert(&lock->outputs, &lock_output->link);
|
||||
|
||||
return lock_output;
|
||||
}
|
||||
|
||||
static void sway_session_lock_destroy(struct sway_session_lock* lock) {
|
||||
struct sway_session_lock_output *lock_output, *tmp_lock_output;
|
||||
wl_list_for_each_safe(lock_output, tmp_lock_output, &lock->outputs, link) {
|
||||
// destroying the node will also destroy the whole lock output
|
||||
wlr_scene_node_destroy(&lock_output->tree->node);
|
||||
}
|
||||
|
||||
if (server.session_lock.lock == lock) {
|
||||
server.session_lock.lock = NULL;
|
||||
}
|
||||
|
||||
if (!lock->abandoned) {
|
||||
wl_list_remove(&lock->destroy.link);
|
||||
wl_list_remove(&lock->unlock.link);
|
||||
wl_list_remove(&lock->new_surface.link);
|
||||
}
|
||||
|
||||
free(lock);
|
||||
}
|
||||
|
||||
static void handle_unlock(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock *lock = wl_container_of(listener, lock, unlock);
|
||||
sway_log(SWAY_DEBUG, "session unlocked");
|
||||
server.session_lock.locked = false;
|
||||
server.session_lock.lock = NULL;
|
||||
server.session_lock.focused = NULL;
|
||||
|
||||
wl_list_remove(&server.session_lock.lock_new_surface.link);
|
||||
wl_list_remove(&server.session_lock.lock_unlock.link);
|
||||
wl_list_remove(&server.session_lock.lock_destroy.link);
|
||||
sway_session_lock_destroy(lock);
|
||||
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
|
@ -145,28 +239,22 @@ static void handle_unlock(struct wl_listener *listener, void *data) {
|
|||
struct sway_output *output = root->outputs->items[i];
|
||||
arrange_layers(output);
|
||||
}
|
||||
|
||||
// redraw everything
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole(output);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_abandon(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock *lock = wl_container_of(listener, lock, destroy);
|
||||
sway_log(SWAY_INFO, "session lock abandoned");
|
||||
server.session_lock.lock = NULL;
|
||||
server.session_lock.focused = NULL;
|
||||
|
||||
wl_list_remove(&server.session_lock.lock_new_surface.link);
|
||||
wl_list_remove(&server.session_lock.lock_unlock.link);
|
||||
wl_list_remove(&server.session_lock.lock_destroy.link);
|
||||
|
||||
// redraw everything
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole(output);
|
||||
struct sway_session_lock_output *lock_output;
|
||||
wl_list_for_each(lock_output, &lock->outputs, link) {
|
||||
wlr_scene_rect_set_color(lock_output->background,
|
||||
(float[4]){ 1.f, 0.f, 0.f, 1.f });
|
||||
}
|
||||
|
||||
lock->abandoned = true;
|
||||
wl_list_remove(&lock->destroy.link);
|
||||
wl_list_remove(&lock->unlock.link);
|
||||
wl_list_remove(&lock->new_surface.link);
|
||||
}
|
||||
|
||||
static void handle_session_lock(struct wl_listener *listener, void *data) {
|
||||
|
@ -174,44 +262,89 @@ static void handle_session_lock(struct wl_listener *listener, void *data) {
|
|||
struct wl_client *client = wl_resource_get_client(lock->resource);
|
||||
|
||||
if (server.session_lock.lock) {
|
||||
if (server.session_lock.lock->abandoned) {
|
||||
sway_log(SWAY_INFO, "Replacing abandoned lock");
|
||||
sway_session_lock_destroy(server.session_lock.lock);
|
||||
} else {
|
||||
sway_log(SWAY_ERROR, "Cannot lock an already locked session");
|
||||
wlr_session_lock_v1_destroy(lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct sway_session_lock *sway_lock = calloc(1, sizeof(*sway_lock));
|
||||
if (!sway_lock) {
|
||||
sway_log(SWAY_ERROR, "failed to allocate a session lock object");
|
||||
wlr_session_lock_v1_destroy(lock);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_init(&sway_lock->outputs);
|
||||
|
||||
sway_log(SWAY_DEBUG, "session locked");
|
||||
server.session_lock.locked = true;
|
||||
server.session_lock.lock = lock;
|
||||
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
seat_unfocus_unless_client(seat, client);
|
||||
}
|
||||
|
||||
wl_signal_add(&lock->events.new_surface, &server.session_lock.lock_new_surface);
|
||||
wl_signal_add(&lock->events.unlock, &server.session_lock.lock_unlock);
|
||||
wl_signal_add(&lock->events.destroy, &server.session_lock.lock_destroy);
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
sway_session_lock_add_output(sway_lock, output);
|
||||
}
|
||||
|
||||
sway_lock->new_surface.notify = handle_new_surface;
|
||||
wl_signal_add(&lock->events.new_surface, &sway_lock->new_surface);
|
||||
sway_lock->unlock.notify = handle_unlock;
|
||||
wl_signal_add(&lock->events.unlock, &sway_lock->unlock);
|
||||
sway_lock->destroy.notify = handle_abandon;
|
||||
wl_signal_add(&lock->events.destroy, &sway_lock->destroy);
|
||||
|
||||
wlr_session_lock_v1_send_locked(lock);
|
||||
|
||||
// redraw everything
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_whole(output);
|
||||
}
|
||||
server.session_lock.lock = sway_lock;
|
||||
}
|
||||
|
||||
static void handle_session_lock_destroy(struct wl_listener *listener, void *data) {
|
||||
assert(server.session_lock.lock == NULL);
|
||||
// if the server shuts down while a lock is active, destroy the lock
|
||||
if (server.session_lock.lock) {
|
||||
sway_session_lock_destroy(server.session_lock.lock);
|
||||
}
|
||||
|
||||
wl_list_remove(&server.session_lock.new_lock.link);
|
||||
wl_list_remove(&server.session_lock.manager_destroy.link);
|
||||
|
||||
server.session_lock.manager = NULL;
|
||||
}
|
||||
|
||||
void sway_session_lock_add_output(struct sway_session_lock *lock,
|
||||
struct sway_output *output) {
|
||||
struct sway_session_lock_output *lock_output =
|
||||
session_lock_output_create(lock, output);
|
||||
|
||||
// if we run out of memory while trying to lock the screen, the best we
|
||||
// can do is kill the sway process. Security conscious users will have
|
||||
// the sway session fall back to a login shell.
|
||||
if (!lock_output) {
|
||||
sway_log(SWAY_ERROR, "aborting: failed to allocate a lock output");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool sway_session_lock_has_surface(struct sway_session_lock *lock,
|
||||
struct wlr_surface *surface) {
|
||||
struct sway_session_lock_output *lock_output;
|
||||
wl_list_for_each(lock_output, &lock->outputs, link) {
|
||||
if (lock_output->surface && lock_output->surface->surface == surface) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void sway_session_lock_init(void) {
|
||||
server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display);
|
||||
|
||||
server.session_lock.lock_new_surface.notify = handle_new_surface;
|
||||
server.session_lock.lock_unlock.notify = handle_unlock;
|
||||
server.session_lock.lock_destroy.notify = handle_abandon;
|
||||
server.session_lock.new_lock.notify = handle_session_lock;
|
||||
server.session_lock.manager_destroy.notify = handle_session_lock_destroy;
|
||||
wl_signal_add(&server.session_lock.manager->events.new_lock,
|
||||
|
|
14
sway/main.c
14
sway/main.c
|
@ -154,11 +154,7 @@ void restore_nofile_limit(void) {
|
|||
}
|
||||
|
||||
void enable_debug_flag(const char *flag) {
|
||||
if (strcmp(flag, "damage=highlight") == 0) {
|
||||
debug.damage = DAMAGE_HIGHLIGHT;
|
||||
} else if (strcmp(flag, "damage=rerender") == 0) {
|
||||
debug.damage = DAMAGE_RERENDER;
|
||||
} else if (strcmp(flag, "noatomic") == 0) {
|
||||
if (strcmp(flag, "noatomic") == 0) {
|
||||
debug.noatomic = true;
|
||||
} else if (strcmp(flag, "txn-wait") == 0) {
|
||||
debug.txn_wait = true;
|
||||
|
@ -166,8 +162,8 @@ void enable_debug_flag(const char *flag) {
|
|||
debug.txn_timings = true;
|
||||
} else if (strncmp(flag, "txn-timeout=", 12) == 0) {
|
||||
server.txn_timeout_ms = atoi(&flag[12]);
|
||||
} else if (strcmp(flag, "noscanout") == 0) {
|
||||
debug.noscanout = true;
|
||||
} else if (strcmp(flag, "legacy-wl-drm") == 0) {
|
||||
debug.legacy_wl_drm = true;
|
||||
} else {
|
||||
sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag);
|
||||
}
|
||||
|
@ -340,6 +336,10 @@ int main(int argc, char **argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (server.linux_dmabuf_v1) {
|
||||
wlr_scene_set_linux_dmabuf_v1(root->root_scene, server.linux_dmabuf_v1);
|
||||
}
|
||||
|
||||
if (validate) {
|
||||
bool valid = load_main_config(config_path, false, true);
|
||||
free(config_path);
|
||||
|
|
|
@ -8,17 +8,16 @@ sway_sources = files(
|
|||
'lock.c',
|
||||
'main.c',
|
||||
'realtime.c',
|
||||
'scene_descriptor.c',
|
||||
'server.c',
|
||||
'sway_text_node.c',
|
||||
'swaynag.c',
|
||||
'xdg_activation_v1.c',
|
||||
'xdg_decoration.c',
|
||||
|
||||
'desktop/desktop.c',
|
||||
'desktop/idle_inhibit_v1.c',
|
||||
'desktop/layer_shell.c',
|
||||
'desktop/output.c',
|
||||
'desktop/render.c',
|
||||
'desktop/surface.c',
|
||||
'desktop/transaction.c',
|
||||
'desktop/xdg_shell.c',
|
||||
'desktop/launcher.c',
|
||||
|
|
66
sway/scene_descriptor.c
Normal file
66
sway/scene_descriptor.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include <stdlib.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include "log.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
|
||||
struct scene_descriptor {
|
||||
void *data;
|
||||
struct wlr_addon addon;
|
||||
};
|
||||
|
||||
static const struct wlr_addon_interface addon_interface;
|
||||
|
||||
static struct scene_descriptor *scene_node_get_descriptor(
|
||||
struct wlr_scene_node *node, enum sway_scene_descriptor_type type) {
|
||||
struct wlr_addon *addon = wlr_addon_find(&node->addons, (void *)type, &addon_interface);
|
||||
if (!addon) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct scene_descriptor *desc = wl_container_of(addon, desc, addon);
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void descriptor_destroy(struct scene_descriptor *desc) {
|
||||
wlr_addon_finish(&desc->addon);
|
||||
free(desc);
|
||||
}
|
||||
|
||||
void *scene_descriptor_try_get(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type) {
|
||||
struct scene_descriptor *desc = scene_node_get_descriptor(node, type);
|
||||
if (!desc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return desc->data;
|
||||
}
|
||||
|
||||
void scene_descriptor_destroy(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type) {
|
||||
struct scene_descriptor *desc = scene_node_get_descriptor(node, type);
|
||||
descriptor_destroy(desc);
|
||||
}
|
||||
|
||||
static void addon_handle_destroy(struct wlr_addon *addon) {
|
||||
struct scene_descriptor *desc = wl_container_of(addon, desc, addon);
|
||||
descriptor_destroy(desc);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface addon_interface = {
|
||||
.name = "sway_scene_descriptor",
|
||||
.destroy = addon_handle_destroy,
|
||||
};
|
||||
|
||||
bool scene_descriptor_assign(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type, void *data) {
|
||||
struct scene_descriptor *desc = calloc(1, sizeof(*desc));
|
||||
if (!desc) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a scene descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_addon_init(&desc->addon, &node->addons, (void *)type, &addon_interface);
|
||||
desc->data = data;
|
||||
return true;
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#include <wlr/types/wlr_content_type_v1.h>
|
||||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
#include <wlr/types/wlr_drm.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
|
@ -191,6 +192,10 @@ bool server_init(struct sway_server *server) {
|
|||
server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer(
|
||||
server->wl_display, 4, server->renderer);
|
||||
}
|
||||
if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL &&
|
||||
debug.legacy_wl_drm) {
|
||||
wlr_drm_create(server->wl_display, server->renderer);
|
||||
}
|
||||
|
||||
server->allocator = wlr_allocator_autocreate(server->backend,
|
||||
server->renderer);
|
||||
|
@ -201,9 +206,6 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->compositor = wlr_compositor_create(server->wl_display, 6,
|
||||
server->renderer);
|
||||
server->compositor_new_surface.notify = handle_compositor_new_surface;
|
||||
wl_signal_add(&server->compositor->events.new_surface,
|
||||
&server->compositor_new_surface);
|
||||
|
||||
wlr_subcompositor_create(server->wl_display);
|
||||
|
||||
|
|
303
sway/sway_text_node.c
Normal file
303
sway/sway_text_node.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <drm_fourcc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include "cairo_util.h"
|
||||
#include "log.h"
|
||||
#include "pango.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/sway_text_node.h"
|
||||
|
||||
struct cairo_buffer {
|
||||
struct wlr_buffer base;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cairo;
|
||||
};
|
||||
|
||||
static void cairo_buffer_handle_destroy(struct wlr_buffer *wlr_buffer) {
|
||||
struct cairo_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||
|
||||
cairo_surface_destroy(buffer->surface);
|
||||
cairo_destroy(buffer->cairo);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static bool cairo_buffer_handle_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
|
||||
uint32_t flags, void **data, uint32_t *format, size_t *stride) {
|
||||
struct cairo_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||
*data = cairo_image_surface_get_data(buffer->surface);
|
||||
*stride = cairo_image_surface_get_stride(buffer->surface);
|
||||
*format = DRM_FORMAT_ARGB8888;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cairo_buffer_handle_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
|
||||
// This space is intentionally left blank
|
||||
}
|
||||
|
||||
static const struct wlr_buffer_impl cairo_buffer_impl = {
|
||||
.destroy = cairo_buffer_handle_destroy,
|
||||
.begin_data_ptr_access = cairo_buffer_handle_begin_data_ptr_access,
|
||||
.end_data_ptr_access = cairo_buffer_handle_end_data_ptr_access,
|
||||
};
|
||||
|
||||
struct text_buffer {
|
||||
struct wlr_scene_buffer *buffer_node;
|
||||
char *text;
|
||||
struct sway_text_node props;
|
||||
|
||||
bool visible;
|
||||
float scale;
|
||||
enum wl_output_subpixel subpixel;
|
||||
|
||||
struct wl_listener outputs_update;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
static int get_text_width(struct sway_text_node *props) {
|
||||
if (props->max_width) {
|
||||
return MIN(props->max_width, props->width);
|
||||
}
|
||||
|
||||
return props->width;
|
||||
}
|
||||
|
||||
static void update_source_box(struct text_buffer *buffer) {
|
||||
struct sway_text_node *props = &buffer->props;
|
||||
struct wlr_fbox source_box = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = ceil(get_text_width(props) * buffer->scale),
|
||||
.height = ceil(props->height * buffer->scale),
|
||||
};
|
||||
|
||||
wlr_scene_buffer_set_source_box(buffer->buffer_node, &source_box);
|
||||
}
|
||||
|
||||
static void render_backing_buffer(struct text_buffer *buffer) {
|
||||
if (!buffer->visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
float scale = buffer->scale;
|
||||
int width = ceil(buffer->props.width * scale);
|
||||
int height = ceil(buffer->props.height * scale);
|
||||
float *color = (float *)&buffer->props.color;
|
||||
float *background = (float *)&buffer->props.background;
|
||||
PangoContext *pango = NULL;
|
||||
|
||||
cairo_font_options_t *fo = cairo_font_options_create();
|
||||
cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
|
||||
enum wl_output_subpixel subpixel = buffer->subpixel;
|
||||
if (subpixel == WL_OUTPUT_SUBPIXEL_NONE || subpixel == WL_OUTPUT_SUBPIXEL_UNKNOWN) {
|
||||
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
|
||||
} else {
|
||||
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
|
||||
cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(subpixel));
|
||||
}
|
||||
|
||||
cairo_surface_t *surface = cairo_image_surface_create(
|
||||
CAIRO_FORMAT_ARGB32, width, height);
|
||||
cairo_status_t status = cairo_surface_status(surface);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
|
||||
cairo_status_to_string(status));
|
||||
goto err;
|
||||
}
|
||||
|
||||
struct cairo_buffer *cairo_buffer = calloc(1, sizeof(*cairo_buffer));
|
||||
if (!cairo_buffer) {
|
||||
sway_log(SWAY_ERROR, "cairo_buffer allocation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
cairo_t *cairo = cairo_create(surface);
|
||||
if (!cairo) {
|
||||
sway_log(SWAY_ERROR, "cairo_create failed");
|
||||
free(cairo_buffer);
|
||||
goto err;
|
||||
}
|
||||
|
||||
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
|
||||
cairo_set_font_options(cairo, fo);
|
||||
pango = pango_cairo_create_context(cairo);
|
||||
|
||||
cairo_set_source_rgba(cairo, background[0], background[1], background[2], background[3]);
|
||||
cairo_rectangle(cairo, 0, 0, width, height);
|
||||
cairo_fill(cairo);
|
||||
|
||||
cairo_set_source_rgba(cairo, color[0], color[1], color[2], color[3]);
|
||||
cairo_move_to(cairo, 0, (config->font_baseline - buffer->props.baseline) * scale);
|
||||
|
||||
render_text(cairo, config->font_description, scale, buffer->props.pango_markup,
|
||||
"%s", buffer->text);
|
||||
|
||||
cairo_surface_flush(surface);
|
||||
|
||||
wlr_buffer_init(&cairo_buffer->base, &cairo_buffer_impl, width, height);
|
||||
cairo_buffer->surface = surface;
|
||||
cairo_buffer->cairo = cairo;
|
||||
|
||||
wlr_scene_buffer_set_buffer(buffer->buffer_node, &cairo_buffer->base);
|
||||
wlr_buffer_drop(&cairo_buffer->base);
|
||||
update_source_box(buffer);
|
||||
|
||||
pixman_region32_t opaque;
|
||||
pixman_region32_init(&opaque);
|
||||
if (background[3] == 1) {
|
||||
pixman_region32_union_rect(&opaque, &opaque, 0, 0,
|
||||
buffer->props.width, buffer->props.height);
|
||||
}
|
||||
wlr_scene_buffer_set_opaque_region(buffer->buffer_node, &opaque);
|
||||
pixman_region32_fini(&opaque);
|
||||
|
||||
err:
|
||||
if (pango) g_object_unref(pango);
|
||||
cairo_font_options_destroy(fo);
|
||||
}
|
||||
|
||||
static void handle_outputs_update(struct wl_listener *listener, void *data) {
|
||||
struct text_buffer *buffer = wl_container_of(listener, buffer, outputs_update);
|
||||
struct wlr_scene_outputs_update_event *event = data;
|
||||
|
||||
float scale = 0;
|
||||
enum wl_output_subpixel subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
|
||||
for (size_t i = 0; i < event->size; i++) {
|
||||
struct wlr_scene_output *output = event->active[i];
|
||||
if (subpixel == WL_OUTPUT_SUBPIXEL_UNKNOWN) {
|
||||
subpixel = output->output->subpixel;
|
||||
} else if (subpixel != output->output->subpixel) {
|
||||
subpixel = WL_OUTPUT_SUBPIXEL_NONE;
|
||||
}
|
||||
|
||||
if (scale != 0 && scale != output->output->scale) {
|
||||
// drop down to gray scale if we encounter outputs with different
|
||||
// scales or else we will have chromatic aberations
|
||||
subpixel = WL_OUTPUT_SUBPIXEL_NONE;
|
||||
}
|
||||
|
||||
if (scale < output->output->scale) {
|
||||
scale = output->output->scale;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->visible = event->size > 0;
|
||||
|
||||
if (scale != buffer->scale || subpixel != buffer->subpixel) {
|
||||
buffer->scale = scale;
|
||||
buffer->subpixel = subpixel;
|
||||
render_backing_buffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct text_buffer *buffer = wl_container_of(listener, buffer, destroy);
|
||||
|
||||
wl_list_remove(&buffer->outputs_update.link);
|
||||
wl_list_remove(&buffer->destroy.link);
|
||||
|
||||
free(buffer->text);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void text_calc_size(struct text_buffer *buffer) {
|
||||
struct sway_text_node *props = &buffer->props;
|
||||
|
||||
cairo_t *c = cairo_create(NULL);
|
||||
if (!c) {
|
||||
sway_log(SWAY_ERROR, "cairo_t allocation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
|
||||
get_text_size(c, config->font_description, &props->width, NULL,
|
||||
&props->baseline, 1, props->pango_markup, "%s", buffer->text);
|
||||
cairo_destroy(c);
|
||||
|
||||
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
||||
get_text_width(props), props->height);
|
||||
}
|
||||
|
||||
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
|
||||
char *text, float color[4], bool pango_markup) {
|
||||
struct text_buffer *buffer = calloc(1, sizeof(*buffer));
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene_buffer *node = wlr_scene_buffer_create(parent, NULL);
|
||||
if (!node) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->buffer_node = node;
|
||||
buffer->props.node = &node->node;
|
||||
buffer->text = strdup(text);
|
||||
if (!buffer->text) {
|
||||
free(buffer);
|
||||
wlr_scene_node_destroy(&node->node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->props.height = config->font_height;
|
||||
buffer->props.pango_markup = pango_markup;
|
||||
memcpy(&buffer->props.color, color, sizeof(*color) * 4);
|
||||
|
||||
buffer->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&node->node.events.destroy, &buffer->destroy);
|
||||
buffer->outputs_update.notify = handle_outputs_update;
|
||||
wl_signal_add(&node->events.outputs_update, &buffer->outputs_update);
|
||||
|
||||
text_calc_size(buffer);
|
||||
|
||||
return &buffer->props;
|
||||
}
|
||||
|
||||
void sway_text_node_set_color(struct sway_text_node *node, float color[4]) {
|
||||
if (memcmp(&node->color, color, sizeof(*color) * 4) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&node->color, color, sizeof(*color) * 4);
|
||||
struct text_buffer *buffer = wl_container_of(node, buffer, props);
|
||||
|
||||
render_backing_buffer(buffer);
|
||||
}
|
||||
|
||||
void sway_text_node_set_text(struct sway_text_node *node, char *text) {
|
||||
struct text_buffer *buffer = wl_container_of(node, buffer, props);
|
||||
if (strcmp(buffer->text, text) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *new_text = strdup(text);
|
||||
if (!new_text) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(buffer->text);
|
||||
buffer->text = new_text;
|
||||
|
||||
text_calc_size(buffer);
|
||||
render_backing_buffer(buffer);
|
||||
}
|
||||
|
||||
void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) {
|
||||
struct text_buffer *buffer = wl_container_of(node, buffer, props);
|
||||
buffer->props.max_width = max_width;
|
||||
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
||||
get_text_width(&buffer->props), buffer->props.height);
|
||||
update_source_box(buffer);
|
||||
render_backing_buffer(buffer);
|
||||
}
|
||||
|
||||
void sway_text_node_set_background(struct sway_text_node *node, float background[4]) {
|
||||
struct text_buffer *buffer = wl_container_of(node, buffer, props);
|
||||
memcpy(&node->background, background, sizeof(*background) * 4);
|
||||
render_backing_buffer(buffer);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -159,3 +159,32 @@ bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void scene_node_disown_children(struct wlr_scene_tree *tree) {
|
||||
// this function can be called as part of destruction code that will be invoked
|
||||
// upon an allocation failure. Let's not crash on NULL due to an allocation error.
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_node *child, *tmp_child;
|
||||
wl_list_for_each_safe(child, tmp_child, &tree->children, link) {
|
||||
wlr_scene_node_reparent(child, root->staging);
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *alloc_scene_tree(struct wlr_scene_tree *parent,
|
||||
bool *failed) {
|
||||
// fallthrough
|
||||
if (*failed) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *tree = wlr_scene_tree_create(parent);
|
||||
if (!tree) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a scene node");
|
||||
*failed = true;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
|
|
@ -87,9 +87,51 @@ static void restore_workspaces(struct sway_output *output) {
|
|||
output_sort_workspaces(output);
|
||||
}
|
||||
|
||||
static void destroy_scene_layers(struct sway_output *output) {
|
||||
wlr_scene_node_destroy(&output->fullscreen_background->node);
|
||||
|
||||
scene_node_disown_children(output->layers.tiling);
|
||||
scene_node_disown_children(output->layers.fullscreen);
|
||||
|
||||
wlr_scene_node_destroy(&output->layers.shell_background->node);
|
||||
wlr_scene_node_destroy(&output->layers.shell_bottom->node);
|
||||
wlr_scene_node_destroy(&output->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&output->layers.fullscreen->node);
|
||||
wlr_scene_node_destroy(&output->layers.shell_top->node);
|
||||
wlr_scene_node_destroy(&output->layers.shell_overlay->node);
|
||||
wlr_scene_node_destroy(&output->layers.session_lock->node);
|
||||
}
|
||||
|
||||
struct sway_output *output_create(struct wlr_output *wlr_output) {
|
||||
struct sway_output *output = calloc(1, sizeof(struct sway_output));
|
||||
node_init(&output->node, N_OUTPUT, output);
|
||||
|
||||
bool failed = false;
|
||||
output->layers.shell_background = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.shell_bottom = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.tiling = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.fullscreen = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.shell_top = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.shell_overlay = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.session_lock = alloc_scene_tree(root->staging, &failed);
|
||||
|
||||
if (!failed) {
|
||||
output->fullscreen_background = wlr_scene_rect_create(
|
||||
output->layers.fullscreen, 0, 0, (float[4]){0.f, 0.f, 0.f, 1.f});
|
||||
|
||||
if (!output->fullscreen_background) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate a background rect");
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
destroy_scene_layers(output);
|
||||
wlr_scene_output_destroy(output->scene_output);
|
||||
free(output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output->wlr_output = wlr_output;
|
||||
wlr_output->data = output;
|
||||
output->detected_subpixel = wlr_output->subpixel;
|
||||
|
@ -102,11 +144,6 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
|
|||
output->workspaces = create_list();
|
||||
output->current.workspaces = create_list();
|
||||
|
||||
size_t len = sizeof(output->layers) / sizeof(output->layers[0]);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
wl_list_init(&output->layers[i]);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -238,20 +275,14 @@ void output_destroy(struct sway_output *output) {
|
|||
"which is still referenced by transactions")) {
|
||||
return;
|
||||
}
|
||||
|
||||
destroy_scene_layers(output);
|
||||
list_free(output->workspaces);
|
||||
list_free(output->current.workspaces);
|
||||
wl_event_source_remove(output->repaint_timer);
|
||||
free(output);
|
||||
}
|
||||
|
||||
static void untrack_output(struct sway_container *con, void *data) {
|
||||
struct sway_output *output = data;
|
||||
int index = list_find(con->outputs, output);
|
||||
if (index != -1) {
|
||||
list_del(con->outputs, index);
|
||||
}
|
||||
}
|
||||
|
||||
void output_disable(struct sway_output *output) {
|
||||
if (!sway_assert(output->enabled, "Expected an enabled output")) {
|
||||
return;
|
||||
|
@ -266,8 +297,6 @@ void output_disable(struct sway_output *output) {
|
|||
|
||||
output_evacuate(output);
|
||||
|
||||
root_for_each_container(untrack_output, output);
|
||||
|
||||
list_del(root->outputs, index);
|
||||
|
||||
output->enabled = false;
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
|
@ -30,13 +32,51 @@ struct sway_root *root_create(struct wl_display *wl_display) {
|
|||
sway_log(SWAY_ERROR, "Unable to allocate sway_root");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene *root_scene = wlr_scene_create();
|
||||
if (!root_scene) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate root scene node");
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_init(&root->node, N_ROOT, root);
|
||||
root->root_scene = root_scene;
|
||||
|
||||
bool failed = false;
|
||||
root->staging = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
root->layer_tree = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
|
||||
root->layers.shell_background = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.shell_bottom = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.tiling = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.floating = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed);
|
||||
#if HAVE_XWAYLAND
|
||||
root->layers.unmanaged = alloc_scene_tree(root->layer_tree, &failed);
|
||||
#endif
|
||||
root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.popup = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.seat = alloc_scene_tree(root->layer_tree, &failed);
|
||||
root->layers.session_lock = alloc_scene_tree(root->layer_tree, &failed);
|
||||
|
||||
if (!failed && !scene_descriptor_assign(&root->layers.seat->node,
|
||||
SWAY_SCENE_DESC_NON_INTERACTIVE, (void *)1)) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&root_scene->tree.node);
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_enabled(&root->staging->node, false);
|
||||
|
||||
root->output_layout = wlr_output_layout_create(wl_display);
|
||||
wl_list_init(&root->all_outputs);
|
||||
#if HAVE_XWAYLAND
|
||||
wl_list_init(&root->xwayland_unmanaged);
|
||||
#endif
|
||||
wl_list_init(&root->drag_icons);
|
||||
wl_signal_init(&root->events.new_node);
|
||||
root->outputs = create_list();
|
||||
root->non_desktop_outputs = create_list();
|
||||
|
@ -53,6 +93,7 @@ void root_destroy(struct sway_root *root) {
|
|||
list_free(root->scratchpad);
|
||||
list_free(root->non_desktop_outputs);
|
||||
list_free(root->outputs);
|
||||
wlr_scene_node_destroy(&root->root_scene->tree.node);
|
||||
free(root);
|
||||
}
|
||||
|
||||
|
|
428
sway/tree/view.c
428
sway/tree/view.c
|
@ -16,7 +16,6 @@
|
|||
#include "log.h"
|
||||
#include "sway/criteria.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/desktop/launcher.h"
|
||||
|
@ -24,8 +23,9 @@
|
|||
#include "sway/ipc-server.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/surface.h"
|
||||
#include "sway/sway_text_node.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
@ -35,15 +35,29 @@
|
|||
#include "pango.h"
|
||||
#include "stringop.h"
|
||||
|
||||
void view_init(struct sway_view *view, enum sway_view_type type,
|
||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||
const struct sway_view_impl *impl) {
|
||||
bool failed = false;
|
||||
view->scene_tree = alloc_scene_tree(root->staging, &failed);
|
||||
view->content_tree = alloc_scene_tree(view->scene_tree, &failed);
|
||||
|
||||
if (!failed && !scene_descriptor_assign(&view->scene_tree->node,
|
||||
SWAY_SCENE_DESC_VIEW, view)) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
return false;
|
||||
}
|
||||
|
||||
view->type = type;
|
||||
view->impl = impl;
|
||||
view->executed_criteria = create_list();
|
||||
wl_list_init(&view->saved_buffers);
|
||||
view->allow_request_urgent = true;
|
||||
view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
|
||||
wl_signal_init(&view->events.unmap);
|
||||
return true;
|
||||
}
|
||||
|
||||
void view_destroy(struct sway_view *view) {
|
||||
|
@ -60,13 +74,10 @@ void view_destroy(struct sway_view *view) {
|
|||
return;
|
||||
}
|
||||
wl_list_remove(&view->events.unmap.listener_list);
|
||||
if (!wl_list_empty(&view->saved_buffers)) {
|
||||
view_remove_saved_buffer(view);
|
||||
}
|
||||
list_free(view->executed_criteria);
|
||||
|
||||
view_assign_ctx(view, NULL);
|
||||
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
free(view->title_format);
|
||||
|
||||
if (view->impl->destroy) {
|
||||
|
@ -443,52 +454,6 @@ void view_close_popups(struct sway_view *view) {
|
|||
}
|
||||
}
|
||||
|
||||
void view_damage_from(struct sway_view *view) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
output_damage_from_view(output, view);
|
||||
}
|
||||
}
|
||||
|
||||
void view_for_each_surface(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data) {
|
||||
if (!view->surface) {
|
||||
return;
|
||||
}
|
||||
if (view->impl->for_each_surface) {
|
||||
view->impl->for_each_surface(view, iterator, user_data);
|
||||
} else {
|
||||
wlr_surface_for_each_surface(view->surface, iterator, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void view_for_each_popup_surface(struct sway_view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data) {
|
||||
if (!view->surface) {
|
||||
return;
|
||||
}
|
||||
if (view->impl->for_each_popup_surface) {
|
||||
view->impl->for_each_popup_surface(view, iterator, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void view_subsurface_create(struct sway_view *view,
|
||||
struct wlr_subsurface *subsurface);
|
||||
|
||||
static void view_init_subsurfaces(struct sway_view *view,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
static void view_child_init_subsurfaces(struct sway_view_child *view_child,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
static void view_handle_surface_new_subsurface(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_view *view =
|
||||
wl_container_of(listener, view, surface_new_subsurface);
|
||||
struct wlr_subsurface *subsurface = data;
|
||||
view_subsurface_create(view, subsurface);
|
||||
}
|
||||
|
||||
static bool view_has_executed_criteria(struct sway_view *view,
|
||||
struct criteria *criteria) {
|
||||
for (int i = 0; i < view->executed_criteria->length; ++i) {
|
||||
|
@ -809,11 +774,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
|
|||
}
|
||||
ipc_event_window(view->container, "new");
|
||||
|
||||
view_init_subsurfaces(view, wlr_surface);
|
||||
wl_signal_add(&wlr_surface->events.new_subsurface,
|
||||
&view->surface_new_subsurface);
|
||||
view->surface_new_subsurface.notify = view_handle_surface_new_subsurface;
|
||||
|
||||
if (decoration) {
|
||||
view_update_csd_from_client(view, decoration);
|
||||
}
|
||||
|
@ -880,8 +840,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
|
|||
void view_unmap(struct sway_view *view) {
|
||||
wl_signal_emit_mutable(&view->events.unmap, view);
|
||||
|
||||
wl_list_remove(&view->surface_new_subsurface.link);
|
||||
|
||||
view->executed_criteria->length = 0;
|
||||
|
||||
if (view->urgent_timer) {
|
||||
|
@ -935,260 +893,28 @@ void view_update_size(struct sway_view *view) {
|
|||
container_set_geometry_from_content(con);
|
||||
}
|
||||
|
||||
void view_center_surface(struct sway_view *view) {
|
||||
void view_center_and_clip_surface(struct sway_view *view) {
|
||||
struct sway_container *con = view->container;
|
||||
// We always center the current coordinates rather than the next, as the
|
||||
// geometry immediately affects the currently active rendering.
|
||||
con->surface_x = fmax(con->current.content_x, con->current.content_x +
|
||||
(con->current.content_width - view->geometry.width) / 2);
|
||||
con->surface_y = fmax(con->current.content_y, con->current.content_y +
|
||||
(con->current.content_height - view->geometry.height) / 2);
|
||||
}
|
||||
|
||||
static const struct sway_view_child_impl subsurface_impl;
|
||||
if (container_is_floating(con)) {
|
||||
// We always center the current coordinates rather than the next, as the
|
||||
// geometry immediately affects the currently active rendering.
|
||||
int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2);
|
||||
int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2);
|
||||
|
||||
static void subsurface_get_view_coords(struct sway_view_child *child,
|
||||
int *sx, int *sy) {
|
||||
struct wlr_surface *surface = child->surface;
|
||||
if (child->parent && child->parent->impl &&
|
||||
child->parent->impl->get_view_coords) {
|
||||
child->parent->impl->get_view_coords(child->parent, sx, sy);
|
||||
wlr_scene_node_set_position(&view->content_tree->node, x, y);
|
||||
} else {
|
||||
*sx = *sy = 0;
|
||||
}
|
||||
struct wlr_subsurface *subsurface =
|
||||
wlr_subsurface_try_from_wlr_surface(surface);
|
||||
*sx += subsurface->current.x;
|
||||
*sy += subsurface->current.y;
|
||||
}
|
||||
|
||||
static void subsurface_destroy(struct sway_view_child *child) {
|
||||
if (!sway_assert(child->impl == &subsurface_impl,
|
||||
"Expected a subsurface")) {
|
||||
return;
|
||||
}
|
||||
struct sway_subsurface *subsurface = (struct sway_subsurface *)child;
|
||||
wl_list_remove(&subsurface->destroy.link);
|
||||
free(subsurface);
|
||||
}
|
||||
|
||||
static const struct sway_view_child_impl subsurface_impl = {
|
||||
.get_view_coords = subsurface_get_view_coords,
|
||||
.destroy = subsurface_destroy,
|
||||
};
|
||||
|
||||
static void subsurface_handle_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, destroy);
|
||||
struct sway_view_child *child = &subsurface->child;
|
||||
view_child_destroy(child);
|
||||
}
|
||||
|
||||
static void view_child_damage(struct sway_view_child *child, bool whole);
|
||||
|
||||
static void view_subsurface_create(struct sway_view *view,
|
||||
struct wlr_subsurface *wlr_subsurface) {
|
||||
struct sway_subsurface *subsurface =
|
||||
calloc(1, sizeof(struct sway_subsurface));
|
||||
if (subsurface == NULL) {
|
||||
sway_log(SWAY_ERROR, "Allocation failed");
|
||||
return;
|
||||
}
|
||||
view_child_init(&subsurface->child, &subsurface_impl, view,
|
||||
wlr_subsurface->surface);
|
||||
|
||||
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
|
||||
subsurface->destroy.notify = subsurface_handle_destroy;
|
||||
|
||||
subsurface->child.mapped = true;
|
||||
|
||||
view_child_damage(&subsurface->child, true);
|
||||
}
|
||||
|
||||
static void view_child_subsurface_create(struct sway_view_child *child,
|
||||
struct wlr_subsurface *wlr_subsurface) {
|
||||
struct sway_subsurface *subsurface =
|
||||
calloc(1, sizeof(struct sway_subsurface));
|
||||
if (subsurface == NULL) {
|
||||
sway_log(SWAY_ERROR, "Allocation failed");
|
||||
return;
|
||||
}
|
||||
subsurface->child.parent = child;
|
||||
wl_list_insert(&child->children, &subsurface->child.link);
|
||||
view_child_init(&subsurface->child, &subsurface_impl, child->view,
|
||||
wlr_subsurface->surface);
|
||||
|
||||
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
|
||||
subsurface->destroy.notify = subsurface_handle_destroy;
|
||||
|
||||
subsurface->child.mapped = true;
|
||||
|
||||
view_child_damage(&subsurface->child, true);
|
||||
}
|
||||
|
||||
static bool view_child_is_mapped(struct sway_view_child *child) {
|
||||
while (child) {
|
||||
if (!child->mapped) {
|
||||
return false;
|
||||
}
|
||||
child = child->parent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void view_child_damage(struct sway_view_child *child, bool whole) {
|
||||
if (!child || !view_child_is_mapped(child) || !child->view || !child->view->container) {
|
||||
return;
|
||||
}
|
||||
int sx, sy;
|
||||
child->impl->get_view_coords(child, &sx, &sy);
|
||||
desktop_damage_surface(child->surface,
|
||||
child->view->container->pending.content_x -
|
||||
child->view->geometry.x + sx,
|
||||
child->view->container->pending.content_y -
|
||||
child->view->geometry.y + sy, whole);
|
||||
}
|
||||
|
||||
static void view_child_handle_surface_commit(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_view_child *child =
|
||||
wl_container_of(listener, child, surface_commit);
|
||||
view_child_damage(child, false);
|
||||
}
|
||||
|
||||
static void view_child_handle_surface_new_subsurface(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct sway_view_child *child =
|
||||
wl_container_of(listener, child, surface_new_subsurface);
|
||||
struct wlr_subsurface *subsurface = data;
|
||||
view_child_subsurface_create(child, subsurface);
|
||||
}
|
||||
|
||||
static void view_child_handle_surface_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_view_child *child =
|
||||
wl_container_of(listener, child, surface_destroy);
|
||||
view_child_destroy(child);
|
||||
}
|
||||
|
||||
static void view_init_subsurfaces(struct sway_view *view,
|
||||
struct wlr_surface *surface) {
|
||||
struct wlr_subsurface *subsurface;
|
||||
wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
|
||||
current.link) {
|
||||
view_subsurface_create(view, subsurface);
|
||||
}
|
||||
wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
|
||||
current.link) {
|
||||
view_subsurface_create(view, subsurface);
|
||||
}
|
||||
}
|
||||
|
||||
static void view_child_init_subsurfaces(struct sway_view_child *view_child,
|
||||
struct wlr_surface *surface) {
|
||||
struct wlr_subsurface *subsurface;
|
||||
wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
|
||||
current.link) {
|
||||
view_child_subsurface_create(view_child, subsurface);
|
||||
}
|
||||
wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
|
||||
current.link) {
|
||||
view_child_subsurface_create(view_child, subsurface);
|
||||
}
|
||||
}
|
||||
|
||||
static void view_child_handle_surface_map(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_view_child *child =
|
||||
wl_container_of(listener, child, surface_map);
|
||||
child->mapped = true;
|
||||
view_child_damage(child, true);
|
||||
}
|
||||
|
||||
static void view_child_handle_surface_unmap(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_view_child *child =
|
||||
wl_container_of(listener, child, surface_unmap);
|
||||
view_child_damage(child, true);
|
||||
child->mapped = false;
|
||||
}
|
||||
|
||||
static void view_child_handle_view_unmap(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_view_child *child =
|
||||
wl_container_of(listener, child, view_unmap);
|
||||
view_child_damage(child, true);
|
||||
child->mapped = false;
|
||||
}
|
||||
|
||||
void view_child_init(struct sway_view_child *child,
|
||||
const struct sway_view_child_impl *impl, struct sway_view *view,
|
||||
struct wlr_surface *surface) {
|
||||
child->impl = impl;
|
||||
child->view = view;
|
||||
child->surface = surface;
|
||||
wl_list_init(&child->children);
|
||||
|
||||
wl_signal_add(&surface->events.commit, &child->surface_commit);
|
||||
child->surface_commit.notify = view_child_handle_surface_commit;
|
||||
wl_signal_add(&surface->events.new_subsurface,
|
||||
&child->surface_new_subsurface);
|
||||
child->surface_new_subsurface.notify =
|
||||
view_child_handle_surface_new_subsurface;
|
||||
wl_signal_add(&surface->events.destroy, &child->surface_destroy);
|
||||
child->surface_destroy.notify = view_child_handle_surface_destroy;
|
||||
|
||||
// Not all child views have a map/unmap event
|
||||
child->surface_map.notify = view_child_handle_surface_map;
|
||||
wl_list_init(&child->surface_map.link);
|
||||
child->surface_unmap.notify = view_child_handle_surface_unmap;
|
||||
wl_list_init(&child->surface_unmap.link);
|
||||
|
||||
wl_signal_add(&view->events.unmap, &child->view_unmap);
|
||||
child->view_unmap.notify = view_child_handle_view_unmap;
|
||||
|
||||
struct sway_container *container = child->view->container;
|
||||
if (container != NULL) {
|
||||
struct sway_workspace *workspace = container->pending.workspace;
|
||||
if (workspace) {
|
||||
surface_enter_output(child->surface, workspace->output);
|
||||
}
|
||||
wlr_scene_node_set_position(&view->content_tree->node, 0, 0);
|
||||
}
|
||||
|
||||
view_child_init_subsurfaces(child, surface);
|
||||
}
|
||||
|
||||
void view_child_destroy(struct sway_view_child *child) {
|
||||
if (view_child_is_mapped(child) && child->view->container != NULL) {
|
||||
view_child_damage(child, true);
|
||||
}
|
||||
|
||||
if (child->parent != NULL) {
|
||||
wl_list_remove(&child->link);
|
||||
child->parent = NULL;
|
||||
}
|
||||
|
||||
struct sway_view_child *subchild, *tmpchild;
|
||||
wl_list_for_each_safe(subchild, tmpchild, &child->children, link) {
|
||||
wl_list_remove(&subchild->link);
|
||||
subchild->parent = NULL;
|
||||
// The subchild lost its parent link, so it cannot see that the parent
|
||||
// is unmapped. Unmap it directly.
|
||||
subchild->mapped = false;
|
||||
}
|
||||
|
||||
wl_list_remove(&child->surface_commit.link);
|
||||
wl_list_remove(&child->surface_destroy.link);
|
||||
wl_list_remove(&child->surface_map.link);
|
||||
wl_list_remove(&child->surface_unmap.link);
|
||||
wl_list_remove(&child->view_unmap.link);
|
||||
wl_list_remove(&child->surface_new_subsurface.link);
|
||||
|
||||
if (child->impl && child->impl->destroy) {
|
||||
child->impl->destroy(child);
|
||||
} else {
|
||||
free(child);
|
||||
// only make sure to clip the content if there is content to clip
|
||||
if (!wl_list_empty(&con->view->content_tree->children)) {
|
||||
wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &(struct wlr_box){
|
||||
.x = con->view->geometry.x,
|
||||
.y = con->view->geometry.y,
|
||||
.width = con->current.content_width,
|
||||
.height = con->current.content_height,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1321,7 +1047,13 @@ void view_update_title(struct sway_view *view, bool force) {
|
|||
view->container->title = title ? strdup(title) : NULL;
|
||||
|
||||
// Update title after the global font height is updated
|
||||
container_update_title_textures(view->container);
|
||||
if (view->container->title_bar.title_text && len) {
|
||||
sway_text_node_set_text(view->container->title_bar.title_text,
|
||||
view->container->formatted_title);
|
||||
container_arrange_title_bar(view->container);
|
||||
} else {
|
||||
container_update_title_bar(view->container);
|
||||
}
|
||||
|
||||
ipc_event_window(view->container, "title");
|
||||
|
||||
|
@ -1388,6 +1120,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
|
|||
return;
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &view->urgent);
|
||||
container_update_itself_and_parents(view->container);
|
||||
} else {
|
||||
view->urgent = (struct timespec){ 0 };
|
||||
if (view->urgent_timer) {
|
||||
|
@ -1395,7 +1128,6 @@ void view_set_urgent(struct sway_view *view, bool enable) {
|
|||
view->urgent_timer = NULL;
|
||||
}
|
||||
}
|
||||
container_damage_whole(view->container);
|
||||
|
||||
ipc_event_window(view->container, "urgent");
|
||||
|
||||
|
@ -1409,40 +1141,54 @@ bool view_is_urgent(struct sway_view *view) {
|
|||
}
|
||||
|
||||
void view_remove_saved_buffer(struct sway_view *view) {
|
||||
if (!sway_assert(!wl_list_empty(&view->saved_buffers), "Expected a saved buffer")) {
|
||||
if (!sway_assert(view->saved_surface_tree, "Expected a saved buffer")) {
|
||||
return;
|
||||
}
|
||||
struct sway_saved_buffer *saved_buf, *tmp;
|
||||
wl_list_for_each_safe(saved_buf, tmp, &view->saved_buffers, link) {
|
||||
wlr_buffer_unlock(&saved_buf->buffer->base);
|
||||
wl_list_remove(&saved_buf->link);
|
||||
free(saved_buf);
|
||||
}
|
||||
|
||||
wlr_scene_node_destroy(&view->saved_surface_tree->node);
|
||||
view->saved_surface_tree = NULL;
|
||||
wlr_scene_node_set_enabled(&view->content_tree->node, true);
|
||||
}
|
||||
|
||||
static void view_save_buffer_iterator(struct wlr_surface *surface,
|
||||
static void view_save_buffer_iterator(struct wlr_scene_buffer *buffer,
|
||||
int sx, int sy, void *data) {
|
||||
struct sway_view *view = data;
|
||||
struct wlr_scene_tree *tree = data;
|
||||
|
||||
if (surface && surface->buffer) {
|
||||
wlr_buffer_lock(&surface->buffer->base);
|
||||
struct sway_saved_buffer *saved_buffer = calloc(1, sizeof(struct sway_saved_buffer));
|
||||
saved_buffer->buffer = surface->buffer;
|
||||
saved_buffer->width = surface->current.width;
|
||||
saved_buffer->height = surface->current.height;
|
||||
saved_buffer->x = view->container->surface_x + sx;
|
||||
saved_buffer->y = view->container->surface_y + sy;
|
||||
saved_buffer->transform = surface->current.transform;
|
||||
wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box);
|
||||
wl_list_insert(view->saved_buffers.prev, &saved_buffer->link);
|
||||
struct wlr_scene_buffer *sbuf = wlr_scene_buffer_create(tree, NULL);
|
||||
if (!sbuf) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a scene buffer when saving a surface");
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_dest_size(sbuf,
|
||||
buffer->dst_width, buffer->dst_height);
|
||||
wlr_scene_buffer_set_opaque_region(sbuf, &buffer->opaque_region);
|
||||
wlr_scene_buffer_set_source_box(sbuf, &buffer->src_box);
|
||||
wlr_scene_node_set_position(&sbuf->node, sx, sy);
|
||||
wlr_scene_buffer_set_transform(sbuf, buffer->transform);
|
||||
wlr_scene_buffer_set_buffer(sbuf, buffer->buffer);
|
||||
}
|
||||
|
||||
void view_save_buffer(struct sway_view *view) {
|
||||
if (!sway_assert(wl_list_empty(&view->saved_buffers), "Didn't expect saved buffer")) {
|
||||
if (!sway_assert(!view->saved_surface_tree, "Didn't expect saved buffer")) {
|
||||
view_remove_saved_buffer(view);
|
||||
}
|
||||
view_for_each_surface(view, view_save_buffer_iterator, view);
|
||||
|
||||
view->saved_surface_tree = wlr_scene_tree_create(view->scene_tree);
|
||||
if (!view->saved_surface_tree) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a scene tree node when saving a surface");
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable and disable the saved surface tree like so to atomitaclly update
|
||||
// the tree. This will prevent over damaging or other weirdness.
|
||||
wlr_scene_node_set_enabled(&view->saved_surface_tree->node, false);
|
||||
|
||||
wlr_scene_node_for_each_buffer(&view->content_tree->node,
|
||||
view_save_buffer_iterator, view->saved_surface_tree);
|
||||
|
||||
wlr_scene_node_set_enabled(&view->content_tree->node, false);
|
||||
wlr_scene_node_set_enabled(&view->saved_surface_tree->node, true);
|
||||
}
|
||||
|
||||
bool view_is_transient_for(struct sway_view *child,
|
||||
|
@ -1450,3 +1196,19 @@ bool view_is_transient_for(struct sway_view *child,
|
|||
return child->impl->is_transient_for &&
|
||||
child->impl->is_transient_for(child, ancestor);
|
||||
}
|
||||
|
||||
static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
|
||||
int x, int y, void *data) {
|
||||
struct timespec *when = data;
|
||||
wl_signal_emit_mutable(&scene_buffer->events.frame_done, when);
|
||||
}
|
||||
|
||||
void view_send_frame_done(struct sway_view *view) {
|
||||
struct timespec when;
|
||||
clock_gettime(CLOCK_MONOTONIC, &when);
|
||||
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &view->content_tree->children, link) {
|
||||
wlr_scene_node_for_each_buffer(node, send_frame_done_iterator, &when);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,18 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
|||
return NULL;
|
||||
}
|
||||
node_init(&ws->node, N_WORKSPACE, ws);
|
||||
|
||||
bool failed = false;
|
||||
ws->layers.tiling = alloc_scene_tree(root->staging, &failed);
|
||||
ws->layers.fullscreen = alloc_scene_tree(root->staging, &failed);
|
||||
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&ws->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&ws->layers.fullscreen->node);
|
||||
free(ws);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ws->name = strdup(name);
|
||||
ws->prev_split_layout = L_NONE;
|
||||
ws->layout = output_get_default_layout(output);
|
||||
|
@ -131,6 +143,11 @@ void workspace_destroy(struct sway_workspace *workspace) {
|
|||
return;
|
||||
}
|
||||
|
||||
scene_node_disown_children(workspace->layers.tiling);
|
||||
scene_node_disown_children(workspace->layers.fullscreen);
|
||||
wlr_scene_node_destroy(&workspace->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&workspace->layers.fullscreen->node);
|
||||
|
||||
free(workspace->name);
|
||||
free(workspace->representation);
|
||||
list_free_items_and_destroy(workspace->output_priority);
|
||||
|
@ -669,7 +686,6 @@ void workspace_detect_urgent(struct sway_workspace *workspace) {
|
|||
if (workspace->urgent != new_urgent) {
|
||||
workspace->urgent = new_urgent;
|
||||
ipc_event_workspace(NULL, workspace, "urgent");
|
||||
output_damage_whole(workspace->output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue