mirror of
https://github.com/swaywm/sway.git
synced 2026-04-24 06:46:22 -04:00
Merge cb4205185c into dcd2076f38
This commit is contained in:
commit
5b99f2b6c3
53 changed files with 2543 additions and 4153 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/util/edges.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/tablet.h"
|
||||
|
|
@ -42,8 +43,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 sway_output *output,
|
||||
pixman_region32_t *damage);
|
||||
bool allow_set_cursor;
|
||||
};
|
||||
|
||||
|
|
@ -67,16 +66,12 @@ struct sway_seat_node {
|
|||
};
|
||||
|
||||
struct sway_drag_icon {
|
||||
struct sway_seat *seat;
|
||||
struct wlr_drag_icon *wlr_drag_icon;
|
||||
struct wl_list link; // sway_root::drag_icons
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wlr_scene_tree *surface_tree;
|
||||
|
||||
double x, y; // in layout-local coordinates
|
||||
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
};
|
||||
|
||||
struct sway_drag {
|
||||
|
|
@ -89,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;
|
||||
|
|
@ -247,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_icon_update_position(struct sway_seat *seat, struct sway_drag_icon *icon);
|
||||
|
||||
enum wlr_edges find_resize_edge(struct sway_container *cont,
|
||||
struct wlr_surface *surface, struct sway_cursor *cursor);
|
||||
|
|
@ -332,13 +336,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 sway_output *output,
|
||||
pixman_region32_t *damage);
|
||||
|
||||
bool seatop_allows_set_cursor(struct sway_seat *seat);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,60 +4,32 @@
|
|||
#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 *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;
|
||||
};
|
||||
|
||||
struct sway_output;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <unistd.h>
|
||||
#include <wayland-server-core.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"
|
||||
|
|
@ -18,15 +19,32 @@ 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 wlr_fbox usable_area;
|
||||
|
||||
struct timespec last_frame;
|
||||
struct wlr_output_damage *damage;
|
||||
|
||||
int lx, ly; // layout coords
|
||||
int width, height; // transformed buffer size
|
||||
|
|
@ -44,8 +62,7 @@ struct sway_output {
|
|||
struct wl_listener commit;
|
||||
struct wl_listener mode;
|
||||
struct wl_listener present;
|
||||
struct wl_listener damage_destroy;
|
||||
struct wl_listener damage_frame;
|
||||
struct wl_listener frame_request;
|
||||
|
||||
struct {
|
||||
struct wl_signal disable;
|
||||
|
|
@ -81,19 +98,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);
|
||||
|
||||
// this ONLY includes the enabled outputs
|
||||
struct sway_output *output_by_name_or_id(const char *name_or_id);
|
||||
|
||||
|
|
@ -106,47 +110,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 sway_output *output, struct timespec *when,
|
||||
pixman_region32_t *damage);
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -164,14 +129,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 sway_output *output,
|
||||
pixman_region32_t *output_damage, 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);
|
||||
|
|
|
|||
26
include/sway/scene_descriptor.h
Normal file
26
include/sway/scene_descriptor.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#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_LAYER_SHELL,
|
||||
SWAY_SCENE_DESC_XWAYLAND_UNMANAGED,
|
||||
SWAY_SCENE_DESC_POPUP,
|
||||
SWAY_SCENE_DESC_DRAG_ICON,
|
||||
};
|
||||
|
||||
struct sway_scene_descriptor {
|
||||
struct wlr_scene_node *node;
|
||||
enum sway_scene_descriptor_type type;
|
||||
void *data;
|
||||
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
void scene_descriptor_assign(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type, void *data);
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,18 @@
|
|||
#endif
|
||||
|
||||
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;
|
||||
|
|
@ -40,7 +52,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;
|
||||
|
||||
|
|
@ -92,15 +103,9 @@ struct sway_server {
|
|||
struct wl_listener output_manager_test;
|
||||
|
||||
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;
|
||||
|
|
@ -139,13 +144,6 @@ 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;
|
||||
};
|
||||
|
||||
extern struct sway_debug debug;
|
||||
|
|
@ -157,12 +155,13 @@ 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);
|
||||
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
|
||||
#if HAVE_XWAYLAND
|
||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||
|
|
|
|||
|
|
@ -1,18 +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;
|
||||
};
|
||||
|
||||
#endif
|
||||
25
include/sway/sway_text_buffer.h
Normal file
25
include/sway/sway_text_buffer.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#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];
|
||||
|
||||
struct wlr_scene_node *node;
|
||||
};
|
||||
|
||||
struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
|
||||
char *text, const float *color, bool pango_markup);
|
||||
|
||||
void sway_text_node_set_color(struct sway_text_node *node, const float *color);
|
||||
|
||||
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);
|
||||
|
||||
#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_rect *border;
|
||||
struct wlr_scene_rect *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.
|
||||
|
|
@ -115,18 +136,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;
|
||||
|
|
@ -146,19 +156,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);
|
||||
|
||||
void container_for_each_child(struct sway_container *container,
|
||||
void (*f)(struct sway_container *container, void *data), void *data);
|
||||
|
||||
|
|
@ -175,13 +172,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);
|
||||
|
|
@ -214,11 +211,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.
|
||||
*/
|
||||
|
|
@ -281,26 +273,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,
|
||||
|
|
@ -348,8 +326,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);
|
||||
|
|
@ -373,4 +349,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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _SWAY_NODE_H
|
||||
#define _SWAY_NODE_H
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "list.h"
|
||||
|
||||
#define MIN_SANE_W 100
|
||||
|
|
@ -74,4 +75,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,7 +3,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
#include "config.h"
|
||||
|
|
@ -16,10 +16,40 @@ 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;
|
||||
|
||||
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 "config.h"
|
||||
#if HAVE_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
|
|
@ -39,16 +40,12 @@ struct sway_view_impl {
|
|||
enum sway_view_prop prop);
|
||||
uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop);
|
||||
uint32_t (*configure)(struct sway_view *view, double lx, double ly,
|
||||
int width, int height);
|
||||
double width, double height);
|
||||
void (*set_activated)(struct sway_view *view, bool activated);
|
||||
void (*set_tiled)(struct sway_view *view, bool tiled);
|
||||
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;
|
||||
|
|
@ -87,15 +79,9 @@ 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_fbox geometry;
|
||||
|
||||
struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
|
||||
struct wl_listener foreign_activate_request;
|
||||
|
|
@ -118,8 +104,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;
|
||||
|
|
@ -144,6 +128,8 @@ struct sway_xdg_shell_view {
|
|||
struct sway_xwayland_view {
|
||||
struct sway_view view;
|
||||
|
||||
struct wlr_scene_surface *surface_scene;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener request_move;
|
||||
struct wl_listener request_resize;
|
||||
|
|
@ -166,14 +152,12 @@ struct sway_xwayland_view {
|
|||
|
||||
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 map;
|
||||
struct wl_listener unmap;
|
||||
|
|
@ -184,7 +168,6 @@ struct sway_xwayland_unmanaged {
|
|||
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);
|
||||
};
|
||||
|
||||
|
|
@ -199,20 +182,9 @@ struct sway_view_child {
|
|||
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 wlr_scene_tree *scene_tree;
|
||||
struct wlr_scene_tree *xdg_surface_tree;
|
||||
};
|
||||
|
||||
struct sway_xdg_popup {
|
||||
|
|
@ -245,8 +217,8 @@ const char *view_get_shell(struct sway_view *view);
|
|||
void view_get_constraints(struct sway_view *view, double *min_width,
|
||||
double *max_width, double *min_height, double *max_height);
|
||||
|
||||
uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
|
||||
int height);
|
||||
uint32_t view_configure(struct sway_view *view, double lx, double ly,
|
||||
double width, double height);
|
||||
|
||||
bool view_inhibit_idle(struct sway_view *view);
|
||||
|
||||
|
|
@ -288,23 +260,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);
|
||||
|
|
@ -372,4 +330,6 @@ void view_save_buffer(struct sway_view *view);
|
|||
|
||||
bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
|
||||
|
||||
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/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
||||
|
|
@ -22,6 +23,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;
|
||||
|
|
|
|||
|
|
@ -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 title_bar_update_iterator(struct sway_container *con, void *data) {
|
||||
container_update_title_bar(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(title_bar_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,5 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
|
|||
}
|
||||
|
||||
con->alpha = val;
|
||||
container_damage_whole(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);
|
||||
|
|
|
|||
|
|
@ -524,10 +524,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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -7,6 +7,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"
|
||||
|
|
@ -16,245 +17,109 @@
|
|||
#include "sway/server.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
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_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)) {
|
||||
static void arrange_surface(struct sway_output *output, const struct wlr_fbox *full_area,
|
||||
struct wlr_fbox *usable_area, struct wlr_scene_tree *tree) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &tree->children, link) {
|
||||
struct sway_scene_descriptor *desc = node->data;
|
||||
|
||||
// the descriptor could be null during the node's destruction
|
||||
if (!desc) {
|
||||
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);
|
||||
|
||||
sway_assert(desc->type == SWAY_SCENE_DESC_LAYER_SHELL,
|
||||
"Corrupted scene tree: expected a layer shell node");
|
||||
|
||||
struct sway_layer_surface *surface = desc->data;
|
||||
wlr_scene_layer_surface_v1_configure(surface->scene,
|
||||
full_area, usable_area);
|
||||
}
|
||||
}
|
||||
|
||||
void arrange_layers(struct sway_output *output) {
|
||||
struct wlr_box usable_area = { 0 };
|
||||
int output_width, output_height;
|
||||
wlr_output_effective_resolution(output->wlr_output,
|
||||
&usable_area.width, &usable_area.height);
|
||||
&output_width, &output_height);
|
||||
struct wlr_fbox usable_area = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = output_width,
|
||||
.height = output_height,
|
||||
};
|
||||
const struct wlr_fbox 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) {
|
||||
sizeof(struct wlr_fbox)) != 0) {
|
||||
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
|
||||
memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
|
||||
memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_fbox));
|
||||
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 &&
|
||||
layer->layer_surface->mapped) {
|
||||
topmost = layer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (topmost != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
if (topmost != NULL) {
|
||||
seat_set_focus_layer(seat, topmost->layer_surface);
|
||||
} else if (seat->focused_layer &&
|
||||
!seat->focused_layer->current.keyboard_interactive) {
|
||||
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(struct sway_layer_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->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_scene_descriptor *desc = node->data;
|
||||
struct sway_layer_surface *surface = desc->data;
|
||||
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->mapped) {
|
||||
return lsurface;
|
||||
&& layer_surface->mapped) {
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -262,293 +127,131 @@ 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);
|
||||
|
||||
// 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);
|
||||
wl_resource_get_client(layer->layer_surface->resource);
|
||||
bool set_focus = seat->exclusive_client == client;
|
||||
|
||||
if (set_focus) {
|
||||
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);
|
||||
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->mapped) {
|
||||
layer->mapped = layer_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;
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (committed || layer_surface->mapped != surface->mapped) {
|
||||
surface->mapped = layer_surface->mapped;
|
||||
arrange_layers(surface->output);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
transaction_commit_dirty();
|
||||
double 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 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->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);
|
||||
wlr_surface_send_enter(sway_layer->layer_surface->surface,
|
||||
sway_layer->layer_surface->output);
|
||||
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->events.map, &subsurface->map);
|
||||
subsurface->unmap.notify = subsurface_handle_unmap;
|
||||
wl_signal_add(&wlr_subsurface->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);
|
||||
}
|
||||
|
||||
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");
|
||||
wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
|
||||
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);
|
||||
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);
|
||||
wl_list_remove(&popup->new_popup.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;
|
||||
double 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,
|
||||
struct wlr_fbox output_toplevel_sx_box = {
|
||||
.x = output->lx - lx,
|
||||
.y = output->ly - ly,
|
||||
.width = output->width,
|
||||
.height = output->height,
|
||||
};
|
||||
|
|
@ -559,25 +262,25 @@ static void popup_unconstrain(struct sway_layer_popup *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_surface *toplevel, struct wlr_scene_tree *parent) {
|
||||
struct sway_layer_popup *popup =
|
||||
calloc(1, sizeof(struct sway_layer_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->events.map, &popup->map);
|
||||
popup->unmap.notify = popup_handle_unmap;
|
||||
wl_signal_add(&wlr_popup->base->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);
|
||||
|
||||
|
|
@ -590,25 +293,20 @@ 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) {
|
||||
struct wlr_layer_surface_v1 *layer_surface = data;
|
||||
sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32
|
||||
" size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",",
|
||||
" size %lfx%lf margin %lf,%lf,%lf,%lf",
|
||||
layer_surface->namespace,
|
||||
layer_surface->pending.layer,
|
||||
layer_surface->pending.anchor,
|
||||
|
|
@ -634,10 +332,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;
|
||||
}
|
||||
|
|
@ -646,39 +340,53 @@ 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;
|
||||
}
|
||||
|
||||
scene_descriptor_assign(&scene_surface->tree->node,
|
||||
SWAY_SCENE_DESC_LAYER_SHELL, surface);
|
||||
if (!scene_surface->tree->node.data) {
|
||||
// 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->events.map, &surface->map);
|
||||
surface->unmap.notify = handle_unmap;
|
||||
wl_signal_add(&layer_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->events.map, &sway_layer->map);
|
||||
sway_layer->unmap.notify = handle_unmap;
|
||||
wl_signal_add(&layer_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->node_destroy.notify = handle_node_destroy;
|
||||
wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
|
||||
|
||||
// Temporarily set the layer's current state to pending
|
||||
// So that we can easily arrange it
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_presentation_time.h>
|
||||
|
|
@ -24,8 +23,8 @@
|
|||
#include "sway/input/seat.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"
|
||||
|
|
@ -58,318 +57,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->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->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 round((offset + length) * scale) - round(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 = round(box->x * scale);
|
||||
box->y = round(box->y * scale);
|
||||
}
|
||||
|
||||
struct sway_workspace *output_get_active_workspace(struct sway_output *output) {
|
||||
struct sway_seat *seat = input_manager_current_seat();
|
||||
|
|
@ -383,201 +70,130 @@ 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_assign(struct wlr_scene_buffer *buffer) {
|
||||
struct buffer_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,
|
||||
double x, double 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) {
|
||||
if (current->data) {
|
||||
struct sway_scene_descriptor *desc = current->data;
|
||||
|
||||
if (desc->type == SWAY_SCENE_DESC_CONTAINER) {
|
||||
struct sway_container *con = desc->data;
|
||||
|
||||
// We can be dealing with a title bar without owned by a
|
||||
// container without a view. This will happen if you have a
|
||||
// nested tabbed view for example.
|
||||
if (con->view) {
|
||||
view_max_render_time = con->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);
|
||||
} else {
|
||||
struct sway_surface *sway_surface = surface->data;
|
||||
wl_event_source_timer_update(sway_surface->frame_done_timer, delay);
|
||||
}
|
||||
}
|
||||
struct buffer_timer *timer = NULL;
|
||||
|
||||
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 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 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;
|
||||
}
|
||||
|
||||
if (server.session_lock.locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wl_list_empty(&view->saved_buffers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
if (output->max_render_time != 0 && view_max_render_time != 0 && delay > 0) {
|
||||
if (buffer->node.data) {
|
||||
struct sway_scene_descriptor *desc = buffer->node.data;
|
||||
sway_assert(desc->type == SWAY_SCENE_DESC_BUFFER_TIMER,
|
||||
"Corrupted scene tree: expected a buffer timer");
|
||||
timer = desc->data;
|
||||
}else{
|
||||
timer = buffer_timer_assign(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
if (surface->buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((float)surface->current.scale != wlr_output->scale ||
|
||||
surface->current.transform != wlr_output->transform) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_output_attach_buffer(wlr_output, &surface->buffer->base);
|
||||
if (!wlr_output_test(wlr_output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_presentation_surface_sampled_on_output(server.presentation, surface,
|
||||
wlr_output);
|
||||
|
||||
return wlr_output_commit(wlr_output);
|
||||
if (timer) {
|
||||
wl_event_source_timer_update(timer->frame_done_timer, delay);
|
||||
} else {
|
||||
wlr_scene_buffer_send_frame_done(buffer, &data->when);
|
||||
}
|
||||
}
|
||||
|
||||
static int output_repaint_timer_handler(void *data) {
|
||||
struct sway_output *output = data;
|
||||
if (output->wlr_output == NULL) {
|
||||
return 0;
|
||||
|
||||
if (output->enabled) {
|
||||
output->wlr_output->frame_pending = false;
|
||||
wlr_scene_output_commit(output->scene_output);
|
||||
}
|
||||
|
||||
output->wlr_output->frame_pending = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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, 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) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool needs_frame;
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
if (!wlr_output_damage_attach_render(output->damage,
|
||||
&needs_frame, &damage)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (needs_frame) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
output_render(output, &now, &damage);
|
||||
} else {
|
||||
wlr_output_rollback(output->wlr_output);
|
||||
}
|
||||
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
|
||||
static void handle_frame_request(struct wl_listener *listener, void *user_data) {
|
||||
struct sway_output *output =
|
||||
wl_container_of(listener, output, damage_frame);
|
||||
wl_container_of(listener, output, frame_request);
|
||||
if (!output->enabled || !output->wlr_output->enabled) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -637,116 +253,8 @@ static void damage_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);
|
||||
}
|
||||
|
||||
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 && output->wlr_output && output->damage) {
|
||||
wlr_output_damage_add_whole(output->damage);
|
||||
}
|
||||
}
|
||||
|
||||
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 (ceil(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,
|
||||
ceil(output->wlr_output->scale) - surface->current.scale);
|
||||
}
|
||||
pixman_region32_translate(&damage, box.x, box.y);
|
||||
wlr_output_damage_add(output->damage, &damage);
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
if (whole) {
|
||||
wlr_output_damage_add_box(output->damage, &box);
|
||||
}
|
||||
|
||||
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);
|
||||
wlr_output_damage_add_box(output->damage, &box);
|
||||
}
|
||||
|
||||
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);
|
||||
wlr_output_damage_add_box(output->damage, &box);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void damage_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_output *output =
|
||||
wl_container_of(listener, output, damage_destroy);
|
||||
if (!output->enabled) {
|
||||
return;
|
||||
}
|
||||
output_disable(output);
|
||||
|
||||
wl_list_remove(&output->damage_destroy.link);
|
||||
wl_list_remove(&output->damage_frame.link);
|
||||
|
||||
transaction_commit_dirty();
|
||||
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) {
|
||||
|
|
@ -778,11 +286,12 @@ static void update_output_manager_config(struct sway_server *server) {
|
|||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_output *output = wl_container_of(listener, output, destroy);
|
||||
struct sway_server *server = output->server;
|
||||
output_begin_destroy(output);
|
||||
|
||||
if (output->enabled) {
|
||||
output_disable(output);
|
||||
}
|
||||
|
||||
output_begin_destroy(output);
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
|
|
@ -790,7 +299,10 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&output->commit.link);
|
||||
wl_list_remove(&output->mode.link);
|
||||
wl_list_remove(&output->present.link);
|
||||
wl_list_remove(&output->frame_request.link);
|
||||
|
||||
wlr_scene_output_destroy(output->scene_output);
|
||||
output->scene_output = NULL;
|
||||
output->wlr_output->data = NULL;
|
||||
output->wlr_output = NULL;
|
||||
|
||||
|
|
@ -824,11 +336,6 @@ static void handle_mode(struct wl_listener *listener, void *data) {
|
|||
update_output_manager_config(output->server);
|
||||
}
|
||||
|
||||
static void update_textures(struct sway_container *con, void *data) {
|
||||
container_update_title_textures(con);
|
||||
container_update_marks_textures(con);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -837,10 +344,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (event->committed & WLR_OUTPUT_STATE_SCALE) {
|
||||
output_for_each_container(output, update_textures, NULL);
|
||||
}
|
||||
|
||||
if (event->committed & (WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) {
|
||||
arrange_layers(output);
|
||||
arrange_output(output);
|
||||
|
|
@ -898,12 +401,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;
|
||||
output->damage = wlr_output_damage_create(wlr_output);
|
||||
output->scene_output = scene_output;
|
||||
|
||||
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
||||
output->destroy.notify = handle_destroy;
|
||||
|
|
@ -913,14 +428,16 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
output->mode.notify = handle_mode;
|
||||
wl_signal_add(&wlr_output->events.present, &output->present);
|
||||
output->present.notify = handle_present;
|
||||
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
|
||||
output->damage_frame.notify = damage_handle_frame;
|
||||
wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
|
||||
output->damage_destroy.notify = damage_handle_destroy;
|
||||
wl_signal_add(&wlr_output->events.frame, &output->frame_request);
|
||||
output->frame_request.notify = handle_frame_request;
|
||||
|
||||
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);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,46 +0,0 @@
|
|||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include "sway/server.h"
|
||||
#include "sway/surface.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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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,464 @@ 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_surface(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_title_bar(struct sway_container *con,
|
||||
int x, int y, int width, int height) {
|
||||
container_update(con);
|
||||
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, height);
|
||||
if (height) {
|
||||
int titlebar_border_thickness = config->titlebar_border_thickness;
|
||||
|
||||
wlr_scene_rect_set_size(con->title_bar.border, width, height);
|
||||
wlr_scene_rect_set_size(con->title_bar.background,
|
||||
width - titlebar_border_thickness * 2,
|
||||
height - titlebar_border_thickness * 2);
|
||||
|
||||
wlr_scene_node_set_position(&con->title_bar.tree->node, x, y);
|
||||
wlr_scene_node_set_position(&con->title_bar.background->node,
|
||||
titlebar_border_thickness, titlebar_border_thickness);
|
||||
|
||||
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 bool 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 {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!arrange_children(con->current.layout, con->current.children,
|
||||
con->current.focused_inactive_child, con->content_tree,
|
||||
width, height, gaps)) {
|
||||
sway_assert(false, "unreachable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!arrange_children(ws->current.layout, ws->current.tiling,
|
||||
ws->current.focused_inactive_child, ws->layers.tiling,
|
||||
width, height, ws->gaps_inner)) {
|
||||
sway_assert(false, "unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
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_fbox *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_scene_descriptor *desc = node->data;
|
||||
|
||||
// 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 (desc) {
|
||||
sway_assert(desc->type == SWAY_SCENE_DESC_POPUP,
|
||||
"Corrupted scene tree: expected a popup node");
|
||||
struct sway_xdg_popup *popup = desc->data;
|
||||
struct wlr_scene_tree *tree = popup->child.view->content_tree;
|
||||
|
||||
double lx, ly;
|
||||
wlr_scene_node_coords(&tree->node, &lx, &ly);
|
||||
wlr_scene_node_set_position(&popup->child.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);
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_overlay->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 +736,6 @@ static void transaction_apply(struct sway_transaction *transaction) {
|
|||
|
||||
node->instruction = NULL;
|
||||
}
|
||||
|
||||
cursor_rebase_all();
|
||||
}
|
||||
|
||||
static void transaction_commit_pending(void);
|
||||
|
|
@ -340,6 +748,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 +825,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 +899,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 +920,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"
|
||||
|
|
@ -21,17 +21,6 @@
|
|||
|
||||
static const struct sway_view_child_impl popup_impl;
|
||||
|
||||
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_destroy(struct sway_view_child *child) {
|
||||
if (!sway_assert(child->impl == &popup_impl,
|
||||
"Expected an xdg_shell popup")) {
|
||||
|
|
@ -40,22 +29,25 @@ static void popup_destroy(struct sway_view_child *child) {
|
|||
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
|
||||
wlr_scene_node_destroy(&child->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);
|
||||
struct wlr_xdg_popup *wlr_popup, struct sway_view *view,
|
||||
struct wlr_scene_tree *parent);
|
||||
|
||||
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);
|
||||
popup_create(wlr_popup, popup->child.view, popup->child.xdg_surface_tree);
|
||||
}
|
||||
|
||||
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -71,7 +63,7 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
|
|||
|
||||
// the output box expressed in the coordinate system of the toplevel parent
|
||||
// of the popup
|
||||
struct wlr_box output_toplevel_sx_box = {
|
||||
struct wlr_fbox output_toplevel_sx_box = {
|
||||
.x = output->lx - view->container->pending.content_x + view->geometry.x,
|
||||
.y = output->ly - view->container->pending.content_y + view->geometry.y,
|
||||
.width = output->width,
|
||||
|
|
@ -82,7 +74,8 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
|
|||
}
|
||||
|
||||
static struct sway_xdg_popup *popup_create(
|
||||
struct wlr_xdg_popup *wlr_popup, struct sway_view *view) {
|
||||
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 =
|
||||
|
|
@ -90,19 +83,30 @@ static struct sway_xdg_popup *popup_create(
|
|||
if (popup == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_create(parent);
|
||||
if (!scene_tree) {
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene_descriptor_assign(&scene_tree->node, SWAY_SCENE_DESC_POPUP, popup);
|
||||
|
||||
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
|
||||
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;
|
||||
|
||||
popup->child.scene_tree = scene_tree;
|
||||
popup->child.xdg_surface_tree =
|
||||
wlr_scene_xdg_surface_create(scene_tree, xdg_surface);
|
||||
|
||||
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
|
||||
popup->new_popup.notify = popup_handle_new_popup;
|
||||
wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
|
||||
popup->destroy.notify = popup_handle_destroy;
|
||||
|
||||
wl_signal_add(&xdg_surface->events.map, &popup->child.surface_map);
|
||||
wl_signal_add(&xdg_surface->events.unmap, &popup->child.surface_unmap);
|
||||
|
||||
popup_unconstrain(popup);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +146,7 @@ static const char *get_string_prop(struct sway_view *view,
|
|||
}
|
||||
|
||||
static uint32_t configure(struct sway_view *view, double lx, double ly,
|
||||
int width, int height) {
|
||||
double width, double height) {
|
||||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
xdg_shell_view_from_view(view);
|
||||
if (xdg_shell_view == NULL) {
|
||||
|
|
@ -194,24 +198,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) {
|
||||
|
|
@ -259,8 +245,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,
|
||||
|
|
@ -273,7 +257,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
struct sway_view *view = &xdg_shell_view->view;
|
||||
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base;
|
||||
|
||||
struct wlr_box new_geo;
|
||||
struct wlr_fbox new_geo;
|
||||
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
|
||||
bool new_size = new_geo.width != view->geometry.width ||
|
||||
new_geo.height != view->geometry.height ||
|
||||
|
|
@ -284,23 +268,27 @@ 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));
|
||||
memcpy(&view->geometry, &new_geo, sizeof(struct wlr_fbox));
|
||||
if (container_is_floating(view->container)) {
|
||||
view_update_size(view);
|
||||
transaction_commit_dirty_client();
|
||||
} else {
|
||||
view_center_surface(view);
|
||||
}
|
||||
desktop_damage_view(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) {
|
||||
|
|
@ -322,7 +310,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;
|
||||
}
|
||||
|
||||
double lx, ly;
|
||||
wlr_scene_node_coords(&popup->child.view->content_tree->node, &lx, &ly);
|
||||
wlr_scene_node_set_position(&popup->child.scene_tree->node, lx, ly);
|
||||
}
|
||||
|
||||
static void handle_request_maximize(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -519,8 +516,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
|
||||
xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel;
|
||||
if (!view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl)) {
|
||||
free(xdg_shell_view);
|
||||
return;
|
||||
}
|
||||
|
||||
xdg_shell_view->map.notify = handle_map;
|
||||
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
|
||||
|
|
@ -531,5 +530,8 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
|
|||
xdg_shell_view->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
|
||||
|
||||
xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel;
|
||||
wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_surface);
|
||||
|
||||
xdg_surface->data = xdg_shell_view;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,16 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.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/tree/view.h"
|
||||
|
|
@ -43,29 +44,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) {
|
||||
|
|
@ -73,17 +57,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();
|
||||
|
|
@ -97,10 +82,10 @@ 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);
|
||||
}
|
||||
|
||||
struct sway_seat *seat = input_manager_current_seat();
|
||||
if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) {
|
||||
|
|
@ -247,8 +232,8 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t configure(struct sway_view *view, double lx, double ly, int width,
|
||||
int height) {
|
||||
static uint32_t configure(struct sway_view *view, double lx, double ly,
|
||||
double width, double height) {
|
||||
struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
|
||||
if (xwayland_view == NULL) {
|
||||
return 0;
|
||||
|
|
@ -396,17 +381,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);
|
||||
|
|
@ -414,18 +388,17 @@ 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);
|
||||
|
|
@ -433,15 +406,20 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
} else {
|
||||
view_center_surface(view);
|
||||
}
|
||||
desktop_damage_view(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) {
|
||||
|
|
@ -486,6 +464,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
|||
|
||||
view_unmap(view);
|
||||
|
||||
xwayland_view->surface_scene = NULL;
|
||||
|
||||
wl_list_remove(&xwayland_view->commit.link);
|
||||
}
|
||||
|
||||
|
|
@ -506,6 +486,9 @@ 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_scene = wlr_scene_surface_create(
|
||||
xwayland_view->view.content_tree, xsurface->surface);
|
||||
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
|
|
@ -712,7 +695,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,165 +37,88 @@ 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) {
|
||||
if (wlr_surface_is_xdg_surface(surface)) {
|
||||
struct wlr_xdg_surface *xdg_surface =
|
||||
wlr_xdg_surface_from_wlr_surface(surface);
|
||||
return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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).
|
||||
*/
|
||||
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_surface **_surface, double *sx, double *sy) {
|
||||
struct wlr_scene_node *scene_node = NULL;
|
||||
size_t num_layers = sizeof(root->layers) / sizeof(struct wlr_scene_tree *);
|
||||
for (int i = num_layers - 1; i >= 0 && !scene_node; i--) {
|
||||
struct wlr_scene_tree *layer = ((struct wlr_scene_tree **) &root->layers)[i];
|
||||
struct sway_scene_descriptor *desc = layer->node.data;
|
||||
|
||||
if (!desc || desc->type != SWAY_SCENE_DESC_NON_INTERACTIVE) {
|
||||
scene_node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
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_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) {
|
||||
if (current->data) {
|
||||
struct sway_scene_descriptor *desc = current->data;
|
||||
|
||||
if (desc->type == SWAY_SCENE_DESC_CONTAINER) {
|
||||
struct sway_container *con = desc->data;
|
||||
return &con->node;
|
||||
} else if (desc->type == SWAY_SCENE_DESC_LAYER_SHELL) {
|
||||
// We don't want to feed through the current workspace on
|
||||
// layer shells
|
||||
return NULL;
|
||||
} else if (desc->type == SWAY_SCENE_DESC_POPUP) {
|
||||
struct sway_xdg_popup *popup = desc->data;
|
||||
struct sway_container *con = popup->child.view->container;
|
||||
return &con->node;
|
||||
}
|
||||
#if HAVE_XWAYLAND
|
||||
else if (desc->type == 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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
@ -541,11 +464,13 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
|
|||
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);
|
||||
}
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &seat->drag_icons->children, link) {
|
||||
struct sway_scene_descriptor *desc = node->data;
|
||||
|
||||
sway_assert(desc && desc->type == SWAY_SCENE_DESC_DRAG_ICON,
|
||||
"Corrupted scene tree: expected a drag icon");
|
||||
drag_icon_update_position(seat, desc->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
|
|||
struct sway_input_manager *input_manager = wl_container_of(
|
||||
listener, input_manager, inhibit_deactivate);
|
||||
struct sway_seat *seat;
|
||||
if (server.session_lock.locked) {
|
||||
if (server.session_lock.lock) {
|
||||
// Don't deactivate the grab of a screenlocker
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,7 +405,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
|||
bool exact_identifier = keyboard->wlr->group != NULL;
|
||||
seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
|
||||
bool input_inhibited = seat->exclusive_client != NULL ||
|
||||
server.session_lock.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);
|
||||
|
|
@ -365,25 +366,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->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);
|
||||
|
||||
void drag_icon_update_position(struct sway_seat *seat, struct sway_drag_icon *icon) {
|
||||
struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon;
|
||||
struct sway_seat *seat = icon->seat;
|
||||
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 + wlr_icon->surface->sx;
|
||||
icon->y = cursor->y + wlr_icon->surface->sy;
|
||||
wlr_scene_node_set_position(&icon->tree->node, cursor->x, cursor->y);
|
||||
break;
|
||||
case WLR_DRAG_GRAB_KEYBOARD_TOUCH:;
|
||||
struct wlr_touch_point *point =
|
||||
|
|
@ -391,38 +382,23 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
|
|||
if (point == NULL) {
|
||||
return;
|
||||
}
|
||||
icon->x = seat->touch_x + wlr_icon->surface->sx;
|
||||
icon->y = seat->touch_y + wlr_icon->surface->sy;
|
||||
wlr_scene_node_set_position(&icon->tree->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);
|
||||
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_commit(struct wl_listener *listener, void *data) {
|
||||
struct sway_drag_icon *icon = wl_container_of(listener, icon, commit);
|
||||
struct wlr_surface *surface = icon->wlr_drag_icon->surface;
|
||||
wlr_scene_node_set_position(&icon->surface_tree->node,
|
||||
surface->sx, surface->sy);
|
||||
}
|
||||
|
||||
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->commit.link);
|
||||
wl_list_remove(&icon->destroy.link);
|
||||
wlr_scene_node_destroy(&icon->tree->node);
|
||||
free(icon);
|
||||
}
|
||||
|
||||
|
|
@ -500,22 +476,40 @@ static void handle_start_drag(struct wl_listener *listener, void *data) {
|
|||
sway_log(SWAY_ERROR, "Allocation failed");
|
||||
return;
|
||||
}
|
||||
icon->seat = seat;
|
||||
|
||||
icon->tree = wlr_scene_tree_create(seat->drag_icons);
|
||||
if (!icon->tree) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a drag icon scene tree");
|
||||
free(icon);
|
||||
return;
|
||||
}
|
||||
|
||||
icon->surface_tree = wlr_scene_subsurface_tree_create(icon->tree,
|
||||
wlr_drag_icon->surface);
|
||||
if (!icon->surface_tree) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a drag icon surface");
|
||||
wlr_scene_node_destroy(&icon->tree->node);
|
||||
free(icon);
|
||||
return;
|
||||
}
|
||||
|
||||
scene_descriptor_assign(&icon->tree->node, SWAY_SCENE_DESC_DRAG_ICON, icon);
|
||||
if (!icon->tree->node.data) {
|
||||
wlr_scene_node_destroy(&icon->tree->node);
|
||||
free(icon);
|
||||
return;
|
||||
}
|
||||
|
||||
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->events.unmap, &icon->unmap);
|
||||
icon->map.notify = drag_icon_handle_map;
|
||||
wl_signal_add(&wlr_drag_icon->events.map, &icon->map);
|
||||
icon->commit.notify = drag_icon_handle_commit;
|
||||
wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->commit);
|
||||
|
||||
icon->destroy.notify = drag_icon_handle_destroy;
|
||||
wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy);
|
||||
|
||||
wl_list_insert(&root->drag_icons, &icon->link);
|
||||
|
||||
drag_icon_update_position(icon);
|
||||
drag_icon_update_position(seat, icon);
|
||||
}
|
||||
seatop_begin_default(seat);
|
||||
}
|
||||
|
|
@ -562,8 +556,18 @@ struct sway_seat *seat_create(const char *seat_name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool alloc_failure = false;
|
||||
seat->scene_tree = alloc_scene_tree(root->layers.seat, &alloc_failure);
|
||||
seat->drag_icons = alloc_scene_tree(seat->scene_tree, &alloc_failure);
|
||||
if (alloc_failure) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -571,6 +575,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;
|
||||
|
|
@ -1075,7 +1080,7 @@ bool seat_is_input_allowed(struct sway_seat *seat,
|
|||
struct wlr_surface *surface) {
|
||||
struct wl_client *client = wl_resource_get_client(surface->resource);
|
||||
return seat->exclusive_client == client ||
|
||||
(seat->exclusive_client == NULL && !server.session_lock.locked);
|
||||
(seat->exclusive_client == NULL && !server.session_lock.lock);
|
||||
}
|
||||
|
||||
static void send_unfocus(struct sway_container *con, void *data) {
|
||||
|
|
@ -1276,8 +1281,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1679,13 +1684,6 @@ void seatop_end(struct sway_seat *seat) {
|
|||
seat->seatop_impl = NULL;
|
||||
}
|
||||
|
||||
void seatop_render(struct sway_seat *seat, struct sway_output *output,
|
||||
pixman_region32_t *damage) {
|
||||
if (seat->seatop_impl->render) {
|
||||
seat->seatop_impl->render(seat, output, damage);
|
||||
}
|
||||
}
|
||||
|
||||
bool seatop_allows_set_cursor(struct sway_seat *seat) {
|
||||
return seat->seatop_impl->allow_set_cursor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "sway/input/seat.h"
|
||||
#include "sway/input/tablet.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "log.h"
|
||||
|
|
@ -53,6 +54,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;
|
||||
|
|
@ -585,6 +589,17 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
|
|||
}
|
||||
}
|
||||
|
||||
static void drag_icons_update_position(struct sway_seat *seat) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &seat->drag_icons->children, link) {
|
||||
struct sway_scene_descriptor *desc = node->data;
|
||||
|
||||
sway_assert(desc && desc->type == SWAY_SCENE_DESC_DRAG_ICON,
|
||||
"Corrupted scene tree: expected drag icon");
|
||||
drag_icon_update_position(seat, desc->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
|
||||
struct seatop_default_event *e = seat->seatop_data;
|
||||
struct sway_cursor *cursor = seat->cursor;
|
||||
|
|
@ -608,12 +623,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;
|
||||
}
|
||||
|
|
@ -643,12 +653,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,19 @@ 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 sway_output *output, pixman_region32_t *damage) {
|
||||
|
||||
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) == 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, output->wlr_output->scale);
|
||||
render_rect(output, damage, &box, color);
|
||||
if (e->indicator_rect) {
|
||||
wlr_scene_node_destroy(&e->indicator_rect->node);
|
||||
e->indicator_rect = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +57,9 @@ 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) {
|
||||
if (e->indicator_rect) {
|
||||
wlr_scene_node_set_enabled(&e->indicator_rect->node, true);
|
||||
}
|
||||
e->threshold_reached = true;
|
||||
cursor_set_image(seat->cursor, "grab", NULL);
|
||||
}
|
||||
|
|
@ -165,6 +158,13 @@ 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) {
|
||||
if (e->indicator_rect) {
|
||||
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;
|
||||
|
|
@ -173,8 +173,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
|
||||
|
|
@ -187,8 +185,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;
|
||||
}
|
||||
|
||||
|
|
@ -201,11 +201,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) {
|
||||
|
|
@ -215,6 +222,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;
|
||||
}
|
||||
|
||||
|
|
@ -256,8 +264,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;
|
||||
|
|
@ -299,12 +306,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) {
|
||||
|
|
@ -439,7 +442,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,
|
||||
|
|
@ -451,6 +454,20 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
|
|||
if (!e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float *indicator = config->border_colors.focused.indicator;
|
||||
const float color[] = {
|
||||
indicator[0] * .5,
|
||||
indicator[1] * .5,
|
||||
indicator[2] * .5,
|
||||
indicator[3] * .5
|
||||
};
|
||||
e->indicator_rect = wlr_scene_rect_create(seat->scene_tree, 0, 0,
|
||||
(const float *) &color);
|
||||
if (e->indicator_rect) {
|
||||
wlr_scene_node_set_enabled(&e->indicator_rect->node, false);
|
||||
}
|
||||
|
||||
e->con = con;
|
||||
e->ref_lx = seat->cursor->cursor->x;
|
||||
e->ref_ly = seat->cursor->cursor->y;
|
||||
|
|
@ -468,6 +485,9 @@ void seatop_begin_move_tiling(struct sway_seat *seat,
|
|||
seatop_begin_move_tiling_threshold(seat, con);
|
||||
struct seatop_move_tiling_event *e = seat->seatop_data;
|
||||
if (e) {
|
||||
if (e->indicator_rect) {
|
||||
wlr_scene_node_set_enabled(&e->indicator_rect->node, true);
|
||||
}
|
||||
e->threshold_reached = true;
|
||||
cursor_set_image(seat->cursor, "grab", NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,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 input_inhibited = seat->exclusive_client != NULL ||
|
||||
server.session_lock.locked;
|
||||
server.session_lock.lock;
|
||||
|
||||
list_t *bindings = config->current_mode->switch_bindings;
|
||||
struct sway_switch_binding *matched_binding = NULL;
|
||||
|
|
|
|||
358
sway/lock.c
358
sway/lock.c
|
|
@ -1,24 +1,35 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "log.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/server.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_mode;
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener mode;
|
||||
|
||||
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) {
|
||||
|
|
@ -26,99 +37,198 @@ static void set_lock_focused_surface(struct wlr_surface *focused) {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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->mapped) {
|
||||
next_focus = candidate->surface->surface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
focus_surface(output->lock, next_focus);
|
||||
}
|
||||
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_output_mode(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_mode);
|
||||
wlr_session_lock_surface_v1_configure(surf->lock_surface,
|
||||
surf->output->width, surf->output->height);
|
||||
}
|
||||
|
||||
static void handle_output_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);
|
||||
if (event->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);
|
||||
static void handle_surface_map(struct wl_listener *listener, void *data) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_surface_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, destroy);
|
||||
struct sway_session_lock_output *output =
|
||||
wl_container_of(listener, output, surface_destroy);
|
||||
refocus_output(output);
|
||||
|
||||
// Move the seat focus to another surface if one is available
|
||||
if (server.session_lock.focused == surf->surface) {
|
||||
struct wlr_surface *next_focus = NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
struct wlr_session_lock_surface_v1 *other;
|
||||
wl_list_for_each(other, &server.session_lock.lock->surfaces, link) {
|
||||
if (other != surf->lock_surface && other->mapped) {
|
||||
next_focus = other->surface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_lock_focused_surface(next_focus);
|
||||
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);
|
||||
}
|
||||
|
||||
wl_list_remove(&surf->map.link);
|
||||
wl_list_remove(&surf->destroy.link);
|
||||
wl_list_remove(&surf->surface_commit.link);
|
||||
wl_list_remove(&surf->output_mode.link);
|
||||
wl_list_remove(&surf->output_commit.link);
|
||||
output_damage_whole(surf->output);
|
||||
free(surf);
|
||||
}
|
||||
|
||||
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_session_lock_surface *surf = calloc(1, sizeof(*surf));
|
||||
if (surf == NULL) {
|
||||
return;
|
||||
}
|
||||
struct sway_output *output = lock_surface->output->data;
|
||||
|
||||
sway_log(SWAY_DEBUG, "new lock layer surface");
|
||||
|
||||
struct sway_output *output = lock_surface->output->data;
|
||||
wlr_session_lock_surface_v1_configure(lock_surface, output->width, output->height);
|
||||
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");
|
||||
|
||||
surf->lock_surface = lock_surface;
|
||||
surf->surface = lock_surface->surface;
|
||||
surf->output = output;
|
||||
surf->map.notify = handle_surface_map;
|
||||
wl_signal_add(&lock_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_mode.notify = handle_output_mode;
|
||||
wl_signal_add(&output->wlr_output->events.mode, &surf->output_mode);
|
||||
surf->output_commit.notify = handle_output_commit;
|
||||
wl_signal_add(&output->wlr_output->events.commit, &surf->output_commit);
|
||||
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->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->mode.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_mode(struct wl_listener *listener, void *data) {
|
||||
struct sway_session_lock_output *output =
|
||||
wl_container_of(listener, output, mode);
|
||||
lock_output_reconfigure(output);
|
||||
}
|
||||
|
||||
static void lock_output_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output_event_commit *event = data;
|
||||
struct sway_session_lock_output *output =
|
||||
wl_container_of(listener, output, commit);
|
||||
if (event->committed & (
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_SCALE |
|
||||
WLR_OUTPUT_STATE_TRANSFORM)) {
|
||||
lock_output_reconfigure(output);
|
||||
}
|
||||
}
|
||||
|
||||
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(struct sway_session_lock_output));
|
||||
if (!lock_output) {
|
||||
sway_log(SWAY_ERROR, "failed to allocate a session lock output");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float *color = (float[4]){ 0.f, 0.f, 0.f, 1.f };
|
||||
if (lock->abandoned) {
|
||||
color[0] = 1.f;
|
||||
}
|
||||
|
||||
struct wlr_scene_rect *background = wlr_scene_rect_create(tree, 0, 0, color);
|
||||
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;
|
||||
}
|
||||
|
||||
lock_output->output = output;
|
||||
lock_output->tree = tree;
|
||||
lock_output->background = background;
|
||||
lock_output->lock = lock;
|
||||
|
||||
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->mode.notify = lock_output_handle_mode;
|
||||
wl_signal_add(&output->wlr_output->events.mode, &lock_output->mode);
|
||||
|
||||
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) {
|
||||
|
|
@ -131,33 +241,27 @@ static void handle_unlock(struct wl_listener *listener, void *data) {
|
|||
seat_set_focus(seat, previous);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
struct sway_seat *seat;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
seat->exclusive_client = NULL;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
|
@ -165,44 +269,78 @@ 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(struct sway_session_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_set_exclusive_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();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
10
sway/main.c
10
sway/main.c
|
|
@ -192,11 +192,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;
|
||||
|
|
@ -204,8 +200,6 @@ 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 {
|
||||
sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag);
|
||||
}
|
||||
|
|
@ -381,6 +375,8 @@ int main(int argc, char **argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
wlr_scene_set_presentation(root->root_scene, server.presentation);
|
||||
|
||||
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_buffer.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',
|
||||
|
||||
|
|
|
|||
33
sway/scene_descriptor.c
Normal file
33
sway/scene_descriptor.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_scene_descriptor *desc =
|
||||
wl_container_of(listener, desc, destroy);
|
||||
|
||||
desc->node->data = NULL;
|
||||
wl_list_remove(&desc->destroy.link);
|
||||
|
||||
free(desc);
|
||||
}
|
||||
|
||||
void scene_descriptor_assign(struct wlr_scene_node *node,
|
||||
enum sway_scene_descriptor_type type, void *data) {
|
||||
struct sway_scene_descriptor *desc =
|
||||
calloc(1, sizeof(struct sway_scene_descriptor));
|
||||
|
||||
if (!desc) {
|
||||
sway_log(SWAY_ERROR, "Could not allocate a scene descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
desc->type = type;
|
||||
desc->data = data;
|
||||
desc->node = node;
|
||||
|
||||
desc->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&node->events.destroy, &desc->destroy);
|
||||
|
||||
node->data = desc;
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
#include <wlr/types/wlr_drm_lease_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>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||
|
|
@ -97,9 +98,6 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->compositor = wlr_compositor_create(server->wl_display,
|
||||
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);
|
||||
|
||||
|
|
@ -204,6 +202,8 @@ bool server_init(struct sway_server *server) {
|
|||
wlr_viewporter_create(server->wl_display);
|
||||
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
|
||||
|
||||
wlr_fractional_scale_manager_v1_create(server->wl_display);
|
||||
|
||||
struct wlr_xdg_foreign_registry *foreign_registry =
|
||||
wlr_xdg_foreign_registry_create(server->wl_display);
|
||||
wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
|
||||
|
|
|
|||
340
sway/sway_text_buffer.c
Normal file
340
sway/sway_text_buffer.c
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <drm_fourcc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include "cairo_util.h"
|
||||
#include "pango.h"
|
||||
#include "sway/sway_text_buffer.h"
|
||||
#include "sway/config.h"
|
||||
#include "log.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;
|
||||
|
||||
float scale;
|
||||
enum wl_output_subpixel subpixel;
|
||||
|
||||
struct wl_list outputs; // text_buffer_output.link
|
||||
|
||||
struct wl_listener output_enter;
|
||||
struct wl_listener output_leave;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct text_buffer_output {
|
||||
struct wl_list link;
|
||||
struct wlr_output *output;
|
||||
struct text_buffer *text_buffer;
|
||||
|
||||
struct wl_listener commit;
|
||||
};
|
||||
|
||||
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) {
|
||||
float scale = buffer->scale;
|
||||
int width = ceil(buffer->props.width * scale);
|
||||
int height = ceil(buffer->props.height * scale);
|
||||
float *color = (float *) &buffer->props.color;
|
||||
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;
|
||||
}
|
||||
|
||||
cairo_t *cairo = cairo_create(surface);
|
||||
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
|
||||
cairo_set_font_options(cairo, fo);
|
||||
pango = pango_cairo_create_context(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);
|
||||
|
||||
struct cairo_buffer *cairo_buffer = calloc(1, sizeof(struct cairo_buffer));
|
||||
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);
|
||||
|
||||
err:
|
||||
if (pango) g_object_unref(pango);
|
||||
cairo_font_options_destroy(fo);
|
||||
}
|
||||
|
||||
static void ensure_backing_buffer(struct text_buffer *buffer) {
|
||||
float scale = 0;
|
||||
enum wl_output_subpixel subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
|
||||
struct text_buffer_output *output;
|
||||
wl_list_for_each(output, &buffer->outputs, link) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// no outputs
|
||||
if (scale == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (scale != buffer->scale || subpixel != buffer->subpixel) {
|
||||
buffer->scale = scale;
|
||||
buffer->subpixel = subpixel;
|
||||
render_backing_buffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_output_commit(struct wl_listener *listener, void *data) {
|
||||
struct text_buffer_output *output = wl_container_of(listener, output, commit);
|
||||
struct wlr_output_event_commit *event = data;
|
||||
|
||||
if (event->committed & (WLR_OUTPUT_STATE_SCALE | WLR_OUTPUT_STATE_SUBPIXEL)) {
|
||||
ensure_backing_buffer(output->text_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_output_enter(struct wl_listener *listener, void *data) {
|
||||
struct text_buffer *buffer = wl_container_of(listener, buffer, output_enter);
|
||||
struct wlr_scene_output *output = data;
|
||||
struct text_buffer_output *buffer_output =
|
||||
calloc(1, sizeof(struct text_buffer_output));
|
||||
if (!buffer_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_output->text_buffer = buffer;
|
||||
|
||||
buffer_output->commit.notify = handle_output_commit;
|
||||
wl_signal_add(&output->output->events.commit, &buffer_output->commit);
|
||||
|
||||
buffer_output->output = output->output;
|
||||
wl_list_insert(&buffer->outputs, &buffer_output->link);
|
||||
ensure_backing_buffer(buffer);
|
||||
}
|
||||
|
||||
static void text_buffer_output_destroy(struct text_buffer_output *output) {
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
wl_list_remove(&output->commit.link);
|
||||
free(output);
|
||||
}
|
||||
|
||||
static struct text_buffer_output *get_text_output_from_wlr_output(
|
||||
struct text_buffer *buffer, struct wlr_output *wlr_output) {
|
||||
struct text_buffer_output *output;
|
||||
wl_list_for_each(output, &buffer->outputs, link) {
|
||||
if (output->output == wlr_output) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void handle_output_leave(struct wl_listener *listener, void *data) {
|
||||
struct text_buffer *buffer = wl_container_of(listener, buffer, output_leave);
|
||||
struct wlr_scene_output *scene_output = data;
|
||||
|
||||
struct text_buffer_output *output = get_text_output_from_wlr_output(
|
||||
buffer, scene_output->output);
|
||||
text_buffer_output_destroy(output);
|
||||
ensure_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->output_enter.link);
|
||||
wl_list_remove(&buffer->output_leave.link);
|
||||
wl_list_remove(&buffer->destroy.link);
|
||||
|
||||
struct text_buffer_output *output, *tmp_output;
|
||||
wl_list_for_each_safe(output, tmp_output, &buffer->outputs, link) {
|
||||
text_buffer_output_destroy(output);
|
||||
}
|
||||
|
||||
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);
|
||||
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, const float *color, bool pango_markup) {
|
||||
struct text_buffer *buffer = calloc(1, sizeof(struct text_buffer));
|
||||
if (buffer == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
wl_list_init(&buffer->outputs);
|
||||
|
||||
buffer->props.height = config->font_height;
|
||||
buffer->props.pango_markup = pango_markup;
|
||||
memcpy(&buffer->props.color, color, sizeof(float) * 4);
|
||||
|
||||
buffer->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&node->node.events.destroy, &buffer->destroy);
|
||||
buffer->output_enter.notify = handle_output_enter;
|
||||
wl_signal_add(&node->events.output_enter, &buffer->output_enter);
|
||||
buffer->output_leave.notify = handle_output_leave;
|
||||
wl_signal_add(&node->events.output_leave, &buffer->output_leave);
|
||||
|
||||
text_calc_size(buffer);
|
||||
|
||||
return &buffer->props;
|
||||
}
|
||||
|
||||
void sway_text_node_set_color(struct sway_text_node *node, const float *color) {
|
||||
if (memcmp(&node->color, color, sizeof(float) * 4) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&node->color, color, sizeof(float) * 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);
|
||||
}
|
||||
|
|
@ -259,8 +259,8 @@ void arrange_workspace(struct sway_workspace *workspace) {
|
|||
return;
|
||||
}
|
||||
struct sway_output *output = workspace->output;
|
||||
struct wlr_box *area = &output->usable_area;
|
||||
sway_log(SWAY_DEBUG, "Usable area for ws: %dx%d@%d,%d",
|
||||
struct wlr_fbox *area = &output->usable_area;
|
||||
sway_log(SWAY_DEBUG, "Usable area for ws: %lfx%lf@%lf,%lf",
|
||||
area->width, area->height, area->x, area->y);
|
||||
|
||||
bool first_arrange = workspace->width == 0 && workspace->height == 0;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -159,3 +159,26 @@ bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void scene_node_disown_children(struct wlr_scene_tree *tree) {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
|
|
@ -88,10 +87,53 @@ 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);
|
||||
|
||||
size_t num_layers = sizeof(output->layers) / sizeof(struct wlr_scene_node *);
|
||||
for (size_t i = 0; i < num_layers; i++) {
|
||||
struct wlr_scene_tree *tree =
|
||||
((struct wlr_scene_tree **) &output->layers)[i];
|
||||
|
||||
if (tree) {
|
||||
wlr_scene_node_destroy(&tree->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 alloc_failure = false;
|
||||
size_t num_layers = sizeof(output->layers) / sizeof(struct wlr_scene_node *);
|
||||
for (size_t i = 0; i < num_layers; i++) {
|
||||
((struct wlr_scene_tree **) &output->layers)[i] =
|
||||
alloc_scene_tree(root->staging, &alloc_failure);
|
||||
}
|
||||
|
||||
if (!alloc_failure) {
|
||||
output->fullscreen_background = wlr_scene_rect_create(
|
||||
output->layers.fullscreen, 0, 0, (float[4]){0., 0., 0., 1.});
|
||||
|
||||
if (!output->fullscreen_background) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate a background rect");
|
||||
alloc_failure = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_failure) {
|
||||
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;
|
||||
output->scale_filter = SCALE_FILTER_NEAREST;
|
||||
|
|
@ -103,11 +145,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;
|
||||
}
|
||||
|
||||
|
|
@ -239,20 +276,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;
|
||||
|
|
@ -267,8 +298,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,10 +3,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.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"
|
||||
|
|
@ -29,13 +31,42 @@ struct sway_root *root_create(void) {
|
|||
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 alloc_failure = false;
|
||||
root->staging = alloc_scene_tree(&root_scene->tree, &alloc_failure);
|
||||
|
||||
size_t num_layers = sizeof(root->layers) / sizeof(struct wlr_scene_tree *);
|
||||
for (size_t i = 0; i < num_layers; i++) {
|
||||
((struct wlr_scene_tree **) &root->layers)[i] =
|
||||
alloc_scene_tree(&root_scene->tree, &alloc_failure);
|
||||
}
|
||||
|
||||
scene_descriptor_assign(&root->layers.seat->node,
|
||||
SWAY_SCENE_DESC_NON_INTERACTIVE, NULL);
|
||||
if (!root->layers.seat->node.data) {
|
||||
alloc_failure = true;
|
||||
}
|
||||
|
||||
if (alloc_failure) {
|
||||
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_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();
|
||||
|
|
@ -51,6 +82,7 @@ void root_destroy(struct sway_root *root) {
|
|||
wl_list_remove(&root->output_layout_change.link);
|
||||
list_free(root->scratchpad);
|
||||
list_free(root->outputs);
|
||||
wlr_scene_node_destroy(&root->root_scene->tree.node);
|
||||
wlr_output_layout_destroy(root->output_layout);
|
||||
free(root);
|
||||
}
|
||||
|
|
|
|||
379
sway/tree/view.c
379
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/input/cursor.h"
|
||||
|
|
@ -24,6 +23,7 @@
|
|||
#include "sway/output.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/sway_text_buffer.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
|
@ -33,15 +33,23 @@
|
|||
#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 alloc_failure = false;
|
||||
view->scene_tree = alloc_scene_tree(root->staging, &alloc_failure);
|
||||
view->content_tree = alloc_scene_tree(view->scene_tree, &alloc_failure);
|
||||
if (alloc_failure) {
|
||||
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) {
|
||||
|
|
@ -58,11 +66,9 @@ 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);
|
||||
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
free(view->title_format);
|
||||
|
||||
if (view->impl->destroy) {
|
||||
|
|
@ -164,8 +170,8 @@ void view_get_constraints(struct sway_view *view, double *min_width,
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
|
||||
int height) {
|
||||
uint32_t view_configure(struct sway_view *view, double lx, double ly,
|
||||
double width, double height) {
|
||||
if (view->impl->configure) {
|
||||
return view->impl->configure(view, lx, ly, width, height);
|
||||
}
|
||||
|
|
@ -433,52 +439,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) {
|
||||
|
|
@ -777,11 +737,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);
|
||||
}
|
||||
|
|
@ -849,8 +804,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);
|
||||
|
||||
if (view->urgent_timer) {
|
||||
wl_event_source_remove(view->urgent_timer);
|
||||
view->urgent_timer = NULL;
|
||||
|
|
@ -906,187 +859,10 @@ void view_center_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);
|
||||
}
|
||||
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 const struct sway_view_child_impl subsurface_impl;
|
||||
|
||||
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);
|
||||
} else {
|
||||
*sx = *sy = 0;
|
||||
}
|
||||
struct wlr_subsurface *subsurface =
|
||||
wlr_subsurface_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;
|
||||
wlr_scene_node_set_position(&view->content_tree->node, x, y);
|
||||
}
|
||||
|
||||
void view_child_init(struct sway_view_child *child,
|
||||
|
|
@ -1096,41 +872,9 @@ void view_child_init(struct sway_view_child *child,
|
|||
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) {
|
||||
wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -1140,18 +884,8 @@ void view_child_destroy(struct sway_view_child *child) {
|
|||
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 {
|
||||
|
|
@ -1300,7 +1034,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");
|
||||
|
||||
|
|
@ -1367,6 +1107,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) {
|
||||
|
|
@ -1374,7 +1115,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");
|
||||
|
||||
|
|
@ -1388,40 +1128,47 @@ 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,
|
||||
int sx, int sy, void *data) {
|
||||
struct sway_view *view = data;
|
||||
static void view_save_buffer_iterator(struct wlr_scene_buffer *buffer,
|
||||
double sx, double sy, void *data) {
|
||||
struct wlr_scene_tree *tree = data;
|
||||
|
||||
if (surface && wlr_surface_has_buffer(surface)) {
|
||||
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_buffer(sbuf, buffer->buffer);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool view_is_transient_for(struct sway_view *child,
|
||||
|
|
@ -1429,3 +1176,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,
|
||||
double x, double 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,18 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
|||
return NULL;
|
||||
}
|
||||
node_init(&ws->node, N_WORKSPACE, ws);
|
||||
|
||||
bool alloc_failure = false;
|
||||
ws->layers.tiling = alloc_scene_tree(root->staging, &alloc_failure);
|
||||
ws->layers.fullscreen = alloc_scene_tree(root->staging, &alloc_failure);
|
||||
|
||||
if (alloc_failure) {
|
||||
wlr_scene_node_destroy(&ws->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&ws->layers.fullscreen->node);
|
||||
free(ws);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ws->name = name ? strdup(name) : NULL;
|
||||
ws->prev_split_layout = L_NONE;
|
||||
ws->layout = output_get_default_layout(output);
|
||||
|
|
@ -129,6 +141,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);
|
||||
|
|
@ -684,7 +701,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…
Add table
Add a link
Reference in a new issue