mirror of
https://github.com/labwc/labwc.git
synced 2026-02-05 04:06:33 -05:00
Merge pull request #264 from labwc/scene-graph
Use wlroots scene-graph API
This commit is contained in:
commit
c73628ced1
51 changed files with 2786 additions and 2838 deletions
|
|
@ -14,7 +14,7 @@ struct action {
|
|||
struct action *action_create(const char *action_name);
|
||||
void action_list_free(struct wl_list *action_list);
|
||||
|
||||
void action(struct view *activator, struct server *server,
|
||||
void actions_run(struct view *activator, struct server *server,
|
||||
struct wl_list *actions, uint32_t resize_edges);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
50
include/buffer.h
Normal file
50
include/buffer.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Based on wlroots/include/types/wlr_buffer.c
|
||||
*
|
||||
* Copyright (c) 2017, 2018 Drew DeVault
|
||||
* Copyright (c) 2018-2021 Simon Ser, Simon Zeni
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef __LABWC_BUFFER_H
|
||||
#define __LABWC_BUFFER_H
|
||||
|
||||
#include <cairo.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
|
||||
struct lab_data_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
||||
cairo_t *cairo;
|
||||
void *data;
|
||||
uint32_t format;
|
||||
size_t stride;
|
||||
bool free_on_destroy;
|
||||
};
|
||||
|
||||
/* Create a buffer which creates a new cairo CAIRO_FORMAT_ARGB32 surface */
|
||||
struct lab_data_buffer *buffer_create_cairo(uint32_t width, uint32_t height,
|
||||
float scale, bool free_on_destroy);
|
||||
|
||||
/* Create a buffer which wraps a given DRM_FORMAT_ARGB8888 pointer */
|
||||
struct lab_data_buffer *buffer_create_wrap(void *pixel_data, uint32_t width,
|
||||
uint32_t height, uint32_t stride, bool free_on_destroy);
|
||||
|
||||
#endif /* __LABWC_BUFFER_H */
|
||||
|
|
@ -2,9 +2,7 @@
|
|||
#ifndef __LABWC_FONT_H
|
||||
#define __LABWC_FONT_H
|
||||
|
||||
struct server;
|
||||
struct wlr_texture;
|
||||
struct wlr_box;
|
||||
struct lab_data_buffer;
|
||||
|
||||
struct font {
|
||||
char *name;
|
||||
|
|
@ -18,16 +16,23 @@ struct font {
|
|||
int font_height(struct font *font);
|
||||
|
||||
/**
|
||||
* texture_create - Create ARGB8888 texture using pango
|
||||
* @server: context (for wlr_renderer)
|
||||
* @texture: texture pointer; existing pointer will be freed
|
||||
* font_buffer_create - Create ARGB8888 lab_data_buffer using pango
|
||||
* @buffer: buffer pointer
|
||||
* @max_width: max allowable width; will be ellipsized if longer
|
||||
* @text: text to be generated as texture
|
||||
* @font: font description
|
||||
* @color: foreground color in rgba format
|
||||
*/
|
||||
void font_texture_create(struct server *server, struct wlr_texture **texture,
|
||||
int max_width, const char *text, struct font *font, float *color);
|
||||
void font_buffer_create(struct lab_data_buffer **buffer, int max_width,
|
||||
const char *text, struct font *font, float *color);
|
||||
|
||||
/**
|
||||
* font_buffer_update - Wrapper around font_buffer_create
|
||||
* Only difference is that if given buffer pointer is != NULL
|
||||
* wlr_buffer_drop() will be called on the buffer.
|
||||
*/
|
||||
void font_buffer_update(struct lab_data_buffer **buffer, int max_width,
|
||||
const char *text, struct font *font, float *color);
|
||||
|
||||
/**
|
||||
* font_finish - free some font related resources
|
||||
|
|
|
|||
5
include/common/scene-helpers.h
Normal file
5
include/common/scene-helpers.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct wlr_scene_rect *lab_wlr_scene_get_rect(struct wlr_scene_node *node);
|
||||
|
|
@ -2,8 +2,9 @@
|
|||
#ifndef __LABWC_MOUSEBIND_H
|
||||
#define __LABWC_MOUSEBIND_H
|
||||
|
||||
#include "ssd.h"
|
||||
#include <wayland-util.h>
|
||||
#include "ssd.h"
|
||||
#include "config/keybind.h"
|
||||
|
||||
enum mouse_event {
|
||||
MOUSE_ACTION_NONE = 0,
|
||||
|
|
|
|||
9
include/debug.h
Normal file
9
include/debug.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef __DEBUG_H
|
||||
#define __DEBUG_H
|
||||
|
||||
struct server;
|
||||
|
||||
void debug_dump_scene(struct server *server);
|
||||
|
||||
#endif /* __DEBUG_H */
|
||||
136
include/labwc.h
136
include/labwc.h
|
|
@ -13,6 +13,7 @@
|
|||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||
|
|
@ -24,15 +25,16 @@
|
|||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#include <wlr/types/wlr_output_management_v1.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||
#include <wlr/types/wlr_pointer_gestures_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_server_decoration.h>
|
||||
#include <wlr/types/wlr_subcompositor.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
|
|
@ -111,6 +113,8 @@ struct seat {
|
|||
struct wl_listener idle_inhibitor_create;
|
||||
};
|
||||
|
||||
struct lab_data_buffer;
|
||||
|
||||
struct server {
|
||||
struct wl_display *wl_display;
|
||||
struct wlr_renderer *renderer;
|
||||
|
|
@ -137,6 +141,7 @@ struct server {
|
|||
struct wl_list unmanaged_surfaces;
|
||||
|
||||
struct seat seat;
|
||||
struct wlr_scene *scene;
|
||||
|
||||
/* cursor interactive */
|
||||
enum input_mode input_mode;
|
||||
|
|
@ -145,6 +150,21 @@ struct server {
|
|||
struct wlr_box grab_box;
|
||||
uint32_t resize_edges;
|
||||
|
||||
/* SSD state */
|
||||
struct view *ssd_focused_view;
|
||||
struct ssd_hover_state ssd_hover_state;
|
||||
|
||||
/* Tree for all non-layer xdg/xwayland-shell surfaces */
|
||||
struct wlr_scene_tree *view_tree;
|
||||
#if HAVE_XWAYLAND
|
||||
/* Tree for unmanaged xsurfaces without initialized view (usually popups) */
|
||||
struct wlr_scene_tree *unmanaged_tree;
|
||||
#endif
|
||||
/* Tree for built in menu */
|
||||
struct wlr_scene_tree *menu_tree;
|
||||
/* Tree for built in OSD / app switcher */
|
||||
struct wlr_scene_tree *osd_tree;
|
||||
|
||||
struct wl_list outputs;
|
||||
struct wl_listener new_output;
|
||||
struct wlr_output_layout *output_layout;
|
||||
|
|
@ -164,23 +184,27 @@ struct server {
|
|||
struct view *cycle_view;
|
||||
|
||||
struct theme *theme;
|
||||
struct menu *rootmenu;
|
||||
struct menu *windowmenu;
|
||||
|
||||
struct menu *menu_current;
|
||||
};
|
||||
|
||||
#define LAB_NR_LAYERS (4)
|
||||
struct output {
|
||||
struct wl_list link; /* server::outputs */
|
||||
struct server *server;
|
||||
struct wlr_output *wlr_output;
|
||||
struct wlr_output_damage *damage;
|
||||
struct wl_list layers[4];
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct wl_list layers[LAB_NR_LAYERS];
|
||||
struct wlr_scene_tree *layer_tree[LAB_NR_LAYERS];
|
||||
struct wlr_scene_tree *layer_popup_tree;
|
||||
struct wlr_box usable_area;
|
||||
struct wlr_texture *osd;
|
||||
|
||||
struct lab_data_buffer *osd_buffer;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener damage_frame;
|
||||
struct wl_listener damage_destroy;
|
||||
struct wl_listener frame;
|
||||
};
|
||||
#undef LAB_NR_LAYERS
|
||||
|
||||
enum view_type {
|
||||
LAB_XDG_SHELL_VIEW,
|
||||
|
|
@ -192,10 +216,6 @@ enum view_type {
|
|||
struct view_impl {
|
||||
void (*configure)(struct view *view, struct wlr_box geo);
|
||||
void (*close)(struct view *view);
|
||||
void (*for_each_popup_surface)(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *data);
|
||||
void (*for_each_surface)(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *data);
|
||||
const char *(*get_string_prop)(struct view *view, const char *prop);
|
||||
void (*map)(struct view *view);
|
||||
void (*move)(struct view *view, double x, double y);
|
||||
|
|
@ -226,6 +246,8 @@ struct view {
|
|||
#endif
|
||||
};
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
struct wlr_scene_node *scene_node;
|
||||
|
||||
bool mapped;
|
||||
bool been_mapped;
|
||||
|
|
@ -255,24 +277,14 @@ struct view {
|
|||
*/
|
||||
struct border padding;
|
||||
|
||||
struct {
|
||||
struct view_pending_move_resize {
|
||||
bool update_x, update_y;
|
||||
double x, y;
|
||||
uint32_t width, height;
|
||||
uint32_t configure_serial;
|
||||
} pending_move_resize;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
struct wl_list parts;
|
||||
struct wlr_box box; /* remember geo so we know when to update */
|
||||
} ssd;
|
||||
|
||||
/* The title is unique to each view, so we store these here */
|
||||
struct {
|
||||
struct wlr_texture *active;
|
||||
struct wlr_texture *inactive;
|
||||
} title;
|
||||
struct ssd ssd;
|
||||
|
||||
struct wlr_foreign_toplevel_handle_v1 *toplevel_handle;
|
||||
struct wl_listener toplevel_handle_request_maximize;
|
||||
|
|
@ -296,7 +308,6 @@ struct view {
|
|||
struct wl_listener set_app_id; /* class on xwayland */
|
||||
struct wl_listener set_decorations; /* xwayland only */
|
||||
struct wl_listener new_popup; /* xdg-shell only */
|
||||
struct wl_listener new_subsurface; /* xdg-shell only */
|
||||
};
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
|
|
@ -314,29 +325,6 @@ struct xwayland_unmanaged {
|
|||
};
|
||||
#endif
|
||||
|
||||
struct view_child {
|
||||
struct wlr_surface *surface;
|
||||
struct view *parent;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener new_subsurface;
|
||||
};
|
||||
|
||||
struct view_subsurface {
|
||||
struct view_child view_child;
|
||||
struct wlr_subsurface *subsurface;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct xdg_popup {
|
||||
struct view_child view_child;
|
||||
struct wlr_xdg_popup *wlr_popup;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener new_popup;
|
||||
};
|
||||
|
||||
struct constraint {
|
||||
struct seat *seat;
|
||||
struct wlr_pointer_constraint_v1 *constraint;
|
||||
|
|
@ -361,12 +349,6 @@ void xwayland_unmanaged_create(struct server *server,
|
|||
struct wlr_xwayland_surface *xsurface);
|
||||
#endif
|
||||
|
||||
void view_child_init(struct view_child *child, struct view *view,
|
||||
struct wlr_surface *wlr_surface);
|
||||
void view_child_finish(struct view_child *child);
|
||||
void view_subsurface_create(struct view *view,
|
||||
struct wlr_subsurface *wlr_subsurface);
|
||||
|
||||
void view_set_activated(struct view *view, bool activated);
|
||||
void view_close(struct view *view);
|
||||
struct border view_border(struct view *view);
|
||||
|
|
@ -393,10 +375,6 @@ void view_toggle_decorations(struct view *view);
|
|||
void view_set_decorations(struct view *view, bool decorations);
|
||||
void view_toggle_fullscreen(struct view *view);
|
||||
void view_adjust_for_layout_change(struct view *view);
|
||||
void view_for_each_surface(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||
void view_for_each_popup_surface(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *data);
|
||||
void view_discover_output(struct view *view);
|
||||
void view_move_to_edge(struct view *view, const char *direction);
|
||||
void view_snap_to_edge(struct view *view, const char *direction);
|
||||
|
|
@ -444,11 +422,33 @@ void desktop_focus_topmost_mapped_view(struct server *server);
|
|||
bool isfocusable(struct view *view);
|
||||
|
||||
/**
|
||||
* desktop_surface_and_view_at - find view and surface at (lx, ly)
|
||||
* Note: If surface points to layer-surface, view will be set to NULL
|
||||
* desktop_node_and_view_at - find view and scene_node at (lx, ly)
|
||||
*
|
||||
* Behavior if node points to a surface:
|
||||
* - If surface is a layer-surface, *view_area will be
|
||||
* set to LAB_SSD_LAYER_SURFACE and view will be NULL.
|
||||
*
|
||||
* - If surface is a 'lost' unmanaged xsurface (one
|
||||
* with a never-mapped parent view), *view_area will
|
||||
* be set to LAB_SSD_UNMANAGED and view will be NULL.
|
||||
*
|
||||
* 'Lost' unmanaged xsurfaces are usually caused by
|
||||
* X11 applications opening popups without setting
|
||||
* the main window as parent. Example: VLC submenus.
|
||||
*
|
||||
* - Any other surface will cause *view_area be set to
|
||||
* LAB_SSD_CLIENT and return the attached view.
|
||||
*
|
||||
* Behavior if node points to internal elements:
|
||||
* - *view_area will be set to the appropiate enum value
|
||||
* and view will be NULL if the node is not part of the SSD.
|
||||
*
|
||||
* If no node is found for the given layout coordinates,
|
||||
* *view_area will be set to LAB_SSD_ROOT and view will be NULL.
|
||||
*
|
||||
*/
|
||||
struct view *desktop_surface_and_view_at(struct server *server, double lx,
|
||||
double ly, struct wlr_surface **surface, double *sx, double *sy,
|
||||
struct view *desktop_node_and_view_at(struct server *server, double lx,
|
||||
double ly, struct wlr_scene_node **scene_node, double *sx, double *sy,
|
||||
enum ssd_part_type *view_area);
|
||||
|
||||
struct view *desktop_view_at_cursor(struct server *server);
|
||||
|
|
@ -473,8 +473,6 @@ void cursor_finish(struct seat *seat);
|
|||
void keyboard_init(struct seat *seat);
|
||||
void keyboard_finish(struct seat *seat);
|
||||
|
||||
void arrange_layers(struct output *output);
|
||||
|
||||
void seat_init(struct server *server);
|
||||
void seat_finish(struct server *server);
|
||||
void seat_reconfigure(struct server *server);
|
||||
|
|
@ -486,24 +484,18 @@ void interactive_begin(struct view *view, enum input_mode mode,
|
|||
void interactive_end(struct view *view);
|
||||
|
||||
void output_init(struct server *server);
|
||||
void output_damage_surface(struct output *output, struct wlr_surface *surface,
|
||||
double lx, double ly, bool whole);
|
||||
void scale_box(struct wlr_box *box, float scale);
|
||||
void output_manager_init(struct server *server);
|
||||
struct output *output_from_wlr_output(struct server *server,
|
||||
struct wlr_output *wlr_output);
|
||||
struct wlr_box output_usable_area_in_layout_coords(struct output *output);
|
||||
struct wlr_box output_usable_area_from_cursor_coords(struct server *server);
|
||||
|
||||
void damage_all_outputs(struct server *server);
|
||||
void damage_view_whole(struct view *view);
|
||||
void damage_view_part(struct view *view);
|
||||
|
||||
void server_init(struct server *server);
|
||||
void server_start(struct server *server);
|
||||
void server_finish(struct server *server);
|
||||
|
||||
/* update onscreen display 'alt-tab' texture */
|
||||
/* update onscreen display 'alt-tab' buffer */
|
||||
void osd_finish(struct server *server);
|
||||
void osd_update(struct server *server);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2,19 +2,14 @@
|
|||
#ifndef __LABWC_LAYERS_H
|
||||
#define __LABWC_LAYERS_H
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
|
||||
struct server;
|
||||
|
||||
enum layer_parent {
|
||||
LAYER_PARENT_LAYER,
|
||||
LAYER_PARENT_POPUP,
|
||||
};
|
||||
struct output;
|
||||
|
||||
struct lab_layer_surface {
|
||||
struct wlr_layer_surface_v1 *layer_surface;
|
||||
struct wl_list link;
|
||||
struct wl_list link; /* output::layers */
|
||||
struct wlr_scene_layer_surface_v1 *scene_layer_surface;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener map;
|
||||
|
|
@ -22,38 +17,26 @@ struct lab_layer_surface {
|
|||
struct wl_listener surface_commit;
|
||||
struct wl_listener output_destroy;
|
||||
struct wl_listener new_popup;
|
||||
struct wl_listener new_subsurface;
|
||||
|
||||
struct wlr_box geo;
|
||||
bool mapped;
|
||||
/* TODO: add extent and layer */
|
||||
/* TODO: add extent? */
|
||||
struct server *server;
|
||||
};
|
||||
|
||||
struct lab_layer_popup {
|
||||
struct wlr_xdg_popup *wlr_popup;
|
||||
enum layer_parent parent_type;
|
||||
union {
|
||||
struct lab_layer_surface *parent_layer;
|
||||
struct lab_layer_popup *parent_popup;
|
||||
};
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wlr_scene_node *scene_node;
|
||||
|
||||
/* To simplify moving popup nodes from the bottom to the top layer */
|
||||
struct wlr_box output_toplevel_sx_box;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener new_popup;
|
||||
};
|
||||
|
||||
struct lab_layer_subsurface {
|
||||
struct wlr_subsurface *wlr_subsurface;
|
||||
struct lab_layer_surface *layer_surface;
|
||||
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
};
|
||||
|
||||
void layers_init(struct server *server);
|
||||
|
||||
void layers_arrange(struct output *output);
|
||||
|
||||
#endif /* __LABWC_LAYERS_H */
|
||||
|
|
|
|||
|
|
@ -3,19 +3,30 @@
|
|||
#define __LABWC_MENU_H
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
|
||||
struct lab_data_buffer;
|
||||
struct wlr_scene_node;
|
||||
|
||||
enum menu_align {
|
||||
LAB_MENU_OPEN_AUTO = 0,
|
||||
LAB_MENU_OPEN_LEFT = 1 << 0,
|
||||
LAB_MENU_OPEN_RIGHT = 1 << 1,
|
||||
LAB_MENU_OPEN_TOP = 1 << 2,
|
||||
LAB_MENU_OPEN_BOTTOM = 1 << 3,
|
||||
};
|
||||
|
||||
struct menu_scene {
|
||||
struct lab_data_buffer *buffer;
|
||||
struct wlr_scene_node *text;
|
||||
struct wlr_scene_node *background;
|
||||
};
|
||||
|
||||
struct menuitem {
|
||||
struct wl_list actions;
|
||||
struct menu *parent;
|
||||
struct menu *submenu;
|
||||
struct wlr_box box;
|
||||
struct {
|
||||
struct wlr_texture *active;
|
||||
struct wlr_texture *inactive;
|
||||
int offset_x;
|
||||
int offset_y;
|
||||
} texture;
|
||||
bool selected;
|
||||
struct menu_scene normal;
|
||||
struct menu_scene selected;
|
||||
struct wl_list link; /* menu::menuitems */
|
||||
};
|
||||
|
||||
|
|
@ -23,27 +34,66 @@ struct menuitem {
|
|||
struct menu {
|
||||
char *id;
|
||||
char *label;
|
||||
bool visible;
|
||||
int item_height;
|
||||
struct menu *parent;
|
||||
struct wlr_box box;
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
} size;
|
||||
struct wl_list menuitems;
|
||||
struct server *server;
|
||||
struct {
|
||||
struct menu *menu;
|
||||
struct menuitem *item;
|
||||
} selection;
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
};
|
||||
|
||||
void menu_init_rootmenu(struct server *server);
|
||||
void menu_init_windowmenu(struct server *server);
|
||||
void menu_finish(void);
|
||||
|
||||
/* menu_move - move to position (x, y) */
|
||||
void menu_move(struct menu *menu, int x, int y);
|
||||
/**
|
||||
* menu_get_by_id - get menu by id
|
||||
*
|
||||
* @id id string defined in menu.xml like "root-menu"
|
||||
*/
|
||||
struct menu *menu_get_by_id(const char *id);
|
||||
|
||||
/* menu_set_selected - select item at (x, y) */
|
||||
void menu_set_selected(struct menu *menu, int x, int y);
|
||||
/**
|
||||
* menu_open - open menu on position (x, y)
|
||||
*
|
||||
* This function will close server->menu_current, open the
|
||||
* new menu and assign @menu to server->menu_current.
|
||||
*
|
||||
* Additionally, server->input_mode wil be set to LAB_INPUT_STATE_MENU.
|
||||
*/
|
||||
void menu_open(struct menu *menu, int x, int y);
|
||||
|
||||
/* menu_action_selected - select item at (x, y) */
|
||||
void menu_action_selected(struct server *server, struct menu *menu);
|
||||
/**
|
||||
* menu_process_cursor_motion
|
||||
*
|
||||
* - handles hover effects
|
||||
* - may open/close submenus
|
||||
*/
|
||||
void menu_process_cursor_motion(struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* menu_call_actions - call actions associated with a menu node
|
||||
*
|
||||
* If menuitem connected to @node does not just open a submenu:
|
||||
* - associated actions will be called
|
||||
* - server->menu_current will be closed
|
||||
* - server->menu_current will be set to NULL
|
||||
*
|
||||
* Returns true if actions have actually been executed
|
||||
*/
|
||||
bool menu_call_actions(struct wlr_scene_node *node);
|
||||
|
||||
/* menu_close - close menu */
|
||||
void menu_close(struct menu *menu);
|
||||
|
||||
/* menu_reconfigure - reload theme and content */
|
||||
void menu_reconfigure(struct server *server, struct menu *menu);
|
||||
void menu_reconfigure(struct server *server);
|
||||
|
||||
#endif /* __LABWC_MENU_H */
|
||||
|
|
|
|||
67
include/node.h
Normal file
67
include/node.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef __LABWC_NODE_DESCRIPTOR_H
|
||||
#define __LABWC_NODE_DESCRIPTOR_H
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct view;
|
||||
struct lab_layer_surface;
|
||||
struct lab_layer_popup;
|
||||
struct menuitem;
|
||||
|
||||
enum node_descriptor_type {
|
||||
LAB_NODE_DESC_NODE = 0,
|
||||
LAB_NODE_DESC_VIEW,
|
||||
LAB_NODE_DESC_XDG_POPUP,
|
||||
LAB_NODE_DESC_LAYER_SURFACE,
|
||||
LAB_NODE_DESC_LAYER_POPUP,
|
||||
LAB_NODE_DESC_MENUITEM,
|
||||
LAB_NODE_DESC_TREE,
|
||||
};
|
||||
|
||||
struct node_descriptor {
|
||||
enum node_descriptor_type type;
|
||||
void *data;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
/**
|
||||
* node_descriptor_create - create node descriptor for wlr_scene_node user_data
|
||||
* @scene_node: wlr_scene_node to attached node_descriptor to
|
||||
* @type: node descriptor type
|
||||
* @data: struct to point to as follows:
|
||||
* - LAB_NODE_DESC_VIEW struct view
|
||||
* - LAB_NODE_DESC_XDG_POPUP struct view
|
||||
* - LAB_NODE_DESC_LAYER_SURFACE struct lab_layer_surface
|
||||
* - LAB_NODE_DESC_LAYER_POPUP struct lab_layer_popup
|
||||
*/
|
||||
void node_descriptor_create(struct wlr_scene_node *scene_node,
|
||||
enum node_descriptor_type type, void *data);
|
||||
|
||||
/**
|
||||
* node_view_from_node - return view struct from node
|
||||
* @wlr_scene_node: wlr_scene_node from which to return data
|
||||
*/
|
||||
struct view *node_view_from_node(struct wlr_scene_node *wlr_scene_node);
|
||||
|
||||
/**
|
||||
* node_lab_surface_from_node - return lab_layer_surface struct from node
|
||||
* @wlr_scene_node: wlr_scene_node from which to return data
|
||||
*/
|
||||
struct lab_layer_surface *node_layer_surface_from_node(
|
||||
struct wlr_scene_node *wlr_scene_node);
|
||||
|
||||
/**
|
||||
* node_layer_popup_from_node - return lab_layer_popup struct from node
|
||||
* @wlr_scene_node: wlr_scene_node from which to return data
|
||||
*/
|
||||
struct lab_layer_popup *node_layer_popup_from_node(
|
||||
struct wlr_scene_node *wlr_scene_node);
|
||||
|
||||
/**
|
||||
* node_menuitem_from_node - return menuitem struct from node
|
||||
* @wlr_scene_node: wlr_scene_node from which to return data
|
||||
*/
|
||||
struct menuitem *node_menuitem_from_node(
|
||||
struct wlr_scene_node *wlr_scene_node);
|
||||
|
||||
#endif /* __LABWC_NODE_DESCRIPTOR_H */
|
||||
174
include/ssd.h
174
include/ssd.h
|
|
@ -2,6 +2,22 @@
|
|||
#ifndef __LABWC_SSD_H
|
||||
#define __LABWC_SSD_H
|
||||
|
||||
#include "buffer.h"
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
#define SSD_HEIGHT 26 /* TODO: use theme->title_height */
|
||||
#define BUTTON_COUNT 4
|
||||
#define BUTTON_WIDTH 26
|
||||
#define EXTENDED_AREA 20
|
||||
|
||||
#define FOR_EACH(tmp, ...) \
|
||||
{ \
|
||||
__typeof__(tmp) _x[] = { __VA_ARGS__, NULL }; \
|
||||
size_t _i = 0; \
|
||||
for ((tmp) = _x[_i]; _i < sizeof(_x) / sizeof(_x[0]) - 1; (tmp) = _x[++_i])
|
||||
|
||||
#define FOR_EACH_END }
|
||||
|
||||
/*
|
||||
* Sequence these according to the order they should be processed for
|
||||
* press and hover events. Bear in mind that some of their respective
|
||||
|
|
@ -26,54 +42,144 @@ enum ssd_part_type {
|
|||
LAB_SSD_CLIENT,
|
||||
LAB_SSD_FRAME,
|
||||
LAB_SSD_ROOT,
|
||||
LAB_SSD_MENU,
|
||||
LAB_SSD_OSD,
|
||||
LAB_SSD_LAYER_SURFACE,
|
||||
LAB_SSD_UNMANAGED,
|
||||
LAB_SSD_END_MARKER
|
||||
};
|
||||
|
||||
/*
|
||||
* Defer including labwc.h because it is using enum ssd_part_type.
|
||||
* This is an issue for headers like mousebind.h which only includes
|
||||
* ssd.h but does not include labwc.h.
|
||||
*/
|
||||
#include "labwc.h"
|
||||
/* Forward declare arguments */
|
||||
struct view;
|
||||
struct wl_list;
|
||||
struct wlr_box;
|
||||
struct wlr_scene_tree;
|
||||
|
||||
struct ssd_sub_tree {
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wl_list parts; /* ssd_part::link */
|
||||
};
|
||||
|
||||
struct ssd_state_title_width {
|
||||
int width;
|
||||
bool truncated;
|
||||
};
|
||||
|
||||
struct ssd {
|
||||
bool enabled;
|
||||
struct wlr_scene_tree *tree;
|
||||
|
||||
/*
|
||||
* Cache for current values.
|
||||
* Used to detect actual changes so we
|
||||
* don't update things we don't have to.
|
||||
*/
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
struct ssd_state_title {
|
||||
char *text;
|
||||
struct ssd_state_title_width active;
|
||||
struct ssd_state_title_width inactive;
|
||||
} title;
|
||||
} state;
|
||||
|
||||
/* An invisble area around the view which allows resizing */
|
||||
struct ssd_sub_tree extents;
|
||||
|
||||
/* The top of the view, containing buttons, title, .. */
|
||||
struct {
|
||||
/* struct wlr_scene_tree *tree; unused for now */
|
||||
struct ssd_sub_tree active;
|
||||
struct ssd_sub_tree inactive;
|
||||
} titlebar;
|
||||
|
||||
/* Borders allow resizing as well */
|
||||
struct {
|
||||
/* struct wlr_scene_tree *tree; unused for now */
|
||||
struct ssd_sub_tree active;
|
||||
struct ssd_sub_tree inactive;
|
||||
} border;
|
||||
};
|
||||
|
||||
struct ssd_part {
|
||||
struct wlr_box box;
|
||||
enum ssd_part_type type;
|
||||
|
||||
/*
|
||||
* The texture pointers are often held in other places such as the
|
||||
* theme struct, so here we use ** in order to keep the code
|
||||
* simple and avoid updating pointers as textures change.
|
||||
*/
|
||||
struct {
|
||||
struct wlr_texture **active;
|
||||
struct wlr_texture **inactive;
|
||||
} texture;
|
||||
/* Buffer pointer. May be NULL */
|
||||
struct lab_data_buffer *buffer;
|
||||
|
||||
/*
|
||||
* If a part does not contain textures, it'll just be rendered as a
|
||||
* rectangle with the following colors.
|
||||
*/
|
||||
struct {
|
||||
float *active;
|
||||
float *inactive;
|
||||
} color;
|
||||
/* This part represented in scene graph */
|
||||
struct wlr_scene_node *node;
|
||||
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct view;
|
||||
struct ssd_hover_state {
|
||||
struct view *view;
|
||||
enum ssd_part_type type;
|
||||
struct wlr_scene_node *node;
|
||||
};
|
||||
|
||||
/* Public SSD API */
|
||||
void ssd_create(struct view *view);
|
||||
void ssd_hide(struct view *view);
|
||||
void ssd_set_active(struct view *view);
|
||||
void ssd_update_title(struct view *view);
|
||||
void ssd_update_geometry(struct view *view);
|
||||
void ssd_reload(struct view *view);
|
||||
void ssd_destroy(struct view *view);
|
||||
/* Returns hover overlay node so it can be disabled later on */
|
||||
struct wlr_scene_node *ssd_button_hover_enable(
|
||||
struct view *view, enum ssd_part_type type);
|
||||
|
||||
/* Public SSD helpers */
|
||||
enum ssd_part_type ssd_at(struct view *view, double lx, double ly);
|
||||
enum ssd_part_type ssd_get_part_type(
|
||||
struct view *view, struct wlr_scene_node *node);
|
||||
uint32_t ssd_resize_edges(enum ssd_part_type type);
|
||||
bool ssd_is_button(enum ssd_part_type type);
|
||||
bool ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate);
|
||||
|
||||
/* SSD internal helpers to create various SSD elements */
|
||||
/* TODO: Replace some common args with a struct */
|
||||
struct ssd_part *add_scene_part(
|
||||
struct wl_list *part_list, enum ssd_part_type type);
|
||||
struct ssd_part *add_scene_rect(
|
||||
struct wl_list *list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, int width, int height, int x, int y,
|
||||
float color[4]);
|
||||
struct ssd_part *add_scene_buffer(
|
||||
struct wl_list *list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, struct wlr_buffer *buffer, int x, int y);
|
||||
struct ssd_part *add_scene_button(
|
||||
struct wl_list *part_list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, float *bg_color,
|
||||
struct wlr_buffer *icon_buffer, int x);
|
||||
struct ssd_part *add_scene_button_corner(
|
||||
struct wl_list *part_list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, struct wlr_buffer *corner_buffer,
|
||||
struct wlr_buffer *icon_buffer, int x);
|
||||
|
||||
/* SSD internal helpers */
|
||||
struct ssd_part *ssd_get_part(
|
||||
struct wl_list *part_list, enum ssd_part_type type);
|
||||
void ssd_destroy_parts(struct wl_list *list);
|
||||
|
||||
/* SSD internal */
|
||||
void ssd_titlebar_create(struct view *view);
|
||||
void ssd_titlebar_update(struct view *view);
|
||||
void ssd_titlebar_destroy(struct view *view);
|
||||
|
||||
void ssd_border_create(struct view *view);
|
||||
void ssd_border_update(struct view *view);
|
||||
void ssd_border_destroy(struct view *view);
|
||||
|
||||
void ssd_extents_create(struct view *view);
|
||||
void ssd_extents_update(struct view *view);
|
||||
void ssd_extents_destroy(struct view *view);
|
||||
|
||||
/* TODO: clean up / update */
|
||||
struct border ssd_thickness(struct view *view);
|
||||
struct wlr_box ssd_max_extents(struct view *view);
|
||||
struct wlr_box ssd_visible_box(struct view *view, enum ssd_part_type type);
|
||||
enum ssd_part_type ssd_at(struct view *view, double lx, double ly);
|
||||
uint32_t ssd_resize_edges(enum ssd_part_type type);
|
||||
void ssd_update_title(struct view *view);
|
||||
void ssd_create(struct view *view);
|
||||
void ssd_destroy(struct view *view);
|
||||
void ssd_update_geometry(struct view *view, bool force);
|
||||
bool ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate);
|
||||
bool ssd_is_button(enum ssd_part_type type);
|
||||
|
||||
#endif /* __LABWC_SSD_H */
|
||||
|
|
|
|||
|
|
@ -54,20 +54,20 @@ struct theme {
|
|||
float osd_label_text_color[4];
|
||||
|
||||
/* textures */
|
||||
struct wlr_texture *xbm_close_active_unpressed;
|
||||
struct wlr_texture *xbm_maximize_active_unpressed;
|
||||
struct wlr_texture *xbm_iconify_active_unpressed;
|
||||
struct wlr_texture *xbm_menu_active_unpressed;
|
||||
struct lab_data_buffer *xbm_close_active_unpressed;
|
||||
struct lab_data_buffer *xbm_maximize_active_unpressed;
|
||||
struct lab_data_buffer *xbm_iconify_active_unpressed;
|
||||
struct lab_data_buffer *xbm_menu_active_unpressed;
|
||||
|
||||
struct wlr_texture *xbm_close_inactive_unpressed;
|
||||
struct wlr_texture *xbm_maximize_inactive_unpressed;
|
||||
struct wlr_texture *xbm_iconify_inactive_unpressed;
|
||||
struct wlr_texture *xbm_menu_inactive_unpressed;
|
||||
struct lab_data_buffer *xbm_close_inactive_unpressed;
|
||||
struct lab_data_buffer *xbm_maximize_inactive_unpressed;
|
||||
struct lab_data_buffer *xbm_iconify_inactive_unpressed;
|
||||
struct lab_data_buffer *xbm_menu_inactive_unpressed;
|
||||
|
||||
struct wlr_texture *corner_top_left_active_normal;
|
||||
struct wlr_texture *corner_top_right_active_normal;
|
||||
struct wlr_texture *corner_top_left_inactive_normal;
|
||||
struct wlr_texture *corner_top_right_inactive_normal;
|
||||
struct lab_data_buffer *corner_top_left_active_normal;
|
||||
struct lab_data_buffer *corner_top_right_active_normal;
|
||||
struct lab_data_buffer *corner_top_left_inactive_normal;
|
||||
struct lab_data_buffer *corner_top_right_inactive_normal;
|
||||
|
||||
/* not set in rc.xml/themerc, but derived from font & padding_height */
|
||||
int title_height;
|
||||
|
|
@ -76,12 +76,10 @@ struct theme {
|
|||
/**
|
||||
* theme_init - read openbox theme and generate button textures
|
||||
* @theme: theme data
|
||||
* @renderer: wlr_renderer for creating button textures
|
||||
* @theme_name: theme-name in <theme-dir>/<theme-name>/openbox-3/themerc
|
||||
* Note <theme-dir> is obtained in theme-dir.c
|
||||
*/
|
||||
void theme_init(struct theme *theme, struct wlr_renderer *renderer,
|
||||
const char *theme_name);
|
||||
void theme_init(struct theme *theme, const char *theme_name);
|
||||
|
||||
/**
|
||||
* theme_finish - free button textures
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
/**
|
||||
* xbm_load - load theme xbm files into global theme struct
|
||||
*/
|
||||
void xbm_load(struct theme *theme, struct wlr_renderer *renderer);
|
||||
void xbm_load(struct theme *theme);
|
||||
|
||||
#endif /* __LABWC_XBM_H */
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ add_project_arguments(cc.get_supported_arguments(
|
|||
version='"@0@"'.format(meson.project_version())
|
||||
git = find_program('git', native: true, required: false)
|
||||
if git.found()
|
||||
git_commit = run_command([git, 'describe', '--dirty'])
|
||||
git_commit = run_command([git, 'describe', '--dirty'], check: false)
|
||||
if git_commit.returncode() == 0
|
||||
version = '"@0@"'.format(git_commit.stdout().strip())
|
||||
endif
|
||||
endif
|
||||
add_project_arguments('-DLABWC_VERSION=@0@'.format(version), language: 'c')
|
||||
|
||||
wlroots_version = ['>=0.15.0', '<0.16.0']
|
||||
wlroots_version = ['>=0.16.0', '<0.17.0']
|
||||
wlroots_proj = subproject(
|
||||
'wlroots',
|
||||
default_options: ['default_library=static', 'examples=false'],
|
||||
|
|
|
|||
35
src/action.c
35
src/action.c
|
|
@ -3,6 +3,7 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include "common/spawn.h"
|
||||
#include "common/zfree.h"
|
||||
#include "debug.h"
|
||||
#include "labwc.h"
|
||||
#include "menu/menu.h"
|
||||
#include "ssd.h"
|
||||
|
|
@ -78,7 +79,8 @@ action_create(const char *action_name)
|
|||
return action;
|
||||
}
|
||||
|
||||
void action_list_free(struct wl_list *action_list) {
|
||||
void action_list_free(struct wl_list *action_list)
|
||||
{
|
||||
struct action *action, *action_tmp;
|
||||
wl_list_for_each_safe(action, action_tmp, action_list, link) {
|
||||
wl_list_remove(&action->link);
|
||||
|
|
@ -90,19 +92,15 @@ void action_list_free(struct wl_list *action_list) {
|
|||
static void
|
||||
show_menu(struct server *server, struct view *view, const char *menu_name)
|
||||
{
|
||||
struct menu *menu = NULL;
|
||||
bool force_menu_top_left = false;
|
||||
|
||||
if (!menu_name) {
|
||||
struct menu *menu = menu_get_by_id(menu_name);
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(menu_name, "root-menu")) {
|
||||
menu = server->rootmenu;
|
||||
server->windowmenu->visible = false;
|
||||
} else if (!strcasecmp(menu_name, "client-menu") && view) {
|
||||
menu = server->windowmenu;
|
||||
server->rootmenu->visible = false;
|
||||
if (!strcasecmp(menu_name, "client-menu")) {
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
enum ssd_part_type type = ssd_at(view, server->seat.cursor->x,
|
||||
server->seat.cursor->y);
|
||||
if (type == LAB_SSD_BUTTON_WINDOW_MENU) {
|
||||
|
|
@ -112,13 +110,8 @@ show_menu(struct server *server, struct view *view, const char *menu_name)
|
|||
} else {
|
||||
force_menu_top_left = true;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
menu->visible = true;
|
||||
server->input_mode = LAB_INPUT_STATE_MENU;
|
||||
|
||||
int x, y;
|
||||
if (force_menu_top_left) {
|
||||
x = view->x;
|
||||
|
|
@ -127,8 +120,7 @@ show_menu(struct server *server, struct view *view, const char *menu_name)
|
|||
x = server->seat.cursor->x;
|
||||
y = server->seat.cursor->y;
|
||||
}
|
||||
menu_move(menu, x, y);
|
||||
damage_all_outputs(server);
|
||||
menu_open(menu, x, y);
|
||||
}
|
||||
|
||||
static struct view *
|
||||
|
|
@ -138,7 +130,8 @@ activator_or_focused_view(struct view *activator, struct server *server)
|
|||
}
|
||||
|
||||
void
|
||||
action(struct view *activator, struct server *server, struct wl_list *actions, uint32_t resize_edges)
|
||||
actions_run(struct view *activator, struct server *server,
|
||||
struct wl_list *actions, uint32_t resize_edges)
|
||||
{
|
||||
if (!actions) {
|
||||
wlr_log(WLR_ERROR, "empty actions");
|
||||
|
|
@ -161,7 +154,7 @@ action(struct view *activator, struct server *server, struct wl_list *actions, u
|
|||
}
|
||||
break;
|
||||
case ACTION_TYPE_DEBUG:
|
||||
/* nothing */
|
||||
debug_dump_scene(server);
|
||||
break;
|
||||
case ACTION_TYPE_EXECUTE:
|
||||
{
|
||||
|
|
@ -218,7 +211,6 @@ action(struct view *activator, struct server *server, struct wl_list *actions, u
|
|||
view = desktop_view_at_cursor(server);
|
||||
if (view) {
|
||||
desktop_focus_and_activate_view(&server->seat, view);
|
||||
damage_all_outputs(server);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_ICONIFY:
|
||||
|
|
@ -235,7 +227,6 @@ action(struct view *activator, struct server *server, struct wl_list *actions, u
|
|||
case ACTION_TYPE_RAISE:
|
||||
if (view) {
|
||||
desktop_move_to_front(view);
|
||||
damage_all_outputs(server);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZE:
|
||||
|
|
|
|||
130
src/buffer.c
Normal file
130
src/buffer.c
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Based on wlroots/types/wlr_buffer.c
|
||||
*
|
||||
* Copyright (c) 2017, 2018 Drew DeVault
|
||||
* Copyright (c) 2018-2021 Simon Ser, Simon Zeni
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include "buffer.h"
|
||||
|
||||
static const struct wlr_buffer_impl data_buffer_impl;
|
||||
|
||||
static struct lab_data_buffer *
|
||||
data_buffer_from_buffer(struct wlr_buffer *buffer)
|
||||
{
|
||||
assert(buffer->impl == &data_buffer_impl);
|
||||
return (struct lab_data_buffer *)buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
data_buffer_destroy(struct wlr_buffer *wlr_buffer)
|
||||
{
|
||||
struct lab_data_buffer *buffer = data_buffer_from_buffer(wlr_buffer);
|
||||
if (!buffer->free_on_destroy) {
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
if (buffer->cairo) {
|
||||
cairo_surface_t *surf = cairo_get_target(buffer->cairo);
|
||||
cairo_destroy(buffer->cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
} else if (buffer->data) {
|
||||
free(buffer->data);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static bool
|
||||
data_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, uint32_t flags,
|
||||
void **data, uint32_t *format, size_t *stride)
|
||||
{
|
||||
struct lab_data_buffer *buffer =
|
||||
wl_container_of(wlr_buffer, buffer, base);
|
||||
assert(buffer->data);
|
||||
*data = (void *)buffer->data;
|
||||
*format = buffer->format;
|
||||
*stride = buffer->stride;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
data_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer)
|
||||
{
|
||||
/* noop */
|
||||
}
|
||||
|
||||
static const struct wlr_buffer_impl data_buffer_impl = {
|
||||
.destroy = data_buffer_destroy,
|
||||
.begin_data_ptr_access = data_buffer_begin_data_ptr_access,
|
||||
.end_data_ptr_access = data_buffer_end_data_ptr_access,
|
||||
};
|
||||
|
||||
struct lab_data_buffer *
|
||||
buffer_create_cairo(uint32_t width, uint32_t height, float scale,
|
||||
bool free_on_destroy)
|
||||
{
|
||||
struct lab_data_buffer *buffer = calloc(1, sizeof(*buffer));
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_buffer_init(&buffer->base, &data_buffer_impl, width, height);
|
||||
|
||||
cairo_surface_t *surf =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
cairo_surface_set_device_scale(surf, scale, scale);
|
||||
|
||||
buffer->cairo = cairo_create(surf);
|
||||
buffer->data = cairo_image_surface_get_data(surf);
|
||||
buffer->format = DRM_FORMAT_ARGB8888;
|
||||
buffer->stride = cairo_image_surface_get_stride(surf);
|
||||
buffer->free_on_destroy = free_on_destroy;
|
||||
|
||||
if (!buffer->data) {
|
||||
cairo_destroy(buffer->cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct lab_data_buffer *
|
||||
buffer_create_wrap(void *pixel_data, uint32_t width, uint32_t height,
|
||||
uint32_t stride, bool free_on_destroy)
|
||||
{
|
||||
struct lab_data_buffer *buffer = calloc(1, sizeof(*buffer));
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_buffer_init(&buffer->base, &data_buffer_impl, width, height);
|
||||
buffer->data = pixel_data;
|
||||
buffer->format = DRM_FORMAT_ARGB8888;
|
||||
buffer->stride = stride;
|
||||
buffer->free_on_destroy = free_on_destroy;
|
||||
return buffer;
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include "common/font.h"
|
||||
#include "labwc.h"
|
||||
#include "buffer.h"
|
||||
|
||||
static PangoRectangle
|
||||
font_extents(struct font *font, const char *string)
|
||||
|
|
@ -49,25 +50,33 @@ font_height(struct font *font)
|
|||
}
|
||||
|
||||
void
|
||||
font_texture_create(struct server *server, struct wlr_texture **texture,
|
||||
int max_width, const char *text, struct font *font, float *color)
|
||||
font_buffer_update(struct lab_data_buffer **buffer, int max_width,
|
||||
const char *text, struct font *font, float *color)
|
||||
{
|
||||
if (*buffer) {
|
||||
wlr_buffer_drop(&(*buffer)->base);
|
||||
*buffer = NULL;
|
||||
}
|
||||
font_buffer_create(buffer, max_width, text, font, color);
|
||||
}
|
||||
|
||||
void
|
||||
font_buffer_create(struct lab_data_buffer **buffer, int max_width,
|
||||
const char *text, struct font *font, float *color)
|
||||
{
|
||||
if (!text || !*text) {
|
||||
return;
|
||||
}
|
||||
if (*texture) {
|
||||
wlr_texture_destroy(*texture);
|
||||
*texture = NULL;
|
||||
}
|
||||
|
||||
PangoRectangle rect = font_extents(font, text);
|
||||
if (max_width && rect.width > max_width) {
|
||||
rect.width = max_width;
|
||||
}
|
||||
/* TODO: scale */
|
||||
*buffer = buffer_create_cairo(rect.width, rect.height, 1, true);
|
||||
|
||||
cairo_surface_t *surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
||||
rect.width, rect.height);
|
||||
cairo_t *cairo = cairo_create(surf);
|
||||
cairo_t *cairo = (*buffer)->cairo;
|
||||
cairo_surface_t *surf = cairo_get_target(cairo);
|
||||
|
||||
cairo_set_source_rgba(cairo, color[0], color[1], color[2], color[3]);
|
||||
cairo_move_to(cairo, 0, 0);
|
||||
|
|
@ -88,13 +97,6 @@ font_texture_create(struct server *server, struct wlr_texture **texture,
|
|||
g_object_unref(layout);
|
||||
|
||||
cairo_surface_flush(surf);
|
||||
unsigned char *data = cairo_image_surface_get_data(surf);
|
||||
*texture = wlr_texture_from_pixels(server->renderer, DRM_FORMAT_ARGB8888,
|
||||
cairo_image_surface_get_stride(surf), rect.width,
|
||||
rect.height, data);
|
||||
|
||||
cairo_destroy(cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ labwc_sources += files(
|
|||
'font.c',
|
||||
'grab-file.c',
|
||||
'nodename.c',
|
||||
'scene-helpers.c',
|
||||
'spawn.c',
|
||||
'string-helpers.c',
|
||||
'zfree.c',
|
||||
|
|
|
|||
11
src/common/scene-helpers.c
Normal file
11
src/common/scene-helpers.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <assert.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct wlr_scene_rect *
|
||||
lab_wlr_scene_get_rect(struct wlr_scene_node *node)
|
||||
{
|
||||
assert(node->type == WLR_SCENE_NODE_RECT);
|
||||
return (struct wlr_scene_rect *)node;
|
||||
}
|
||||
228
src/cursor.c
228
src/cursor.c
|
|
@ -12,15 +12,30 @@
|
|||
#include "ssd.h"
|
||||
#include "config/mousebind.h"
|
||||
|
||||
static bool
|
||||
is_surface(enum ssd_part_type view_area)
|
||||
{
|
||||
return view_area == LAB_SSD_CLIENT
|
||||
|| view_area == LAB_SSD_LAYER_SURFACE
|
||||
#if HAVE_XWAYLAND
|
||||
|| view_area == LAB_SSD_UNMANAGED
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
cursor_rebase(struct seat *seat, uint32_t time_msec)
|
||||
{
|
||||
double sx, sy;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_scene_node *node;
|
||||
enum ssd_part_type view_area = LAB_SSD_NONE;
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
desktop_surface_and_view_at(seat->server, seat->cursor->x,
|
||||
seat->cursor->y, &surface, &sx, &sy, &view_area);
|
||||
desktop_node_and_view_at(seat->server, seat->cursor->x,
|
||||
seat->cursor->y, &node, &sx, &sy, &view_area);
|
||||
if (is_surface(view_area)) {
|
||||
surface = wlr_scene_surface_from_node(node)->surface;
|
||||
}
|
||||
|
||||
if (surface) {
|
||||
wlr_seat_pointer_notify_clear_focus(seat->seat);
|
||||
|
|
@ -37,7 +52,7 @@ request_cursor_notify(struct wl_listener *listener, void *data)
|
|||
{
|
||||
struct seat *seat = wl_container_of(listener, seat, request_cursor);
|
||||
/*
|
||||
* This event is rasied by the seat when a client provides a cursor
|
||||
* This event is raised by the seat when a client provides a cursor
|
||||
* image
|
||||
*/
|
||||
struct wlr_seat_pointer_request_set_cursor_event *event = data;
|
||||
|
|
@ -98,7 +113,6 @@ request_start_drag_notify(struct wl_listener *listener, void *data)
|
|||
static void
|
||||
process_cursor_move(struct server *server, uint32_t time)
|
||||
{
|
||||
damage_all_outputs(server);
|
||||
double dx = server->seat.cursor->x - server->grab_x;
|
||||
double dy = server->seat.cursor->y - server->grab_y;
|
||||
struct view *view = server->grabbed_view;
|
||||
|
|
@ -113,7 +127,6 @@ process_cursor_move(struct server *server, uint32_t time)
|
|||
static void
|
||||
process_cursor_resize(struct server *server, uint32_t time)
|
||||
{
|
||||
damage_all_outputs(server);
|
||||
double dx = server->seat.cursor->x - server->grab_x;
|
||||
double dy = server->seat.cursor->y - server->grab_y;
|
||||
|
||||
|
|
@ -170,28 +183,10 @@ input_inhibit_blocks_surface(struct seat *seat, struct wl_resource *resource)
|
|||
inhibiting_client != wl_resource_get_client(resource);
|
||||
}
|
||||
|
||||
static struct output *
|
||||
get_output(struct server *server, struct wlr_cursor *cursor)
|
||||
{
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
server->output_layout, cursor->x, cursor->y);
|
||||
return output_from_wlr_output(server, wlr_output);
|
||||
}
|
||||
|
||||
static void
|
||||
damage_whole_current_output(struct server *server)
|
||||
{
|
||||
struct output *output = get_output(server, server->seat.cursor);
|
||||
if (output) {
|
||||
wlr_output_damage_add_whole(output->damage);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_cursor_motion(struct server *server, uint32_t time)
|
||||
{
|
||||
static bool cursor_name_set_by_server;
|
||||
static enum ssd_part_type last_button_hover = LAB_SSD_NONE;
|
||||
|
||||
/* If the mode is non-passthrough, delegate to those functions. */
|
||||
if (server->input_mode == LAB_INPUT_STATE_MOVE) {
|
||||
|
|
@ -200,53 +195,47 @@ process_cursor_motion(struct server *server, uint32_t time)
|
|||
} else if (server->input_mode == LAB_INPUT_STATE_RESIZE) {
|
||||
process_cursor_resize(server, time);
|
||||
return;
|
||||
} else if (server->input_mode == LAB_INPUT_STATE_MENU) {
|
||||
struct menu *menu = NULL;
|
||||
if (server->rootmenu->visible) {
|
||||
menu = server->rootmenu;
|
||||
} else if (server->windowmenu->visible) {
|
||||
menu = server->windowmenu;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
menu_set_selected(menu,
|
||||
server->seat.cursor->x, server->seat.cursor->y);
|
||||
damage_all_outputs(server);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, find view under the pointer and send the event along */
|
||||
double sx, sy;
|
||||
struct wlr_seat *wlr_seat = server->seat.seat;
|
||||
struct wlr_surface *surface = NULL;
|
||||
struct wlr_scene_node *node;
|
||||
enum ssd_part_type view_area = LAB_SSD_NONE;
|
||||
struct view *view = desktop_surface_and_view_at(server,
|
||||
server->seat.cursor->x, server->seat.cursor->y, &surface,
|
||||
struct view *view = desktop_node_and_view_at(server,
|
||||
server->seat.cursor->x, server->seat.cursor->y, &node,
|
||||
&sx, &sy, &view_area);
|
||||
|
||||
struct wlr_surface *surface = NULL;
|
||||
if (is_surface(view_area)) {
|
||||
surface = wlr_scene_surface_from_node(node)->surface;
|
||||
}
|
||||
|
||||
/* resize handles */
|
||||
uint32_t resize_edges = ssd_resize_edges(view_area);
|
||||
|
||||
/* Set cursor */
|
||||
if (!view) {
|
||||
/* root, etc. */
|
||||
if (view_area == LAB_SSD_ROOT || view_area == LAB_SSD_MENU) {
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
} else {
|
||||
if (resize_edges) {
|
||||
cursor_name_set_by_server = true;
|
||||
cursor_set(&server->seat,
|
||||
wlr_xcursor_get_resize_name(resize_edges));
|
||||
} else if (ssd_part_contains(LAB_SSD_PART_TITLEBAR, view_area)) {
|
||||
/* title and buttons */
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
cursor_name_set_by_server = true;
|
||||
} else if (cursor_name_set_by_server) {
|
||||
/* window content */
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
cursor_name_set_by_server = false;
|
||||
}
|
||||
} else if (resize_edges) {
|
||||
cursor_name_set_by_server = true;
|
||||
cursor_set(&server->seat,
|
||||
wlr_xcursor_get_resize_name(resize_edges));
|
||||
} else if (ssd_part_contains(LAB_SSD_PART_TITLEBAR, view_area)) {
|
||||
/* title and buttons */
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
cursor_name_set_by_server = true;
|
||||
} else if (cursor_name_set_by_server) {
|
||||
/* xdg/xwindow window content */
|
||||
/* layershell or unmanaged */
|
||||
cursor_set(&server->seat, XCURSOR_DEFAULT);
|
||||
cursor_name_set_by_server = false;
|
||||
}
|
||||
|
||||
if (view_area == LAB_SSD_MENU) {
|
||||
menu_process_cursor_motion(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view && rc.focus_follow_mouse) {
|
||||
desktop_focus_and_activate_view(&server->seat, view);
|
||||
|
|
@ -270,21 +259,28 @@ process_cursor_motion(struct server *server, uint32_t time)
|
|||
}
|
||||
|
||||
mousebind->pressed_in_context = false;
|
||||
action(NULL, server, &mousebind->actions, resize_edges);
|
||||
actions_run(NULL, server, &mousebind->actions, resize_edges);
|
||||
}
|
||||
}
|
||||
|
||||
/* Required for iconify/maximize/close button mouse-over deco */
|
||||
/* SSD button mouse-over */
|
||||
struct ssd_hover_state *hover = &server->ssd_hover_state;
|
||||
if (ssd_is_button(view_area)) {
|
||||
if (last_button_hover != view_area) {
|
||||
/* Cursor entered new button area */
|
||||
damage_whole_current_output(server);
|
||||
last_button_hover = view_area;
|
||||
/* Cursor entered new button area */
|
||||
if (hover->view != view || hover->type != view_area) {
|
||||
if (hover->node) {
|
||||
wlr_scene_node_set_enabled(hover->node, false);
|
||||
}
|
||||
hover->view = view;
|
||||
hover->type = view_area;
|
||||
hover->node = ssd_button_hover_enable(view, view_area);
|
||||
}
|
||||
} else if (last_button_hover != LAB_SSD_NONE) {
|
||||
} else if (hover->node) {
|
||||
/* Cursor left button area */
|
||||
damage_whole_current_output(server);
|
||||
last_button_hover = LAB_SSD_NONE;
|
||||
wlr_scene_node_set_enabled(hover->node, false);
|
||||
hover->view = NULL;
|
||||
hover->type = LAB_SSD_NONE;
|
||||
hover->node = NULL;
|
||||
}
|
||||
|
||||
if (surface &&
|
||||
|
|
@ -507,12 +503,19 @@ handle_release_mousebinding(struct view *view, struct server *server,
|
|||
break;
|
||||
}
|
||||
continue;
|
||||
case MOUSE_ACTION_DRAG:
|
||||
if (mousebind->pressed_in_context) {
|
||||
/* Swallow the release event as well as the press one */
|
||||
activated_any = true;
|
||||
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
activated_any = true;
|
||||
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
|
||||
action(view, server, &mousebind->actions, resize_edges);
|
||||
actions_run(view, server, &mousebind->actions, resize_edges);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
@ -576,6 +579,9 @@ handle_press_mousebinding(struct view *view, struct server *server,
|
|||
* counted as a DOUBLECLICK.
|
||||
*/
|
||||
if (!double_click) {
|
||||
/* Swallow the press event as well as the release one */
|
||||
activated_any = true;
|
||||
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
|
||||
mousebind->pressed_in_context = true;
|
||||
}
|
||||
continue;
|
||||
|
|
@ -591,7 +597,7 @@ handle_press_mousebinding(struct view *view, struct server *server,
|
|||
}
|
||||
activated_any = true;
|
||||
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
|
||||
action(view, server, &mousebind->actions, resize_edges);
|
||||
actions_run(view, server, &mousebind->actions, resize_edges);
|
||||
}
|
||||
}
|
||||
return activated_any && activated_any_frame;
|
||||
|
|
@ -610,27 +616,48 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
wlr_idle_notify_activity(seat->wlr_idle, seat->seat);
|
||||
|
||||
double sx, sy;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_scene_node *node;
|
||||
enum ssd_part_type view_area = LAB_SSD_NONE;
|
||||
uint32_t resize_edges;
|
||||
uint32_t resize_edges = 0;
|
||||
|
||||
/**
|
||||
* Used in WLR_BUTTON_RELEASED, set on WLR_BUTTON_PRESSED
|
||||
*
|
||||
* Automatically initialized with 0 / false and
|
||||
* checkpatch.pl complains when done manually.
|
||||
*/
|
||||
static bool close_menu;
|
||||
|
||||
/* bindings to the Frame context swallow mouse events if activated */
|
||||
bool triggered_frame_binding = false;
|
||||
|
||||
struct view *view = desktop_surface_and_view_at(server,
|
||||
server->seat.cursor->x, server->seat.cursor->y, &surface,
|
||||
struct view *view = desktop_node_and_view_at(server,
|
||||
server->seat.cursor->x, server->seat.cursor->y, &node,
|
||||
&sx, &sy, &view_area);
|
||||
|
||||
struct wlr_surface *surface = NULL;
|
||||
if (is_surface(view_area)) {
|
||||
surface = wlr_scene_surface_from_node(node)->surface;
|
||||
}
|
||||
|
||||
/* get modifiers */
|
||||
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
||||
uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard);
|
||||
struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard;
|
||||
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
|
||||
|
||||
/* handle _release_ */
|
||||
if (event->state == WLR_BUTTON_RELEASED) {
|
||||
if (server->input_mode == LAB_INPUT_STATE_MENU) {
|
||||
if (close_menu) {
|
||||
if (server->menu_current) {
|
||||
menu_close(server->menu_current);
|
||||
server->menu_current = NULL;
|
||||
}
|
||||
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
|
||||
cursor_rebase(&server->seat, event->time_msec);
|
||||
close_menu = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
damage_all_outputs(server);
|
||||
if (server->input_mode != LAB_INPUT_STATE_PASSTHROUGH) {
|
||||
/* Exit interactive move/resize/menu mode. */
|
||||
if (server->grabbed_view == view) {
|
||||
|
|
@ -640,56 +667,41 @@ cursor_button(struct wl_listener *listener, void *data)
|
|||
server->grabbed_view = NULL;
|
||||
}
|
||||
cursor_rebase(&server->seat, event->time_msec);
|
||||
}
|
||||
|
||||
/* Handle _release_ on root window */
|
||||
if (!view) {
|
||||
handle_release_mousebinding(NULL, server, event->button,
|
||||
modifiers, LAB_SSD_ROOT, 0);
|
||||
return;
|
||||
}
|
||||
goto mousebindings;
|
||||
}
|
||||
|
||||
/* Handle _press */
|
||||
if (server->input_mode == LAB_INPUT_STATE_MENU) {
|
||||
if (server->rootmenu->visible) {
|
||||
menu_action_selected(server, server->rootmenu);
|
||||
} else if (server->windowmenu->visible) {
|
||||
menu_action_selected(server, server->windowmenu);
|
||||
if (view_area != LAB_SSD_MENU) {
|
||||
/* We close the menu on release so we don't leak a stray release */
|
||||
close_menu = true;
|
||||
} else if (menu_call_actions(node)) {
|
||||
/* Action was successfull, may fail if item just opens a submenu */
|
||||
close_menu = true;
|
||||
}
|
||||
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
|
||||
cursor_rebase(&server->seat, event->time_msec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle _press_ on a layer surface */
|
||||
if (!view && surface) {
|
||||
if (!wlr_surface_is_layer_surface(surface)) {
|
||||
return;
|
||||
}
|
||||
if (view_area == LAB_SSD_LAYER_SURFACE) {
|
||||
struct wlr_layer_surface_v1 *layer =
|
||||
wlr_layer_surface_v1_from_wlr_surface(surface);
|
||||
if (layer->current.keyboard_interactive) {
|
||||
seat_set_focus_layer(&server->seat, layer);
|
||||
}
|
||||
wlr_seat_pointer_notify_button(seat->seat, event->time_msec,
|
||||
event->button, event->state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle _press_ on root window */
|
||||
if (!view) {
|
||||
handle_press_mousebinding(NULL, server,
|
||||
event->button, modifiers, LAB_SSD_ROOT, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine closest resize edges in case action is Resize */
|
||||
resize_edges = ssd_resize_edges(view_area);
|
||||
if (!resize_edges) {
|
||||
resize_edges |= server->seat.cursor->x < view->x + view->w / 2
|
||||
? WLR_EDGE_LEFT : WLR_EDGE_RIGHT;
|
||||
resize_edges |= server->seat.cursor->y < view->y + view->h / 2
|
||||
? WLR_EDGE_TOP : WLR_EDGE_BOTTOM;
|
||||
if (view) {
|
||||
/* Determine closest resize edges in case action is Resize */
|
||||
resize_edges = ssd_resize_edges(view_area);
|
||||
if (!resize_edges) {
|
||||
resize_edges |= server->seat.cursor->x < view->x + view->w / 2
|
||||
? WLR_EDGE_LEFT : WLR_EDGE_RIGHT;
|
||||
resize_edges |= server->seat.cursor->y < view->y + view->h / 2
|
||||
? WLR_EDGE_TOP : WLR_EDGE_BOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
mousebindings:
|
||||
|
|
@ -702,7 +714,7 @@ mousebindings:
|
|||
server, event->button, modifiers,
|
||||
view_area, resize_edges);
|
||||
}
|
||||
if (!triggered_frame_binding) {
|
||||
if (surface && !triggered_frame_binding) {
|
||||
/* Notify client with pointer focus of button press */
|
||||
wlr_seat_pointer_notify_button(seat->seat, event->time_msec,
|
||||
event->button, event->state);
|
||||
|
|
|
|||
33
src/damage.c
33
src/damage.c
|
|
@ -1,33 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include "labwc.h"
|
||||
|
||||
void
|
||||
damage_all_outputs(struct server *server)
|
||||
{
|
||||
struct output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
if (output && output->wlr_output && output->damage) {
|
||||
wlr_output_damage_add_whole(output->damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
damage_view_part(struct view *view)
|
||||
{
|
||||
struct output *output;
|
||||
wl_list_for_each (output, &view->server->outputs, link) {
|
||||
output_damage_surface(output, view->surface, view->x, view->y,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
damage_view_whole(struct view *view)
|
||||
{
|
||||
struct output *output;
|
||||
wl_list_for_each (output, &view->server->outputs, link) {
|
||||
output_damage_surface(output, view->surface, view->x, view->y,
|
||||
true);
|
||||
}
|
||||
}
|
||||
181
src/debug.c
Normal file
181
src/debug.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "buffer.h"
|
||||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
|
||||
#define HEADER_CHARS "------------------------------"
|
||||
|
||||
#define INDENT_SIZE 3
|
||||
#define IGNORE_SSD true
|
||||
#define IGNORE_MENU true
|
||||
#define LEFT_COL_SPACE 35
|
||||
|
||||
static const char *
|
||||
get_node_type(enum wlr_scene_node_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case WLR_SCENE_NODE_ROOT:
|
||||
return "root";
|
||||
case WLR_SCENE_NODE_TREE:
|
||||
return "tree";
|
||||
case WLR_SCENE_NODE_SURFACE:
|
||||
return "surface";
|
||||
case WLR_SCENE_NODE_RECT:
|
||||
return "rect";
|
||||
case WLR_SCENE_NODE_BUFFER:
|
||||
return "buffer";
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_layer_name(uint32_t layer)
|
||||
{
|
||||
switch (layer) {
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
|
||||
return "layer-background";
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
|
||||
return "layer-bottom";
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
|
||||
return "layer-top";
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
|
||||
return "layer-overlay";
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_view_part(struct view *view, struct wlr_scene_node *node)
|
||||
{
|
||||
if (view && node == &view->scene_tree->node) {
|
||||
return "view";
|
||||
}
|
||||
if (view && node == view->scene_node) {
|
||||
return "view->scene_node";
|
||||
}
|
||||
if (!view || !view->ssd.tree) {
|
||||
return NULL;
|
||||
}
|
||||
if (node == &view->ssd.tree->node) {
|
||||
return "view->ssd";
|
||||
}
|
||||
if (node == &view->ssd.titlebar.active.tree->node) {
|
||||
return "titlebar.active";
|
||||
}
|
||||
if (node == &view->ssd.titlebar.inactive.tree->node) {
|
||||
return "titlebar.inactive";
|
||||
}
|
||||
if (node == &view->ssd.border.active.tree->node) {
|
||||
return "border.active";
|
||||
}
|
||||
if (node == &view->ssd.border.inactive.tree->node) {
|
||||
return "border.inactive";
|
||||
}
|
||||
if (node == &view->ssd.extents.tree->node) {
|
||||
return "extents";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_special(struct server *server, struct wlr_scene_node *node,
|
||||
struct view **last_view)
|
||||
{
|
||||
if (node == &server->scene->node) {
|
||||
return "server->scene";
|
||||
}
|
||||
if (node == &server->osd_tree->node) {
|
||||
return "server->osd_tree";
|
||||
}
|
||||
if (node == &server->menu_tree->node) {
|
||||
return "server->menu_tree";
|
||||
}
|
||||
if (node->parent == &server->scene->node) {
|
||||
struct output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (node == &output->layer_tree[i]->node) {
|
||||
return get_layer_name(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if HAVE_XWAYLAND
|
||||
if (node == &server->unmanaged_tree->node) {
|
||||
return "server->unmanaged_tree";
|
||||
}
|
||||
#endif
|
||||
if (node == &server->view_tree->node) {
|
||||
return "server->view_tree";
|
||||
}
|
||||
if (node->parent == &server->view_tree->node) {
|
||||
*last_view = node_view_from_node(node);
|
||||
}
|
||||
const char *view_part = get_view_part(*last_view, node);
|
||||
if (view_part) {
|
||||
return view_part;
|
||||
}
|
||||
return get_node_type(node->type);
|
||||
}
|
||||
|
||||
struct pad {
|
||||
uint8_t left;
|
||||
uint8_t right;
|
||||
};
|
||||
|
||||
static struct pad
|
||||
get_center_padding(const char *text, uint8_t max_width)
|
||||
{
|
||||
struct pad pad;
|
||||
size_t text_len = strlen(text);
|
||||
pad.left = (double)(max_width - text_len) / 2 + 0.5f;
|
||||
pad.right = max_width - pad.left - text_len;
|
||||
return pad;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_tree(struct server *server, struct wlr_scene_node *node,
|
||||
int pos, int x, int y)
|
||||
{
|
||||
static struct view *view;
|
||||
const char *type = get_special(server, node, &view);
|
||||
|
||||
if (pos) {
|
||||
printf("%*c+-- ", pos, ' ');
|
||||
} else {
|
||||
struct pad node_pad = get_center_padding("Node", 16);
|
||||
printf(" %*c %4s %4s %*c%s\n", LEFT_COL_SPACE + 4, ' ',
|
||||
"X", "Y", node_pad.left, ' ', "Node");
|
||||
printf(" %*c %.4s %.4s %.16s\n", LEFT_COL_SPACE + 4, ' ',
|
||||
HEADER_CHARS, HEADER_CHARS, HEADER_CHARS);
|
||||
printf(" ");
|
||||
}
|
||||
int padding = LEFT_COL_SPACE - pos - strlen(type);
|
||||
if (!pos) {
|
||||
padding += 3;
|
||||
}
|
||||
printf("%s %*c %4d %4d [%p]\n", type, padding, ' ', x, y, node);
|
||||
|
||||
if ((IGNORE_MENU && node == &server->menu_tree->node)
|
||||
|| (IGNORE_SSD && view && view->ssd.tree
|
||||
&& node == &view->ssd.tree->node)) {
|
||||
printf("%*c%s\n", pos + 4 + INDENT_SIZE, ' ', "<skipping children>");
|
||||
return;
|
||||
}
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &node->state.children, state.link) {
|
||||
dump_tree(server, child, pos + INDENT_SIZE,
|
||||
x + child->state.x, y + child->state.y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
debug_dump_scene(struct server *server)
|
||||
{
|
||||
printf("\n");
|
||||
dump_tree(server, &server->scene->node, 0, 0, 0);
|
||||
printf("\n");
|
||||
}
|
||||
225
src/desktop.c
225
src/desktop.c
|
|
@ -3,6 +3,7 @@
|
|||
#include <assert.h>
|
||||
#include "labwc.h"
|
||||
#include "layers.h"
|
||||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
|
||||
static void
|
||||
|
|
@ -10,6 +11,7 @@ move_to_front(struct view *view)
|
|||
{
|
||||
wl_list_remove(&view->link);
|
||||
wl_list_insert(&view->server->views, &view->link);
|
||||
wlr_scene_node_raise_to_top(&view->scene_tree->node);
|
||||
}
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
|
|
@ -197,7 +199,6 @@ desktop_cycle_view(struct server *server, struct view *current,
|
|||
view = wl_container_of(view->link.prev, view, link);
|
||||
} while (&view->link == &server->views || !isfocusable(view));
|
||||
}
|
||||
damage_all_outputs(server);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
|
@ -255,189 +256,85 @@ desktop_focus_topmost_mapped_view(struct server *server)
|
|||
desktop_move_to_front(view);
|
||||
}
|
||||
|
||||
static bool
|
||||
_view_at(struct view *view, double lx, double ly, struct wlr_surface **surface,
|
||||
double *sx, double *sy)
|
||||
{
|
||||
/*
|
||||
* XDG toplevels may have nested surfaces, such as popup windows for
|
||||
* context menus or tooltips. This function tests if any of those are
|
||||
* underneath the coordinates lx and ly (in output Layout Coordinates).
|
||||
* If so, it sets the surface pointer to that wlr_surface and the sx and
|
||||
* sy coordinates to the coordinates relative to that surface's top-left
|
||||
* corner.
|
||||
*/
|
||||
double view_sx = lx - view->x;
|
||||
double view_sy = ly - view->y;
|
||||
double _sx, _sy;
|
||||
struct wlr_surface *_surface = NULL;
|
||||
|
||||
switch (view->type) {
|
||||
case LAB_XDG_SHELL_VIEW:
|
||||
_surface = wlr_xdg_surface_surface_at(
|
||||
view->xdg_surface, view_sx, view_sy, &_sx, &_sy);
|
||||
break;
|
||||
#if HAVE_XWAYLAND
|
||||
case LAB_XWAYLAND_VIEW:
|
||||
_surface = wlr_surface_surface_at(view->surface, view_sx,
|
||||
view_sy, &_sx, &_sy);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_surface) {
|
||||
*sx = _sx;
|
||||
*sy = _sy;
|
||||
*surface = _surface;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct
|
||||
wlr_surface *layer_surface_at(struct wl_list *layer, double ox, double oy,
|
||||
double *sx, double *sy)
|
||||
{
|
||||
struct lab_layer_surface *surface;
|
||||
wl_list_for_each_reverse(surface, layer, link) {
|
||||
double _sx = ox - surface->geo.x;
|
||||
double _sy = oy - surface->geo.y;
|
||||
struct wlr_surface *wlr_surface;
|
||||
wlr_surface = wlr_layer_surface_v1_surface_at(
|
||||
surface->layer_surface, _sx, _sy, sx, sy);
|
||||
if (wlr_surface) {
|
||||
return wlr_surface;
|
||||
}
|
||||
}
|
||||
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 output *output, struct wl_list *layer,
|
||||
double ox, double oy, double *sx, double *sy)
|
||||
{
|
||||
struct lab_layer_surface *lab_layer;
|
||||
wl_list_for_each_reverse(lab_layer, layer, link) {
|
||||
double _sx = ox - lab_layer->geo.x;
|
||||
double _sy = oy - lab_layer->geo.y;
|
||||
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
|
||||
lab_layer->layer_surface, _sx, _sy, sx, sy);
|
||||
if (sub && surface_is_xdg_popup(sub)) {
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct view *
|
||||
desktop_surface_and_view_at(struct server *server, double lx, double ly,
|
||||
struct wlr_surface **surface, double *sx, double *sy,
|
||||
desktop_node_and_view_at(struct server *server, double lx, double ly,
|
||||
struct wlr_scene_node **scene_node, double *sx, double *sy,
|
||||
enum ssd_part_type *view_area)
|
||||
{
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
server->output_layout, lx, ly);
|
||||
struct output *output = output_from_wlr_output(server, wlr_output);
|
||||
struct wlr_scene_node *node =
|
||||
wlr_scene_node_at(&server->scene->node, lx, ly, sx, sy);
|
||||
|
||||
if (!output) {
|
||||
*scene_node = node;
|
||||
if (!node) {
|
||||
*view_area = LAB_SSD_ROOT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double ox = lx, oy = ly;
|
||||
wlr_output_layout_output_coords(output->server->output_layout,
|
||||
wlr_output, &ox, &oy);
|
||||
|
||||
/* Overlay-layer */
|
||||
*surface = layer_surface_at(
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check all layer popups */
|
||||
*surface = layer_surface_popup_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
}
|
||||
*surface = layer_surface_popup_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
}
|
||||
*surface = layer_surface_popup_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Top-layer */
|
||||
*surface = layer_surface_at(
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct view *view;
|
||||
wl_list_for_each (view, &server->views, link) {
|
||||
if (!view->mapped) {
|
||||
continue;
|
||||
if (node->type == WLR_SCENE_NODE_SURFACE) {
|
||||
struct wlr_surface *surface =
|
||||
wlr_scene_surface_from_node(node)->surface;
|
||||
if (wlr_surface_is_layer_surface(surface)) {
|
||||
*view_area = LAB_SSD_LAYER_SURFACE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This ignores server-side deco */
|
||||
if (_view_at(view, lx, ly, surface, sx, sy)) {
|
||||
*view_area = LAB_SSD_CLIENT;
|
||||
return view;
|
||||
#if HAVE_XWAYLAND
|
||||
if (node->parent == &server->unmanaged_tree->node) {
|
||||
*view_area = LAB_SSD_UNMANAGED;
|
||||
return NULL;
|
||||
}
|
||||
if (!view->ssd.enabled) {
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
struct wlr_scene_node *osd = &server->osd_tree->node;
|
||||
while (node) {
|
||||
struct node_descriptor *desc = node->data;
|
||||
/* TODO: convert to switch() */
|
||||
if (desc) {
|
||||
if (desc->type == LAB_NODE_DESC_VIEW) {
|
||||
goto has_view_data;
|
||||
}
|
||||
if (desc->type == LAB_NODE_DESC_XDG_POPUP) {
|
||||
goto has_view_data;
|
||||
}
|
||||
if (desc->type == LAB_NODE_DESC_LAYER_POPUP) {
|
||||
/* FIXME: we shouldn't have to set *view_area */
|
||||
*view_area = LAB_SSD_CLIENT;
|
||||
return NULL;
|
||||
}
|
||||
if (desc->type == LAB_NODE_DESC_MENUITEM) {
|
||||
/* Always return the top scene node for menu items */
|
||||
*scene_node = node;
|
||||
*view_area = LAB_SSD_MENU;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, let's deal with the server-side deco */
|
||||
*view_area = ssd_at(view, lx, ly);
|
||||
if (*view_area != LAB_SSD_NONE) {
|
||||
return view;
|
||||
if (node == osd) {
|
||||
*view_area = LAB_SSD_OSD;
|
||||
return NULL;
|
||||
}
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
*surface = layer_surface_at(
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
}
|
||||
*surface = layer_surface_at(
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
ox, oy, sx, sy);
|
||||
if (*surface) {
|
||||
return NULL;
|
||||
if (!node) {
|
||||
wlr_log(WLR_ERROR, "Unknown node detected");
|
||||
}
|
||||
*view_area = LAB_SSD_NONE;
|
||||
return NULL;
|
||||
|
||||
struct view *view;
|
||||
struct node_descriptor *desc;
|
||||
has_view_data:
|
||||
desc = node->data;
|
||||
view = desc->data;
|
||||
*view_area = ssd_get_part_type(view, *scene_node);
|
||||
return view;
|
||||
}
|
||||
|
||||
struct view *
|
||||
desktop_view_at_cursor(struct server *server)
|
||||
{
|
||||
double sx, sy;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_scene_node *node;
|
||||
enum ssd_part_type view_area = LAB_SSD_NONE;
|
||||
|
||||
return desktop_surface_and_view_at(server,
|
||||
return desktop_node_and_view_at(server,
|
||||
server->seat.cursor->x, server->seat.cursor->y,
|
||||
&surface, &sx, &sy, &view_area);
|
||||
&node, &sx, &sy, &view_area);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include "action.h"
|
||||
#include "buffer.h"
|
||||
#include "key-state.h"
|
||||
#include "labwc.h"
|
||||
|
||||
|
|
@ -40,15 +41,15 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data)
|
|||
|
||||
if (server->cycle_view) {
|
||||
struct wlr_event_keyboard_key *event = data;
|
||||
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
||||
damage_all_outputs(server);
|
||||
struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard;
|
||||
if ((event->state == WL_KEYBOARD_KEY_STATE_RELEASED)
|
||||
&& !any_modifiers_pressed(device->keyboard)) {
|
||||
&& !any_modifiers_pressed(keyboard)) {
|
||||
/* end cycle */
|
||||
desktop_focus_and_activate_view(&server->seat,
|
||||
server->cycle_view);
|
||||
desktop_move_to_front(server->cycle_view);
|
||||
server->cycle_view = NULL;
|
||||
osd_finish(server);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym)
|
|||
for (size_t i = 0; i < keybind->keysyms_len; i++) {
|
||||
if (xkb_keysym_to_lower(sym) == keybind->keysyms[i]) {
|
||||
wlr_keyboard_set_repeat_info(kb, 0, 0);
|
||||
action(NULL, server, &keybind->actions, 0);
|
||||
actions_run(NULL, server, &keybind->actions, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -94,13 +95,13 @@ handle_compositor_keybindings(struct wl_listener *listener,
|
|||
{
|
||||
struct seat *seat = wl_container_of(listener, seat, keyboard_key);
|
||||
struct server *server = seat->server;
|
||||
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
||||
struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard;
|
||||
|
||||
/* Translate libinput keycode -> xkbcommon */
|
||||
uint32_t keycode = event->keycode + 8;
|
||||
/* Get a list of keysyms based on the keymap for this keyboard */
|
||||
const xkb_keysym_t *syms;
|
||||
int nsyms = xkb_state_key_get_syms(device->keyboard->xkb_state, keycode, &syms);
|
||||
int nsyms = xkb_state_key_get_syms(keyboard->xkb_state, keycode, &syms);
|
||||
|
||||
bool handled = false;
|
||||
|
||||
|
|
@ -115,14 +116,13 @@ handle_compositor_keybindings(struct wl_listener *listener,
|
|||
&& event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
||||
int nr_bound_keys = key_state_bound_key_remove(keycode);
|
||||
if (!nr_bound_keys) {
|
||||
wlr_keyboard_set_repeat_info(device->keyboard,
|
||||
wlr_keyboard_set_repeat_info(keyboard,
|
||||
rc.repeat_rate, rc.repeat_delay);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t modifiers =
|
||||
wlr_keyboard_get_modifiers(device->keyboard);
|
||||
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
|
||||
|
||||
/* Catch C-A-F1 to C-A-F12 to change tty */
|
||||
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
|
|
@ -137,7 +137,6 @@ handle_compositor_keybindings(struct wl_listener *listener,
|
|||
}
|
||||
|
||||
if (server->cycle_view) {
|
||||
damage_all_outputs(server);
|
||||
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
for (int i = 0; i < nsyms; i++) {
|
||||
if (syms[i] == XKB_KEY_Escape) {
|
||||
|
|
@ -188,7 +187,7 @@ keyboard_key_notify(struct wl_listener *listener, void *data)
|
|||
struct server *server = seat->server;
|
||||
struct wlr_event_keyboard_key *event = data;
|
||||
struct wlr_seat *wlr_seat = server->seat.seat;
|
||||
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
||||
struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard;
|
||||
wlr_idle_notify_activity(seat->wlr_idle, seat->seat);
|
||||
|
||||
bool handled = false;
|
||||
|
|
@ -199,7 +198,7 @@ keyboard_key_notify(struct wl_listener *listener, void *data)
|
|||
}
|
||||
|
||||
if (!handled) {
|
||||
wlr_seat_set_keyboard(wlr_seat, device);
|
||||
wlr_seat_set_keyboard(wlr_seat, &keyboard->base);
|
||||
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
||||
event->keycode, event->state);
|
||||
}
|
||||
|
|
|
|||
534
src/layers.c
534
src/layers.c
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* layers.c - layer-shell implementation
|
||||
*
|
||||
* Based on:
|
||||
* Based on
|
||||
* - https://git.sr.ht/~sircmpwm/wio
|
||||
* - https://github.com/swaywm/sway
|
||||
* Copyright (C) 2019 Drew DeVault and Sway developers
|
||||
|
|
@ -16,208 +16,54 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include "layers.h"
|
||||
#include "labwc.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 anchors;
|
||||
int *positive_axis;
|
||||
int *negative_axis;
|
||||
int margin;
|
||||
} edges[] = {
|
||||
{
|
||||
.anchors =
|
||||
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,
|
||||
},
|
||||
{
|
||||
.anchors =
|
||||
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,
|
||||
},
|
||||
{
|
||||
.anchors =
|
||||
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,
|
||||
},
|
||||
{
|
||||
.anchors =
|
||||
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].anchors) == edges[i].anchors) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @list: struct lab_layer_surface
|
||||
*/
|
||||
static void
|
||||
arrange_layer(struct wlr_output *output, struct wl_list *list,
|
||||
struct wlr_box *usable_area, bool exclusive)
|
||||
{
|
||||
struct lab_layer_surface *surface;
|
||||
struct wlr_box full_area = { 0 };
|
||||
wlr_output_effective_resolution(output, &full_area.width,
|
||||
&full_area.height);
|
||||
wl_list_for_each_reverse(surface, list, link) {
|
||||
struct wlr_layer_surface_v1 *layer = surface->layer_surface;
|
||||
struct wlr_layer_surface_v1_state *state = &layer->current;
|
||||
if (exclusive != (state->exclusive_zone > 0)) {
|
||||
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 ((state->anchor & both_horiz) && box.width == 0) {
|
||||
box.x = bounds.x;
|
||||
box.width = bounds.width;
|
||||
} 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 ((state->anchor & both_vert) && box.height == 0) {
|
||||
box.y = bounds.y;
|
||||
box.height = bounds.height;
|
||||
} 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 ((state->anchor & both_horiz) == both_horiz) {
|
||||
box.x += state->margin.left;
|
||||
box.width -= state->margin.left + state->margin.right;
|
||||
} 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 ((state->anchor & both_vert) == both_vert) {
|
||||
box.y += state->margin.top;
|
||||
box.height -= state->margin.top + state->margin.bottom;
|
||||
} 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 (box.width < 0 || box.height < 0) {
|
||||
wlr_log(WLR_ERROR, "surface has no positive size");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Apply */
|
||||
surface->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);
|
||||
}
|
||||
}
|
||||
#include "node.h"
|
||||
|
||||
void
|
||||
arrange_layers(struct output *output)
|
||||
layers_arrange(struct output *output)
|
||||
{
|
||||
assert(output);
|
||||
|
||||
struct wlr_box usable_area = { 0 };
|
||||
struct wlr_box full_area = { 0 };
|
||||
wlr_output_effective_resolution(output->wlr_output,
|
||||
&usable_area.width, &usable_area.height);
|
||||
&full_area.width, &full_area.height);
|
||||
struct wlr_box usable_area = full_area;
|
||||
|
||||
struct server *server = output->server;
|
||||
struct wlr_scene_output *scene_output =
|
||||
wlr_scene_get_scene_output(server->scene, output->wlr_output);
|
||||
if (!scene_output) {
|
||||
wlr_log(WLR_DEBUG, "no wlr_scene_output");
|
||||
return;
|
||||
}
|
||||
|
||||
int nr_layers = sizeof(output->layers) / sizeof(output->layers[0]);
|
||||
for (int i = 0; i < nr_layers; i++) {
|
||||
struct lab_layer_surface *lab_layer_surface;
|
||||
wl_list_for_each(lab_layer_surface, &output->layers[i], link) {
|
||||
struct wlr_scene_layer_surface_v1 *scene_layer_surface =
|
||||
lab_layer_surface->scene_layer_surface;
|
||||
wlr_scene_layer_surface_v1_configure(
|
||||
scene_layer_surface, &full_area, &usable_area);
|
||||
}
|
||||
|
||||
wlr_scene_node_set_position(&output->layer_tree[i]->node,
|
||||
scene_output->x, scene_output->y);
|
||||
}
|
||||
|
||||
/* Exclusive surfaces */
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&usable_area, true);
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&usable_area, true);
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
&usable_area, true);
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
&usable_area, true);
|
||||
memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
|
||||
|
||||
/* TODO: re-arrange all views taking into account updated usable_area */
|
||||
|
||||
/* Non-exclusive surfaces */
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&usable_area, false);
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&usable_area, false);
|
||||
arrange_layer(output->wlr_output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
&usable_area, false);
|
||||
arrange_layer(output->wlr_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]);
|
||||
size_t nlayers = sizeof(layers_above_shell)
|
||||
/ sizeof(layers_above_shell[0]);
|
||||
struct lab_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) {
|
||||
struct wlr_layer_surface_v1 *layer_surface =
|
||||
layer->scene_layer_surface->layer_surface;
|
||||
if (layer_surface->current.keyboard_interactive) {
|
||||
topmost = layer;
|
||||
break;
|
||||
}
|
||||
|
|
@ -228,11 +74,13 @@ arrange_layers(struct output *output)
|
|||
}
|
||||
struct seat *seat = &output->server->seat;
|
||||
if (topmost) {
|
||||
seat_set_focus_layer(seat, topmost->layer_surface);
|
||||
seat_set_focus_layer(seat,
|
||||
topmost->scene_layer_surface->layer_surface);
|
||||
} else if (seat->focused_layer &&
|
||||
!seat->focused_layer->current.keyboard_interactive) {
|
||||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
/* FIXME: should we call a desktop_arrange_all_views() here? */
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -240,9 +88,8 @@ output_destroy_notify(struct wl_listener *listener, void *data)
|
|||
{
|
||||
struct lab_layer_surface *layer =
|
||||
wl_container_of(listener, layer, output_destroy);
|
||||
layer->layer_surface->output = NULL;
|
||||
wl_list_remove(&layer->output_destroy.link);
|
||||
wlr_layer_surface_v1_destroy(layer->layer_surface);
|
||||
wlr_layer_surface_v1_destroy(layer->scene_layer_surface->layer_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -250,8 +97,10 @@ surface_commit_notify(struct wl_listener *listener, void *data)
|
|||
{
|
||||
struct lab_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->layer_surface->output;
|
||||
struct wlr_layer_surface_v1 *layer_surface =
|
||||
layer->scene_layer_surface->layer_surface;
|
||||
struct wlr_output *wlr_output =
|
||||
layer->scene_layer_surface->layer_surface->output;
|
||||
|
||||
if (!wlr_output) {
|
||||
return;
|
||||
|
|
@ -262,19 +111,17 @@ surface_commit_notify(struct wl_listener *listener, void *data)
|
|||
layer->mapped = layer_surface->mapped;
|
||||
struct output *output =
|
||||
output_from_wlr_output(layer->server, wlr_output);
|
||||
arrange_layers(output);
|
||||
layers_arrange(output);
|
||||
}
|
||||
damage_all_outputs(layer->server);
|
||||
}
|
||||
|
||||
static void
|
||||
unmap(struct lab_layer_surface *layer)
|
||||
{
|
||||
struct seat *seat = &layer->server->seat;
|
||||
if (seat->focused_layer == layer->layer_surface) {
|
||||
if (seat->focused_layer == layer->scene_layer_surface->layer_surface) {
|
||||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
damage_all_outputs(layer->server);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -282,18 +129,20 @@ destroy_notify(struct wl_listener *listener, void *data)
|
|||
{
|
||||
struct lab_layer_surface *layer = wl_container_of(
|
||||
listener, layer, destroy);
|
||||
if (layer->layer_surface->mapped) {
|
||||
if (layer->scene_layer_surface->layer_surface->mapped) {
|
||||
unmap(layer);
|
||||
}
|
||||
|
||||
wl_list_remove(&layer->link);
|
||||
wl_list_remove(&layer->destroy.link);
|
||||
wl_list_remove(&layer->map.link);
|
||||
wl_list_remove(&layer->unmap.link);
|
||||
wl_list_remove(&layer->surface_commit.link);
|
||||
if (layer->layer_surface->output) {
|
||||
if (layer->scene_layer_surface->layer_surface->output) {
|
||||
wl_list_remove(&layer->output_destroy.link);
|
||||
struct output *output = output_from_wlr_output(
|
||||
layer->server, layer->layer_surface->output);
|
||||
arrange_layers(output);
|
||||
struct output *output = output_from_wlr_output(layer->server,
|
||||
layer->scene_layer_surface->layer_surface->output);
|
||||
layers_arrange(output);
|
||||
}
|
||||
free(layer);
|
||||
}
|
||||
|
|
@ -301,150 +150,18 @@ destroy_notify(struct wl_listener *listener, void *data)
|
|||
static void
|
||||
unmap_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_surface *l = wl_container_of(listener, l, unmap);
|
||||
unmap(l);
|
||||
return;
|
||||
struct lab_layer_surface *lab_layer_surface =
|
||||
wl_container_of(listener, lab_layer_surface, unmap);
|
||||
unmap(lab_layer_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
map_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct wlr_layer_surface_v1 *l = data;
|
||||
wlr_surface_send_enter(l->surface, l->output);
|
||||
}
|
||||
|
||||
static void
|
||||
subsurface_damage(struct lab_layer_subsurface *subsurface, bool whole)
|
||||
{
|
||||
struct lab_layer_surface *layer = subsurface->layer_surface;
|
||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||
if (!wlr_output) {
|
||||
return;
|
||||
}
|
||||
// struct 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;
|
||||
damage_all_outputs(layer->server);
|
||||
}
|
||||
|
||||
static void
|
||||
subsurface_handle_unmap(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_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 lab_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 lab_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, commit);
|
||||
subsurface_damage(subsurface, false);
|
||||
}
|
||||
|
||||
static void
|
||||
subsurface_handle_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, destroy);
|
||||
|
||||
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 struct
|
||||
lab_layer_subsurface *create_subsurface(struct wlr_subsurface *wlr_subsurface,
|
||||
struct lab_layer_surface *layer_surface)
|
||||
{
|
||||
struct lab_layer_subsurface *subsurface =
|
||||
calloc(1, sizeof(struct lab_layer_subsurface));
|
||||
if (!subsurface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subsurface->wlr_subsurface = wlr_subsurface;
|
||||
subsurface->layer_surface = layer_surface;
|
||||
|
||||
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
|
||||
new_subsurface_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_surface *lab_layer_surface =
|
||||
wl_container_of(listener, lab_layer_surface, new_subsurface);
|
||||
struct wlr_subsurface *wlr_subsurface = data;
|
||||
create_subsurface(wlr_subsurface, lab_layer_surface);
|
||||
}
|
||||
|
||||
|
||||
static struct
|
||||
lab_layer_surface *popup_get_layer(struct lab_layer_popup *popup)
|
||||
{
|
||||
while (popup->parent_type == LAYER_PARENT_POPUP) {
|
||||
popup = popup->parent_popup;
|
||||
}
|
||||
return popup->parent_layer;
|
||||
}
|
||||
|
||||
static void
|
||||
popup_damage(struct lab_layer_popup *layer_popup, bool whole)
|
||||
{
|
||||
struct lab_layer_surface *layer;
|
||||
while (true) {
|
||||
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
|
||||
layer_popup = layer_popup->parent_popup;
|
||||
} else {
|
||||
layer = layer_popup->parent_layer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
damage_all_outputs(layer->server);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_map(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_popup *popup = wl_container_of(listener, popup, map);
|
||||
struct lab_layer_surface *layer = popup_get_layer(popup);
|
||||
struct wlr_output *wlr_output = layer->layer_surface->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 lab_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 lab_layer_popup *popup = wl_container_of(listener, popup, commit);
|
||||
popup_damage(popup, false);
|
||||
return;
|
||||
struct wlr_layer_surface_v1 *layer_surface = data;
|
||||
wlr_surface_send_enter(layer_surface->surface, layer_surface->output);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -452,40 +169,16 @@ popup_handle_destroy(struct wl_listener *listener, void *data)
|
|||
{
|
||||
struct lab_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 lab_layer_popup *popup)
|
||||
{
|
||||
struct lab_layer_surface *layer = popup_get_layer(popup);
|
||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
|
||||
struct output *output = layer->layer_surface->output->data;
|
||||
|
||||
struct wlr_box output_box = { 0 };
|
||||
wlr_output_effective_resolution(output->wlr_output, &output_box.width,
|
||||
&output_box.height);
|
||||
|
||||
struct wlr_box output_toplevel_sx_box = {
|
||||
.x = -layer->geo.x,
|
||||
.y = -layer->geo.y,
|
||||
.width = output_box.width,
|
||||
.height = output_box.height,
|
||||
};
|
||||
|
||||
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
|
||||
}
|
||||
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||
|
||||
static struct lab_layer_popup *
|
||||
create_popup(struct wlr_xdg_popup *wlr_popup,
|
||||
enum layer_parent parent_type, void *parent)
|
||||
create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_node *parent,
|
||||
struct wlr_box *output_toplevel_sx_box)
|
||||
{
|
||||
struct lab_layer_popup *popup =
|
||||
calloc(1, sizeof(struct lab_layer_popup));
|
||||
|
|
@ -494,41 +187,98 @@ create_popup(struct wlr_xdg_popup *wlr_popup,
|
|||
}
|
||||
|
||||
popup->wlr_popup = wlr_popup;
|
||||
popup->parent_type = parent_type;
|
||||
popup->parent_layer = parent;
|
||||
popup->scene_node =
|
||||
wlr_scene_xdg_surface_create(parent, wlr_popup->base);
|
||||
if (!popup->scene_node) {
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
node_descriptor_create(popup->scene_node,
|
||||
LAB_NODE_DESC_LAYER_POPUP, popup);
|
||||
|
||||
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);
|
||||
|
||||
popup_unconstrain(popup);
|
||||
|
||||
wlr_xdg_popup_unconstrain_from_box(wlr_popup, output_toplevel_sx_box);
|
||||
return popup;
|
||||
}
|
||||
|
||||
/* This popup's parent is a layer popup */
|
||||
static void
|
||||
popup_handle_new_popup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_popup *lab_layer_popup =
|
||||
wl_container_of(listener, lab_layer_popup, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
create_popup(wlr_popup, LAYER_PARENT_POPUP, lab_layer_popup);
|
||||
struct lab_layer_popup *new_popup = create_popup(wlr_popup,
|
||||
lab_layer_popup->scene_node,
|
||||
&lab_layer_popup->output_toplevel_sx_box);
|
||||
new_popup->output_toplevel_sx_box =
|
||||
lab_layer_popup->output_toplevel_sx_box;
|
||||
}
|
||||
|
||||
/*
|
||||
* We move popups from the bottom to the top layer so that they are
|
||||
* rendered above views.
|
||||
*/
|
||||
static void
|
||||
move_popup_to_top_layer(struct lab_layer_surface *toplevel,
|
||||
struct lab_layer_popup *popup)
|
||||
{
|
||||
struct server *server = toplevel->server;
|
||||
struct wlr_output *wlr_output =
|
||||
toplevel->scene_layer_surface->layer_surface->output;
|
||||
struct output *output = output_from_wlr_output(server, wlr_output);
|
||||
struct wlr_box box = { 0 };
|
||||
wlr_output_layout_get_box(server->output_layout, wlr_output, &box);
|
||||
int lx = toplevel->scene_layer_surface->node->state.x + box.x;
|
||||
int ly = toplevel->scene_layer_surface->node->state.y + box.y;
|
||||
|
||||
struct wlr_scene_node *node = popup->scene_node;
|
||||
wlr_scene_node_reparent(node, &output->layer_popup_tree->node);
|
||||
wlr_scene_node_set_position(&output->layer_popup_tree->node, lx, ly);
|
||||
}
|
||||
|
||||
/* This popup's parent is a shell-layer surface */
|
||||
static void
|
||||
new_popup_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_surface *lab_layer_surface =
|
||||
wl_container_of(listener, lab_layer_surface, new_popup);
|
||||
struct lab_layer_surface *toplevel =
|
||||
wl_container_of(listener, toplevel, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
create_popup(wlr_popup, LAYER_PARENT_LAYER, lab_layer_surface);
|
||||
struct output *output =
|
||||
toplevel->scene_layer_surface->layer_surface->output->data;
|
||||
|
||||
struct wlr_box output_box = { 0 };
|
||||
wlr_output_layout_get_box(output->server->output_layout,
|
||||
output->wlr_output, &output_box);
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(toplevel->scene_layer_surface->node, &lx, &ly);
|
||||
|
||||
/*
|
||||
* Output geometry expressed in the coordinate system of the toplevel
|
||||
* parent of popup. We store this struct the lab_layer_popup struct
|
||||
* to make it easier to unconstrain children when we move popups from
|
||||
* the bottom to the top layer.
|
||||
*/
|
||||
struct wlr_box output_toplevel_sx_box = {
|
||||
.x = output_box.x - lx,
|
||||
.y = output_box.y - ly,
|
||||
.width = output_box.width,
|
||||
.height = output_box.height,
|
||||
};
|
||||
struct lab_layer_popup *popup = create_popup(wlr_popup,
|
||||
toplevel->scene_layer_surface->node,
|
||||
&output_toplevel_sx_box);
|
||||
popup->output_toplevel_sx_box = output_toplevel_sx_box;
|
||||
|
||||
if (toplevel->scene_layer_surface->layer_surface->current.layer
|
||||
== ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
|
||||
move_popup_to_top_layer(toplevel, popup);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -567,15 +317,19 @@ new_layer_surface_notify(struct wl_listener *listener, void *data)
|
|||
surface->new_popup.notify = new_popup_notify;
|
||||
wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
|
||||
|
||||
surface->new_subsurface.notify = new_subsurface_notify;
|
||||
wl_signal_add(&layer_surface->surface->events.new_subsurface,
|
||||
&surface->new_subsurface);
|
||||
|
||||
surface->layer_surface = layer_surface;
|
||||
layer_surface->data = surface;
|
||||
surface->server = server;
|
||||
|
||||
struct output *output = layer_surface->output->data;
|
||||
|
||||
struct wlr_scene_tree *selected_layer =
|
||||
output->layer_tree[layer_surface->current.layer];
|
||||
|
||||
surface->scene_layer_surface = wlr_scene_layer_surface_v1_create(
|
||||
&selected_layer->node, layer_surface);
|
||||
node_descriptor_create(surface->scene_layer_surface->node,
|
||||
LAB_NODE_DESC_LAYER_SURFACE, surface);
|
||||
|
||||
surface->server = server;
|
||||
surface->scene_layer_surface->layer_surface = layer_surface;
|
||||
|
||||
surface->output_destroy.notify = output_destroy_notify;
|
||||
wl_signal_add(&layer_surface->output->events.destroy,
|
||||
&surface->output_destroy);
|
||||
|
|
@ -593,7 +347,7 @@ new_layer_surface_notify(struct wl_listener *listener, void *data)
|
|||
*/
|
||||
struct wlr_layer_surface_v1_state old_state = layer_surface->current;
|
||||
layer_surface->current = layer_surface->pending;
|
||||
arrange_layers(output);
|
||||
layers_arrange(output);
|
||||
layer_surface->current = old_state;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ main(int argc, char *argv[])
|
|||
server_start(&server);
|
||||
|
||||
struct theme theme = { 0 };
|
||||
theme_init(&theme, server.renderer, rc.theme_name);
|
||||
theme_init(&theme, rc.theme_name);
|
||||
server.theme = &theme;
|
||||
|
||||
menu_init_rootmenu(&server);
|
||||
|
|
|
|||
341
src/menu/menu.c
341
src/menu/menu.c
|
|
@ -19,6 +19,8 @@
|
|||
#include "menu/menu.h"
|
||||
#include "theme.h"
|
||||
#include "action.h"
|
||||
#include "buffer.h"
|
||||
#include "node.h"
|
||||
|
||||
#define MENUWIDTH (110)
|
||||
#define MENU_ITEM_PADDING_Y (4)
|
||||
|
|
@ -51,12 +53,19 @@ menu_create(struct server *server, const char *id, const char *label)
|
|||
menu->label = strdup(label);
|
||||
menu->parent = current_menu;
|
||||
menu->server = server;
|
||||
menu->size.width = MENUWIDTH;
|
||||
/* menu->size.height will be kept up to date by adding items */
|
||||
menu->scene_tree = wlr_scene_tree_create(&server->menu_tree->node);
|
||||
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
|
||||
return menu;
|
||||
}
|
||||
|
||||
static struct menu *
|
||||
get_menu_by_id(const char *id)
|
||||
struct menu *
|
||||
menu_get_by_id(const char *id)
|
||||
{
|
||||
if (!id) {
|
||||
return NULL;
|
||||
}
|
||||
struct menu *menu;
|
||||
for (int i = 0; i < nr_menus; ++i) {
|
||||
menu = menus + i;
|
||||
|
|
@ -74,6 +83,7 @@ item_create(struct menu *menu, const char *text)
|
|||
if (!menuitem) {
|
||||
return NULL;
|
||||
}
|
||||
menuitem->parent = menu;
|
||||
struct server *server = menu->server;
|
||||
struct theme *theme = server->theme;
|
||||
struct font font = {
|
||||
|
|
@ -81,19 +91,57 @@ item_create(struct menu *menu, const char *text)
|
|||
.size = rc.font_size_menuitem,
|
||||
};
|
||||
|
||||
menuitem->box.width = MENUWIDTH;
|
||||
menuitem->box.height = font_height(&font) + 2 * MENU_ITEM_PADDING_Y;
|
||||
if (!menu->item_height) {
|
||||
menu->item_height = font_height(&font) + 2 * MENU_ITEM_PADDING_Y;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
int item_max_width = MENUWIDTH - 2 * MENU_ITEM_PADDING_X;
|
||||
font_texture_create(server, &menuitem->texture.active, item_max_width,
|
||||
text, &font, theme->menu_items_active_text_color);
|
||||
font_texture_create(server, &menuitem->texture.inactive, item_max_width,
|
||||
text, &font, theme->menu_items_text_color);
|
||||
struct wlr_scene_node *parent = &menu->scene_tree->node;
|
||||
|
||||
/* center align vertically */
|
||||
menuitem->texture.offset_y =
|
||||
(menuitem->box.height - menuitem->texture.active->height) / 2;
|
||||
menuitem->texture.offset_x = MENU_ITEM_PADDING_X;
|
||||
/* Font buffer */
|
||||
font_buffer_create(&menuitem->normal.buffer, item_max_width,
|
||||
text, &font, theme->menu_items_text_color);
|
||||
font_buffer_create(&menuitem->selected.buffer, item_max_width,
|
||||
text, &font, theme->menu_items_active_text_color);
|
||||
|
||||
/* Item background nodes */
|
||||
menuitem->normal.background = &wlr_scene_rect_create(parent,
|
||||
MENUWIDTH, menu->item_height,
|
||||
theme->menu_items_bg_color)->node;
|
||||
menuitem->selected.background = &wlr_scene_rect_create(parent,
|
||||
MENUWIDTH, menu->item_height,
|
||||
theme->menu_items_active_bg_color)->node;
|
||||
|
||||
/* Font nodes */
|
||||
menuitem->normal.text = &wlr_scene_buffer_create(
|
||||
menuitem->normal.background, &menuitem->normal.buffer->base)->node;
|
||||
menuitem->selected.text = &wlr_scene_buffer_create(
|
||||
menuitem->selected.background, &menuitem->selected.buffer->base)->node;
|
||||
|
||||
/* Node descriptors for top scene nodes of menuitem */
|
||||
node_descriptor_create(menuitem->normal.background,
|
||||
LAB_NODE_DESC_MENUITEM, menuitem);
|
||||
node_descriptor_create(menuitem->selected.background,
|
||||
LAB_NODE_DESC_MENUITEM, menuitem);
|
||||
|
||||
/* Center font nodes */
|
||||
y = (menu->item_height - menuitem->normal.buffer->base.height) / 2;
|
||||
x = MENU_ITEM_PADDING_X;
|
||||
wlr_scene_node_set_position(menuitem->normal.text, x, y);
|
||||
wlr_scene_node_set_position(menuitem->selected.text, x, y);
|
||||
|
||||
/* Position the item in relation to its menu */
|
||||
int item_count = wl_list_length(&menu->menuitems);
|
||||
y = item_count * menu->item_height;
|
||||
wlr_scene_node_set_position(menuitem->normal.background, 0, y);
|
||||
wlr_scene_node_set_position(menuitem->selected.background, 0, y);
|
||||
|
||||
/* Hide selected state */
|
||||
wlr_scene_node_set_enabled(menuitem->selected.background, false);
|
||||
|
||||
/* Update menu extents */
|
||||
menu->size.height = (item_count + 1) * menu->item_height;
|
||||
|
||||
wl_list_insert(&menu->menuitems, &menuitem->link);
|
||||
wl_list_init(&menuitem->actions);
|
||||
|
|
@ -204,7 +252,7 @@ handle_menu_element(xmlNode *n, struct server *server)
|
|||
current_menu = current_menu->parent;
|
||||
--menu_level;
|
||||
} else if (id) {
|
||||
struct menu *menu = get_menu_by_id(id);
|
||||
struct menu *menu = menu_get_by_id(id);
|
||||
if (menu) {
|
||||
current_item = item_create(current_menu, menu->label);
|
||||
current_item->submenu = menu;
|
||||
|
|
@ -280,78 +328,127 @@ err:
|
|||
free(b.buf);
|
||||
}
|
||||
|
||||
static int
|
||||
menu_get_full_width(struct menu *menu)
|
||||
{
|
||||
int width = menu->size.width - menu->server->theme->menu_overlap_x;
|
||||
int child_width;
|
||||
int max_child_width = 0;
|
||||
struct menuitem *item;
|
||||
wl_list_for_each_reverse(item, &menu->menuitems, link) {
|
||||
if (!item->submenu) {
|
||||
continue;
|
||||
}
|
||||
child_width = menu_get_full_width(item->submenu);
|
||||
if (child_width > max_child_width) {
|
||||
max_child_width = child_width;
|
||||
}
|
||||
}
|
||||
return width + max_child_width;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_configure(struct menu *menu, int x, int y)
|
||||
menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
|
||||
{
|
||||
struct theme *theme = menu->server->theme;
|
||||
|
||||
menu->box.x = x;
|
||||
menu->box.y = y;
|
||||
/* Get output local coordinates + output usable area */
|
||||
double ox = lx;
|
||||
double oy = ly;
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
menu->server->output_layout, lx, ly);
|
||||
wlr_output_layout_output_coords(menu->server->output_layout,
|
||||
wlr_output, &ox, &oy);
|
||||
struct wlr_box usable = output_usable_area_from_cursor_coords(menu->server);
|
||||
|
||||
int offset = 0;
|
||||
struct menuitem *menuitem;
|
||||
wl_list_for_each_reverse (menuitem, &menu->menuitems, link) {
|
||||
menuitem->box.x = menu->box.x;
|
||||
menuitem->box.y = menu->box.y + offset;
|
||||
offset += menuitem->box.height;
|
||||
if (menuitem->submenu) {
|
||||
menu_configure(menuitem->submenu, menuitem->box.x
|
||||
+ MENUWIDTH - theme->menu_overlap_x,
|
||||
menuitem->box.y + theme->menu_overlap_y);
|
||||
if (align == LAB_MENU_OPEN_AUTO) {
|
||||
int full_width = menu_get_full_width(menu);
|
||||
if (ox + full_width > usable.width) {
|
||||
align = LAB_MENU_OPEN_LEFT;
|
||||
} else {
|
||||
align = LAB_MENU_OPEN_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
menu->box.width = MENUWIDTH;
|
||||
menu->box.height = offset;
|
||||
if (oy + menu->size.height > usable.height) {
|
||||
align &= ~LAB_MENU_OPEN_BOTTOM;
|
||||
align |= LAB_MENU_OPEN_TOP;
|
||||
} else {
|
||||
align &= ~LAB_MENU_OPEN_TOP;
|
||||
align |= LAB_MENU_OPEN_BOTTOM;
|
||||
}
|
||||
|
||||
if (align & LAB_MENU_OPEN_LEFT) {
|
||||
lx -= MENUWIDTH - theme->menu_overlap_x;
|
||||
}
|
||||
if (align & LAB_MENU_OPEN_TOP) {
|
||||
ly -= menu->size.height;
|
||||
if (menu->parent) {
|
||||
/* For submenus adjust y to bottom left corner */
|
||||
ly += menu->item_height;
|
||||
}
|
||||
}
|
||||
wlr_scene_node_set_position(&menu->scene_tree->node, lx, ly);
|
||||
|
||||
int rel_y;
|
||||
int new_lx, new_ly;
|
||||
struct menuitem *item;
|
||||
wl_list_for_each_reverse(item, &menu->menuitems, link) {
|
||||
if (!item->submenu) {
|
||||
continue;
|
||||
}
|
||||
if (align & LAB_MENU_OPEN_RIGHT) {
|
||||
new_lx = lx + MENUWIDTH - theme->menu_overlap_x;
|
||||
} else {
|
||||
new_lx = lx;
|
||||
}
|
||||
rel_y = item->normal.background->state.y;
|
||||
new_ly = ly + rel_y - theme->menu_overlap_y;
|
||||
menu_configure(item->submenu, new_lx, new_ly, align);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
menu_init_rootmenu(struct server *server)
|
||||
{
|
||||
parse_xml("menu.xml", server);
|
||||
server->rootmenu = get_menu_by_id("root-menu");
|
||||
struct menu *menu = menu_get_by_id("root-menu");
|
||||
|
||||
/* Default menu if no menu.xml found */
|
||||
if (!server->rootmenu) {
|
||||
if (!menu) {
|
||||
current_menu = NULL;
|
||||
server->rootmenu = menu_create(server, "root-menu", "");
|
||||
menu = menu_create(server, "root-menu", "");
|
||||
}
|
||||
if (wl_list_empty(&server->rootmenu->menuitems)) {
|
||||
current_item = item_create(server->rootmenu, "Reconfigure");
|
||||
if (wl_list_empty(&menu->menuitems)) {
|
||||
current_item = item_create(menu, "Reconfigure");
|
||||
fill_item("name.action", "Reconfigure");
|
||||
current_item = item_create(server->rootmenu, "Exit");
|
||||
current_item = item_create(menu, "Exit");
|
||||
fill_item("name.action", "Exit");
|
||||
}
|
||||
|
||||
server->rootmenu->visible = true;
|
||||
menu_configure(server->rootmenu, 100, 100);
|
||||
}
|
||||
|
||||
void
|
||||
menu_init_windowmenu(struct server *server)
|
||||
{
|
||||
server->windowmenu = get_menu_by_id("client-menu");
|
||||
struct menu *menu = menu_get_by_id("client-menu");
|
||||
|
||||
/* Default menu if no menu.xml found */
|
||||
if (!server->windowmenu) {
|
||||
if (!menu) {
|
||||
current_menu = NULL;
|
||||
server->windowmenu = menu_create(server, "client-menu", "");
|
||||
menu = menu_create(server, "client-menu", "");
|
||||
}
|
||||
if (wl_list_empty(&server->windowmenu->menuitems)) {
|
||||
current_item = item_create(server->windowmenu, "Minimize");
|
||||
if (wl_list_empty(&menu->menuitems)) {
|
||||
current_item = item_create(menu, "Minimize");
|
||||
fill_item("name.action", "Iconify");
|
||||
current_item = item_create(server->windowmenu, "Maximize");
|
||||
current_item = item_create(menu, "Maximize");
|
||||
fill_item("name.action", "ToggleMaximize");
|
||||
current_item = item_create(server->windowmenu, "Fullscreen");
|
||||
current_item = item_create(menu, "Fullscreen");
|
||||
fill_item("name.action", "ToggleFullscreen");
|
||||
current_item = item_create(server->windowmenu, "Decorations");
|
||||
current_item = item_create(menu, "Decorations");
|
||||
fill_item("name.action", "ToggleDecorations");
|
||||
current_item = item_create(server->windowmenu, "Close");
|
||||
current_item = item_create(menu, "Close");
|
||||
fill_item("name.action", "Close");
|
||||
}
|
||||
|
||||
server->windowmenu->visible = true;
|
||||
menu_configure(server->windowmenu, 100, 100);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -364,104 +461,130 @@ menu_finish(void)
|
|||
wl_list_for_each_safe(item, next, &menu->menuitems, link) {
|
||||
wl_list_remove(&item->link);
|
||||
action_list_free(&item->actions);
|
||||
wlr_scene_node_destroy(item->normal.text);
|
||||
wlr_scene_node_destroy(item->selected.text);
|
||||
wlr_scene_node_destroy(item->normal.background);
|
||||
wlr_scene_node_destroy(item->selected.background);
|
||||
wlr_buffer_drop(&item->normal.buffer->base);
|
||||
wlr_buffer_drop(&item->selected.buffer->base);
|
||||
free(item);
|
||||
}
|
||||
wlr_scene_node_destroy(&menu->scene_tree->node);
|
||||
}
|
||||
zfree(menus);
|
||||
alloc_menus = 0;
|
||||
nr_menus = 0;
|
||||
}
|
||||
|
||||
/* Sets selection (or clears selection if passing NULL) */
|
||||
static void
|
||||
menu_set_selection(struct menu *menu, struct menuitem *item)
|
||||
{
|
||||
/* Clear old selection */
|
||||
if (menu->selection.item) {
|
||||
wlr_scene_node_set_enabled(
|
||||
menu->selection.item->normal.background, true);
|
||||
wlr_scene_node_set_enabled(
|
||||
menu->selection.item->selected.background, false);
|
||||
}
|
||||
/* Set new selection */
|
||||
if (item) {
|
||||
wlr_scene_node_set_enabled(item->normal.background, false);
|
||||
wlr_scene_node_set_enabled(item->selected.background, true);
|
||||
}
|
||||
menu->selection.item = item;
|
||||
}
|
||||
|
||||
static void
|
||||
close_all_submenus(struct menu *menu)
|
||||
{
|
||||
struct menuitem *item;
|
||||
wl_list_for_each (item, &menu->menuitems, link) {
|
||||
if (item->submenu) {
|
||||
item->submenu->visible = false;
|
||||
wlr_scene_node_set_enabled(&item->submenu->scene_tree->node, false);
|
||||
close_all_submenus(item->submenu);
|
||||
}
|
||||
}
|
||||
menu->selection.menu = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
menu_move(struct menu *menu, int x, int y)
|
||||
menu_open(struct menu *menu, int x, int y)
|
||||
{
|
||||
assert(menu);
|
||||
if (menu->server->menu_current) {
|
||||
menu_close(menu->server->menu_current);
|
||||
}
|
||||
close_all_submenus(menu);
|
||||
menu_configure(menu, x, y);
|
||||
menu_set_selection(menu, NULL);
|
||||
menu_configure(menu, x, y, LAB_MENU_OPEN_AUTO);
|
||||
wlr_scene_node_set_enabled(&menu->scene_tree->node, true);
|
||||
menu->server->menu_current = menu;
|
||||
menu->server->input_mode = LAB_INPUT_STATE_MENU;
|
||||
}
|
||||
|
||||
/* TODO: consider renaming function to menu_process_cursor_motion */
|
||||
void
|
||||
menu_set_selected(struct menu *menu, int x, int y)
|
||||
menu_process_cursor_motion(struct wlr_scene_node *node)
|
||||
{
|
||||
if (!menu->visible) {
|
||||
assert(node && node->data);
|
||||
struct menuitem *item = node_menuitem_from_node(node);
|
||||
|
||||
if (node == item->selected.background) {
|
||||
/* We are on an already selected item */
|
||||
return;
|
||||
}
|
||||
|
||||
struct menuitem *item;
|
||||
wl_list_for_each (item, &menu->menuitems, link) {
|
||||
item->selected = wlr_box_contains_point(&item->box, x, y);
|
||||
|
||||
if (!item->selected) {
|
||||
if (item->submenu && item->submenu->visible) {
|
||||
/*
|
||||
* Handle the case where a submenu is already
|
||||
* open.
|
||||
*/
|
||||
item->selected = true;
|
||||
menu_set_selected(item->submenu, x, y);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're now on an item that has mouse-focus */
|
||||
if (item->submenu) {
|
||||
if (item->submenu->visible) {
|
||||
/* do nothing - submenu already open */
|
||||
} else {
|
||||
/* open submenu */
|
||||
close_all_submenus(menu);
|
||||
item->submenu->visible = true;
|
||||
menu_set_selected(item->submenu, x, y);
|
||||
}
|
||||
} else {
|
||||
close_all_submenus(menu);
|
||||
}
|
||||
/* We are on an item that has new mouse-focus */
|
||||
menu_set_selection(item->parent, item);
|
||||
if (item->parent->selection.menu) {
|
||||
/* Close old submenu tree */
|
||||
menu_close(item->parent->selection.menu);
|
||||
}
|
||||
|
||||
if (item->submenu) {
|
||||
/* And open the new one */
|
||||
wlr_scene_node_set_enabled(
|
||||
&item->submenu->scene_tree->node, true);
|
||||
}
|
||||
item->parent->selection.menu = item->submenu;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_clear_selection(struct menu *menu)
|
||||
|
||||
bool
|
||||
menu_call_actions(struct wlr_scene_node *node)
|
||||
{
|
||||
struct menuitem *item;
|
||||
wl_list_for_each (item, &menu->menuitems, link) {
|
||||
item->selected = false;
|
||||
if (item->submenu) {
|
||||
menu_clear_selection(item->submenu);
|
||||
}
|
||||
assert(node && node->data);
|
||||
struct menuitem *item = node_menuitem_from_node(node);
|
||||
|
||||
if (item->submenu) {
|
||||
/* We received a click on an item that just opens a submenu */
|
||||
return false;
|
||||
}
|
||||
|
||||
actions_run(NULL, item->parent->server, &item->actions, 0);
|
||||
menu_close(item->parent->server->menu_current);
|
||||
item->parent->server->menu_current = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
menu_close(struct menu *menu)
|
||||
{
|
||||
if (!menu) {
|
||||
wlr_log(WLR_ERROR, "Trying to close non exiting menu");
|
||||
return;
|
||||
}
|
||||
/* TODO: Maybe reset input state here instead of in cursor.c ? */
|
||||
wlr_scene_node_set_enabled(&menu->scene_tree->node, false);
|
||||
menu_set_selection(menu, NULL);
|
||||
if (menu->selection.menu) {
|
||||
menu_close(menu->selection.menu);
|
||||
menu->selection.menu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
menu_action_selected(struct server *server, struct menu *menu)
|
||||
{
|
||||
struct menuitem *menuitem;
|
||||
wl_list_for_each (menuitem, &menu->menuitems, link) {
|
||||
if (menuitem->selected && !menuitem->submenu) {
|
||||
action(NULL, server, &menuitem->actions, 0);
|
||||
break;
|
||||
}
|
||||
if (menuitem->submenu) {
|
||||
menu_action_selected(server, menuitem->submenu);
|
||||
}
|
||||
}
|
||||
menu_clear_selection(menu);
|
||||
}
|
||||
|
||||
void
|
||||
menu_reconfigure(struct server *server, struct menu *menu)
|
||||
menu_reconfigure(struct server *server)
|
||||
{
|
||||
menu_finish();
|
||||
menu_init_rootmenu(server);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
labwc_sources = files(
|
||||
'action.c',
|
||||
'buffer.c',
|
||||
'cursor.c',
|
||||
'damage.c',
|
||||
'debug.c',
|
||||
'desktop.c',
|
||||
'foreign.c',
|
||||
'interactive.c',
|
||||
|
|
@ -9,16 +10,14 @@ labwc_sources = files(
|
|||
'key-state.c',
|
||||
'layers.c',
|
||||
'main.c',
|
||||
'node.c',
|
||||
'osd.c',
|
||||
'output.c',
|
||||
'resistance.c',
|
||||
'seat.c',
|
||||
'server.c',
|
||||
'ssd.c',
|
||||
'subsurface.c',
|
||||
'theme.c',
|
||||
'view.c',
|
||||
'view-child.c',
|
||||
'view-impl.c',
|
||||
'xdg.c',
|
||||
'xdg-deco.c',
|
||||
|
|
@ -37,3 +36,4 @@ subdir('common')
|
|||
subdir('config')
|
||||
subdir('xbm')
|
||||
subdir('menu')
|
||||
subdir('ssd')
|
||||
|
|
|
|||
75
src/node.c
Normal file
75
src/node.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "node.h"
|
||||
|
||||
static void
|
||||
descriptor_destroy(struct node_descriptor *node_descriptor)
|
||||
{
|
||||
if (!node_descriptor) {
|
||||
return;
|
||||
}
|
||||
wl_list_remove(&node_descriptor->destroy.link);
|
||||
free(node_descriptor);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct node_descriptor *node_descriptor =
|
||||
wl_container_of(listener, node_descriptor, destroy);
|
||||
descriptor_destroy(node_descriptor);
|
||||
}
|
||||
|
||||
void
|
||||
node_descriptor_create(struct wlr_scene_node *scene_node,
|
||||
enum node_descriptor_type type, void *data)
|
||||
{
|
||||
struct node_descriptor *node_descriptor =
|
||||
calloc(1, sizeof(struct node_descriptor));
|
||||
if (!node_descriptor) {
|
||||
return;
|
||||
}
|
||||
node_descriptor->type = type;
|
||||
node_descriptor->data = data;
|
||||
node_descriptor->destroy.notify = destroy_notify;
|
||||
wl_signal_add(&scene_node->events.destroy, &node_descriptor->destroy);
|
||||
scene_node->data = node_descriptor;
|
||||
}
|
||||
|
||||
struct view *
|
||||
node_view_from_node(struct wlr_scene_node *wlr_scene_node)
|
||||
{
|
||||
assert(wlr_scene_node->data);
|
||||
struct node_descriptor *node_descriptor = wlr_scene_node->data;
|
||||
assert(node_descriptor->type == LAB_NODE_DESC_VIEW
|
||||
|| node_descriptor->type == LAB_NODE_DESC_XDG_POPUP);
|
||||
return (struct view *)node_descriptor->data;
|
||||
}
|
||||
|
||||
struct lab_layer_surface *
|
||||
node_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node)
|
||||
{
|
||||
assert(wlr_scene_node->data);
|
||||
struct node_descriptor *node_descriptor = wlr_scene_node->data;
|
||||
assert(node_descriptor->type == LAB_NODE_DESC_LAYER_SURFACE);
|
||||
return (struct lab_layer_surface *)node_descriptor->data;
|
||||
}
|
||||
|
||||
struct lab_layer_popup *
|
||||
node_layer_popup_from_node(struct wlr_scene_node *wlr_scene_node)
|
||||
{
|
||||
assert(wlr_scene_node->data);
|
||||
struct node_descriptor *node_descriptor = wlr_scene_node->data;
|
||||
assert(node_descriptor->type == LAB_NODE_DESC_LAYER_POPUP);
|
||||
return (struct lab_layer_popup *)node_descriptor->data;
|
||||
}
|
||||
|
||||
struct menuitem *
|
||||
node_menuitem_from_node(struct wlr_scene_node *wlr_scene_node)
|
||||
{
|
||||
assert(wlr_scene_node->data);
|
||||
struct node_descriptor *node_descriptor = wlr_scene_node->data;
|
||||
assert(node_descriptor->type == LAB_NODE_DESC_MENUITEM);
|
||||
return (struct menuitem *)node_descriptor->data;
|
||||
}
|
||||
50
src/osd.c
50
src/osd.c
|
|
@ -4,6 +4,7 @@
|
|||
#include <drm_fourcc.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "buffer.h"
|
||||
#include "common/buf.h"
|
||||
#include "common/font.h"
|
||||
#include "config/rcxml.h"
|
||||
|
|
@ -73,22 +74,42 @@ get_osd_height(struct wl_list *views)
|
|||
return height;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_osd_nodes(struct server *server)
|
||||
{
|
||||
struct wlr_scene_node *child, *next;
|
||||
struct wl_list *children = &server->osd_tree->node.state.children;
|
||||
wl_list_for_each_safe(child, next, children, state.link) {
|
||||
wlr_scene_node_destroy(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
osd_finish(struct server *server)
|
||||
{
|
||||
destroy_osd_nodes(server);
|
||||
wlr_scene_node_set_enabled(&server->osd_tree->node, false);
|
||||
}
|
||||
|
||||
void
|
||||
osd_update(struct server *server)
|
||||
{
|
||||
struct wlr_renderer *renderer = server->renderer;
|
||||
struct theme *theme = server->theme;
|
||||
|
||||
destroy_osd_nodes(server);
|
||||
struct output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
float scale = output->wlr_output->scale;
|
||||
int w = (OSD_ITEM_WIDTH + (2 * OSD_BORDER_WIDTH)) * scale;
|
||||
int h = get_osd_height(&server->views) * scale;
|
||||
|
||||
cairo_surface_t *surf =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
|
||||
cairo_surface_set_device_scale(surf, scale, scale);
|
||||
cairo_t *cairo = cairo_create(surf);
|
||||
if (output->osd_buffer) {
|
||||
wlr_buffer_drop(&output->osd_buffer->base);
|
||||
}
|
||||
output->osd_buffer = buffer_create_cairo(w, h, scale, true);
|
||||
|
||||
cairo_t *cairo = output->osd_buffer->cairo;
|
||||
cairo_surface_t *surf = cairo_get_target(cairo);
|
||||
|
||||
/* background */
|
||||
set_source(cairo, theme->osd_bg_color);
|
||||
|
|
@ -176,21 +197,14 @@ osd_update(struct server *server)
|
|||
pango_cairo_show_layout(cairo, layout);
|
||||
y += OSD_ITEM_HEIGHT;
|
||||
}
|
||||
|
||||
g_object_unref(layout);
|
||||
|
||||
/* convert to wlr_texture */
|
||||
cairo_surface_flush(surf);
|
||||
unsigned char *data = cairo_image_surface_get_data(surf);
|
||||
struct wlr_texture *texture = wlr_texture_from_pixels(renderer,
|
||||
DRM_FORMAT_ARGB8888, cairo_image_surface_get_stride(surf),
|
||||
w, h, data);
|
||||
|
||||
cairo_destroy(cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
if (output->osd) {
|
||||
wlr_texture_destroy(output->osd);
|
||||
}
|
||||
output->osd = texture;
|
||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(
|
||||
&server->osd_tree->node, &output->osd_buffer->base);
|
||||
|
||||
/* TODO: set position properly */
|
||||
wlr_scene_node_set_position(&scene_buffer->node, 10, 10);
|
||||
wlr_scene_node_set_enabled(&server->osd_tree->node, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1012
src/output.c
1012
src/output.c
File diff suppressed because it is too large
Load diff
|
|
@ -310,7 +310,6 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
|
|||
if (!layer) {
|
||||
seat->focused_layer = NULL;
|
||||
desktop_focus_topmost_mapped_view(seat->server);
|
||||
damage_all_outputs(seat->server);
|
||||
return;
|
||||
}
|
||||
seat_focus_surface(seat, layer->surface);
|
||||
|
|
|
|||
36
src/server.c
36
src/server.c
|
|
@ -7,6 +7,7 @@
|
|||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
#include <wlr/types/wlr_input_inhibitor.h>
|
||||
#include <wlr/types/wlr_presentation_time.h>
|
||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||
#include <wlr/types/wlr_screencopy_v1.h>
|
||||
#include <wlr/types/wlr_viewporter.h>
|
||||
|
|
@ -32,7 +33,7 @@ reload_config_and_theme(void)
|
|||
rcxml_finish();
|
||||
rcxml_read(NULL);
|
||||
theme_finish(g_server->theme);
|
||||
theme_init(g_server->theme, g_server->renderer, rc.theme_name);
|
||||
theme_init(g_server->theme, rc.theme_name);
|
||||
|
||||
struct view *view;
|
||||
wl_list_for_each (view, &g_server->views, link) {
|
||||
|
|
@ -40,12 +41,11 @@ reload_config_and_theme(void)
|
|||
continue;
|
||||
}
|
||||
view->margin = ssd_thickness(view);
|
||||
ssd_update_geometry(view, true);
|
||||
ssd_reload(view);
|
||||
}
|
||||
|
||||
menu_reconfigure(g_server, g_server->rootmenu);
|
||||
menu_reconfigure(g_server);
|
||||
seat_reconfigure(g_server);
|
||||
damage_all_outputs(g_server);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -120,7 +120,7 @@ seat_disinhibit_input(struct seat *seat)
|
|||
*/
|
||||
struct output *output;
|
||||
wl_list_for_each(output, &seat->server->outputs, link) {
|
||||
arrange_layers(output);
|
||||
layers_arrange(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +216,20 @@ server_init(struct server *server)
|
|||
wl_list_init(&server->views);
|
||||
wl_list_init(&server->unmanaged_surfaces);
|
||||
|
||||
server->scene = wlr_scene_create();
|
||||
if (!server->scene) {
|
||||
wlr_log(WLR_ERROR, "unable to create scene");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
server->view_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
#if HAVE_XWAYLAND
|
||||
server->unmanaged_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
#endif
|
||||
server->menu_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
server->osd_tree = wlr_scene_tree_create(&server->scene->node);
|
||||
|
||||
output_init(server);
|
||||
|
||||
/*
|
||||
* Create some hands-off wlroots interfaces. The compositor is
|
||||
* necessary for clients to allocate surfaces and the data device
|
||||
|
|
@ -229,6 +243,7 @@ server_init(struct server *server)
|
|||
wlr_log(WLR_ERROR, "unable to create the wlroots compositor");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
wlr_subcompositor_create(server->wl_display);
|
||||
|
||||
struct wlr_data_device_manager *device_manager = NULL;
|
||||
device_manager = wlr_data_device_manager_create(server->wl_display);
|
||||
|
|
@ -249,7 +264,6 @@ server_init(struct server *server)
|
|||
*/
|
||||
wlr_primary_selection_v1_device_manager_create(server->wl_display);
|
||||
|
||||
output_init(server);
|
||||
seat_init(server);
|
||||
|
||||
/* Init xdg-shell */
|
||||
|
|
@ -284,6 +298,14 @@ server_init(struct server *server)
|
|||
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER :
|
||||
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT);
|
||||
|
||||
struct wlr_presentation *presentation =
|
||||
wlr_presentation_create(server->wl_display, server->backend);
|
||||
if (!presentation) {
|
||||
wlr_log(WLR_ERROR, "unable to create presentation interface");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
wlr_scene_set_presentation(server->scene, presentation);
|
||||
|
||||
wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
||||
wlr_screencopy_manager_v1_create(server->wl_display);
|
||||
wlr_data_control_manager_v1_create(server->wl_display);
|
||||
|
|
@ -394,6 +416,8 @@ server_start(struct server *server)
|
|||
void
|
||||
server_finish(struct server *server)
|
||||
{
|
||||
|
||||
/* TODO: clean up various scene_tree nodes */
|
||||
#if HAVE_XWAYLAND
|
||||
wlr_xwayland_destroy(server->xwayland);
|
||||
#endif
|
||||
|
|
|
|||
466
src/ssd.c
466
src/ssd.c
|
|
@ -1,466 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Helpers for view server side decorations
|
||||
*
|
||||
* Copyright (C) Johan Malm 2020-2021
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "config/rcxml.h"
|
||||
#include "common/font.h"
|
||||
#include "labwc.h"
|
||||
#include "theme.h"
|
||||
#include "ssd.h"
|
||||
|
||||
#define INVISIBLE_MARGIN (16)
|
||||
|
||||
struct border
|
||||
ssd_thickness(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
struct border border = {
|
||||
.top = theme->title_height + theme->border_width,
|
||||
.bottom = theme->border_width,
|
||||
.left = theme->border_width,
|
||||
.right = theme->border_width,
|
||||
};
|
||||
return border;
|
||||
}
|
||||
|
||||
struct wlr_box
|
||||
ssd_max_extents(struct view *view)
|
||||
{
|
||||
struct border border = ssd_thickness(view);
|
||||
struct wlr_box box = {
|
||||
.x = view->x - border.left,
|
||||
.y = view->y - border.top,
|
||||
.width = view->w + border.left + border.right,
|
||||
.height = view->h + border.top + border.bottom,
|
||||
};
|
||||
return box;
|
||||
}
|
||||
|
||||
#define NR_BUTTONS (4)
|
||||
|
||||
/**
|
||||
* ssd_box - the 'full' decoration geometry which includes both visible
|
||||
* and invisible parts. It typically includes an invisible margin outside
|
||||
* the decoration.
|
||||
*
|
||||
* This function is used for determining decoration parts during user-
|
||||
* interactive operations such as mouse hover or button press
|
||||
*/
|
||||
static struct wlr_box
|
||||
ssd_box(struct view *view, enum ssd_part_type type)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
struct wlr_box box = { 0 };
|
||||
int16_t button_height = theme->title_height;
|
||||
int16_t button_width = theme->title_height;
|
||||
int16_t corner_square = theme->title_height + theme->border_width;
|
||||
int16_t title_x_padding = (double)corner_square / 2;
|
||||
|
||||
switch (type) {
|
||||
case LAB_SSD_BUTTON_CLOSE:
|
||||
box.x = view->x + view->w - button_width * 1;
|
||||
box.y = view->y - button_height;
|
||||
box.width = button_width;
|
||||
box.height = button_height;
|
||||
break;
|
||||
case LAB_SSD_BUTTON_MAXIMIZE:
|
||||
box.x = view->x + view->w - button_width * 2;
|
||||
box.y = view->y - button_height;
|
||||
box.width = button_width;
|
||||
box.height = button_height;
|
||||
break;
|
||||
case LAB_SSD_BUTTON_ICONIFY:
|
||||
box.x = view->x + view->w - button_width * 3;
|
||||
box.y = view->y - button_height;
|
||||
box.width = button_width;
|
||||
box.height = button_height;
|
||||
break;
|
||||
case LAB_SSD_BUTTON_WINDOW_MENU:
|
||||
box.x = view->x;
|
||||
box.y = view->y - button_height;
|
||||
box.width = button_width;
|
||||
box.height = button_height;
|
||||
break;
|
||||
case LAB_SSD_PART_TITLEBAR:
|
||||
box.x = view->x;
|
||||
box.y = view->y - theme->title_height;
|
||||
box.width = view->w;
|
||||
box.height = theme->title_height;
|
||||
break;
|
||||
case LAB_SSD_PART_TITLE:
|
||||
box.x = view->x + button_width + title_x_padding;
|
||||
box.y = view->y - theme->title_height;
|
||||
box.width = view->w - title_x_padding * 2 - NR_BUTTONS * button_width;
|
||||
box.height = theme->title_height;
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_TOP_LEFT:
|
||||
box.x = view->x - theme->border_width - INVISIBLE_MARGIN;
|
||||
box.y = view->y - corner_square - INVISIBLE_MARGIN;
|
||||
box.width = corner_square + INVISIBLE_MARGIN;
|
||||
box.height = corner_square + INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_TOP_RIGHT:
|
||||
box.x = view->x + view->w - theme->title_height;
|
||||
box.y = view->y - corner_square - INVISIBLE_MARGIN;
|
||||
box.width = corner_square + INVISIBLE_MARGIN;
|
||||
box.height = corner_square + INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
|
||||
box.x = view->x + view->w - corner_square;
|
||||
box.y = view->y + view->h - corner_square;
|
||||
box.width = corner_square + INVISIBLE_MARGIN;
|
||||
box.height = corner_square + INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
|
||||
box.x = view->x - theme->border_width - INVISIBLE_MARGIN;
|
||||
box.y = view->y + view->h - corner_square;
|
||||
box.width = corner_square + INVISIBLE_MARGIN;
|
||||
box.height = corner_square + INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_TOP:
|
||||
box.x = view->x + theme->title_height;
|
||||
box.y = view->y - corner_square - INVISIBLE_MARGIN;
|
||||
box.width = view->w - 2 * theme->title_height;
|
||||
box.height = theme->border_width + INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_RIGHT:
|
||||
box.x = view->x + view->w;
|
||||
box.y = view->y;
|
||||
box.width = theme->border_width + INVISIBLE_MARGIN;
|
||||
box.height = view->h;
|
||||
break;
|
||||
case LAB_SSD_PART_BOTTOM:
|
||||
box.x = view->x - theme->border_width;
|
||||
box.y = view->y + view->h;
|
||||
box.width = view->w + 2 * theme->border_width;
|
||||
box.height = theme->border_width + INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_LEFT:
|
||||
box.x = view->x - theme->border_width - INVISIBLE_MARGIN;
|
||||
box.y = view->y;
|
||||
box.width = theme->border_width + INVISIBLE_MARGIN;
|
||||
box.height = view->h;
|
||||
break;
|
||||
case LAB_SSD_CLIENT:
|
||||
box.x = view->x;
|
||||
box.y = view->y;
|
||||
box.width = view->w;
|
||||
box.height = view->h;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
static void
|
||||
center_vertically(struct wlr_box *box, struct wlr_texture *texture)
|
||||
{
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
box->y += (box->height - texture->height) / 2;
|
||||
}
|
||||
|
||||
static void
|
||||
center_horizontally(struct view *view, struct wlr_box *box,
|
||||
struct wlr_texture *texture)
|
||||
{
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
box->x = view->x + (view->w - texture->width) / 2;
|
||||
}
|
||||
|
||||
static void
|
||||
justify_right(struct view *view, struct wlr_box *box,
|
||||
struct wlr_texture *texture)
|
||||
{
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
box->x = view->x + (box->width - texture->width);
|
||||
}
|
||||
|
||||
bool
|
||||
ssd_is_button(enum ssd_part_type type)
|
||||
{
|
||||
return type == LAB_SSD_BUTTON_CLOSE ||
|
||||
type == LAB_SSD_BUTTON_MAXIMIZE ||
|
||||
type == LAB_SSD_BUTTON_ICONIFY ||
|
||||
type == LAB_SSD_BUTTON_WINDOW_MENU;
|
||||
}
|
||||
|
||||
struct wlr_box
|
||||
ssd_visible_box(struct view *view, enum ssd_part_type type)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
struct wlr_box box = { 0 };
|
||||
switch (type) {
|
||||
case LAB_SSD_BUTTON_CLOSE:
|
||||
box = ssd_box(view, type);
|
||||
break;
|
||||
case LAB_SSD_BUTTON_MAXIMIZE:
|
||||
box = ssd_box(view, type);
|
||||
break;
|
||||
case LAB_SSD_BUTTON_ICONIFY:
|
||||
box = ssd_box(view, type);
|
||||
break;
|
||||
case LAB_SSD_BUTTON_WINDOW_MENU:
|
||||
box = ssd_box(view, type);
|
||||
break;
|
||||
case LAB_SSD_PART_TITLEBAR:
|
||||
box = ssd_box(view, type);
|
||||
box.x += theme->title_height;
|
||||
box.width -= 2 * theme->title_height;
|
||||
break;
|
||||
case LAB_SSD_PART_TITLE:
|
||||
box = ssd_box(view, type);
|
||||
center_vertically(&box, view->title.active);
|
||||
if (theme->window_label_text_justify == LAB_JUSTIFY_CENTER) {
|
||||
center_horizontally(view, &box, view->title.active);
|
||||
} else if (theme->window_label_text_justify == LAB_JUSTIFY_RIGHT) {
|
||||
justify_right(view, &box, view->title.active);
|
||||
}
|
||||
if (view->title.active) {
|
||||
box.width = view->title.active->width;
|
||||
box.height = view->title.active->height;
|
||||
}
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_TOP_LEFT:
|
||||
box = ssd_box(view, type);
|
||||
box.x += INVISIBLE_MARGIN;
|
||||
box.y += INVISIBLE_MARGIN;
|
||||
box.width -= INVISIBLE_MARGIN;
|
||||
box.height -= INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_TOP_RIGHT:
|
||||
box = ssd_box(view, type);
|
||||
box.y += INVISIBLE_MARGIN;
|
||||
box.width -= INVISIBLE_MARGIN;
|
||||
box.height -= INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_TOP:
|
||||
box = ssd_box(view, type);
|
||||
box.y += INVISIBLE_MARGIN;
|
||||
box.height -= INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_RIGHT:
|
||||
box = ssd_box(view, type);
|
||||
box.width -= INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_BOTTOM:
|
||||
box = ssd_box(view, type);
|
||||
box.height -= INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_LEFT:
|
||||
box = ssd_box(view, type);
|
||||
box.x += INVISIBLE_MARGIN;
|
||||
box.width -= INVISIBLE_MARGIN;
|
||||
break;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
enum ssd_part_type
|
||||
ssd_at(struct view *view, double lx, double ly)
|
||||
{
|
||||
enum ssd_part_type type;
|
||||
for (type = 0; type < LAB_SSD_END_MARKER; ++type) {
|
||||
struct wlr_box box = ssd_box(view, type);
|
||||
if (wlr_box_contains_point(&box, lx, ly)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return LAB_SSD_NONE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ssd_resize_edges(enum ssd_part_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case LAB_SSD_PART_TOP:
|
||||
return WLR_EDGE_TOP;
|
||||
case LAB_SSD_PART_RIGHT:
|
||||
return WLR_EDGE_RIGHT;
|
||||
case LAB_SSD_PART_BOTTOM:
|
||||
return WLR_EDGE_BOTTOM;
|
||||
case LAB_SSD_PART_LEFT:
|
||||
return WLR_EDGE_LEFT;
|
||||
case LAB_SSD_PART_CORNER_TOP_LEFT:
|
||||
return WLR_EDGE_TOP | WLR_EDGE_LEFT;
|
||||
case LAB_SSD_PART_CORNER_TOP_RIGHT:
|
||||
return WLR_EDGE_RIGHT | WLR_EDGE_TOP;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
|
||||
return WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
|
||||
return WLR_EDGE_BOTTOM | WLR_EDGE_LEFT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct ssd_part *
|
||||
add_part(struct view *view, enum ssd_part_type type)
|
||||
{
|
||||
struct ssd_part *part = calloc(1, sizeof(struct ssd_part));
|
||||
part->type = type;
|
||||
wl_list_insert(&view->ssd.parts, &part->link);
|
||||
return part;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_update_title(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
|
||||
struct font font = {
|
||||
.name = rc.font_name_activewindow,
|
||||
.size = rc.font_size_activewindow,
|
||||
};
|
||||
|
||||
struct ssd_part *part;
|
||||
wl_list_for_each(part, &view->ssd.parts, link) {
|
||||
if (part->type == LAB_SSD_PART_TITLE) {
|
||||
part->box = ssd_box(view, part->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (part->type != LAB_SSD_PART_TITLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int max_width = part->box.width > 0 ? part->box.width : 1000;
|
||||
|
||||
font_texture_create(view->server, &view->title.active, max_width,
|
||||
view_get_string_prop(view, "title"),
|
||||
&font, theme->window_active_label_text_color);
|
||||
|
||||
font_texture_create(view->server, &view->title.inactive, max_width,
|
||||
view_get_string_prop(view, "title"),
|
||||
&font, theme->window_inactive_label_text_color);
|
||||
|
||||
part->box = ssd_visible_box(view, part->type);
|
||||
}
|
||||
|
||||
void
|
||||
ssd_create(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
struct ssd_part *part;
|
||||
|
||||
view->ssd.box.x = view->x;
|
||||
view->ssd.box.y = view->y;
|
||||
view->ssd.box.width = view->w;
|
||||
view->ssd.box.height = view->h;
|
||||
|
||||
/* border */
|
||||
enum ssd_part_type border[4] = {
|
||||
LAB_SSD_PART_TOP,
|
||||
LAB_SSD_PART_RIGHT,
|
||||
LAB_SSD_PART_BOTTOM,
|
||||
LAB_SSD_PART_LEFT,
|
||||
};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
part = add_part(view, border[i]);
|
||||
part->box = ssd_visible_box(view, border[i]);
|
||||
part->color.active = theme->window_active_border_color;
|
||||
part->color.inactive = theme->window_inactive_border_color;
|
||||
}
|
||||
|
||||
/* titlebar */
|
||||
part = add_part(view, LAB_SSD_PART_TITLEBAR);
|
||||
part->box = ssd_visible_box(view, LAB_SSD_PART_TITLEBAR);
|
||||
part->color.active = theme->window_active_title_bg_color;
|
||||
part->color.inactive = theme->window_inactive_title_bg_color;
|
||||
|
||||
/* titlebar top-left corner */
|
||||
part = add_part(view, LAB_SSD_PART_CORNER_TOP_LEFT);
|
||||
part->box = ssd_visible_box(view, part->type);
|
||||
part->texture.active = &theme->corner_top_left_active_normal;
|
||||
part->texture.inactive = &theme->corner_top_left_inactive_normal;
|
||||
|
||||
/* titlebar top-right corner */
|
||||
part = add_part(view, LAB_SSD_PART_CORNER_TOP_RIGHT);
|
||||
part->box = ssd_visible_box(view, part->type);
|
||||
part->texture.active = &theme->corner_top_right_active_normal;
|
||||
part->texture.inactive = &theme->corner_top_right_inactive_normal;
|
||||
|
||||
/* title text */
|
||||
part = add_part(view, LAB_SSD_PART_TITLE);
|
||||
ssd_update_title(view);
|
||||
part->texture.active = &view->title.active;
|
||||
part->texture.inactive = &view->title.inactive;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_destroy(struct view *view)
|
||||
{
|
||||
struct ssd_part *part, *next;
|
||||
wl_list_for_each_safe(part, next, &view->ssd.parts, link) {
|
||||
wl_list_remove(&part->link);
|
||||
free(part);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
geometry_changed(struct view *view)
|
||||
{
|
||||
return view->x != view->ssd.box.x || view->y != view->ssd.box.y ||
|
||||
view->w != view->ssd.box.width ||
|
||||
view->h != view->ssd.box.height;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_update_geometry(struct view *view, bool force)
|
||||
{
|
||||
if (!geometry_changed(view) && !force) {
|
||||
return;
|
||||
}
|
||||
struct ssd_part *part;
|
||||
wl_list_for_each(part, &view->ssd.parts, link) {
|
||||
part->box = ssd_visible_box(view, part->type);
|
||||
}
|
||||
view->ssd.box.x = view->x;
|
||||
view->ssd.box.y = view->y;
|
||||
view->ssd.box.width = view->w;
|
||||
view->ssd.box.height = view->h;
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
||||
bool
|
||||
ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate)
|
||||
{
|
||||
if (whole == candidate) {
|
||||
return true;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_TITLEBAR) {
|
||||
return candidate >= LAB_SSD_BUTTON_CLOSE && candidate <= LAB_SSD_PART_TITLE;
|
||||
}
|
||||
if (whole == LAB_SSD_FRAME) {
|
||||
return candidate >= LAB_SSD_BUTTON_CLOSE && candidate <= LAB_SSD_CLIENT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_TOP) {
|
||||
return candidate == LAB_SSD_PART_CORNER_TOP_LEFT || candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_RIGHT) {
|
||||
return candidate == LAB_SSD_PART_CORNER_TOP_RIGHT || candidate == LAB_SSD_PART_CORNER_BOTTOM_RIGHT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_BOTTOM) {
|
||||
return candidate == LAB_SSD_PART_CORNER_BOTTOM_RIGHT || candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_LEFT) {
|
||||
return candidate == LAB_SSD_PART_CORNER_TOP_LEFT || candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
7
src/ssd/meson.build
Normal file
7
src/ssd/meson.build
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
labwc_sources += files(
|
||||
'ssd.c',
|
||||
'ssd_part.c',
|
||||
'ssd_titlebar.c',
|
||||
'ssd_border.c',
|
||||
'ssd_extents.c',
|
||||
)
|
||||
296
src/ssd/ssd.c
Normal file
296
src/ssd/ssd.c
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
/*
|
||||
* Helpers for view server side decorations
|
||||
*
|
||||
* Copyright (C) Johan Malm 2020-2021
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "config/rcxml.h"
|
||||
#include "common/font.h"
|
||||
#include "labwc.h"
|
||||
#include "theme.h"
|
||||
#include "ssd.h"
|
||||
|
||||
/* TODO: use theme->title_height instead of SSD_HEIGHT */
|
||||
struct border
|
||||
ssd_thickness(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
struct border border = {
|
||||
.top = SSD_HEIGHT,
|
||||
.bottom = theme->border_width,
|
||||
.left = theme->border_width,
|
||||
.right = theme->border_width,
|
||||
};
|
||||
return border;
|
||||
}
|
||||
|
||||
struct wlr_box
|
||||
ssd_max_extents(struct view *view)
|
||||
{
|
||||
struct border border = ssd_thickness(view);
|
||||
struct wlr_box box = {
|
||||
.x = view->x - border.left,
|
||||
.y = view->y - border.top,
|
||||
.width = view->w + border.left + border.right,
|
||||
.height = view->h + border.top + border.bottom,
|
||||
};
|
||||
return box;
|
||||
}
|
||||
|
||||
bool
|
||||
ssd_is_button(enum ssd_part_type type)
|
||||
{
|
||||
return type == LAB_SSD_BUTTON_CLOSE
|
||||
|| type == LAB_SSD_BUTTON_MAXIMIZE
|
||||
|| type == LAB_SSD_BUTTON_ICONIFY
|
||||
|| type == LAB_SSD_BUTTON_WINDOW_MENU;
|
||||
}
|
||||
|
||||
enum ssd_part_type
|
||||
ssd_get_part_type(struct view *view, struct wlr_scene_node *node)
|
||||
{
|
||||
if (!node) {
|
||||
return LAB_SSD_NONE;
|
||||
} else if (node->type == WLR_SCENE_NODE_SURFACE) {
|
||||
return LAB_SSD_CLIENT;
|
||||
} else if (!view->ssd.tree) {
|
||||
return LAB_SSD_NONE;
|
||||
}
|
||||
|
||||
struct wl_list *part_list = NULL;
|
||||
struct wlr_scene_node *grandparent =
|
||||
node->parent ? node->parent->parent : NULL;
|
||||
|
||||
/* active titlebar */
|
||||
if (node->parent == &view->ssd.titlebar.active.tree->node) {
|
||||
part_list = &view->ssd.titlebar.active.parts;
|
||||
} else if (grandparent == &view->ssd.titlebar.active.tree->node) {
|
||||
part_list = &view->ssd.titlebar.active.parts;
|
||||
|
||||
/* extents */
|
||||
} else if (node->parent == &view->ssd.extents.tree->node) {
|
||||
part_list = &view->ssd.extents.parts;
|
||||
|
||||
/* active border */
|
||||
} else if (node->parent == &view->ssd.border.active.tree->node) {
|
||||
part_list = &view->ssd.border.active.parts;
|
||||
|
||||
/* inactive titlebar */
|
||||
} else if (node->parent == &view->ssd.titlebar.inactive.tree->node) {
|
||||
part_list = &view->ssd.titlebar.inactive.parts;
|
||||
} else if (grandparent == &view->ssd.titlebar.inactive.tree->node) {
|
||||
part_list = &view->ssd.titlebar.inactive.parts;
|
||||
|
||||
/* inactive border */
|
||||
} else if (node->parent == &view->ssd.border.inactive.tree->node) {
|
||||
part_list = &view->ssd.border.inactive.parts;
|
||||
}
|
||||
|
||||
if (part_list) {
|
||||
struct ssd_part *part;
|
||||
wl_list_for_each(part, part_list, link) {
|
||||
if (node == part->node) {
|
||||
return part->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return LAB_SSD_NONE;
|
||||
}
|
||||
|
||||
enum ssd_part_type
|
||||
ssd_at(struct view *view, double lx, double ly)
|
||||
{
|
||||
double sx, sy;
|
||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||
&view->server->scene->node, lx, ly, &sx, &sy);
|
||||
return ssd_get_part_type(view, node);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ssd_resize_edges(enum ssd_part_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case LAB_SSD_PART_TOP:
|
||||
return WLR_EDGE_TOP;
|
||||
case LAB_SSD_PART_RIGHT:
|
||||
return WLR_EDGE_RIGHT;
|
||||
case LAB_SSD_PART_BOTTOM:
|
||||
return WLR_EDGE_BOTTOM;
|
||||
case LAB_SSD_PART_LEFT:
|
||||
return WLR_EDGE_LEFT;
|
||||
case LAB_SSD_PART_CORNER_TOP_LEFT:
|
||||
return WLR_EDGE_TOP | WLR_EDGE_LEFT;
|
||||
case LAB_SSD_PART_CORNER_TOP_RIGHT:
|
||||
return WLR_EDGE_RIGHT | WLR_EDGE_TOP;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
|
||||
return WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
|
||||
return WLR_EDGE_BOTTOM | WLR_EDGE_LEFT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_ssd_set_active(struct ssd *ssd, bool active)
|
||||
{
|
||||
wlr_scene_node_set_enabled(&ssd->border.active.tree->node, active);
|
||||
wlr_scene_node_set_enabled(&ssd->titlebar.active.tree->node, active);
|
||||
wlr_scene_node_set_enabled(&ssd->border.inactive.tree->node, !active);
|
||||
wlr_scene_node_set_enabled(&ssd->titlebar.inactive.tree->node, !active);
|
||||
}
|
||||
|
||||
void
|
||||
ssd_create(struct view *view)
|
||||
{
|
||||
if (view->ssd.tree) {
|
||||
/* SSD was hidden. Just enable it */
|
||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, true);
|
||||
return;
|
||||
}
|
||||
|
||||
view->ssd.tree = wlr_scene_tree_create(&view->scene_tree->node);
|
||||
wlr_scene_node_lower_to_bottom(&view->ssd.tree->node);
|
||||
ssd_extents_create(view);
|
||||
ssd_titlebar_create(view);
|
||||
ssd_border_create(view);
|
||||
}
|
||||
|
||||
void
|
||||
ssd_update_geometry(struct view *view)
|
||||
{
|
||||
/* TODO: verify we are not called without reason. like in commit handlers */
|
||||
if (!view->ssd.tree || !view->scene_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (view->ssd.enabled && !view->ssd.tree->node.state.enabled) {
|
||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, true);
|
||||
}
|
||||
if (!view->ssd.enabled && view->ssd.tree->node.state.enabled) {
|
||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
|
||||
}
|
||||
|
||||
int width = view->w;
|
||||
int height = view->h;
|
||||
if (width == view->ssd.state.width && height == view->ssd.state.height) {
|
||||
return;
|
||||
}
|
||||
ssd_extents_update(view);
|
||||
ssd_border_update(view);
|
||||
ssd_titlebar_update(view);
|
||||
|
||||
view->ssd.state.width = width;
|
||||
view->ssd.state.height = height;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_hide(struct view *view)
|
||||
{
|
||||
if (!view->ssd.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_ERROR, "Hiding SSD");
|
||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
|
||||
}
|
||||
|
||||
void ssd_reload(struct view *view)
|
||||
{
|
||||
if (!view->ssd.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool view_was_active = view->server->ssd_focused_view == view;
|
||||
ssd_destroy(view);
|
||||
ssd_create(view);
|
||||
if (view_was_active) {
|
||||
view->server->ssd_focused_view = view;
|
||||
} else {
|
||||
_ssd_set_active(&view->ssd, false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ssd_destroy(struct view *view)
|
||||
{
|
||||
if (!view->ssd.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Maybe reset focused view */
|
||||
if (view->server->ssd_focused_view == view) {
|
||||
view->server->ssd_focused_view = NULL;
|
||||
}
|
||||
|
||||
/* Maybe reset hover view */
|
||||
struct ssd_hover_state *hover_state;
|
||||
hover_state = &view->server->ssd_hover_state;
|
||||
if (hover_state->view == view) {
|
||||
hover_state->view = NULL;
|
||||
hover_state->type = LAB_SSD_NONE;
|
||||
hover_state->node = NULL;
|
||||
}
|
||||
|
||||
/* Destroy subcomponents */
|
||||
ssd_titlebar_destroy(view);
|
||||
ssd_border_destroy(view);
|
||||
ssd_extents_destroy(view);
|
||||
wlr_scene_node_destroy(&view->ssd.tree->node);
|
||||
view->ssd.tree = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate)
|
||||
{
|
||||
if (whole == candidate) {
|
||||
return true;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_TITLEBAR) {
|
||||
return candidate >= LAB_SSD_BUTTON_CLOSE
|
||||
&& candidate <= LAB_SSD_PART_TITLE;
|
||||
}
|
||||
if (whole == LAB_SSD_FRAME) {
|
||||
return candidate >= LAB_SSD_BUTTON_CLOSE
|
||||
&& candidate <= LAB_SSD_CLIENT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_TOP) {
|
||||
return candidate == LAB_SSD_PART_CORNER_TOP_LEFT
|
||||
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_RIGHT) {
|
||||
return candidate == LAB_SSD_PART_CORNER_TOP_RIGHT
|
||||
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_RIGHT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_BOTTOM) {
|
||||
return candidate == LAB_SSD_PART_CORNER_BOTTOM_RIGHT
|
||||
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
|
||||
}
|
||||
if (whole == LAB_SSD_PART_LEFT) {
|
||||
return candidate == LAB_SSD_PART_CORNER_TOP_LEFT
|
||||
|| candidate == LAB_SSD_PART_CORNER_BOTTOM_LEFT;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_set_active(struct view *view)
|
||||
{
|
||||
if (!view->ssd.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct view *last = view->server->ssd_focused_view;
|
||||
if (last == view) {
|
||||
return;
|
||||
}
|
||||
if (last && last->ssd.tree) {
|
||||
_ssd_set_active(&last->ssd, false);
|
||||
}
|
||||
_ssd_set_active(&view->ssd, true);
|
||||
view->server->ssd_focused_view = view;
|
||||
}
|
||||
106
src/ssd/ssd_border.c
Normal file
106
src/ssd/ssd_border.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include "labwc.h"
|
||||
#include "ssd.h"
|
||||
#include "theme.h"
|
||||
#include "common/scene-helpers.h"
|
||||
|
||||
#define FOR_EACH_STATE(view, tmp) FOR_EACH(tmp, \
|
||||
&(view)->ssd.border.active, \
|
||||
&(view)->ssd.border.inactive)
|
||||
|
||||
void
|
||||
ssd_border_create(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
int width = view->w;
|
||||
int height = view->h;
|
||||
int full_width = width + 2 * theme->border_width;
|
||||
|
||||
float *color;
|
||||
struct wlr_scene_node *parent;
|
||||
struct ssd_sub_tree *subtree;
|
||||
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
subtree->tree = wlr_scene_tree_create(&view->ssd.tree->node);
|
||||
parent = &subtree->tree->node;
|
||||
wlr_scene_node_set_position(parent, -theme->border_width, 0);
|
||||
if (subtree == &view->ssd.border.active) {
|
||||
color = theme->window_active_border_color;
|
||||
} else {
|
||||
color = theme->window_inactive_border_color;
|
||||
wlr_scene_node_set_enabled(parent, false);
|
||||
}
|
||||
wl_list_init(&subtree->parts);
|
||||
add_scene_rect(&subtree->parts, LAB_SSD_PART_LEFT, parent,
|
||||
theme->border_width, height, 0, 0, color);
|
||||
add_scene_rect(&subtree->parts, LAB_SSD_PART_RIGHT, parent,
|
||||
theme->border_width, height,
|
||||
theme->border_width + width, 0, color);
|
||||
add_scene_rect(&subtree->parts, LAB_SSD_PART_BOTTOM, parent,
|
||||
full_width, theme->border_width,
|
||||
0, height, color);
|
||||
add_scene_rect(&subtree->parts, LAB_SSD_PART_TOP, parent,
|
||||
full_width - 2 * BUTTON_WIDTH, theme->border_width,
|
||||
BUTTON_WIDTH, -SSD_HEIGHT, color);
|
||||
} FOR_EACH_END
|
||||
}
|
||||
|
||||
void
|
||||
ssd_border_update(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
|
||||
int width = view->w;
|
||||
int height = view->h;
|
||||
int full_width = width + 2 * theme->border_width;
|
||||
|
||||
struct ssd_part *part;
|
||||
struct wlr_scene_rect *rect;
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
wl_list_for_each(part, &subtree->parts, link) {
|
||||
rect = lab_wlr_scene_get_rect(part->node);
|
||||
switch (part->type) {
|
||||
case LAB_SSD_PART_LEFT:
|
||||
wlr_scene_rect_set_size(rect, theme->border_width, height);
|
||||
continue;
|
||||
case LAB_SSD_PART_RIGHT:
|
||||
wlr_scene_rect_set_size(rect, theme->border_width, height);
|
||||
wlr_scene_node_set_position(
|
||||
part->node, theme->border_width + width, 0);
|
||||
continue;
|
||||
case LAB_SSD_PART_BOTTOM:
|
||||
wlr_scene_rect_set_size(rect, full_width, theme->border_width);
|
||||
wlr_scene_node_set_position(part->node, 0, height);
|
||||
continue;
|
||||
case LAB_SSD_PART_TOP:
|
||||
wlr_scene_rect_set_size(rect,
|
||||
full_width - 2 * BUTTON_WIDTH,
|
||||
theme->border_width);
|
||||
wlr_scene_node_set_position(part->node,
|
||||
BUTTON_WIDTH, -SSD_HEIGHT);
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} FOR_EACH_END
|
||||
}
|
||||
|
||||
void
|
||||
ssd_border_destroy(struct view *view)
|
||||
{
|
||||
if (!view->ssd.border.active.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
ssd_destroy_parts(&subtree->parts);
|
||||
wlr_scene_node_destroy(&subtree->tree->node);
|
||||
subtree->tree = NULL;
|
||||
} FOR_EACH_END
|
||||
}
|
||||
|
||||
#undef FOR_EACH_STATE
|
||||
128
src/ssd/ssd_extents.c
Normal file
128
src/ssd/ssd_extents.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include "labwc.h"
|
||||
#include "ssd.h"
|
||||
#include "theme.h"
|
||||
#include "common/scene-helpers.h"
|
||||
|
||||
void
|
||||
ssd_extents_create(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
float invisible[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
struct wl_list *part_list = &view->ssd.extents.parts;
|
||||
int width = view->w;
|
||||
int height = view->h;
|
||||
int full_height = height + theme->border_width + SSD_HEIGHT;
|
||||
int full_width = width + 2 * theme->border_width;
|
||||
int extended_area = EXTENDED_AREA;
|
||||
|
||||
view->ssd.extents.tree = wlr_scene_tree_create(&view->ssd.tree->node);
|
||||
struct wlr_scene_node *parent = &view->ssd.extents.tree->node;
|
||||
if (view->maximized || view->fullscreen) {
|
||||
wlr_scene_node_set_enabled(parent, false);
|
||||
}
|
||||
wl_list_init(&view->ssd.extents.parts);
|
||||
wlr_scene_node_set_position(parent,
|
||||
-(theme->border_width + extended_area), -(SSD_HEIGHT + extended_area));
|
||||
|
||||
/* Top */
|
||||
add_scene_rect(part_list, LAB_SSD_PART_CORNER_TOP_LEFT, parent,
|
||||
extended_area, extended_area,
|
||||
0, 0, invisible);
|
||||
add_scene_rect(part_list, LAB_SSD_PART_TOP, parent,
|
||||
full_width, extended_area,
|
||||
extended_area, 0, invisible);
|
||||
add_scene_rect(part_list, LAB_SSD_PART_CORNER_TOP_RIGHT, parent,
|
||||
extended_area, extended_area,
|
||||
extended_area + full_width, 0, invisible);
|
||||
|
||||
/* Sides */
|
||||
add_scene_rect(part_list, LAB_SSD_PART_LEFT, parent,
|
||||
extended_area, full_height,
|
||||
0, extended_area, invisible);
|
||||
add_scene_rect(part_list, LAB_SSD_PART_RIGHT, parent,
|
||||
extended_area, full_height,
|
||||
extended_area + full_width, extended_area, invisible);
|
||||
|
||||
/* Bottom */
|
||||
add_scene_rect(part_list, LAB_SSD_PART_CORNER_BOTTOM_LEFT, parent,
|
||||
extended_area, extended_area,
|
||||
0, extended_area + full_height, invisible);
|
||||
add_scene_rect(part_list, LAB_SSD_PART_BOTTOM, parent,
|
||||
full_width, extended_area,
|
||||
extended_area, extended_area + full_height, invisible);
|
||||
add_scene_rect(part_list, LAB_SSD_PART_CORNER_BOTTOM_RIGHT, parent,
|
||||
extended_area, extended_area,
|
||||
extended_area + full_width, extended_area + full_height, invisible);
|
||||
}
|
||||
|
||||
void
|
||||
ssd_extents_update(struct view *view)
|
||||
{
|
||||
if (view->maximized || view->fullscreen) {
|
||||
wlr_scene_node_set_enabled(&view->ssd.extents.tree->node, false);
|
||||
return;
|
||||
}
|
||||
if (!view->ssd.extents.tree->node.state.enabled) {
|
||||
wlr_scene_node_set_enabled(&view->ssd.extents.tree->node, true);
|
||||
}
|
||||
|
||||
struct theme *theme = view->server->theme;
|
||||
|
||||
int width = view->w;
|
||||
int height = view->h;
|
||||
int full_height = height + theme->border_width + SSD_HEIGHT;
|
||||
int full_width = width + 2 * theme->border_width;
|
||||
int extended_area = EXTENDED_AREA;
|
||||
|
||||
struct ssd_part *part;
|
||||
struct wlr_scene_rect *rect;
|
||||
wl_list_for_each(part, &view->ssd.extents.parts, link) {
|
||||
rect = lab_wlr_scene_get_rect(part->node);
|
||||
switch (part->type) {
|
||||
case LAB_SSD_PART_TOP:
|
||||
wlr_scene_rect_set_size(rect, full_width, extended_area);
|
||||
continue;
|
||||
case LAB_SSD_PART_CORNER_TOP_RIGHT:
|
||||
wlr_scene_node_set_position(
|
||||
part->node, extended_area + full_width, 0);
|
||||
continue;
|
||||
case LAB_SSD_PART_LEFT:
|
||||
wlr_scene_rect_set_size(rect, extended_area, full_height);
|
||||
continue;
|
||||
case LAB_SSD_PART_RIGHT:
|
||||
wlr_scene_rect_set_size(rect, extended_area, full_height);
|
||||
wlr_scene_node_set_position(
|
||||
part->node, extended_area + full_width, extended_area);
|
||||
continue;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
|
||||
wlr_scene_node_set_position(
|
||||
part->node, 0, extended_area + full_height);
|
||||
continue;
|
||||
case LAB_SSD_PART_BOTTOM:
|
||||
wlr_scene_rect_set_size(rect, full_width, extended_area);
|
||||
wlr_scene_node_set_position(
|
||||
part->node, extended_area, extended_area + full_height);
|
||||
continue;
|
||||
case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
|
||||
wlr_scene_node_set_position(part->node,
|
||||
extended_area + full_width, extended_area + full_height);
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ssd_extents_destroy(struct view *view)
|
||||
{
|
||||
if (!view->ssd.extents.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssd_destroy_parts(&view->ssd.extents.parts);
|
||||
wlr_scene_node_destroy(&view->ssd.extents.tree->node);
|
||||
view->ssd.extents.tree = NULL;
|
||||
}
|
||||
118
src/ssd/ssd_part.c
Normal file
118
src/ssd/ssd_part.c
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <assert.h>
|
||||
#include "labwc.h"
|
||||
#include "ssd.h"
|
||||
|
||||
struct ssd_part *
|
||||
add_scene_part(struct wl_list *part_list, enum ssd_part_type type)
|
||||
{
|
||||
struct ssd_part *part = calloc(1, sizeof(struct ssd_part));
|
||||
part->type = type;
|
||||
wl_list_insert(part_list->prev, &part->link);
|
||||
return part;
|
||||
}
|
||||
|
||||
struct ssd_part *
|
||||
add_scene_rect(struct wl_list *list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, int width, int height,
|
||||
int x, int y, float color[4])
|
||||
{
|
||||
/*
|
||||
* When initialized without surface being mapped,
|
||||
* size may be negative. Just set to 0, next call
|
||||
* to ssd_*_update() will update the rect to use
|
||||
* its correct size.
|
||||
*/
|
||||
width = width >= 0 ? width : 0;
|
||||
height = height >= 0 ? height : 0;
|
||||
|
||||
struct ssd_part *part = add_scene_part(list, type);
|
||||
part->node = &wlr_scene_rect_create(
|
||||
parent, width, height, color)->node;
|
||||
wlr_scene_node_set_position(part->node, x, y);
|
||||
return part;
|
||||
}
|
||||
|
||||
struct ssd_part *
|
||||
add_scene_buffer(struct wl_list *list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, struct wlr_buffer *buffer,
|
||||
int x, int y)
|
||||
{
|
||||
struct ssd_part *part = add_scene_part(list, type);
|
||||
part->node = &wlr_scene_buffer_create(parent, buffer)->node;
|
||||
wlr_scene_node_set_position(part->node, x, y);
|
||||
return part;
|
||||
}
|
||||
|
||||
static void
|
||||
finish_scene_button(struct wl_list *part_list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, struct wlr_buffer *icon_buffer)
|
||||
{
|
||||
float hover_bg[4] = {0.15f, 0.15f, 0.15f, 0.3f};
|
||||
|
||||
/* Icon */
|
||||
add_scene_buffer(part_list, type, parent, icon_buffer,
|
||||
(BUTTON_WIDTH - icon_buffer->width) / 2,
|
||||
(SSD_HEIGHT - icon_buffer->height) / 2);
|
||||
|
||||
/* Hover overlay */
|
||||
struct ssd_part *hover_part;
|
||||
hover_part = add_scene_rect(part_list, type, parent,
|
||||
BUTTON_WIDTH, SSD_HEIGHT, 0, 0, hover_bg);
|
||||
wlr_scene_node_set_enabled(hover_part->node, false);
|
||||
}
|
||||
|
||||
struct ssd_part *
|
||||
add_scene_button_corner(struct wl_list *part_list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, struct wlr_buffer *corner_buffer,
|
||||
struct wlr_buffer *icon_buffer, int x)
|
||||
{
|
||||
struct ssd_part *part;
|
||||
/* Background */
|
||||
part = add_scene_buffer(part_list, type, parent, corner_buffer, x, 0);
|
||||
finish_scene_button(part_list, type, part->node, icon_buffer);
|
||||
return part;
|
||||
}
|
||||
|
||||
struct ssd_part *
|
||||
add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
|
||||
struct wlr_scene_node *parent, float *bg_color,
|
||||
struct wlr_buffer *icon_buffer, int x)
|
||||
{
|
||||
struct ssd_part *part;
|
||||
/* Background */
|
||||
part = add_scene_rect(part_list, type, parent,
|
||||
BUTTON_WIDTH, SSD_HEIGHT, x, 0, bg_color);
|
||||
finish_scene_button(part_list, type, part->node, icon_buffer);
|
||||
return part;
|
||||
}
|
||||
|
||||
struct ssd_part *
|
||||
ssd_get_part(struct wl_list *part_list, enum ssd_part_type type)
|
||||
{
|
||||
struct ssd_part *part;
|
||||
wl_list_for_each(part, part_list, link) {
|
||||
if (part->type == type) {
|
||||
return part;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_destroy_parts(struct wl_list *list)
|
||||
{
|
||||
struct ssd_part *part, *tmp;
|
||||
wl_list_for_each_reverse_safe(part, tmp, list, link) {
|
||||
if (part->node) {
|
||||
wlr_scene_node_destroy(part->node);
|
||||
}
|
||||
if (part->buffer) {
|
||||
wlr_buffer_drop(&part->buffer->base);
|
||||
}
|
||||
wl_list_remove(&part->link);
|
||||
free(part);
|
||||
}
|
||||
assert(wl_list_empty(list));
|
||||
}
|
||||
304
src/ssd/ssd_titlebar.c
Normal file
304
src/ssd/ssd_titlebar.c
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "labwc.h"
|
||||
#include "ssd.h"
|
||||
#include "theme.h"
|
||||
#include "common/font.h"
|
||||
#include "common/scene-helpers.h"
|
||||
|
||||
#define FOR_EACH_STATE(view, tmp) FOR_EACH(tmp, \
|
||||
&(view)->ssd.titlebar.active, \
|
||||
&(view)->ssd.titlebar.inactive)
|
||||
|
||||
void
|
||||
ssd_titlebar_create(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
int width = view->w;
|
||||
int full_width = width + 2 * theme->border_width;
|
||||
|
||||
float *color;
|
||||
struct wlr_scene_node *parent;
|
||||
struct wlr_buffer *corner_top_left;
|
||||
struct wlr_buffer *corner_top_right;
|
||||
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
subtree->tree = wlr_scene_tree_create(&view->ssd.tree->node);
|
||||
parent = &subtree->tree->node;
|
||||
wlr_scene_node_set_position(parent, -theme->border_width, -SSD_HEIGHT);
|
||||
if (subtree == &view->ssd.titlebar.active) {
|
||||
color = theme->window_active_title_bg_color;
|
||||
corner_top_left = &theme->corner_top_left_active_normal->base;
|
||||
corner_top_right = &theme->corner_top_right_active_normal->base;
|
||||
} else {
|
||||
color = theme->window_inactive_title_bg_color;
|
||||
corner_top_left = &theme->corner_top_left_inactive_normal->base;
|
||||
corner_top_right = &theme->corner_top_right_inactive_normal->base;
|
||||
wlr_scene_node_set_enabled(parent, false);
|
||||
}
|
||||
wl_list_init(&subtree->parts);
|
||||
|
||||
/* Title */
|
||||
add_scene_rect(&subtree->parts, LAB_SSD_PART_TITLEBAR, parent,
|
||||
full_width - BUTTON_WIDTH * BUTTON_COUNT, SSD_HEIGHT,
|
||||
BUTTON_WIDTH, 0, color);
|
||||
/* Buttons */
|
||||
add_scene_button_corner(&subtree->parts, LAB_SSD_BUTTON_WINDOW_MENU,
|
||||
parent, corner_top_left,
|
||||
&theme->xbm_menu_active_unpressed->base, 0);
|
||||
add_scene_button(&subtree->parts, LAB_SSD_BUTTON_ICONIFY, parent,
|
||||
color, &theme->xbm_iconify_active_unpressed->base,
|
||||
full_width - BUTTON_WIDTH * 3);
|
||||
add_scene_button(&subtree->parts, LAB_SSD_BUTTON_MAXIMIZE, parent,
|
||||
color, &theme->xbm_maximize_active_unpressed->base,
|
||||
full_width - BUTTON_WIDTH * 2);
|
||||
add_scene_button_corner(&subtree->parts, LAB_SSD_BUTTON_CLOSE, parent,
|
||||
corner_top_right, &theme->xbm_close_active_unpressed->base,
|
||||
full_width - BUTTON_WIDTH * 1);
|
||||
} FOR_EACH_END
|
||||
ssd_update_title(view);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_direct_child(struct wlr_scene_node *node, struct ssd_sub_tree *subtree)
|
||||
{
|
||||
return node->parent == &subtree->tree->node;
|
||||
}
|
||||
|
||||
void
|
||||
ssd_titlebar_update(struct view *view)
|
||||
{
|
||||
int width = view->w;
|
||||
if (width == view->ssd.state.width) {
|
||||
return;
|
||||
}
|
||||
int full_width = width + 2 * view->server->theme->border_width;
|
||||
|
||||
struct ssd_part *part;
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
wl_list_for_each(part, &subtree->parts, link) {
|
||||
switch (part->type) {
|
||||
case LAB_SSD_PART_TITLEBAR:
|
||||
wlr_scene_rect_set_size(lab_wlr_scene_get_rect(part->node),
|
||||
full_width - BUTTON_WIDTH * BUTTON_COUNT, SSD_HEIGHT);
|
||||
continue;
|
||||
case LAB_SSD_BUTTON_ICONIFY:
|
||||
if (is_direct_child(part->node, subtree)) {
|
||||
wlr_scene_node_set_position(part->node,
|
||||
full_width - BUTTON_WIDTH * 3, 0);
|
||||
}
|
||||
continue;
|
||||
case LAB_SSD_BUTTON_MAXIMIZE:
|
||||
if (is_direct_child(part->node, subtree)) {
|
||||
wlr_scene_node_set_position(part->node,
|
||||
full_width - BUTTON_WIDTH * 2, 0);
|
||||
}
|
||||
continue;
|
||||
case LAB_SSD_BUTTON_CLOSE:
|
||||
if (is_direct_child(part->node, subtree)) {
|
||||
wlr_scene_node_set_position(part->node,
|
||||
full_width - BUTTON_WIDTH * 1, 0);
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} FOR_EACH_END
|
||||
ssd_update_title(view);
|
||||
}
|
||||
|
||||
void
|
||||
ssd_titlebar_destroy(struct view *view)
|
||||
{
|
||||
if (!view->ssd.titlebar.active.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
ssd_destroy_parts(&subtree->parts);
|
||||
wlr_scene_node_destroy(&subtree->tree->node);
|
||||
subtree->tree = NULL;
|
||||
} FOR_EACH_END
|
||||
|
||||
if (view->ssd.state.title.text) {
|
||||
free(view->ssd.state.title.text);
|
||||
view->ssd.state.title.text = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For ssd_update_title* we do not early out because
|
||||
* .active and .inactive may result in different sizes
|
||||
* of the title (font family/size) or background of
|
||||
* the title (different button/border width).
|
||||
*/
|
||||
|
||||
static void
|
||||
ssd_update_title_positions(struct view *view)
|
||||
{
|
||||
struct theme *theme = view->server->theme;
|
||||
int width = view->w;
|
||||
int full_width = width + 2 * view->server->theme->border_width;
|
||||
|
||||
int x, y;
|
||||
struct wlr_scene_rect *rect;
|
||||
struct ssd_part *part;
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLE);
|
||||
if (!part) {
|
||||
/* view->surface never been mapped */
|
||||
continue;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
y = (SSD_HEIGHT - part->buffer->base.height) / 2;
|
||||
rect = lab_wlr_scene_get_rect(part->node->parent);
|
||||
if (rect->width <= 0) {
|
||||
wlr_scene_node_set_position(part->node, x, y);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (theme->window_label_text_justify == LAB_JUSTIFY_CENTER) {
|
||||
if (part->buffer->base.width + BUTTON_WIDTH * 2 <= rect->width) {
|
||||
/* Center based on the full width */
|
||||
x = (full_width - part->buffer->base.width) / 2;
|
||||
x -= BUTTON_WIDTH;
|
||||
} else {
|
||||
/*
|
||||
* Center based on the width between the buttons.
|
||||
* Title jumps around once this is hit but its still
|
||||
* better than to hide behind the buttons on the right.
|
||||
*/
|
||||
x = (rect->width - part->buffer->base.width) / 2;
|
||||
}
|
||||
} else if (theme->window_label_text_justify == LAB_JUSTIFY_RIGHT) {
|
||||
x = rect->width - part->buffer->base.width;
|
||||
} else if (theme->window_label_text_justify == LAB_JUSTIFY_LEFT) {
|
||||
/* TODO: maybe add some theme x padding here? */
|
||||
}
|
||||
wlr_scene_node_set_position(part->node, x, y);
|
||||
} FOR_EACH_END
|
||||
}
|
||||
|
||||
void
|
||||
ssd_update_title(struct view *view)
|
||||
{
|
||||
if (!view->ssd.tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *title = (char *)view_get_string_prop(view, "title");
|
||||
if (!title || !*title) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct theme *theme = view->server->theme;
|
||||
struct ssd_state_title *state = &view->ssd.state.title;
|
||||
bool title_unchanged = state->text && !strcmp(title, state->text);
|
||||
|
||||
/* TODO: Do we only have active window fonts? */
|
||||
struct font font = {
|
||||
.name = rc.font_name_activewindow,
|
||||
.size = rc.font_size_activewindow,
|
||||
};
|
||||
|
||||
float *text_color;
|
||||
struct wlr_scene_rect *rect;
|
||||
struct ssd_part *part;
|
||||
struct ssd_part *parent_part;
|
||||
struct ssd_sub_tree *subtree;
|
||||
struct ssd_state_title_width *dstate;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
parent_part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
|
||||
assert(parent_part);
|
||||
|
||||
if (subtree == &view->ssd.titlebar.active) {
|
||||
dstate = &state->active;
|
||||
text_color = theme->window_active_label_text_color;
|
||||
} else {
|
||||
dstate = &state->inactive;
|
||||
text_color = theme->window_inactive_label_text_color;
|
||||
}
|
||||
|
||||
rect = lab_wlr_scene_get_rect(parent_part->node);
|
||||
if (rect->width <= 0) {
|
||||
dstate->truncated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (title_unchanged
|
||||
&& !dstate->truncated && dstate->width < rect->width) {
|
||||
/* title the same + we don't need to resize title */
|
||||
continue;
|
||||
}
|
||||
|
||||
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLE);
|
||||
if (!part) {
|
||||
part = add_scene_part(&subtree->parts, LAB_SSD_PART_TITLE);
|
||||
}
|
||||
if (part->node) {
|
||||
wlr_scene_node_destroy(part->node);
|
||||
}
|
||||
font_buffer_update(
|
||||
&part->buffer, rect->width, title, &font, text_color);
|
||||
part->node = &wlr_scene_buffer_create(
|
||||
parent_part->node, &part->buffer->base)->node;
|
||||
dstate->width = part->buffer->base.width;
|
||||
dstate->truncated = rect->width <= dstate->width;
|
||||
} FOR_EACH_END
|
||||
|
||||
if (!title_unchanged) {
|
||||
if (state->text) {
|
||||
free(state->text);
|
||||
}
|
||||
state->text = strdup(title);
|
||||
}
|
||||
ssd_update_title_positions(view);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the wlr_scene_node for hover effect.
|
||||
* To disable the hover effect later on just call
|
||||
* wlr_scene_node_set_enabled(node, false).
|
||||
*/
|
||||
struct wlr_scene_node *
|
||||
ssd_button_hover_enable(struct view *view, enum ssd_part_type type)
|
||||
{
|
||||
if (!view->ssd.tree) {
|
||||
wlr_log(WLR_ERROR, "%s() for destroyed view", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(ssd_is_button(type));
|
||||
struct ssd_part *part;
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(view, subtree) {
|
||||
if (subtree->tree->node.state.enabled) {
|
||||
part = ssd_get_part(&subtree->parts, type);
|
||||
if (!part) {
|
||||
wlr_log(WLR_ERROR, "hover enable failed to find button");
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &part->node->state.children, state.link) {
|
||||
if (child->type == WLR_SCENE_NODE_RECT) {
|
||||
wlr_scene_node_set_enabled(child, true);
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
} FOR_EACH_END
|
||||
|
||||
wlr_log(WLR_ERROR, "hover enable failed to find button");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef FOR_EACH_STATE
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020 the sway authors
|
||||
* This file is only needed in support of tracking damage
|
||||
*/
|
||||
|
||||
#include "labwc.h"
|
||||
|
||||
static void
|
||||
subsurface_handle_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view_subsurface *subsurface = wl_container_of(listener,
|
||||
subsurface, destroy);
|
||||
struct view_child *view_child = (struct view_child *)subsurface;
|
||||
if (!view_child) {
|
||||
return;
|
||||
}
|
||||
wl_list_remove(&subsurface->destroy.link);
|
||||
view_child_finish(&subsurface->view_child);
|
||||
free(subsurface);
|
||||
}
|
||||
|
||||
void
|
||||
view_subsurface_create(struct view *view, struct wlr_subsurface *wlr_subsurface)
|
||||
{
|
||||
struct view_subsurface *subsurface =
|
||||
calloc(1, sizeof(struct view_subsurface));
|
||||
if (!subsurface) {
|
||||
return;
|
||||
}
|
||||
view_child_init(&subsurface->view_child, view, wlr_subsurface->surface);
|
||||
subsurface->subsurface = wlr_subsurface;
|
||||
|
||||
subsurface->destroy.notify = subsurface_handle_destroy;
|
||||
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
|
||||
}
|
||||
47
src/theme.c
47
src/theme.c
|
|
@ -25,6 +25,8 @@
|
|||
#include "config/rcxml.h"
|
||||
#include "theme.h"
|
||||
#include "xbm/xbm.h"
|
||||
#include "buffer.h"
|
||||
#include "ssd.h"
|
||||
|
||||
static int
|
||||
hex_to_dec(char c)
|
||||
|
|
@ -336,8 +338,8 @@ set_source(cairo_t *cairo, float *c)
|
|||
cairo_set_source_rgba(cairo, c[0], c[1], c[2], c[3]);
|
||||
}
|
||||
|
||||
static struct wlr_texture *
|
||||
rounded_rect(struct wlr_renderer *renderer, struct rounded_corner_ctx *ctx)
|
||||
static struct lab_data_buffer *
|
||||
rounded_rect(struct rounded_corner_ctx *ctx)
|
||||
{
|
||||
/* 1 degree in radians (=2π/360) */
|
||||
double deg = 0.017453292519943295;
|
||||
|
|
@ -350,9 +352,12 @@ rounded_rect(struct wlr_renderer *renderer, struct rounded_corner_ctx *ctx)
|
|||
double h = ctx->box->height;
|
||||
double r = ctx->radius;
|
||||
|
||||
cairo_surface_t *surf =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
|
||||
cairo_t *cairo = cairo_create(surf);
|
||||
struct lab_data_buffer *buffer;
|
||||
/* TODO: scale */
|
||||
buffer = buffer_create_cairo(w, h, 1, true);
|
||||
|
||||
cairo_t *cairo = buffer->cairo;
|
||||
cairo_surface_t *surf = cairo_get_target(cairo);
|
||||
|
||||
/* set transparent background */
|
||||
cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
|
||||
|
|
@ -405,28 +410,19 @@ rounded_rect(struct wlr_renderer *renderer, struct rounded_corner_ctx *ctx)
|
|||
wlr_log(WLR_ERROR, "unknown corner type");
|
||||
}
|
||||
cairo_stroke(cairo);
|
||||
|
||||
/* convert to wlr_texture */
|
||||
cairo_surface_flush(surf);
|
||||
unsigned char *data = cairo_image_surface_get_data(surf);
|
||||
struct wlr_texture *texture = wlr_texture_from_pixels(renderer,
|
||||
DRM_FORMAT_ARGB8888, cairo_image_surface_get_stride(surf),
|
||||
w, h, data);
|
||||
|
||||
cairo_destroy(cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
return texture;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
create_corners(struct theme *theme, struct wlr_renderer *renderer)
|
||||
create_corners(struct theme *theme)
|
||||
{
|
||||
int corner_square = theme->title_height + theme->border_width;
|
||||
struct wlr_box box = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = corner_square,
|
||||
.height = corner_square,
|
||||
.width = BUTTON_WIDTH,
|
||||
.height = SSD_HEIGHT,
|
||||
};
|
||||
|
||||
struct rounded_corner_ctx ctx = {
|
||||
|
|
@ -437,20 +433,20 @@ create_corners(struct theme *theme, struct wlr_renderer *renderer)
|
|||
.border_color = theme->window_active_border_color,
|
||||
.corner = LAB_CORNER_TOP_LEFT,
|
||||
};
|
||||
theme->corner_top_left_active_normal = rounded_rect(renderer, &ctx);
|
||||
theme->corner_top_left_active_normal = rounded_rect(&ctx);
|
||||
|
||||
ctx.fill_color = theme->window_inactive_title_bg_color,
|
||||
ctx.border_color = theme->window_inactive_border_color,
|
||||
theme->corner_top_left_inactive_normal = rounded_rect(renderer, &ctx);
|
||||
theme->corner_top_left_inactive_normal = rounded_rect(&ctx);
|
||||
|
||||
ctx.corner = LAB_CORNER_TOP_RIGHT;
|
||||
ctx.fill_color = theme->window_active_title_bg_color,
|
||||
ctx.border_color = theme->window_active_border_color,
|
||||
theme->corner_top_right_active_normal = rounded_rect(renderer, &ctx);
|
||||
theme->corner_top_right_active_normal = rounded_rect(&ctx);
|
||||
|
||||
ctx.fill_color = theme->window_inactive_title_bg_color,
|
||||
ctx.border_color = theme->window_inactive_border_color,
|
||||
theme->corner_top_right_inactive_normal = rounded_rect(renderer, &ctx);
|
||||
theme->corner_top_right_inactive_normal = rounded_rect(&ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -480,8 +476,7 @@ post_processing(struct theme *theme)
|
|||
}
|
||||
|
||||
void
|
||||
theme_init(struct theme *theme, struct wlr_renderer *renderer,
|
||||
const char *theme_name)
|
||||
theme_init(struct theme *theme, const char *theme_name)
|
||||
{
|
||||
/*
|
||||
* Set some default values. This is particularly important on
|
||||
|
|
@ -491,8 +486,8 @@ theme_init(struct theme *theme, struct wlr_renderer *renderer,
|
|||
|
||||
theme_read(theme, theme_name);
|
||||
post_processing(theme);
|
||||
create_corners(theme, renderer);
|
||||
xbm_load(theme, renderer);
|
||||
create_corners(theme);
|
||||
xbm_load(theme);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020 the sway authors
|
||||
* This file is only needed in support of tracking damage
|
||||
*/
|
||||
|
||||
#include "labwc.h"
|
||||
|
||||
static void
|
||||
view_child_handle_commit(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view_child *child = wl_container_of(listener, child, commit);
|
||||
damage_all_outputs(child->parent->server);
|
||||
}
|
||||
|
||||
static void
|
||||
view_child_handle_new_subsurface(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view_child *child;
|
||||
child = wl_container_of(listener, child, new_subsurface);
|
||||
struct wlr_subsurface *wlr_subsurface = data;
|
||||
view_subsurface_create(child->parent, wlr_subsurface);
|
||||
}
|
||||
|
||||
void
|
||||
view_child_finish(struct view_child *child)
|
||||
{
|
||||
wl_list_remove(&child->commit.link);
|
||||
wl_list_remove(&child->new_subsurface.link);
|
||||
}
|
||||
|
||||
void
|
||||
view_child_init(struct view_child *child, struct view *view,
|
||||
struct wlr_surface *wlr_surface)
|
||||
{
|
||||
child->parent = view;
|
||||
child->surface = wlr_surface;
|
||||
child->commit.notify = view_child_handle_commit;
|
||||
wl_signal_add(&wlr_surface->events.commit, &child->commit);
|
||||
child->new_subsurface.notify = view_child_handle_new_subsurface;
|
||||
wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface);
|
||||
}
|
||||
|
|
@ -12,6 +12,4 @@ view_impl_map(struct view *view)
|
|||
|
||||
view_update_title(view);
|
||||
view_update_app_id(view);
|
||||
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
|
|
|||
47
src/view.c
47
src/view.c
|
|
@ -7,6 +7,9 @@
|
|||
void
|
||||
view_set_activated(struct view *view, bool activated)
|
||||
{
|
||||
if (view->ssd.enabled) {
|
||||
ssd_set_active(view);
|
||||
}
|
||||
if (view->impl->set_activated) {
|
||||
view->impl->set_activated(view, activated);
|
||||
}
|
||||
|
|
@ -31,6 +34,7 @@ view_move(struct view *view, double x, double y)
|
|||
view->impl->move(view, x, y);
|
||||
}
|
||||
view_discover_output(view);
|
||||
wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -254,7 +258,7 @@ view_toggle_decorations(struct view *view)
|
|||
{
|
||||
if (!view->fullscreen) {
|
||||
view->ssd.enabled = !view->ssd.enabled;
|
||||
ssd_update_geometry(view, true);
|
||||
ssd_update_geometry(view);
|
||||
if (view->maximized) {
|
||||
view_apply_maximized_geometry(view);
|
||||
}
|
||||
|
|
@ -266,7 +270,7 @@ view_set_decorations(struct view *view, bool decorations)
|
|||
{
|
||||
if (view->ssd.enabled != decorations && !view->fullscreen) {
|
||||
view->ssd.enabled = decorations;
|
||||
ssd_update_geometry(view, true);
|
||||
ssd_update_geometry(view);
|
||||
if (view->maximized) {
|
||||
view_apply_maximized_geometry(view);
|
||||
}
|
||||
|
|
@ -341,24 +345,6 @@ view_adjust_for_layout_change(struct view *view)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator,
|
||||
void *user_data)
|
||||
{
|
||||
if (view->impl->for_each_surface) {
|
||||
view->impl->for_each_surface(view, iterator, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
view_for_each_popup_surface(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *data)
|
||||
{
|
||||
if (view->impl->for_each_popup_surface) {
|
||||
view->impl->for_each_popup_surface(view, iterator, data);
|
||||
}
|
||||
}
|
||||
|
||||
struct border
|
||||
view_border(struct view *view)
|
||||
{
|
||||
|
|
@ -371,27 +357,9 @@ view_border(struct view *view)
|
|||
return border;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_enter_for_each_surface(struct wlr_surface *surface, int sx, int sy,
|
||||
void *user_data)
|
||||
{
|
||||
struct wlr_output *wlr_output = user_data;
|
||||
wlr_surface_send_enter(surface, wlr_output);
|
||||
}
|
||||
|
||||
static void
|
||||
surface_leave_for_each_surface(struct wlr_surface *surface, int sx, int sy,
|
||||
void *user_data)
|
||||
{
|
||||
struct wlr_output *wlr_output = user_data;
|
||||
wlr_surface_send_leave(surface, wlr_output);
|
||||
}
|
||||
|
||||
static void
|
||||
view_output_enter(struct view *view, struct wlr_output *wlr_output)
|
||||
{
|
||||
view_for_each_surface(view, surface_enter_for_each_surface,
|
||||
wlr_output);
|
||||
if (view->toplevel_handle) {
|
||||
wlr_foreign_toplevel_handle_v1_output_enter(
|
||||
view->toplevel_handle, wlr_output);
|
||||
|
|
@ -401,8 +369,6 @@ view_output_enter(struct view *view, struct wlr_output *wlr_output)
|
|||
static void
|
||||
view_output_leave(struct view *view, struct wlr_output *wlr_output)
|
||||
{
|
||||
view_for_each_surface(view, surface_leave_for_each_surface,
|
||||
wlr_output);
|
||||
if (view->toplevel_handle) {
|
||||
wlr_foreign_toplevel_handle_v1_output_leave(
|
||||
view->toplevel_handle, wlr_output);
|
||||
|
|
@ -641,7 +607,6 @@ view_update_title(struct view *view)
|
|||
}
|
||||
ssd_update_title(view);
|
||||
wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, title);
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "theme.h"
|
||||
#include "xbm/parse.h"
|
||||
#include "xbm/xbm.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* built-in 6x6 buttons */
|
||||
char menu_button_normal[] = { 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 };
|
||||
|
|
@ -23,28 +24,6 @@ char max_button_normal[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
|
|||
char max_button_toggled[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f };
|
||||
char close_button_normal[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 };
|
||||
|
||||
static struct wlr_texture *
|
||||
texture_from_pixmap(struct wlr_renderer *renderer, struct pixmap *pixmap)
|
||||
{
|
||||
if (!pixmap) {
|
||||
return NULL;
|
||||
}
|
||||
return wlr_texture_from_pixels(renderer, DRM_FORMAT_ARGB8888,
|
||||
pixmap->width * 4, pixmap->width,
|
||||
pixmap->height, pixmap->data);
|
||||
}
|
||||
|
||||
static struct wlr_texture *
|
||||
texture_from_builtin(struct wlr_renderer *renderer, const char *button)
|
||||
{
|
||||
struct pixmap pixmap = parse_xbm_builtin(button, 6);
|
||||
struct wlr_texture *texture = texture_from_pixmap(renderer, &pixmap);
|
||||
if (pixmap.data) {
|
||||
free(pixmap.data);
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
static char *
|
||||
xbm_path(const char *button)
|
||||
{
|
||||
|
|
@ -55,62 +34,59 @@ xbm_path(const char *button)
|
|||
}
|
||||
|
||||
static void
|
||||
load_button(struct wlr_renderer *renderer, const char *filename,
|
||||
struct wlr_texture **texture, char *button)
|
||||
load_button(const char *filename, struct lab_data_buffer **buffer, char *button)
|
||||
{
|
||||
if (*texture) {
|
||||
wlr_texture_destroy(*texture);
|
||||
*texture = NULL;
|
||||
struct pixmap pixmap = {0};
|
||||
if (*buffer) {
|
||||
wlr_buffer_drop(&(*buffer)->base);
|
||||
*buffer = NULL;
|
||||
}
|
||||
|
||||
/* Read file into memory as it's easier to tokenzie that way */
|
||||
char *buffer = grab_file(xbm_path(filename));
|
||||
if (!buffer) {
|
||||
goto out;
|
||||
char *token_buffer = grab_file(xbm_path(filename));
|
||||
if (token_buffer) {
|
||||
struct token *tokens = tokenize_xbm(token_buffer);
|
||||
free(token_buffer);
|
||||
pixmap = parse_xbm_tokens(tokens);
|
||||
if (tokens) {
|
||||
free(tokens);
|
||||
}
|
||||
}
|
||||
if (!pixmap.data) {
|
||||
pixmap = parse_xbm_builtin(button, 6);
|
||||
}
|
||||
struct token *tokens = tokenize_xbm(buffer);
|
||||
free(buffer);
|
||||
|
||||
struct pixmap pixmap = parse_xbm_tokens(tokens);
|
||||
*texture = texture_from_pixmap(renderer, &pixmap);
|
||||
if (tokens) {
|
||||
free(tokens);
|
||||
}
|
||||
if (pixmap.data) {
|
||||
free(pixmap.data);
|
||||
}
|
||||
out:
|
||||
if (!(*texture)) {
|
||||
*texture = texture_from_builtin(renderer, button);
|
||||
}
|
||||
/* Create buffer with free_on_destroy being true */
|
||||
*buffer = buffer_create_wrap(pixmap.data, pixmap.width, pixmap.height,
|
||||
pixmap.width * 4, true);
|
||||
}
|
||||
|
||||
void
|
||||
xbm_load(struct theme *theme, struct wlr_renderer *r)
|
||||
xbm_load(struct theme *theme)
|
||||
{
|
||||
parse_set_color(theme->window_active_button_menu_unpressed_image_color);
|
||||
load_button(r, "menu.xbm", &theme->xbm_menu_active_unpressed,
|
||||
load_button("menu.xbm", &theme->xbm_menu_active_unpressed,
|
||||
menu_button_normal);
|
||||
parse_set_color(theme->window_active_button_iconify_unpressed_image_color);
|
||||
load_button(r, "iconify.xbm", &theme->xbm_iconify_active_unpressed,
|
||||
load_button("iconify.xbm", &theme->xbm_iconify_active_unpressed,
|
||||
iconify_button_normal);
|
||||
parse_set_color(theme->window_active_button_max_unpressed_image_color);
|
||||
load_button(r, "max.xbm", &theme->xbm_maximize_active_unpressed,
|
||||
load_button("max.xbm", &theme->xbm_maximize_active_unpressed,
|
||||
max_button_normal);
|
||||
parse_set_color(theme->window_active_button_close_unpressed_image_color);
|
||||
load_button(r, "close.xbm", &theme->xbm_close_active_unpressed,
|
||||
load_button("close.xbm", &theme->xbm_close_active_unpressed,
|
||||
close_button_normal);
|
||||
|
||||
parse_set_color(theme->window_inactive_button_menu_unpressed_image_color);
|
||||
load_button(r, "menu.xbm", &theme->xbm_menu_inactive_unpressed,
|
||||
load_button("menu.xbm", &theme->xbm_menu_inactive_unpressed,
|
||||
menu_button_normal);
|
||||
parse_set_color(theme->window_inactive_button_iconify_unpressed_image_color);
|
||||
load_button(r, "iconify.xbm", &theme->xbm_iconify_inactive_unpressed,
|
||||
load_button("iconify.xbm", &theme->xbm_iconify_inactive_unpressed,
|
||||
iconify_button_normal);
|
||||
parse_set_color(theme->window_inactive_button_max_unpressed_image_color);
|
||||
load_button(r, "max.xbm", &theme->xbm_maximize_inactive_unpressed,
|
||||
load_button("max.xbm", &theme->xbm_maximize_inactive_unpressed,
|
||||
max_button_normal);
|
||||
parse_set_color(theme->window_inactive_button_close_unpressed_image_color);
|
||||
load_button(r, "close.xbm", &theme->xbm_close_inactive_unpressed,
|
||||
load_button("close.xbm", &theme->xbm_close_inactive_unpressed,
|
||||
close_button_normal);
|
||||
}
|
||||
|
|
|
|||
109
src/xdg-popup.c
109
src/xdg-popup.c
|
|
@ -3,47 +3,54 @@
|
|||
* Copyright (C) 2020 the sway authors
|
||||
*
|
||||
* This file is only needed in support of
|
||||
* - tracking damage
|
||||
* - unconstraining XDG popups
|
||||
* - keeping non-layer-shell xdg-popups outside the layers.c code
|
||||
*/
|
||||
|
||||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
|
||||
struct view_child {
|
||||
struct wlr_surface *surface;
|
||||
struct view *parent;
|
||||
};
|
||||
|
||||
struct xdg_popup {
|
||||
struct view_child view_child;
|
||||
struct wlr_xdg_popup *wlr_popup;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener new_popup;
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_popup_destroy(struct view_child *view_child)
|
||||
popup_unconstrain(struct view *view, struct wlr_xdg_popup *popup)
|
||||
{
|
||||
if (!view_child) {
|
||||
return;
|
||||
}
|
||||
struct xdg_popup *popup = (struct xdg_popup *)view_child;
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->map.link);
|
||||
wl_list_remove(&popup->unmap.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
view_child_finish(&popup->view_child);
|
||||
free(popup);
|
||||
}
|
||||
struct server *server = view->server;
|
||||
struct wlr_box *popup_box = &popup->geometry;
|
||||
struct wlr_output_layout *output_layout = server->output_layout;
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
output_layout, view->x + popup_box->x, view->y + popup_box->y);
|
||||
|
||||
static void
|
||||
handle_xdg_popup_map(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct xdg_popup *popup = wl_container_of(listener, popup, map);
|
||||
damage_all_outputs(popup->view_child.parent->server);
|
||||
}
|
||||
struct wlr_box output_box;
|
||||
wlr_output_layout_get_box(output_layout, wlr_output, &output_box);
|
||||
|
||||
static void
|
||||
handle_xdg_popup_unmap(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct xdg_popup *popup = wl_container_of(listener, popup, unmap);
|
||||
damage_all_outputs(popup->view_child.parent->server);
|
||||
struct wlr_box output_toplevel_box = {
|
||||
.x = output_box.x - view->x,
|
||||
.y = output_box.y - view->y,
|
||||
.width = output_box.width,
|
||||
.height = output_box.height,
|
||||
};
|
||||
wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct xdg_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
struct view_child *view_child = (struct view_child *)popup;
|
||||
xdg_popup_destroy(view_child);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -54,28 +61,6 @@ popup_handle_new_xdg_popup(struct wl_listener *listener, void *data)
|
|||
xdg_popup_create(popup->view_child.parent, wlr_popup);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_unconstrain(struct xdg_popup *popup)
|
||||
{
|
||||
struct view *view = popup->view_child.parent;
|
||||
struct server *server = view->server;
|
||||
struct wlr_box *popup_box = &popup->wlr_popup->geometry;
|
||||
struct wlr_output_layout *output_layout = server->output_layout;
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
output_layout, view->x + popup_box->x, view->y + popup_box->y);
|
||||
struct wlr_box *output_box = wlr_output_layout_get_box(
|
||||
output_layout, wlr_output);
|
||||
|
||||
struct wlr_box output_toplevel_box = {
|
||||
.x = output_box->x - view->x,
|
||||
.y = output_box->y - view->y,
|
||||
.width = output_box->width,
|
||||
.height = output_box->height,
|
||||
};
|
||||
wlr_xdg_popup_unconstrain_from_box(
|
||||
popup->wlr_popup, &output_toplevel_box);
|
||||
}
|
||||
|
||||
void
|
||||
xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup)
|
||||
{
|
||||
|
|
@ -85,16 +70,32 @@ xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup)
|
|||
}
|
||||
|
||||
popup->wlr_popup = wlr_popup;
|
||||
view_child_init(&popup->view_child, view, wlr_popup->base->surface);
|
||||
popup->view_child.parent = view;
|
||||
popup->view_child.surface = wlr_popup->base->surface;
|
||||
|
||||
popup->destroy.notify = handle_xdg_popup_destroy;
|
||||
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||
popup->map.notify = handle_xdg_popup_map;
|
||||
wl_signal_add(&wlr_popup->base->events.map, &popup->map);
|
||||
popup->unmap.notify = handle_xdg_popup_unmap;
|
||||
wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
|
||||
popup->new_popup.notify = popup_handle_new_xdg_popup;
|
||||
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||
|
||||
popup_unconstrain(popup);
|
||||
/*
|
||||
* We must add xdg popups to the scene graph so they get rendered. The
|
||||
* wlroots scene graph provides a helper for this, but to use it we must
|
||||
* provide the proper parent scene node of the xdg popup. To enable
|
||||
* this, we always set the user data field of xdg_surfaces to the
|
||||
* corresponding scene node.
|
||||
*/
|
||||
if (!wlr_surface_is_xdg_surface(wlr_popup->parent)) {
|
||||
wlr_log(WLR_ERROR, "xdg_surface is not xdg");
|
||||
return;
|
||||
}
|
||||
struct wlr_xdg_surface *parent =
|
||||
wlr_xdg_surface_from_wlr_surface(wlr_popup->parent);
|
||||
struct wlr_scene_node *parent_node = parent->surface->data;
|
||||
wlr_popup->base->surface->data =
|
||||
wlr_scene_xdg_surface_create(parent_node, wlr_popup->base);
|
||||
node_descriptor_create(wlr_popup->base->surface->data,
|
||||
LAB_NODE_DESC_XDG_POPUP, view);
|
||||
|
||||
popup_unconstrain(view, wlr_popup);
|
||||
}
|
||||
|
|
|
|||
126
src/xdg.c
126
src/xdg.c
|
|
@ -1,12 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <assert.h>
|
||||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
|
||||
/*
|
||||
* xdg_popup_create() and view_subsurface_create() are only called for the
|
||||
* purposes of tracking damage.
|
||||
*/
|
||||
static void
|
||||
handle_new_xdg_popup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
@ -15,14 +12,6 @@ handle_new_xdg_popup(struct wl_listener *listener, void *data)
|
|||
xdg_popup_create(view, wlr_popup);
|
||||
}
|
||||
|
||||
static void
|
||||
new_subsurface_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view *view = wl_container_of(listener, view, new_subsurface);
|
||||
struct wlr_subsurface *wlr_subsurface = data;
|
||||
view_subsurface_create(view, wlr_subsurface);
|
||||
}
|
||||
|
||||
static bool
|
||||
has_ssd(struct view *view)
|
||||
{
|
||||
|
|
@ -70,8 +59,8 @@ handle_commit(struct wl_listener *listener, void *data)
|
|||
view->pending_move_resize.configure_serial = 0;
|
||||
}
|
||||
}
|
||||
ssd_update_geometry(view, false);
|
||||
damage_view_part(view);
|
||||
wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y);
|
||||
ssd_update_geometry(view);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -98,7 +87,11 @@ handle_destroy(struct wl_listener *listener, void *data)
|
|||
interactive_end(view);
|
||||
wl_list_remove(&view->link);
|
||||
wl_list_remove(&view->destroy.link);
|
||||
ssd_destroy(view);
|
||||
if (view->scene_tree) {
|
||||
ssd_destroy(view);
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
view->scene_tree = NULL;
|
||||
}
|
||||
free(view);
|
||||
}
|
||||
|
||||
|
|
@ -139,29 +132,23 @@ static void
|
|||
handle_request_minimize(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view *view = wl_container_of(listener, view, request_minimize);
|
||||
struct wlr_xdg_surface *surface = data;
|
||||
if (view) {
|
||||
view_minimize(view, surface->toplevel->requested.minimized);
|
||||
}
|
||||
view_minimize(view, view->xdg_surface->toplevel->requested.minimized);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request_maximize(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view *view = wl_container_of(listener, view, request_maximize);
|
||||
struct wlr_xdg_surface *surface = data;
|
||||
if (view) {
|
||||
view_maximize(view, surface->toplevel->requested.maximized);
|
||||
}
|
||||
|
||||
view_maximize(view, view->xdg_surface->toplevel->requested.maximized);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request_fullscreen(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct view *view = wl_container_of(listener, view, request_fullscreen);
|
||||
struct wlr_xdg_toplevel_set_fullscreen_event *e = data;
|
||||
view_set_fullscreen(view, e->fullscreen, e->output);
|
||||
view_set_fullscreen(view,
|
||||
view->xdg_surface->toplevel->requested.fullscreen,
|
||||
view->xdg_surface->toplevel->requested.fullscreen_output);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -194,15 +181,16 @@ xdg_toplevel_view_configure(struct view *view, struct wlr_box geo)
|
|||
view->pending_move_resize.width = MAX(geo.width, min_width);
|
||||
view->pending_move_resize.height = MAX(geo.height, min_height);
|
||||
|
||||
uint32_t serial = wlr_xdg_toplevel_set_size(view->xdg_surface,
|
||||
uint32_t serial = wlr_xdg_toplevel_set_size(view->xdg_surface->toplevel,
|
||||
(uint32_t)geo.width, (uint32_t)geo.height);
|
||||
if (serial > 0) {
|
||||
view->pending_move_resize.configure_serial = serial;
|
||||
} else if (view->pending_move_resize.configure_serial == 0) {
|
||||
view->x = geo.x;
|
||||
view->y = geo.y;
|
||||
ssd_update_geometry(view, false);
|
||||
damage_all_outputs(view->server);
|
||||
wlr_scene_node_set_position(&view->scene_tree->node,
|
||||
view->x, view->y);
|
||||
ssd_update_geometry(view);
|
||||
}
|
||||
}
|
||||
#undef MAX
|
||||
|
|
@ -212,28 +200,12 @@ xdg_toplevel_view_move(struct view *view, double x, double y)
|
|||
{
|
||||
view->x = x;
|
||||
view->y = y;
|
||||
ssd_update_geometry(view, false);
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_view_close(struct view *view)
|
||||
{
|
||||
wlr_xdg_toplevel_send_close(view->xdg_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_view_for_each_popup_surface(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *data)
|
||||
{
|
||||
wlr_xdg_surface_for_each_popup_surface(view->xdg_surface, iterator, data);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_view_for_each_surface(struct view *view,
|
||||
wlr_surface_iterator_func_t iterator, void *data)
|
||||
{
|
||||
wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, data);
|
||||
wlr_xdg_toplevel_send_close(view->xdg_surface->toplevel);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -248,7 +220,7 @@ update_padding(struct view *view)
|
|||
static void
|
||||
xdg_toplevel_view_maximize(struct view *view, bool maximized)
|
||||
{
|
||||
wlr_xdg_toplevel_set_maximized(view->xdg_surface, maximized);
|
||||
wlr_xdg_toplevel_set_maximized(view->xdg_surface->toplevel, maximized);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -256,14 +228,14 @@ xdg_toplevel_view_set_activated(struct view *view, bool activated)
|
|||
{
|
||||
struct wlr_xdg_surface *surface = view->xdg_surface;
|
||||
if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
|
||||
wlr_xdg_toplevel_set_activated(surface, activated);
|
||||
wlr_xdg_toplevel_set_activated(surface->toplevel, activated);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_view_set_fullscreen(struct view *view, bool fullscreen)
|
||||
{
|
||||
wlr_xdg_toplevel_set_fullscreen(view->xdg_surface, fullscreen);
|
||||
wlr_xdg_toplevel_set_fullscreen(view->xdg_surface->toplevel, fullscreen);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -277,7 +249,8 @@ parent_of(struct view *view)
|
|||
{
|
||||
struct view *p;
|
||||
wl_list_for_each (p, &view->server->views, link) {
|
||||
if (p->xdg_surface == view->xdg_surface->toplevel->parent) {
|
||||
if (p->xdg_surface->toplevel
|
||||
== view->xdg_surface->toplevel->parent) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
|
@ -328,8 +301,12 @@ xdg_toplevel_view_get_string_prop(struct view *view, const char *prop)
|
|||
static void
|
||||
xdg_toplevel_view_map(struct view *view)
|
||||
{
|
||||
if (view->mapped) {
|
||||
return;
|
||||
}
|
||||
view->mapped = true;
|
||||
view->surface = view->xdg_surface->surface;
|
||||
wlr_scene_node_set_enabled(&view->scene_tree->node, true);
|
||||
if (!view->been_mapped) {
|
||||
struct wlr_xdg_toplevel_requested *requested =
|
||||
&view->xdg_surface->toplevel->requested;
|
||||
|
|
@ -352,16 +329,6 @@ xdg_toplevel_view_map(struct view *view)
|
|||
if (!view->maximized && !view->fullscreen) {
|
||||
position_xdg_toplevel_view(view);
|
||||
}
|
||||
|
||||
struct wlr_subsurface *subsurface;
|
||||
wl_list_for_each(subsurface, &view->surface->current.subsurfaces_below,
|
||||
current.link) {
|
||||
view_subsurface_create(view, subsurface);
|
||||
}
|
||||
wl_list_for_each(subsurface, &view->surface->current.subsurfaces_above,
|
||||
current.link) {
|
||||
view_subsurface_create(view, subsurface);
|
||||
}
|
||||
view_discover_output(view);
|
||||
|
||||
view->been_mapped = true;
|
||||
|
|
@ -370,9 +337,6 @@ xdg_toplevel_view_map(struct view *view)
|
|||
view->commit.notify = handle_commit;
|
||||
wl_signal_add(&view->xdg_surface->surface->events.commit,
|
||||
&view->commit);
|
||||
view->new_subsurface.notify = new_subsurface_notify;
|
||||
wl_signal_add(&view->surface->events.new_subsurface,
|
||||
&view->new_subsurface);
|
||||
|
||||
view_impl_map(view);
|
||||
}
|
||||
|
|
@ -382,9 +346,8 @@ xdg_toplevel_view_unmap(struct view *view)
|
|||
{
|
||||
if (view->mapped) {
|
||||
view->mapped = false;
|
||||
damage_all_outputs(view->server);
|
||||
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
||||
wl_list_remove(&view->commit.link);
|
||||
wl_list_remove(&view->new_subsurface.link);
|
||||
desktop_focus_topmost_mapped_view(view->server);
|
||||
}
|
||||
}
|
||||
|
|
@ -392,8 +355,6 @@ xdg_toplevel_view_unmap(struct view *view)
|
|||
static const struct view_impl xdg_toplevel_view_impl = {
|
||||
.configure = xdg_toplevel_view_configure,
|
||||
.close = xdg_toplevel_view_close,
|
||||
.for_each_popup_surface = xdg_toplevel_view_for_each_popup_surface,
|
||||
.for_each_surface = xdg_toplevel_view_for_each_surface,
|
||||
.get_string_prop = xdg_toplevel_view_get_string_prop,
|
||||
.map = xdg_toplevel_view_map,
|
||||
.move = xdg_toplevel_view_move,
|
||||
|
|
@ -403,15 +364,28 @@ static const struct view_impl xdg_toplevel_view_impl = {
|
|||
.maximize = xdg_toplevel_view_maximize,
|
||||
};
|
||||
|
||||
/*
|
||||
* We use the following struct user_data pointers:
|
||||
* - wlr_xdg_surface->data = view
|
||||
* for the wlr_xdg_toplevel_decoration_v1 implementation
|
||||
* - wlr_surface->data = scene_node
|
||||
* to help the popups find their parent nodes
|
||||
*/
|
||||
void
|
||||
xdg_surface_new(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct server *server =
|
||||
wl_container_of(listener, server, new_xdg_surface);
|
||||
struct wlr_xdg_surface *xdg_surface = data;
|
||||
|
||||
/*
|
||||
* We deal with popups in xdg-popup.c and layers.c as they have to be
|
||||
* treated differently
|
||||
*/
|
||||
if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_xdg_surface_ping(xdg_surface);
|
||||
|
||||
struct view *view = calloc(1, sizeof(struct view));
|
||||
|
|
@ -419,10 +393,26 @@ xdg_surface_new(struct wl_listener *listener, void *data)
|
|||
view->type = LAB_XDG_SHELL_VIEW;
|
||||
view->impl = &xdg_toplevel_view_impl;
|
||||
view->xdg_surface = xdg_surface;
|
||||
wl_list_init(&view->ssd.parts);
|
||||
|
||||
view->scene_tree = wlr_scene_tree_create(&view->server->view_tree->node);
|
||||
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
||||
|
||||
view->scene_node = wlr_scene_xdg_surface_create(
|
||||
&view->scene_tree->node, view->xdg_surface);
|
||||
if (!view->scene_node) {
|
||||
/* TODO: might need further clean up */
|
||||
wl_resource_post_no_memory(view->surface->resource);
|
||||
return;
|
||||
}
|
||||
node_descriptor_create(&view->scene_tree->node,
|
||||
LAB_NODE_DESC_VIEW, view);
|
||||
|
||||
/* In support of xdg_toplevel_decoration */
|
||||
xdg_surface->data = view;
|
||||
|
||||
/* In support of xdg popups */
|
||||
xdg_surface->surface->data = view->scene_node;
|
||||
|
||||
view->map.notify = handle_map;
|
||||
wl_signal_add(&xdg_surface->events.map, &view->map);
|
||||
view->unmap.notify = handle_unmap;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,22 @@ unmanaged_handle_commit(struct wl_listener *listener, void *data)
|
|||
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
||||
unmanaged->lx = xsurface->x;
|
||||
unmanaged->ly = xsurface->y;
|
||||
damage_all_outputs(unmanaged->server);
|
||||
}
|
||||
|
||||
static struct view *
|
||||
parent_view(struct server *server, struct wlr_xwayland_surface *surface)
|
||||
{
|
||||
struct wlr_xwayland_surface *s = surface;
|
||||
while (s->parent) {
|
||||
s = s->parent;
|
||||
}
|
||||
struct view *view;
|
||||
wl_list_for_each(view, &server->views, link) {
|
||||
if (view->xwayland_surface == s) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -38,10 +53,24 @@ unmanaged_handle_map(struct wl_listener *listener, void *data)
|
|||
|
||||
unmanaged->lx = xsurface->x;
|
||||
unmanaged->ly = xsurface->y;
|
||||
damage_all_outputs(unmanaged->server);
|
||||
if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
|
||||
seat_focus_surface(&unmanaged->server->seat, xsurface->surface);
|
||||
}
|
||||
|
||||
int lx = unmanaged->lx;
|
||||
int ly = unmanaged->ly;
|
||||
struct wlr_scene_node *parent, *node;
|
||||
struct view *view = parent_view(unmanaged->server, xsurface);
|
||||
if (!view || !view->scene_node) {
|
||||
parent = &unmanaged->server->unmanaged_tree->node;
|
||||
} else {
|
||||
lx -= view->x;
|
||||
ly -= view->y;
|
||||
parent = &view->scene_tree->node;
|
||||
}
|
||||
/* node will be destroyed automatically once surface is destroyed */
|
||||
node = &wlr_scene_surface_create(parent, xsurface->surface)->node;
|
||||
wlr_scene_node_set_position(node, lx, ly);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -50,7 +79,6 @@ unmanaged_handle_unmap(struct wl_listener *listener, void *data)
|
|||
struct xwayland_unmanaged *unmanaged =
|
||||
wl_container_of(listener, unmanaged, unmap);
|
||||
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
||||
damage_all_outputs(unmanaged->server);
|
||||
wl_list_remove(&unmanaged->link);
|
||||
wl_list_remove(&unmanaged->commit.link);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <assert.h>
|
||||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
|
||||
static void
|
||||
|
|
@ -10,21 +11,37 @@ handle_commit(struct wl_listener *listener, void *data)
|
|||
assert(view->surface);
|
||||
|
||||
/* Must receive commit signal before accessing surface->current* */
|
||||
view->w = view->surface->current.width;
|
||||
view->h = view->surface->current.height;
|
||||
struct wlr_surface_state *state = &view->surface->current;
|
||||
struct view_pending_move_resize *pending = &view->pending_move_resize;
|
||||
|
||||
if (view->pending_move_resize.update_x) {
|
||||
view->x = view->pending_move_resize.x +
|
||||
view->pending_move_resize.width - view->w;
|
||||
view->pending_move_resize.update_x = false;
|
||||
bool move_pending = pending->update_x || pending->update_y;
|
||||
bool size_changed = view->w != state->width || view->h != state->height;
|
||||
|
||||
if (!move_pending && !size_changed) {
|
||||
return;
|
||||
}
|
||||
if (view->pending_move_resize.update_y) {
|
||||
view->y = view->pending_move_resize.y +
|
||||
view->pending_move_resize.height - view->h;
|
||||
view->pending_move_resize.update_y = false;
|
||||
|
||||
view->w = state->width;
|
||||
view->h = state->height;
|
||||
|
||||
if (pending->update_x) {
|
||||
/* Adjust x for queued up configure events */
|
||||
view->x = pending->x + pending->width - view->w;
|
||||
}
|
||||
ssd_update_geometry(view, false);
|
||||
damage_view_whole(view);
|
||||
if (pending->update_y) {
|
||||
/* Adjust y for queued up configure events */
|
||||
view->y = pending->y + pending->height - view->h;
|
||||
}
|
||||
if (move_pending) {
|
||||
wlr_scene_node_set_position(&view->scene_tree->node,
|
||||
view->x, view->y);
|
||||
}
|
||||
if ((int)pending->width == view->w && (int)pending->height == view->h) {
|
||||
/* We reached the end of all queued size changing configure events */
|
||||
pending->update_x = false;
|
||||
pending->update_y = false;
|
||||
}
|
||||
ssd_update_geometry(view);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -90,7 +107,11 @@ handle_destroy(struct wl_listener *listener, void *data)
|
|||
wl_list_remove(&view->request_configure.link);
|
||||
wl_list_remove(&view->request_maximize.link);
|
||||
wl_list_remove(&view->request_fullscreen.link);
|
||||
ssd_destroy(view);
|
||||
if (view->scene_tree) {
|
||||
ssd_destroy(view);
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
view->scene_tree = NULL;
|
||||
}
|
||||
free(view);
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +128,6 @@ handle_request_configure(struct wl_listener *listener, void *data)
|
|||
wlr_xwayland_surface_configure(view->xwayland_surface,
|
||||
event->x, event->y, MAX(event->width, min_width),
|
||||
MAX(event->height, min_height));
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
#undef MAX
|
||||
|
||||
|
|
@ -173,7 +193,6 @@ configure(struct view *view, struct wlr_box geo)
|
|||
wlr_xwayland_surface_configure(view->xwayland_surface, (int16_t)geo.x,
|
||||
(int16_t)geo.y, (uint16_t)geo.width,
|
||||
(uint16_t)geo.height);
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -184,25 +203,12 @@ move(struct view *view, double x, double y)
|
|||
struct wlr_xwayland_surface *s = view->xwayland_surface;
|
||||
wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y,
|
||||
(uint16_t)s->width, (uint16_t)s->height);
|
||||
ssd_update_geometry(view, false);
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
||||
static void
|
||||
_close(struct view *view)
|
||||
{
|
||||
wlr_xwayland_surface_close(view->xwayland_surface);
|
||||
damage_all_outputs(view->server);
|
||||
}
|
||||
|
||||
static void
|
||||
for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator,
|
||||
void *data)
|
||||
{
|
||||
if (!view->surface) {
|
||||
return;
|
||||
}
|
||||
wlr_surface_for_each_surface(view->surface, iterator, data);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -254,7 +260,11 @@ top_left_edge_boundary_check(struct view *view)
|
|||
static void
|
||||
map(struct view *view)
|
||||
{
|
||||
if (view->mapped) {
|
||||
return;
|
||||
}
|
||||
view->mapped = true;
|
||||
wlr_scene_node_set_enabled(&view->scene_tree->node, true);
|
||||
if (!view->fullscreen && view->xwayland_surface->fullscreen) {
|
||||
view_set_fullscreen(view, true, NULL);
|
||||
}
|
||||
|
|
@ -264,7 +274,18 @@ map(struct view *view)
|
|||
view->w = view->xwayland_surface->width;
|
||||
view->h = view->xwayland_surface->height;
|
||||
}
|
||||
view->surface = view->xwayland_surface->surface;
|
||||
|
||||
if (view->surface != view->xwayland_surface->surface) {
|
||||
view->surface = view->xwayland_surface->surface;
|
||||
view->scene_node = wlr_scene_subsurface_tree_create(
|
||||
&view->scene_tree->node, view->surface);
|
||||
if (!view->scene_node) {
|
||||
/* TODO: might need further clean up */
|
||||
wl_resource_post_no_memory(view->surface->resource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
view->ssd.enabled = want_deco(view);
|
||||
|
||||
if (view->ssd.enabled) {
|
||||
|
|
@ -304,7 +325,7 @@ unmap(struct view *view)
|
|||
{
|
||||
if (view->mapped) {
|
||||
view->mapped = false;
|
||||
damage_all_outputs(view->server);
|
||||
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
||||
wl_list_remove(&view->commit.link);
|
||||
desktop_focus_topmost_mapped_view(view->server);
|
||||
}
|
||||
|
|
@ -338,7 +359,6 @@ set_fullscreen(struct view *view, bool fullscreen)
|
|||
static const struct view_impl xwl_view_impl = {
|
||||
.configure = configure,
|
||||
.close = _close,
|
||||
.for_each_surface = for_each_surface,
|
||||
.get_string_prop = get_string_prop,
|
||||
.map = map,
|
||||
.move = move,
|
||||
|
|
@ -370,8 +390,10 @@ xwayland_surface_new(struct wl_listener *listener, void *data)
|
|||
view->type = LAB_XWAYLAND_VIEW;
|
||||
view->impl = &xwl_view_impl;
|
||||
view->xwayland_surface = xsurface;
|
||||
wl_list_init(&view->ssd.parts);
|
||||
|
||||
view->scene_tree = wlr_scene_tree_create(&view->server->view_tree->node);
|
||||
node_descriptor_create(&view->scene_tree->node,
|
||||
LAB_NODE_DESC_VIEW, view);
|
||||
xsurface->data = view;
|
||||
|
||||
view->map.notify = handle_map;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[wrap-git]
|
||||
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
revision = 0.15.1
|
||||
revision = master
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue