diff --git a/.reuse/dep5 b/.reuse/dep5 index 9faf247c6537d04e531cc2ca6312af06aade9803..41aaa1c9529cebe18e42b90167b9c82a30fe7608 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -67,7 +67,7 @@ Files: src/virtual.c src/virtual.h src/xcursor.h - src/xdg_shell.c + src/xdg-toplevel-decoration.c Copyright: The wlroots authors The Phoc authors diff --git a/doc/meson.build b/doc/meson.build index b238a0af52ea8245d42d612680b63e28fa569c3b..7eb99bf653c394a7017ca1dfe7303ebf9e3331c7 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -35,6 +35,7 @@ custom_target('phoc-doc', '--output-dir=@OUTPUT@', '--no-namespace-dir', '--content-dir=@0@'.format(meson.current_source_dir()), + '--fatal-warnings', '@INPUT1@', ], depend_files: [ expand_content_md_files ], diff --git a/helpers/doc-check b/helpers/doc-check index c8368dfb62362bbb40bc00568fc01f9e58afa4b5..595850f3d6942bcf0d5428689664f4b33fdadfa2 100755 --- a/helpers/doc-check +++ b/helpers/doc-check @@ -9,7 +9,6 @@ meson compile -C "${DIR}" doc/phoc-doc |& tee "${LOG}" if grep -vE '('\ 'register as boxed type or \(skip\)'\ -'|symbol=.handle_.*Unknown namespace for symbol'\ '|wayland-server-core.h:.* syntax error, unexpected'\ '|argument pressed_keysyms: Unresolved type:'\ '|argument iterator: Unresolved type: .wlr_surface_iterator_func_t.'\ diff --git a/src/desktop.c b/src/desktop.c index 1e2a5012bf24d1845cb1f3893e98320c6b4fb04f..fff1d4f639f5cd1d4550069572bdd5b43742f8bb 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -51,6 +51,7 @@ #include "layer-shell-effects.h" #include "xdg-surface.h" +#include "xdg-toplevel-decoration.h" #include "xwayland-surface.h" /* Maximum protocol versions we support */ @@ -719,11 +720,11 @@ phoc_desktop_constructed (GObject *object) self->xdg_shell = wlr_xdg_shell_create(wl_display, PHOC_XDG_SHELL_VERSION); wl_signal_add(&self->xdg_shell->events.new_surface, &self->xdg_shell_surface); - self->xdg_shell_surface.notify = handle_xdg_shell_surface; + self->xdg_shell_surface.notify = phoc_handle_xdg_shell_surface; self->layer_shell = wlr_layer_shell_v1_create (wl_display, PHOC_LAYER_SHELL_VERSION); wl_signal_add(&self->layer_shell->events.new_surface, &self->layer_shell_surface); - self->layer_shell_surface.notify = handle_layer_shell_surface; + self->layer_shell_surface.notify = phoc_handle_layer_shell_surface; priv->layer_shell_effects = phoc_layer_shell_effects_new (); self->tablet_v2 = wlr_tablet_v2_create (wl_display); @@ -782,7 +783,7 @@ phoc_desktop_constructed (GObject *object) wl_signal_add (&self->xdg_decoration_manager->events.new_toplevel_decoration, &self->xdg_toplevel_decoration); - self->xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; + self->xdg_toplevel_decoration.notify = phoc_handle_xdg_toplevel_decoration; wlr_viewporter_create (wl_display); wlr_single_pixel_buffer_manager_v1_create (wl_display); wlr_fractional_scale_manager_v1_create (wl_display, PHOC_FRACTIONAL_SCALE_VERSION); @@ -801,9 +802,9 @@ phoc_desktop_constructed (GObject *object) self->pointer_gestures = wlr_pointer_gestures_v1_create (wl_display); self->output_manager_v1 = wlr_output_manager_v1_create (wl_display); - self->output_manager_apply.notify = handle_output_manager_apply; + self->output_manager_apply.notify = phoc_handle_output_manager_apply; wl_signal_add (&self->output_manager_v1->events.apply, &self->output_manager_apply); - self->output_manager_test.notify = handle_output_manager_test; + self->output_manager_test.notify = phoc_handle_output_manager_test; wl_signal_add (&self->output_manager_v1->events.test, &self->output_manager_test); self->output_power_manager_v1 = wlr_output_power_manager_v1_create (wl_display); diff --git a/src/desktop.h b/src/desktop.h index 925cf171b2f6a9428d8f5554b35114c15dbc3ec3..adff65cfe857835ea936a735383eb54208c28809 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -138,10 +138,5 @@ PhocPhoshPrivate *phoc_desktop_get_phosh_private (PhocDesktop *s void phoc_desktop_notify_activity (PhocDesktop *self, PhocSeat *seat); - -void handle_xdg_shell_surface(struct wl_listener *listener, void *data); -void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data); -void handle_layer_shell_surface(struct wl_listener *listener, void *data); - gboolean phoc_desktop_is_privileged_protocol (PhocDesktop *self, const struct wl_global *global); diff --git a/src/layer-shell-effects.c b/src/layer-shell-effects.c index 9527a37acfec7ac2beeec009c52cc81a4dfa6dd2..2c4edc9ff47ee7e3d3ede40c3be6b1b677fcd358 100644 --- a/src/layer-shell-effects.c +++ b/src/layer-shell-effects.c @@ -498,10 +498,10 @@ alpha_surface_handle_commit (struct wl_listener *listener, void *data) phoc_layer_surface_get_output (layer_surface); output = phoc_layer_surface_get_output (layer_surface); - phoc_output_damage_whole_local_surface (output, - layer_surface->layer_surface->surface, - layer_surface->geo.x, layer_surface->geo.y); - + phoc_output_damage_whole_surface (output, + layer_surface->layer_surface->surface, + layer_surface->geo.x, + layer_surface->geo.y); } diff --git a/src/layer-surface.c b/src/layer-surface.c index 426aa10ae4c26e4aacb4ff7b3e69c57c0f9ca1d3..0cec2d21fad967e6b33c337c14e2743c9333c2e7 100644 --- a/src/layer-surface.c +++ b/src/layer-surface.c @@ -202,8 +202,10 @@ phoc_layer_surface_unmap (PhocLayerSurface *self) wlr_output = layer_surface->output; if (wlr_output != NULL) { - phoc_output_damage_whole_local_surface(wlr_output->data, layer_surface->surface, - self->geo.x, self->geo.y); + phoc_output_damage_whole_surface (wlr_output->data, + layer_surface->surface, + self->geo.x, + self->geo.y); } } diff --git a/src/layer_shell.c b/src/layer_shell.c index 01dde2fde6000adf0754072927056727883486be..6e18eb8cea2fc129e41274cdde32e00b94618429 100644 --- a/src/layer_shell.c +++ b/src/layer_shell.c @@ -401,13 +401,19 @@ handle_surface_commit (struct wl_listener *listener, void *data) bool geo_changed = memcmp (&old_geo, &layer_surface->geo, sizeof (struct wlr_box)) != 0; if (geo_changed || layer_changed) { - phoc_output_damage_whole_local_surface (output, wlr_layer_surface->surface, - old_geo.x, old_geo.y); - phoc_output_damage_whole_local_surface (output, wlr_layer_surface->surface, - layer_surface->geo.x, layer_surface->geo.y); + phoc_output_damage_whole_surface (output, + wlr_layer_surface->surface, + old_geo.x, + old_geo.y); + phoc_output_damage_whole_surface (output, + wlr_layer_surface->surface, + layer_surface->geo.x, + layer_surface->geo.y); } else { - phoc_output_damage_from_local_surface (output, wlr_layer_surface->surface, - layer_surface->geo.x, layer_surface->geo.y); + phoc_output_damage_from_surface (output, + wlr_layer_surface->surface, + layer_surface->geo.x, + layer_surface->geo.y); } } } @@ -490,9 +496,9 @@ popup_damage (PhocLayerPopup *layer_popup, bool whole) return; if (whole) - phoc_output_damage_whole_local_surface (output, surface, ox, oy); + phoc_output_damage_whole_surface (output, surface, ox, oy); else - phoc_output_damage_from_local_surface (output, surface, ox, oy); + phoc_output_damage_from_surface (output, surface, ox, oy); } @@ -656,13 +662,13 @@ subsurface_damage (PhocLayerSubsurface *subsurface, bool whole) int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; if (whole) { - phoc_output_damage_whole_local_surface (output, - subsurface->wlr_subsurface->surface, - ox, oy); + phoc_output_damage_whole_surface (output, + subsurface->wlr_subsurface->surface, + ox, oy); } else { - phoc_output_damage_from_local_surface (output, - subsurface->wlr_subsurface->surface, - ox, oy); + phoc_output_damage_from_surface (output, + subsurface->wlr_subsurface->surface, + ox, oy); } } @@ -815,9 +821,10 @@ handle_map (struct wl_listener *listener, void *data) layer_surface->new_subsurface.notify = handle_new_subsurface; wl_signal_add (&wlr_layer_surface->surface->events.new_subsurface, &layer_surface->new_subsurface); - phoc_output_damage_whole_local_surface (output, - wlr_layer_surface->surface, layer_surface->geo.x, - layer_surface->geo.y); + phoc_output_damage_whole_surface (output, + wlr_layer_surface->surface, + layer_surface->geo.x, + layer_surface->geo.y); phoc_utils_wlr_surface_enter_output (wlr_layer_surface->surface, output->wlr_output); @@ -851,7 +858,7 @@ handle_unmap (struct wl_listener *listener, void *data) void -handle_layer_shell_surface (struct wl_listener *listener, void *data) +phoc_handle_layer_shell_surface (struct wl_listener *listener, void *data) { struct wlr_layer_surface_v1 *wlr_layer_surface = data; PhocDesktop *desktop = wl_container_of (listener, desktop, layer_shell_surface); diff --git a/src/layers.h b/src/layers.h index 92b64b4b8ffb9ca838ffc1d98c301a3785a9be2a..f36f6895d1a72a60160f216228680c491fc2cc40 100644 --- a/src/layers.h +++ b/src/layers.h @@ -60,4 +60,6 @@ void phoc_layer_shell_update_focus (void); void phoc_layer_shell_update_osk (PhocOutput *output, gboolean arrange); PhocLayerSurface *phoc_layer_shell_find_osk (PhocOutput *output); +void phoc_handle_layer_shell_surface (struct wl_listener *listener, void *data); + G_END_DECLS diff --git a/src/meson.build b/src/meson.build index d9bfe3865e341f20fb611aad07ca0049461edf30..58bbe6f942c662d8cf73c6b64392fa3611ee0b87 100644 --- a/src/meson.build +++ b/src/meson.build @@ -80,6 +80,8 @@ sources = files( 'server.h', 'settings.c', 'settings.h', + 'subsurface.c', + 'subsurface.h', 'switch.c', 'switch.h', 'tablet.c', @@ -92,15 +94,20 @@ sources = files( 'utils.h', 'view.c', 'view.h', + 'view-child.c', + 'view-child-private.h', 'view-deco.c', 'view-deco.h', 'virtual.c', 'virtual.h', 'xdg-activation-v1.c', 'xdg-activation-v1.h', - 'xdg_shell.c', + 'xdg-popup.c', + 'xdg-popup.h', 'xdg-surface.c', 'xdg-surface.h', + 'xdg-toplevel-decoration.c', + 'xdg-toplevel-decoration.h', ) + phoc_anim_sources libphoc_generated_sources = [ phoc_config_h, diff --git a/src/output.c b/src/output.c index 4117dce1dcbcdc9caf803ba31becf2bd3016b303..96331e53cb97d327cd3642c8a7aa43d1c72555a0 100644 --- a/src/output.c +++ b/src/output.c @@ -1490,10 +1490,10 @@ phoc_output_damage_whole_drag_icon (PhocOutput *self, PhocDragIcon *icon) } void -phoc_output_damage_whole_local_surface (PhocOutput *self, - struct wlr_surface *surface, - double ox, - double oy) +phoc_output_damage_whole_surface (PhocOutput *self, + struct wlr_surface *surface, + double ox, + double oy) { bool whole = true; @@ -1502,8 +1502,10 @@ phoc_output_damage_whole_local_surface (PhocOutput *self, } void -phoc_output_damage_from_local_surface (PhocOutput *self, struct wlr_surface - *surface, double ox, double oy) +phoc_output_damage_from_surface (PhocOutput *self, + struct wlr_surface *surface, + double ox, + double oy) { bool whole = false; @@ -1599,7 +1601,7 @@ output_manager_apply_config (PhocDesktop *desktop, void -handle_output_manager_apply (struct wl_listener *listener, void *data) +phoc_handle_output_manager_apply (struct wl_listener *listener, void *data) { PhocDesktop *desktop = wl_container_of (listener, desktop, output_manager_apply); struct wlr_output_configuration_v1 *config = data; @@ -1609,7 +1611,7 @@ handle_output_manager_apply (struct wl_listener *listener, void *data) void -handle_output_manager_test (struct wl_listener *listener, void *data) +phoc_handle_output_manager_test (struct wl_listener *listener, void *data) { PhocDesktop *desktop = wl_container_of (listener, desktop, output_manager_apply); struct wlr_output_configuration_v1 *config = data; diff --git a/src/output.h b/src/output.h index e4dbc273c18ea0d669f1bdf0471f41f30b4d7db5..94c1d46ef6c7c168d752a02daa0a939b6856b7f2 100644 --- a/src/output.h +++ b/src/output.h @@ -112,8 +112,8 @@ GList * phoc_output_get_layer_surfaces_for_layer (PhocOutput enum zwlr_layer_shell_v1_layer layer); /* signal handlers */ -void handle_output_manager_apply (struct wl_listener *listener, void *data); -void handle_output_manager_test (struct wl_listener *listener, void *data); +void phoc_handle_output_manager_apply (struct wl_listener *listener, void *data); +void phoc_handle_output_manager_test (struct wl_listener *listener, void *data); void phoc_output_handle_output_power_manager_set_mode (struct wl_listener *listener, void *data); void phoc_output_handle_gamma_control_set_gamma (struct wl_listener *listener, void *data); @@ -123,10 +123,10 @@ void phoc_output_damage_whole (PhocOutput *output); void phoc_output_damage_from_view (PhocOutput *self, PhocView *view, bool whole); void phoc_output_damage_whole_drag_icon (PhocOutput *self, PhocDragIcon *icon); -void phoc_output_damage_from_local_surface (PhocOutput *self, struct wlr_surface *surface, double - ox, double oy); -void phoc_output_damage_whole_local_surface (PhocOutput *self, struct wlr_surface *surface, - double ox, double oy); +void phoc_output_damage_from_surface (PhocOutput *self, struct wlr_surface *surface, + double ox, double oy); +void phoc_output_damage_whole_surface (PhocOutput *self, struct wlr_surface *surface, + double ox, double oy); void phoc_output_update_shell_reveal (PhocOutput *self); void phoc_output_force_shell_reveal (PhocOutput *self, gboolean force); diff --git a/src/subsurface.c b/src/subsurface.c new file mode 100644 index 0000000000000000000000000000000000000000..bacd215d6f34c37e1318e49be06839d9be9624c4 --- /dev/null +++ b/src/subsurface.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phoc-subsurface" + +#include "phoc-config.h" + +#include "subsurface.h" + + +enum { + PROP_0, + PROP_WLR_SUBSURFACE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +/** + * PhocSubsurface: + * + * A subsurface attached to a [type@View] or [type@ViewChild]. + */ +typedef struct _PhocSubsurface { + PhocViewChild parent_instance; + + struct wlr_subsurface *wlr_subsurface; + + struct wl_listener destroy; +} PhocSubsurface; + + +G_DEFINE_FINAL_TYPE (PhocSubsurface, phoc_subsurface, PHOC_TYPE_VIEW_CHILD) + +static void +subsurface_get_pos (PhocViewChild *child, int *sx, int *sy) +{ + struct wlr_surface *wlr_surface; + struct wlr_subsurface *wlr_subsurface; + + wlr_surface = child->wlr_surface; + if (child->parent) + phoc_view_child_get_pos (child->parent, sx, sy); + else + *sx = *sy = 0; + + wlr_subsurface = wlr_subsurface_try_from_wlr_surface (wlr_surface); + g_assert (wlr_subsurface); + *sx += wlr_subsurface->current.x; + *sy += wlr_subsurface->current.y; +} + + +static void +phoc_subsurface_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhocSubsurface *self = PHOC_SUBSURFACE (object); + + switch (property_id) { + case PROP_WLR_SUBSURFACE: + self->wlr_subsurface = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phoc_subsurface_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhocSubsurface *self = PHOC_SUBSURFACE (object); + + switch (property_id) { + case PROP_WLR_SUBSURFACE: + g_value_set_pointer (value, self->wlr_subsurface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +subsurface_handle_destroy (struct wl_listener *listener, void *data) +{ + PhocSubsurface *self = wl_container_of (listener, self, destroy); + + g_object_unref (self); +} + + + +static void +phoc_subsurface_constructed (GObject *object) +{ + PhocSubsurface *self = PHOC_SUBSURFACE (object); + + G_OBJECT_CLASS (phoc_subsurface_parent_class)->constructed (object); + + PHOC_VIEW_CHILD (self)->mapped = self->wlr_subsurface->surface->mapped; + + self->destroy.notify = subsurface_handle_destroy; + wl_signal_add (&self->wlr_subsurface->events.destroy, &self->destroy); +} + + +static void +phoc_subsurface_finalize (GObject *object) +{ + PhocSubsurface *self = PHOC_SUBSURFACE (object); + + wl_list_remove (&self->destroy.link); + + G_OBJECT_CLASS (phoc_subsurface_parent_class)->finalize (object); +} + + +static void +phoc_subsurface_class_init (PhocSubsurfaceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhocViewChildClass *view_child_class = PHOC_VIEW_CHILD_CLASS (klass); + + object_class->constructed = phoc_subsurface_constructed; + object_class->finalize = phoc_subsurface_finalize; + object_class->get_property = phoc_subsurface_get_property; + object_class->set_property = phoc_subsurface_set_property; + + view_child_class->get_pos = subsurface_get_pos; + + props[PROP_WLR_SUBSURFACE] = + g_param_spec_pointer ("wlr-subsurface", "", "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phoc_subsurface_init (PhocSubsurface *self) +{ +} + + +PhocSubsurface * +phoc_subsurface_new (PhocView *view, struct wlr_subsurface *wlr_subsurface) +{ + return g_object_new (PHOC_TYPE_SUBSURFACE, + "view", view, + "wlr-surface", wlr_subsurface->surface, + "wlr-subsurface", wlr_subsurface, + NULL); +} diff --git a/src/subsurface.h b/src/subsurface.h new file mode 100644 index 0000000000000000000000000000000000000000..07123400d4677777f1db1d8327db50b18e4314df --- /dev/null +++ b/src/subsurface.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "view-child-private.h" + +#include + +G_BEGIN_DECLS + +#define PHOC_TYPE_SUBSURFACE (phoc_subsurface_get_type ()) + +G_DECLARE_FINAL_TYPE (PhocSubsurface, phoc_subsurface, PHOC, SUBSURFACE, PhocViewChild) + +PhocSubsurface *phoc_subsurface_new (PhocView *view, struct wlr_subsurface *wlr_subsurface); + +G_END_DECLS diff --git a/src/view-child-private.h b/src/view-child-private.h new file mode 100644 index 0000000000000000000000000000000000000000..f406640d77fcea316df9044e7b156a0174822922 --- /dev/null +++ b/src/view-child-private.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +/** + * PhocViewChild: + * @link: Link to PhocView::child_surfaces + * @view: The [type@PhocView] this child belongs to + * @parent: (nullable): The parent of this child if another child + * @children: (nullable): children of this child + * + * A child of a [type@View], e.g. a [type@XdgPopup] or subsurface + */ +typedef struct _PhocView PhocView; + +typedef struct _PhocViewChild PhocViewChild; +struct _PhocViewChild { + GObject parent_instance; + + PhocView *view; + PhocViewChild *parent; + GSList *children; + struct wlr_surface *wlr_surface; + struct wl_list link; // PhocViewPrivate::child_surfaces + bool mapped; + + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener commit; + struct wl_listener new_subsurface; +}; + +/** + * PhocViewChildClass: + * @parent_class: The object class structure needs to be the first + * element in the widget class structure in order for the class mechanism + * to work correctly. This allows a PhocViewClass pointer to be cast to + * a GObjectClass pointer. + * @map: Invoked on map. Chain up to parent. + * @unmap: Invoked on unmap. Chain up to parent. + * @get_pos: Get the child's position relative to it's parent. + */ +typedef struct _PhocViewChildClass +{ + GObjectClass parent_class; + + void (*map) (PhocViewChild *self); + void (*unmap) (PhocViewChild *self); + void (*get_pos) (PhocViewChild *self, int *sx, int *sy); +} PhocViewChildClass; + +#define PHOC_TYPE_VIEW_CHILD (phoc_view_child_get_type ()) + +GType phoc_view_child_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (PhocViewChild, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (PhocViewChildClass, g_type_class_unref) +static inline PhocViewChild * PHOC_VIEW_CHILD (gpointer ptr) { + return G_TYPE_CHECK_INSTANCE_CAST (ptr, phoc_view_child_get_type (), PhocViewChild); } +static inline PhocViewChildClass * PHOC_VIEW_CHILD_CLASS (gpointer ptr) { + return G_TYPE_CHECK_CLASS_CAST (ptr, phoc_view_child_get_type (), PhocViewChildClass); } +static inline gboolean PHOC_IS_VIEW_CHILD (gpointer ptr) { + return G_TYPE_CHECK_INSTANCE_TYPE (ptr, phoc_view_child_get_type ()); } +static inline gboolean PHOC_IS_VIEW_CHILD_CLASS (gpointer ptr) { + return G_TYPE_CHECK_CLASS_TYPE (ptr, phoc_view_child_get_type ()); } +static inline PhocViewChildClass * PHOC_VIEW_CHILD_GET_CLASS (gpointer ptr) { + return G_TYPE_INSTANCE_GET_CLASS (ptr, phoc_view_child_get_type (), PhocViewChildClass); } + +PhocView * phoc_view_child_get_view (PhocViewChild *self); +void phoc_view_child_apply_damage (PhocViewChild *self); +void phoc_view_child_damage_whole (PhocViewChild *self); +void phoc_view_child_get_pos (PhocViewChild *self, int *sx, int *sy); + +G_END_DECLS diff --git a/src/view-child.c b/src/view-child.c new file mode 100644 index 0000000000000000000000000000000000000000..decda39315e8e679feb8e46362fc4223c7d9338a --- /dev/null +++ b/src/view-child.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phoc-view-child" + +#include "phoc-config.h" + +#include "desktop.h" +#include "input.h" +#include "output.h" +#include "server.h" +#include "subsurface.h" +#include "utils.h" +#include "view-private.h" +#include "view-child-private.h" + + +enum { + PROP_0, + PROP_VIEW, + PROP_WLR_SURFACE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + + +G_DEFINE_TYPE (PhocViewChild, phoc_view_child, G_TYPE_OBJECT) + + +static void +phoc_view_child_subsurface_create (PhocViewChild *self, struct wlr_subsurface *wlr_subsurface) +{ + PhocSubsurface *subsurface = phoc_subsurface_new (self->view, wlr_subsurface); + + PHOC_VIEW_CHILD (subsurface)->parent = self; + self->children = g_slist_prepend (self->children, subsurface); + + phoc_view_child_damage_whole (PHOC_VIEW_CHILD (subsurface)); +} + + +static void +phoc_view_child_init_subsurfaces (PhocViewChild *self, struct wlr_surface *surface) +{ + struct wlr_subsurface *subsurface; + + wl_list_for_each (subsurface, &surface->current.subsurfaces_below, current.link) + phoc_view_child_subsurface_create (self, subsurface); + + wl_list_for_each (subsurface, &surface->current.subsurfaces_above, current.link) + phoc_view_child_subsurface_create (self, subsurface); +} + + +static bool +phoc_view_child_is_mapped (PhocViewChild *self) +{ + while (self) { + if (!self->mapped) + return false; + + self = self->parent; + } + return true; +} + + +static void +phoc_view_child_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhocViewChild *self = PHOC_VIEW_CHILD (object); + + switch (property_id) { + case PROP_VIEW: + /* TODO: Should hold a ref */ + self->view = g_value_get_object (value); + break; + case PROP_WLR_SURFACE: + self->wlr_surface = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phoc_view_child_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhocViewChild *self = PHOC_VIEW_CHILD (object); + + switch (property_id) { + case PROP_VIEW: + g_value_set_object (value, self->view); + break; + case PROP_WLR_SURFACE: + g_value_set_pointer (value, self->wlr_surface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phoc_view_child_handle_map (struct wl_listener *listener, void *data) +{ + PhocViewChild *self = wl_container_of (listener, self, map); + + PHOC_VIEW_CHILD_GET_CLASS (self)->map (self); +} + + +static void +phoc_view_child_handle_unmap (struct wl_listener *listener, void *data) +{ + PhocViewChild *self = wl_container_of (listener, self, unmap); + + PHOC_VIEW_CHILD_GET_CLASS (self)->unmap (self); +} + + +static void +phoc_view_child_handle_new_subsurface (struct wl_listener *listener, void *data) +{ + PhocViewChild *self = wl_container_of (listener, self, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + + phoc_view_child_subsurface_create (self, wlr_subsurface); +} + + +static void +phoc_view_child_handle_commit (struct wl_listener *listener, void *data) +{ + PhocViewChild *self = wl_container_of (listener, self, commit); + + phoc_view_child_apply_damage (self); +} + + +static void +phoc_view_child_constructed (GObject *object) +{ + PhocViewChild *self = PHOC_VIEW_CHILD (object); + + G_OBJECT_CLASS (phoc_view_child_parent_class)->constructed (object); + + self->map.notify = phoc_view_child_handle_map; + wl_signal_add (&self->wlr_surface->events.map, &self->map); + + self->unmap.notify = phoc_view_child_handle_unmap; + wl_signal_add (&self->wlr_surface->events.unmap, &self->unmap); + + self->commit.notify = phoc_view_child_handle_commit; + wl_signal_add (&self->wlr_surface->events.commit, &self->commit); + + self->new_subsurface.notify = phoc_view_child_handle_new_subsurface; + wl_signal_add (&self->wlr_surface->events.new_subsurface, &self->new_subsurface); + + phoc_view_add_child (self->view, self); + + phoc_view_child_init_subsurfaces (self, self->wlr_surface); +} + + +static void +phoc_view_child_finalize (GObject *object) +{ + PhocViewChild *self = PHOC_VIEW_CHILD (object); + + if (phoc_view_child_is_mapped (self) && phoc_view_is_mapped (self->view)) + phoc_view_child_damage_whole (self); + + /* Remove from parent if it's also a PhocViewChild */ + if (self->parent != NULL) { + self->parent->children = g_slist_remove (self->parent->children, self); + self->parent = NULL; + } + + /* Detach us from all children */ + for (GSList *elem = self->children; elem; elem = elem->next) { + PhocViewChild *subchild = elem->data; + subchild->parent = NULL; + /* The subchild lost its parent, so it cannot see that the parent is unmapped. Unmap it directly */ + /* TODO: But then we won't damage them on destroy? */ + subchild->mapped = false; + } + g_clear_pointer (&self->children, g_slist_free); + + wl_list_remove (&self->link); + + wl_list_remove (&self->map.link); + wl_list_remove (&self->unmap.link); + wl_list_remove (&self->commit.link); + wl_list_remove (&self->new_subsurface.link); + + self->view = NULL; + self->wlr_surface = NULL; + + G_OBJECT_CLASS (phoc_view_child_parent_class)->finalize (object); +} + + +static void +phoc_view_child_map_default (PhocViewChild *self) +{ + PhocInput *input = phoc_server_get_input (phoc_server_get_default ()); + PhocView *view = self->view; + + self->mapped = true; + phoc_view_child_damage_whole (self); + + struct wlr_box box; + phoc_view_get_box (view, &box); + + PhocOutput *output; + wl_list_for_each (output, &view->desktop->outputs, link) { + bool intersects = wlr_output_layout_intersects (view->desktop->layout, + output->wlr_output, &box); + if (intersects) + phoc_utils_wlr_surface_enter_output (self->wlr_surface, output->wlr_output); + } + + phoc_input_update_cursor_focus (input); +} + + +static void +phoc_view_child_unmap_default (PhocViewChild *self) +{ + PhocInput *input = phoc_server_get_input (phoc_server_get_default ()); + + phoc_view_child_damage_whole (self); + phoc_input_update_cursor_focus (input); + self->mapped = false; +} + + +G_NORETURN +static void +phoc_view_child_get_pos_default (PhocViewChild *self, int *sx, int *sy) +{ + g_assert_not_reached (); +} + + +static void +phoc_view_child_class_init (PhocViewChildClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhocViewChildClass *view_child_class = PHOC_VIEW_CHILD_CLASS (klass); + + object_class->get_property = phoc_view_child_get_property; + object_class->set_property = phoc_view_child_set_property; + object_class->constructed = phoc_view_child_constructed; + object_class->finalize = phoc_view_child_finalize; + + view_child_class->map = phoc_view_child_map_default; + view_child_class->unmap = phoc_view_child_unmap_default; + view_child_class->get_pos = phoc_view_child_get_pos_default; + + props[PROP_VIEW] = + g_param_spec_object ("view", "", "", + PHOC_TYPE_VIEW, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + props[PROP_WLR_SURFACE] = + g_param_spec_pointer ("wlr-surface", "", "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phoc_view_child_init (PhocViewChild *self) +{ +} + +/** + * phoc_view_child_apply_damage: + * @self: A view child + * + * This is the equivalent of `phoc_view_apply_damage` but for [type@ViewChild]. + */ +void +phoc_view_child_apply_damage (PhocViewChild *self) +{ + if (!self || !phoc_view_child_is_mapped (self) || !phoc_view_is_mapped (self->view)) + return; + + phoc_view_apply_damage (self->view); +} + +/** + * phoc_view_child_damage_whole: + * @self: A view child + * + * This is the equivalent of [method@View.damage_whole] but for + * [type@ViewChild]. + */ +void +phoc_view_child_damage_whole (PhocViewChild *self) +{ + PhocOutput *output; + int sx, sy; + struct wlr_box view_box; + + if (!self || !phoc_view_child_is_mapped (self) || !phoc_view_is_mapped (self->view)) + return; + + phoc_view_get_box (self->view, &view_box); + phoc_view_child_get_pos (self, &sx, &sy); + + wl_list_for_each (output, &self->view->desktop->outputs, link) { + struct wlr_box output_box; + wlr_output_layout_get_box (self->view->desktop->layout, output->wlr_output, &output_box); + phoc_output_damage_whole_surface (output, + self->wlr_surface, + view_box.x + sx - output_box.x, + view_box.y + sy - output_box.y); + } +} + + +void +phoc_view_child_get_pos (PhocViewChild *self, int *sx, int *sy) +{ + g_assert (PHOC_IS_VIEW_CHILD (self)); + + PHOC_VIEW_CHILD_GET_CLASS (self)->get_pos (self, sx, sy); +} + +/** + * phoc_view_child_get_view: + * @self: A view child + * + * Get the view this child belongs to. + * + * Returns: (transfer none): The containing view + */ +PhocView * +phoc_view_child_get_view (PhocViewChild *self) +{ + g_assert (PHOC_IS_VIEW_CHILD (self)); + + return self->view; +} diff --git a/src/view.c b/src/view.c index 470f685552db50723beda48eade6ea96e2121f4d..fc4837eae4ad4d9e8c8e37a2a433cecd3b2060b1 100644 --- a/src/view.c +++ b/src/view.c @@ -16,8 +16,10 @@ #include "input.h" #include "seat.h" #include "server.h" +#include "subsurface.h" #include "utils.h" #include "timed-animation.h" +#include "view-child-private.h" #include "view-private.h" #define PHOC_ANIM_DURATION_WINDOW_FADE 150 @@ -73,20 +75,10 @@ typedef struct _PhocViewPrivate { } PhocViewPrivate; G_DEFINE_TYPE_WITH_PRIVATE (PhocView, phoc_view, G_TYPE_OBJECT) - #define PHOC_VIEW_SELF(p) PHOC_PRIV_CONTAINER(PHOC_VIEW, PhocView, (p)) static bool view_center (PhocView *view, PhocOutput *output); -typedef struct _PhocSubsurface { - PhocViewChild child; - struct wlr_subsurface *wlr_subsurface; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; -} PhocSubsurface; - static struct wlr_foreign_toplevel_handle_v1 * phoc_view_get_toplevel_handle (PhocView *self) @@ -839,236 +831,18 @@ view_center (PhocView *view, PhocOutput *output) } -static bool -phoc_view_child_is_mapped (PhocViewChild *child) -{ - while (child) { - if (!child->mapped) { - return false; - } - child = child->parent; - } - return true; -} - -static void -phoc_view_child_handle_commit (struct wl_listener *listener, void *data) -{ - PhocViewChild *child = wl_container_of(listener, child, commit); - - phoc_view_child_apply_damage (child); -} - -static void phoc_view_subsurface_create (PhocView *view, struct wlr_subsurface *wlr_subsurface); -static void phoc_view_child_subsurface_create (PhocViewChild *child, struct wlr_subsurface *wlr_subsurface); - -static void -phoc_view_child_handle_new_subsurface (struct wl_listener *listener, void *data) -{ - PhocViewChild *child = wl_container_of(listener, child, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - - phoc_view_child_subsurface_create (child, wlr_subsurface); -} - static void phoc_view_init_subsurfaces (PhocView *view, struct wlr_surface *surface) { struct wlr_subsurface *subsurface; wl_list_for_each(subsurface, &surface->current.subsurfaces_below, current.link) - phoc_view_subsurface_create (view, subsurface); + phoc_subsurface_new (view, subsurface); wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) - phoc_view_subsurface_create (view, subsurface); -} - -static void -phoc_view_child_init_subsurfaces (PhocViewChild *child, struct wlr_surface *surface) -{ - struct wlr_subsurface *subsurface; - - wl_list_for_each (subsurface, &surface->current.subsurfaces_below, current.link) - phoc_view_child_subsurface_create (child, subsurface); - - wl_list_for_each (subsurface, &surface->current.subsurfaces_above, current.link) - phoc_view_child_subsurface_create (child, subsurface); -} - - -void -phoc_view_child_map (PhocViewChild *child, struct wlr_surface *wlr_surface) -{ - PhocInput *input = phoc_server_get_input (phoc_server_get_default ()); - PhocView *view = child->view; - - child->mapped = true; - phoc_view_child_damage_whole (child); - - struct wlr_box box; - phoc_view_get_box (view, &box); - - PhocOutput *output; - wl_list_for_each (output, &view->desktop->outputs, link) { - bool intersects = wlr_output_layout_intersects (view->desktop->layout, - output->wlr_output, &box); - if (intersects) - phoc_utils_wlr_surface_enter_output (wlr_surface, output->wlr_output); - } - - phoc_input_update_cursor_focus (input); -} - - -void -phoc_view_child_unmap (PhocViewChild *child) -{ - PhocInput *input = phoc_server_get_input (phoc_server_get_default ()); - - phoc_view_child_damage_whole (child); - phoc_input_update_cursor_focus (input); - child->mapped = false; -} - - -void -phoc_view_child_init (PhocViewChild *child, - const PhocViewChildInterface *impl, - PhocView *view, - struct wlr_surface *wlr_surface) -{ - PhocViewPrivate *priv; - - g_assert (impl->destroy); - child->impl = impl; - child->view = view; - child->wlr_surface = wlr_surface; - - child->commit.notify = phoc_view_child_handle_commit; - wl_signal_add(&wlr_surface->events.commit, &child->commit); - - child->new_subsurface.notify = phoc_view_child_handle_new_subsurface; - wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); - - priv = phoc_view_get_instance_private (view); - wl_list_insert (&priv->child_surfaces, &child->link); - - phoc_view_child_init_subsurfaces (child, wlr_surface); -} - - -static const PhocViewChildInterface subsurface_impl; - -static void -subsurface_get_pos (PhocViewChild *child, int *sx, int *sy) -{ - struct wlr_surface *wlr_surface; - struct wlr_subsurface *wlr_subsurface; - - g_assert (child->impl == &subsurface_impl); - - wlr_surface = child->wlr_surface; - if (child->parent && child->parent->impl && child->parent->impl->get_pos) - child->parent->impl->get_pos (child->parent, sx, sy); - else - *sx = *sy = 0; - - wlr_subsurface = wlr_subsurface_try_from_wlr_surface (wlr_surface); - g_assert (wlr_subsurface); - *sx += wlr_subsurface->current.x; - *sy += wlr_subsurface->current.y; -} - - -static void -subsurface_destroy (PhocViewChild *child) -{ - PhocSubsurface *subsurface = (PhocSubsurface *)child; - - g_assert (child->impl == &subsurface_impl); - wl_list_remove (&subsurface->destroy.link); - wl_list_remove (&subsurface->map.link); - wl_list_remove (&subsurface->unmap.link); - g_free (subsurface); -} - - -static const PhocViewChildInterface subsurface_impl = { - .get_pos = subsurface_get_pos, - .destroy = subsurface_destroy, -}; - - -static void -subsurface_handle_destroy (struct wl_listener *listener, void *data) -{ - PhocSubsurface *subsurface = wl_container_of(listener, subsurface, destroy); - phoc_view_child_destroy(&subsurface->child); -} - -static void -subsurface_handle_map (struct wl_listener *listener, void *data) -{ - PhocSubsurface *subsurface = wl_container_of (listener, subsurface, map); - - /* Chain up to parent */ - phoc_view_child_map (&subsurface->child, subsurface->wlr_subsurface->surface); -} - - -static void -subsurface_handle_unmap (struct wl_listener *listener,void *data) -{ - PhocSubsurface *subsurface = wl_container_of (listener, subsurface, unmap); - - /* Chain up to parent */ - phoc_view_child_unmap (&subsurface->child); -} - - -static void -phoc_view_subsurface_create (PhocView *view, struct wlr_subsurface *wlr_subsurface) -{ - PhocSubsurface *subsurface = g_new0 (PhocSubsurface, 1); - - subsurface->wlr_subsurface = wlr_subsurface; - phoc_view_child_init (&subsurface->child, &subsurface_impl, - view, wlr_subsurface->surface); - subsurface->child.mapped = wlr_subsurface->surface->mapped; - - subsurface->destroy.notify = subsurface_handle_destroy; - wl_signal_add (&wlr_subsurface->events.destroy, &subsurface->destroy); - - subsurface->map.notify = subsurface_handle_map; - wl_signal_add (&wlr_subsurface->surface->events.map, &subsurface->map); - - subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add (&wlr_subsurface->surface->events.unmap, &subsurface->unmap); + phoc_subsurface_new (view, subsurface); } -static void -phoc_view_child_subsurface_create (PhocViewChild *child, struct wlr_subsurface *wlr_subsurface) -{ - PhocSubsurface *subsurface = g_new0 (PhocSubsurface, 1); - - subsurface->child.parent = child; - child->children = g_slist_prepend (child->children, &subsurface->child); - subsurface->wlr_subsurface = wlr_subsurface; - phoc_view_child_init (&subsurface->child, &subsurface_impl, child->view, - wlr_subsurface->surface); - subsurface->child.mapped = wlr_subsurface->surface->mapped; - - subsurface->destroy.notify = subsurface_handle_destroy; - wl_signal_add (&wlr_subsurface->events.destroy, &subsurface->destroy); - - subsurface->map.notify = subsurface_handle_map; - wl_signal_add (&wlr_subsurface->surface->events.map, &subsurface->map); - - subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add (&wlr_subsurface->surface->events.unmap, &subsurface->unmap); - - phoc_view_child_damage_whole (&subsurface->child); -} static void phoc_view_handle_surface_new_subsurface (struct wl_listener *listener, void *data) @@ -1077,7 +851,7 @@ phoc_view_handle_surface_new_subsurface (struct wl_listener *listener, void *dat PhocView *self = PHOC_VIEW_SELF (priv); struct wlr_subsurface *wlr_subsurface = data; - phoc_view_subsurface_create (self, wlr_subsurface); + phoc_subsurface_new (self, wlr_subsurface); } static gchar * @@ -1154,15 +928,7 @@ phoc_view_map (PhocView *self, struct wlr_surface *surface) g_assert (self->wlr_surface == NULL); self->wlr_surface = surface; - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &self->wlr_surface->current.subsurfaces_below, current.link) { - phoc_view_subsurface_create(self, subsurface); - } - wl_list_for_each(subsurface, &self->wlr_surface->current.subsurfaces_above, current.link) { - phoc_view_subsurface_create(self, subsurface); - } - - phoc_view_init_subsurfaces (self, surface); + phoc_view_init_subsurfaces (self, self->wlr_surface); priv->surface_new_subsurface.notify = phoc_view_handle_surface_new_subsurface; wl_signal_add (&self->wlr_surface->events.new_subsurface, &priv->surface_new_subsurface); @@ -1229,9 +995,8 @@ phoc_view_unmap (PhocView *view) wl_list_remove (&priv->surface_new_subsurface.link); PhocViewChild *child, *tmp; - wl_list_for_each_safe(child, tmp, &priv->child_surfaces, link) { - phoc_view_child_destroy(child); - } + wl_list_for_each_safe (child, tmp, &priv->child_surfaces, link) + g_object_unref (child); if (phoc_view_is_fullscreen (view)) { phoc_output_damage_whole (priv->fullscreen_output); @@ -1950,90 +1715,6 @@ phoc_view_get_output (PhocView *view) return PHOC_OUTPUT (wlr_output->data); } -/** - * phoc_view_child_destroy: - * @child: The view child to destroy - * - * Destroys a view child freeing its resources. - */ -void -phoc_view_child_destroy (PhocViewChild *child) -{ - if (child == NULL) - return; - - if (phoc_view_child_is_mapped (child) && phoc_view_is_mapped (child->view)) - phoc_view_child_damage_whole (child); - - /* Remove from parent if it's also a PhocChild */ - if (child->parent != NULL) { - child->parent->children = g_slist_remove (child->parent->children, child); - child->parent = NULL; - } - - /* Detach us from all children */ - for (GSList *elem = child->children; elem; elem = elem->next) { - PhocViewChild *subchild = elem->data; - subchild->parent = NULL; - /* The subchild lost its parent, so it cannot see that the parent is unmapped. Unmap it directly */ - subchild->mapped = false; - } - g_clear_pointer (&child->children, g_slist_free); - - wl_list_remove(&child->link); - wl_list_remove(&child->commit.link); - wl_list_remove(&child->new_subsurface.link); - - child->impl->destroy(child); -} - -/* - * phoc_view_child_apply_damage: - * @child: A view child - * - * This is the equivalent of [method@Phoc.View.apply_damage] but for - * [struct@Phoc.ViewChild]. - */ -void -phoc_view_child_apply_damage (PhocViewChild *child) -{ - if (!child || !phoc_view_child_is_mapped (child) || !phoc_view_is_mapped (child->view)) - return; - - phoc_view_apply_damage (child->view); -} - -/** - * phoc_view_child_damage_whole: - * @child: A view child - * - * This is the equivalent of [method@Phoc.View.damage_whole] but for - * [struct@Phoc.ViewChild]. - */ -void -phoc_view_child_damage_whole (PhocViewChild *child) -{ - PhocOutput *output; - int sx, sy; - struct wlr_box view_box; - - if (!child || !phoc_view_child_is_mapped (child) || !phoc_view_is_mapped (child->view)) - return; - - phoc_view_get_box (child->view, &view_box); - child->impl->get_pos (child, &sx, &sy); - - wl_list_for_each (output, &child->view->desktop->outputs, link) { - struct wlr_box output_box; - wlr_output_layout_get_box (child->view->desktop->layout, output->wlr_output, &output_box); - phoc_output_damage_whole_local_surface (output, child->wlr_surface, - view_box.x + sx - output_box.x, - view_box.y + sy - output_box.y); - - } -} - - /** * phoc_view_set_scale_to_fit: * @self: The view @@ -2406,6 +2087,19 @@ phoc_view_arrange (PhocView *self, PhocOutput *output, gboolean center) view_center (self, output); } + +void +phoc_view_add_child (PhocView *self, PhocViewChild *child) +{ + PhocViewPrivate *priv; + + g_assert (PHOC_IS_VIEW (self)); + g_assert (PHOC_IS_VIEW_CHILD (child)); + + priv = phoc_view_get_instance_private (child->view); + wl_list_insert (&priv->child_surfaces, &child->link); +} + /** * phoc_view_set_always_on_top: * @self: a view @@ -2419,7 +2113,6 @@ phoc_view_set_always_on_top (PhocView *self, gboolean on_top) PhocViewPrivate *priv; g_assert (PHOC_IS_VIEW (self)); - priv = phoc_view_get_instance_private (self); priv->always_on_top = on_top; @@ -2439,7 +2132,6 @@ phoc_view_is_always_on_top (PhocView *self) PhocViewPrivate *priv; g_assert (PHOC_IS_VIEW (self)); - priv = phoc_view_get_instance_private (self); return priv->always_on_top; diff --git a/src/view.h b/src/view.h index c6c2de55775916391a1542116812ef491d4edba6..90b08a5ac652efbc5d03db8e84b4222a3d412cec 100644 --- a/src/view.h +++ b/src/view.h @@ -1,5 +1,7 @@ #pragma once +#include "view-child-private.h" + #include #include #include @@ -12,7 +14,6 @@ G_BEGIN_DECLS typedef struct _PhocBling PhocBling; -typedef struct _PhocView PhocView; typedef struct _PhocDesktop PhocDesktop; typedef struct _PhocOutput PhocOutput; @@ -54,6 +55,7 @@ typedef enum { */ /* TODO: we keep the struct public for now due to the list links but we should avoid other member access */ +typedef struct _PhocView PhocView; struct _PhocView { GObject parent_instance; @@ -139,36 +141,6 @@ static inline gboolean PHOC_IS_VIEW_CLASS (gpointer ptr) { static inline PhocViewClass * PHOC_VIEW_GET_CLASS (gpointer ptr) { return G_TYPE_INSTANCE_GET_CLASS (ptr, phoc_view_get_type (), PhocViewClass); } -typedef struct _PhocViewChild PhocViewChild; - -typedef struct _PhocViewChildInterface { - void (*get_pos)(PhocViewChild *child, int *sx, int *sy); - void (*destroy)(PhocViewChild *child); -} PhocViewChildInterface; - -/** - * PhocViewChild: - * @link: Link to PhocView::child_surfaces - * @view: The [type@PhocView] this child belongs to - * @parent: (nullable): The parent of this child if another child - * @children: (nullable): children of this child - * - * A child of a [type@PhocView], e.g. a popup or subsurface - */ -typedef struct _PhocViewChild { - const PhocViewChildInterface *impl; - - PhocView *view; - PhocViewChild *parent; - GSList *children; - struct wlr_surface *wlr_surface; - struct wl_list link; - bool mapped; - - struct wl_listener commit; - struct wl_listener new_subsurface; -} PhocViewChild; - void phoc_view_appear_activated (PhocView *view, bool activated); void phoc_view_activate (PhocView *self, bool activate); void phoc_view_damage_whole (PhocView *view); @@ -239,15 +211,6 @@ gboolean phoc_view_get_tiled_box (PhocView *self, void phoc_view_add_bling (PhocView *self, PhocBling *bling); void phoc_view_remove_bling (PhocView *self, PhocBling *bling); GSList *phoc_view_get_blings (PhocView *self); - -void phoc_view_child_init (PhocViewChild *child, - const PhocViewChildInterface *impl, - PhocView *view, - struct wlr_surface *wlr_surface); -void phoc_view_child_destroy (PhocViewChild *child); -void phoc_view_child_apply_damage (PhocViewChild *child); -void phoc_view_child_damage_whole (PhocViewChild *child); -void phoc_view_child_map (PhocViewChild *child, struct wlr_surface *wlr_surface); -void phoc_view_child_unmap (PhocViewChild *child); +void phoc_view_add_child (PhocView *self, PhocViewChild *child); G_END_DECLS diff --git a/src/xdg-popup.c b/src/xdg-popup.c new file mode 100644 index 0000000000000000000000000000000000000000..51d898eb1e4d1ae301580fa6fa05abe904c70217 --- /dev/null +++ b/src/xdg-popup.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phoc-xdg-popup" + +#include "phoc-config.h" + +#include +#include +#include +#include "cursor.h" +#include "desktop.h" +#include "input.h" +#include "server.h" +#include "view.h" +#include "view-child-private.h" +#include "utils.h" +#include "xdg-popup.h" + +enum { + PROP_0, + PROP_WLR_POPUP, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +/** + * PhocXdgPopup: + * + * A popup as defined in the xdg-shell protocol + */ +typedef struct _PhocXdgPopup { + PhocViewChild parent_instance; + + struct wlr_xdg_popup *wlr_popup; + + struct wl_listener destroy; + struct wl_listener new_popup; + struct wl_listener reposition; + struct wl_listener surface_commit; +} PhocXdgPopup; + +G_DEFINE_FINAL_TYPE (PhocXdgPopup, phoc_xdg_popup, PHOC_TYPE_VIEW_CHILD) + + +static void +popup_get_pos (PhocViewChild *child, int *sx, int *sy) +{ + PhocXdgPopup *self = PHOC_XDG_POPUP (child); + struct wlr_xdg_popup *wlr_popup = self->wlr_popup; + struct wlr_xdg_surface *base = self->wlr_popup->base; + + wlr_xdg_popup_get_toplevel_coords (wlr_popup, + wlr_popup->current.geometry.x - base->current.geometry.x, + wlr_popup->current.geometry.y - base->current.geometry.y, + sx, sy); +} + + +static void +popup_unconstrain (PhocXdgPopup* self) +{ + /* get the output of the popup's positioner anchor point and convert it to + * the toplevel parent's coordinate system and then pass it to + * wlr_xdg_popup_unconstrain_from_box */ + PhocView *view = phoc_view_child_get_view (PHOC_VIEW_CHILD (self)); + + PhocOutput *output = phoc_desktop_layout_get_output (view->desktop, view->box.x, view->box.y); + if (output == NULL) + return; + + struct wlr_box output_box; + wlr_output_layout_get_box (view->desktop->layout, output->wlr_output, &output_box); + struct wlr_box usable_area = output->usable_area; + usable_area.x += output_box.x; + usable_area.y += output_box.y; + + /* the output box expressed in the coordinate system of the toplevel parent + * of the popup */ + struct wlr_box output_toplevel_sx_box = { + .x = usable_area.x - view->box.x, + .y = usable_area.y - view->box.y, + .width = usable_area.width, + .height = usable_area.height, + }; + + wlr_xdg_popup_unconstrain_from_box (self->wlr_popup, &output_toplevel_sx_box); +} + + +static void +popup_handle_destroy (struct wl_listener *listener, void *data) +{ + PhocXdgPopup *self = wl_container_of (listener, self, destroy); + + g_object_unref (self); +} + + +static void +popup_handle_new_popup (struct wl_listener *listener, void *data) +{ + PhocXdgPopup *self = wl_container_of (listener, self, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + + phoc_xdg_popup_new (phoc_view_child_get_view (PHOC_VIEW_CHILD (self)), wlr_popup); +} + + +static void +popup_handle_reposition (struct wl_listener *listener, void *data) +{ + PhocXdgPopup *self = wl_container_of (listener, self, reposition); + + /* clear the old popup positon */ + /* TODO: this is too much damage */ + phoc_view_damage_whole (phoc_view_child_get_view (PHOC_VIEW_CHILD (self))); + + popup_unconstrain (self); +} + + +static void +popup_handle_surface_commit (struct wl_listener *listener, void *data) +{ + PhocXdgPopup *self = wl_container_of (listener, self, surface_commit); + + if (self->wlr_popup->base->initial_commit) + popup_unconstrain (self); +} + + +static void +phoc_xdg_popup_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhocXdgPopup *self = PHOC_XDG_POPUP (object); + + switch (property_id) { + case PROP_WLR_POPUP: + self->wlr_popup = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phoc_xdg_popup_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhocXdgPopup *self = PHOC_XDG_POPUP (object); + + switch (property_id) { + case PROP_WLR_POPUP: + g_value_set_pointer (value, self->wlr_popup); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phoc_xdg_popup_constructed (GObject *object) +{ + PhocXdgPopup *self = PHOC_XDG_POPUP (object); + struct wlr_xdg_surface *xdg_surface = self->wlr_popup->base; + + G_OBJECT_CLASS (phoc_xdg_popup_parent_class)->constructed (object); + + self->destroy.notify = popup_handle_destroy; + wl_signal_add (&self->wlr_popup->base->events.destroy, &self->destroy); + + self->new_popup.notify = popup_handle_new_popup; + wl_signal_add (&self->wlr_popup->base->events.new_popup, &self->new_popup); + + self->reposition.notify = popup_handle_reposition; + wl_signal_add (&self->wlr_popup->events.reposition, &self->reposition); + + wl_signal_add (&xdg_surface->surface->events.commit, &self->surface_commit); + self->surface_commit.notify = popup_handle_surface_commit; +} + + +static void +phoc_xdg_popup_finalize (GObject *object) +{ + PhocXdgPopup *self = PHOC_XDG_POPUP (object); + + wl_list_remove (&self->surface_commit.link); + wl_list_remove (&self->reposition.link); + wl_list_remove (&self->new_popup.link); + wl_list_remove (&self->destroy.link); + + G_OBJECT_CLASS (phoc_xdg_popup_parent_class)->finalize (object); +} + + +static void +phoc_xdg_popup_class_init (PhocXdgPopupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhocViewChildClass *view_child_class = PHOC_VIEW_CHILD_CLASS (klass); + + object_class->constructed = phoc_xdg_popup_constructed; + object_class->finalize = phoc_xdg_popup_finalize; + object_class->get_property = phoc_xdg_popup_get_property; + object_class->set_property = phoc_xdg_popup_set_property; + + view_child_class->get_pos = popup_get_pos; + + props[PROP_WLR_POPUP] = + g_param_spec_pointer ("wlr-popup", "", "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phoc_xdg_popup_init (PhocXdgPopup *self) +{ +} + + +PhocXdgPopup * +phoc_xdg_popup_new (PhocView *view, struct wlr_xdg_popup *wlr_xdg_popup) +{ + return g_object_new (PHOC_TYPE_XDG_POPUP, + "view", view, + "wlr-popup", wlr_xdg_popup, + "wlr-surface", wlr_xdg_popup->base->surface, + NULL); +} diff --git a/src/xdg-popup.h b/src/xdg-popup.h new file mode 100644 index 0000000000000000000000000000000000000000..68ae7d33a5b55ca648ad09a1835da9906338ec23 --- /dev/null +++ b/src/xdg-popup.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "view.h" +#include "view-child-private.h" + +#include + +G_BEGIN_DECLS + +#define PHOC_TYPE_XDG_POPUP (phoc_xdg_popup_get_type ()) + +G_DECLARE_FINAL_TYPE (PhocXdgPopup, phoc_xdg_popup, PHOC, XDG_POPUP, PhocViewChild) + +PhocXdgPopup *phoc_xdg_popup_new (PhocView *view, + struct wlr_xdg_popup *wlr_popup); + +G_END_DECLS diff --git a/src/xdg-surface-private.h b/src/xdg-surface-private.h index 7514c2230d8766cb01f65ae4026154376dd18f6c..75778c344020cfb1bf435c966e2a190225b03161 100644 --- a/src/xdg-surface-private.h +++ b/src/xdg-surface-private.h @@ -6,17 +6,13 @@ #pragma once -#include +#include "xdg-surface.h" +#include "xdg-toplevel-decoration.h" -#include +#include G_BEGIN_DECLS -typedef struct _PhocXdgPopup PhocXdgPopup; -typedef struct _PhocXdgToplevelDecoration PhocXdgToplevelDecoration; - -PhocXdgPopup *phoc_xdg_popup_create (PhocView *view, - struct wlr_xdg_popup *wlr_popup); void phoc_xdg_surface_set_decoration (PhocXdgSurface *self, PhocXdgToplevelDecoration *decoration); PhocXdgToplevelDecoration * diff --git a/src/xdg-surface.c b/src/xdg-surface.c index ae9392b81ba8460120075990926c636d0d8d6408..942a7bbdf65a5ace12f25e67acfbfd8fee6907d6 100644 --- a/src/xdg-surface.c +++ b/src/xdg-surface.c @@ -13,8 +13,10 @@ #include "cursor.h" #include "server.h" #include "view-private.h" +#include "xdg-popup.h" #include "xdg-surface.h" #include "xdg-surface-private.h" +#include "xdg-toplevel-decoration.h" #include #include @@ -34,9 +36,10 @@ static GParamSpec *props[PROP_LAST_PROP]; /** * PhocXdgSurface: * - * An xdg surface. + * An xdg toplevel surface as defined in the xdg-shell protocol. For + * popups see [type@XdgPopup]. * - * For how to setup such an object see handle_xdg_shell_surface. + * For details on how to setup such an object see [func@handle_xdg_shell_surface]. */ typedef struct _PhocXdgSurface { PhocView view; @@ -492,7 +495,7 @@ handle_new_popup (struct wl_listener *listener, void *data) PhocXdgSurface *self = wl_container_of (listener, self, new_popup); struct wlr_xdg_popup *wlr_popup = data; - phoc_xdg_popup_create (PHOC_VIEW (self), wlr_popup); + phoc_xdg_popup_new (PHOC_VIEW (self), wlr_popup); } @@ -691,3 +694,32 @@ phoc_xdg_surface_get_wlr_xdg_surface (PhocXdgSurface *self) return self->xdg_surface; } + + +void +phoc_handle_xdg_shell_surface (struct wl_listener *listener, void *data) +{ + struct wlr_xdg_surface *surface = data; + + if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + g_debug ("New xdg popup"); + return; + } + + g_assert (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + PhocDesktop *desktop = wl_container_of (listener, desktop, xdg_shell_surface); + g_debug ("new xdg toplevel: title=%s, app_id=%s", + surface->toplevel->title, surface->toplevel->app_id); + + wlr_xdg_surface_ping (surface); + PhocXdgSurface *phoc_surface = phoc_xdg_surface_new (surface); + + // Check for app-id override coming from gtk-shell + PhocGtkShell *gtk_shell = phoc_desktop_get_gtk_shell (desktop); + PhocGtkSurface *gtk_surface = phoc_gtk_shell_get_gtk_surface_from_wlr_surface (gtk_shell, + surface->surface); + if (gtk_surface && phoc_gtk_surface_get_app_id (gtk_surface)) + phoc_view_set_app_id (PHOC_VIEW (phoc_surface), phoc_gtk_surface_get_app_id (gtk_surface)); + else + phoc_view_set_app_id (PHOC_VIEW (phoc_surface), surface->toplevel->app_id); +} diff --git a/src/xdg-surface.h b/src/xdg-surface.h index f9b197fe654bf344313bf83f3694d9202ab437d2..ad380a2dbc2faa37c51ec2f4c31a287cfcd0b486 100644 --- a/src/xdg-surface.h +++ b/src/xdg-surface.h @@ -26,4 +26,6 @@ struct wlr_surface *phoc_xdg_surface_get_wlr_surface_at (PhocXdgSurface *self, double *sub_x, double *sub_y); +void phoc_handle_xdg_shell_surface (struct wl_listener *listener, void *data); + G_END_DECLS diff --git a/src/xdg-toplevel-decoration.c b/src/xdg-toplevel-decoration.c new file mode 100644 index 0000000000000000000000000000000000000000..9af2ec1f23dad38381bdb664b7e0ecc555045406 --- /dev/null +++ b/src/xdg-toplevel-decoration.c @@ -0,0 +1,104 @@ +#define G_LOG_DOMAIN "phoc-xdg-toplevel-decoration" + +#include "phoc-config.h" +#include "xdg-surface-private.h" +#include "xdg-toplevel-decoration.h" + +#include +#include +#include +#include "xdg-surface.h" +#include "desktop.h" +#include "server.h" +#include "utils.h" + + +typedef struct _PhocXdgToplevelDecoration { + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; + PhocXdgSurface *surface; + struct wl_listener destroy; + struct wl_listener request_mode; + struct wl_listener surface_commit; +} PhocXdgToplevelDecoration; + + +static void +decoration_handle_destroy (struct wl_listener *listener, void *data) +{ + PhocXdgToplevelDecoration *decoration = wl_container_of (listener, decoration, destroy); + + g_debug ("Destroy xdg toplevel decoration %p", decoration); + + if (decoration->surface) { + phoc_xdg_surface_set_decoration (decoration->surface, NULL); + phoc_view_set_decorated (PHOC_VIEW (decoration->surface), FALSE); + g_signal_handlers_disconnect_by_data (decoration->surface, decoration); + } + wl_list_remove (&decoration->destroy.link); + wl_list_remove (&decoration->request_mode.link); + wl_list_remove (&decoration->surface_commit.link); + + free (decoration); +} + +static void +decoration_handle_request_mode (struct wl_listener *listener, void *data) +{ + PhocXdgToplevelDecoration *decoration = wl_container_of (listener, decoration, request_mode); + + enum wlr_xdg_toplevel_decoration_v1_mode mode = decoration->wlr_decoration->requested_mode; + + if (mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE) { + mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } + wlr_xdg_toplevel_decoration_v1_set_mode (decoration->wlr_decoration, mode); +} + +static void +decoration_handle_surface_commit (struct wl_listener *listener, void *data) +{ + PhocXdgToplevelDecoration *decoration = wl_container_of (listener, decoration, surface_commit); + + bool decorated = decoration->wlr_decoration->current.mode == + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + phoc_view_set_decorated (PHOC_VIEW (decoration->surface), decorated); +} + + +static void +on_xdg_surface_destroy (PhocXdgSurface *surface, PhocXdgToplevelDecoration *decoration) +{ + g_assert (PHOC_IS_XDG_SURFACE (surface)); + + decoration->surface = NULL; +} + + +void +phoc_handle_xdg_toplevel_decoration (struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration = data; + PhocXdgSurface *xdg_surface = PHOC_XDG_SURFACE (wlr_decoration->toplevel->base->data); + g_assert (xdg_surface != NULL); + struct wlr_xdg_surface *wlr_xdg_surface = phoc_xdg_surface_get_wlr_xdg_surface (xdg_surface); + PhocXdgToplevelDecoration *decoration = g_new0 (PhocXdgToplevelDecoration, 1); + + g_debug ("New xdg toplevel decoration %p", decoration); + + decoration->wlr_decoration = wlr_decoration; + decoration->surface = xdg_surface; + phoc_xdg_surface_set_decoration (xdg_surface, decoration); + + decoration->destroy.notify = decoration_handle_destroy; + wl_signal_add (&wlr_decoration->events.destroy, &decoration->destroy); + + decoration->request_mode.notify = decoration_handle_request_mode; + wl_signal_add (&wlr_decoration->events.request_mode, &decoration->request_mode); + + decoration->surface_commit.notify = decoration_handle_surface_commit; + wl_signal_add (&wlr_xdg_surface->surface->events.commit, &decoration->surface_commit); + + g_signal_connect (xdg_surface, "surface-destroy", G_CALLBACK (on_xdg_surface_destroy), decoration); + + decoration_handle_request_mode (&decoration->request_mode, wlr_decoration); +} diff --git a/src/xdg-toplevel-decoration.h b/src/xdg-toplevel-decoration.h new file mode 100644 index 0000000000000000000000000000000000000000..1af5ae3bdab39d7536c24e921a3de5a435f35c5a --- /dev/null +++ b/src/xdg-toplevel-decoration.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "xdg-surface.h" + +#include + +#include + +G_BEGIN_DECLS + +typedef struct _PhocXdgToplevelDecoration PhocXdgToplevelDecoration; + +void phoc_handle_xdg_toplevel_decoration (struct wl_listener *listener, void *data); + +G_END_DECLS diff --git a/src/xdg_shell.c b/src/xdg_shell.c deleted file mode 100644 index d3a860785d4a508fc68d29b71acbcd2e67e09b7e..0000000000000000000000000000000000000000 --- a/src/xdg_shell.c +++ /dev/null @@ -1,296 +0,0 @@ -#define G_LOG_DOMAIN "phoc-xdg-shell" - -#include "phoc-config.h" -#include "xdg-surface.h" -#include "xdg-surface-private.h" - -#include -#include -#include -#include -#include -#include "cursor.h" -#include "desktop.h" -#include "input.h" -#include "server.h" -#include "view.h" -#include "utils.h" - -typedef struct _PhocXdgToplevelDecoration { - struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; - PhocXdgSurface *surface; - struct wl_listener destroy; - struct wl_listener request_mode; - struct wl_listener surface_commit; -} PhocXdgToplevelDecoration; - -typedef struct _PhocXdgPopup { - PhocViewChild 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 wl_listener reposition; -} PhocXdgPopup; - -static const PhocViewChildInterface popup_impl; - -static void -popup_destroy (PhocViewChild *child) -{ - g_assert (child->impl == &popup_impl); - PhocXdgPopup *popup = (PhocXdgPopup *)child; - - wl_list_remove (&popup->reposition.link); - wl_list_remove (&popup->new_popup.link); - wl_list_remove (&popup->unmap.link); - wl_list_remove (&popup->map.link); - wl_list_remove (&popup->destroy.link); - - free (popup); -} - - -static void -popup_get_pos (PhocViewChild *child, int *sx, int *sy) -{ - PhocXdgPopup *popup = (PhocXdgPopup *)child; - struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; - - wlr_xdg_popup_get_toplevel_coords (wlr_popup, - wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x, - wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y, - sx, sy); -} - - -static const PhocViewChildInterface popup_impl = { - .get_pos = popup_get_pos, - .destroy = popup_destroy, -}; - - -static void -popup_unconstrain (PhocXdgPopup* popup) -{ - // get the output of the popup's positioner anchor point and convert it to - // the toplevel parent's coordinate system and then pass it to - // wlr_xdg_popup_unconstrain_from_box - PhocView *view = PHOC_VIEW (popup->child.view); - - PhocOutput *output = phoc_desktop_layout_get_output (view->desktop, view->box.x, view->box.y); - if (output == NULL) - return; - - struct wlr_box output_box; - wlr_output_layout_get_box (view->desktop->layout, output->wlr_output, &output_box); - struct wlr_box usable_area = output->usable_area; - usable_area.x += output_box.x; - usable_area.y += output_box.y; - - // the output box expressed in the coordinate system of the toplevel parent - // of the popup - struct wlr_box output_toplevel_sx_box = { - .x = usable_area.x - view->box.x, - .y = usable_area.y - view->box.y, - .width = usable_area.width, - .height = usable_area.height, - }; - - wlr_xdg_popup_unconstrain_from_box (popup->wlr_popup, &output_toplevel_sx_box); -} - - -static void -popup_handle_destroy (struct wl_listener *listener, void *data) -{ - PhocXdgPopup *popup = wl_container_of (listener, popup, destroy); - - phoc_view_child_destroy (&popup->child); -} - -static void -popup_handle_map (struct wl_listener *listener, void *data) -{ - PhocXdgPopup *popup = wl_container_of (listener, popup, map); - - /* Chain up to parent */ - phoc_view_child_map (&popup->child, popup->child.wlr_surface); -} - -static void -popup_handle_unmap (struct wl_listener *listener, void *data) -{ - PhocXdgPopup *popup = wl_container_of (listener, popup, unmap); - - /* Chain up to parent */ - phoc_view_child_unmap (&popup->child); -} - - -static void -popup_handle_new_popup (struct wl_listener *listener, void *data) -{ - PhocXdgPopup *popup = wl_container_of (listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - - phoc_xdg_popup_create (popup->child.view, wlr_popup); -} - - -static void -popup_handle_reposition (struct wl_listener *listener, void *data) -{ - PhocXdgPopup *popup = wl_container_of (listener, popup, reposition); - - /* clear the old popup positon */ - /* TODO: this is too much damage */ - phoc_view_damage_whole (popup->child.view); - - popup_unconstrain (popup); -} - - -PhocXdgPopup * -phoc_xdg_popup_create (PhocView *view, struct wlr_xdg_popup *wlr_popup) -{ - PhocXdgPopup *popup = calloc (1, sizeof(PhocXdgPopup)); - - if (popup == NULL) - return NULL; - - popup->wlr_popup = wlr_popup; - phoc_view_child_init (&popup->child, &popup_impl, view, wlr_popup->base->surface); - - popup->destroy.notify = popup_handle_destroy; - wl_signal_add (&wlr_popup->base->events.destroy, &popup->destroy); - - popup->map.notify = popup_handle_map; - wl_signal_add (&wlr_popup->base->surface->events.map, &popup->map); - - popup->unmap.notify = popup_handle_unmap; - wl_signal_add (&wlr_popup->base->surface->events.unmap, &popup->unmap); - - popup->new_popup.notify = popup_handle_new_popup; - wl_signal_add (&wlr_popup->base->events.new_popup, &popup->new_popup); - - popup->reposition.notify = popup_handle_reposition; - wl_signal_add (&wlr_popup->events.reposition, &popup->reposition); - - popup_unconstrain (popup); - - return popup; -} - - -void -handle_xdg_shell_surface (struct wl_listener *listener, void *data) -{ - struct wlr_xdg_surface *surface = data; - - g_assert (surface->role != WLR_XDG_SURFACE_ROLE_NONE); - if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - g_debug ("new xdg popup"); - return; - } - - PhocDesktop *desktop = wl_container_of(listener, desktop, xdg_shell_surface); - g_debug ("new xdg toplevel: title=%s, app_id=%s", - surface->toplevel->title, surface->toplevel->app_id); - - wlr_xdg_surface_ping (surface); - PhocXdgSurface *phoc_surface = phoc_xdg_surface_new (surface); - - // Check for app-id override coming from gtk-shell - PhocGtkShell *gtk_shell = phoc_desktop_get_gtk_shell (desktop); - PhocGtkSurface *gtk_surface = phoc_gtk_shell_get_gtk_surface_from_wlr_surface (gtk_shell, - surface->surface); - if (gtk_surface && phoc_gtk_surface_get_app_id (gtk_surface)) - phoc_view_set_app_id (PHOC_VIEW (phoc_surface), phoc_gtk_surface_get_app_id (gtk_surface)); - else - phoc_view_set_app_id (PHOC_VIEW (phoc_surface), surface->toplevel->app_id); -} - - -static void -decoration_handle_destroy (struct wl_listener *listener, void *data) -{ - PhocXdgToplevelDecoration *decoration = wl_container_of (listener, decoration, destroy); - - g_debug ("Destroy xdg toplevel decoration %p", decoration); - - if (decoration->surface) { - phoc_xdg_surface_set_decoration (decoration->surface, NULL); - phoc_view_set_decorated (PHOC_VIEW (decoration->surface), FALSE); - g_signal_handlers_disconnect_by_data (decoration->surface, decoration); - } - wl_list_remove (&decoration->destroy.link); - wl_list_remove (&decoration->request_mode.link); - wl_list_remove (&decoration->surface_commit.link); - - free (decoration); -} - -static void -decoration_handle_request_mode (struct wl_listener *listener, void *data) -{ - PhocXdgToplevelDecoration *decoration = wl_container_of (listener, decoration, request_mode); - - enum wlr_xdg_toplevel_decoration_v1_mode mode = decoration->wlr_decoration->requested_mode; - - if (mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE) { - mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - } - wlr_xdg_toplevel_decoration_v1_set_mode (decoration->wlr_decoration, mode); -} - -static void -decoration_handle_surface_commit (struct wl_listener *listener, void *data) -{ - PhocXdgToplevelDecoration *decoration = wl_container_of (listener, decoration, surface_commit); - - bool decorated = decoration->wlr_decoration->current.mode == - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - phoc_view_set_decorated (PHOC_VIEW (decoration->surface), decorated); -} - - -static void -on_xdg_surface_destroy (PhocXdgSurface *surface, PhocXdgToplevelDecoration *decoration) -{ - g_assert (PHOC_IS_XDG_SURFACE (surface)); - - decoration->surface = NULL; -} - - -void -handle_xdg_toplevel_decoration (struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration = data; - PhocXdgSurface *xdg_surface = PHOC_XDG_SURFACE (wlr_decoration->toplevel->base->data); - g_assert (xdg_surface != NULL); - struct wlr_xdg_surface *wlr_xdg_surface = phoc_xdg_surface_get_wlr_xdg_surface (xdg_surface); - PhocXdgToplevelDecoration *decoration = g_new0 (PhocXdgToplevelDecoration, 1); - - g_debug ("New xdg toplevel decoration %p", decoration); - - decoration->wlr_decoration = wlr_decoration; - decoration->surface = xdg_surface; - phoc_xdg_surface_set_decoration (xdg_surface, decoration); - - decoration->destroy.notify = decoration_handle_destroy; - wl_signal_add (&wlr_decoration->events.destroy, &decoration->destroy); - - decoration->request_mode.notify = decoration_handle_request_mode; - wl_signal_add (&wlr_decoration->events.request_mode, &decoration->request_mode); - - decoration->surface_commit.notify = decoration_handle_surface_commit; - wl_signal_add (&wlr_xdg_surface->surface->events.commit, &decoration->surface_commit); - - g_signal_connect (xdg_surface, "surface-destroy", G_CALLBACK (on_xdg_surface_destroy), decoration); - - decoration_handle_request_mode (&decoration->request_mode, wlr_decoration); -}