diff --git a/src/layout-manager.c b/src/layout-manager.c index eee204d946f71cbd5c1dac3f07510df5e439a284..42b2a8086e5f38fa029039f85fbccf21ea70a2f7 100644 --- a/src/layout-manager.c +++ b/src/layout-manager.c @@ -1,7 +1,9 @@ /* - * Copyright (C) 2023 Guido Günther + * Copyright (C) 2023-2025 The Phosh Developers * * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther */ #define G_LOG_DOMAIN "phosh-layout-manager" @@ -42,26 +44,36 @@ struct _PhoshLayoutManager { PhoshLayoutClockPosition clock_pos; guint clock_shift; guint corner_shift; + guint network_box_shift; + guint indicators_box_shift; PhoshMonitor *builtin; }; G_DEFINE_TYPE (PhoshLayoutManager, phosh_layout_manager, G_TYPE_OBJECT) +/* Width of an item in the indicator box */ +#define BOX_ITEM_WIDTH 24 /* px */ + +/* The minimum space needed when shifting the indicator area due to a + * cutout. This is less than the `*_box_rect.width` as the clock will + * just be shifted by GTK in those cases */ +#define CORNER_CUTOUT_SHIFT_THRESHOLD (PHOSH_TOP_BAR_MIN_PADDING + 3 * BOX_ITEM_WIDTH) + /* Space we want reserved for the central clock */ -static GdkRectangle center_clock_rect = { +static const GdkRectangle center_clock_rect = { .width = 40, .height = PHOSH_TOP_BAR_HEIGHT }; -static GdkRectangle network_box_rect = { +static const GdkRectangle network_box_rect = { /* Relevant icons are wifi, bt, 2 * wwan, network status */ - .width = 24 /* px */ * 5, + .width = BOX_ITEM_WIDTH * 5, .height = PHOSH_TOP_BAR_HEIGHT }; -static GdkRectangle indicators_box_rect = { +static const GdkRectangle indicators_box_rect = { /* Relevant icons are battery, vpn, location and language */ - .width = 24 /* px */ * 4 /* max icons */, + .width = BOX_ITEM_WIDTH * 4 /* max icons */, .height = PHOSH_TOP_BAR_HEIGHT }; @@ -115,10 +127,10 @@ get_clock_pos (PhoshLayoutManager *self, guint *clock_shift) bounds = gm_cutout_get_bounds (cutout); notch = (GdkRectangle) { - .x = bounds->x / scale, - .y = bounds->y / scale, - .width = bounds->width / scale, - .height = bounds->height / scale + .x = floor (bounds->x / scale), + .y = floor (bounds->y / scale), + .width = ceil (bounds->width / scale), + .height = ceil (bounds->height / scale), }; /* Look for top-bar notch */ @@ -153,6 +165,76 @@ get_clock_pos (PhoshLayoutManager *self, guint *clock_shift) return clock_pos; } +/** + * get_cutout_shifts: + * @self: The layout manager + * + * Get the shifts for network and indicator box. + * + * If the network box can't be left aligned due to the built-in + * display having a notch shift it to the right. Similar for the + * indicators but shift them to the left. + * + * We assume the panel uses its native orientation. + */ +static void +get_cutout_shifts (PhoshLayoutManager *self, guint *network, guint *indicators) +{ + PhoshShellLayout layout; + GListModel *cutouts; + float scale; + GdkRectangle indicators_box = indicators_box_rect; + GdkRectangle network_box = network_box_rect; + guint width; + + layout = g_settings_get_enum (self->settings, SHELL_LAYOUT_KEY); + if (layout != PHOSH_SHELL_LAYOUT_DEVICE) + goto out; + + if (self->builtin == NULL) + goto out; + + if (phosh_monitor_get_transform (self->builtin) != PHOSH_MONITOR_TRANSFORM_NORMAL) + goto out; + + scale = phosh_monitor_get_fractional_scale (self->builtin); + width = self->builtin->logical.width; + + network_box.x = PHOSH_TOP_BAR_MIN_PADDING; + indicators_box.x = width - indicators_box.width - PHOSH_TOP_BAR_MIN_PADDING; + + cutouts = gm_display_panel_get_cutouts (self->panel); + for (int i = 0; i < g_list_model_get_n_items (cutouts); i++) { + g_autoptr (GmCutout) cutout = g_list_model_get_item (cutouts, i); + const GmRect *phys_bounds = gm_cutout_get_bounds (cutout); + GdkRectangle bounds; + int available_space; + + bounds = (GdkRectangle) { + .x = floor (phys_bounds->x / scale), + .y = floor (phys_bounds->y / scale), + .width = ceil (phys_bounds->width / scale), + .height = ceil (phys_bounds->height / scale), + }; + + available_space = ((width - center_clock_rect.width) / 2) - (bounds.x + bounds.width) - + CORNER_CUTOUT_SHIFT_THRESHOLD; + if (gdk_rectangle_intersect (&bounds, &network_box, NULL) && available_space > 0) + *network = bounds.x + bounds.width + PHOSH_TOP_BAR_CUTOUT_MIN_PADDING; + + available_space = ((width - center_clock_rect.width) / 2) - (width - bounds.x) - + CORNER_CUTOUT_SHIFT_THRESHOLD; + if (gdk_rectangle_intersect (&bounds, &indicators_box, NULL) && available_space > 0) + *indicators = (self->builtin->width / scale - bounds.x) + PHOSH_TOP_BAR_CUTOUT_MIN_PADDING; + } + + out: + *network = MAX (*network, PHOSH_TOP_BAR_MIN_PADDING); + *indicators = MAX (*indicators, PHOSH_TOP_BAR_MIN_PADDING); + + g_debug ("Network box: %d, indicators shift: %d", *network, *indicators); +} + /** * get_corner_shift: * @self: The layout manager @@ -208,19 +290,29 @@ static void update_layout (PhoshLayoutManager *self) { PhoshLayoutClockPosition pos; - guint corner_shift, shift = 0; + guint corner_shift, clock_shift = 0; + guint network_box_shift = 0, indicators_box_shift = 0; corner_shift = get_corner_shift (self); - pos = get_clock_pos (self, &shift); + get_cutout_shifts (self, &network_box_shift, &indicators_box_shift); + pos = get_clock_pos (self, &clock_shift); + + indicators_box_shift = MAX (indicators_box_shift, corner_shift); + network_box_shift = MAX (network_box_shift, corner_shift); if (self->corner_shift == corner_shift && - self->clock_pos == pos && self->clock_shift == shift) { + self->network_box_shift == network_box_shift && + self->indicators_box_shift == indicators_box_shift && + self->clock_pos == pos && + self->clock_shift == clock_shift) { return; } self->clock_pos = pos; - self->clock_shift = shift; + self->clock_shift = clock_shift; self->corner_shift = corner_shift; + self->network_box_shift = network_box_shift; + self->indicators_box_shift = indicators_box_shift; g_signal_emit (self, signals[LAYOUT_CHANGED], 0); } @@ -301,7 +393,9 @@ phosh_layout_manager_init (PhoshLayoutManager *self) PhoshShell *shell = phosh_shell_get_default (); g_autoptr (GmDeviceInfo) info = NULL; - self->corner_shift = PHOSH_TOP_BAR_MIN_PADDING; + self->network_box_shift = PHOSH_TOP_BAR_MIN_PADDING; + self->indicators_box_shift = PHOSH_TOP_BAR_MIN_PADDING; + self->settings = g_settings_new ("sm.puri.phosh"); compatibles = gm_device_tree_get_compatibles (NULL, &err); @@ -358,18 +452,22 @@ phosh_layout_manager_get_clock_shift (PhoshLayoutManager *self) } /** - * phosh_layout_manager_get_corner_shift: + * phosh_layout_manager_get_box_shifts: * @self: The layout manager + * @network_shift: (out): The shift of the network box + * @indicators_shift: (out): The shift of the indicators box * * Gets the amount of pixels UI elements should be moved to towards the - * center because of rounded corners. - * - * Returns: Returns the shift in pixels. + * center because of rounded corners or notches. */ -guint -phosh_layout_manager_get_corner_shift (PhoshLayoutManager *self) +void +phosh_layout_manager_get_box_shifts (PhoshLayoutManager *self, + guint *network_shift, + guint *indicators_shift) { - g_return_val_if_fail (PHOSH_IS_LAYOUT_MANAGER (self), 0); + g_return_if_fail (PHOSH_IS_LAYOUT_MANAGER (self)); + g_return_if_fail (network_shift && indicators_shift); - return self->corner_shift; + *network_shift = self->network_box_shift; + *indicators_shift = self->indicators_box_shift; } diff --git a/src/layout-manager.h b/src/layout-manager.h index a8563e7c1c660204b0368c5da4aa4a00ab3c3bfe..54b8dc4d4282599674e5e44d17d8f88c6cfa1ac3 100644 --- a/src/layout-manager.h +++ b/src/layout-manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Guido Günther + * Copyright (C) 2023-2025 The Phosh Developers * * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -21,6 +21,7 @@ G_DECLARE_FINAL_TYPE (PhoshLayoutManager, phosh_layout_manager, PHOSH, LAYOUT_MA PhoshLayoutManager *phosh_layout_manager_new (void); PhoshLayoutClockPosition phosh_layout_manager_get_clock_pos (PhoshLayoutManager *self); guint phosh_layout_manager_get_clock_shift (PhoshLayoutManager *self); -guint phosh_layout_manager_get_corner_shift (PhoshLayoutManager *self); - +void phosh_layout_manager_get_box_shifts (PhoshLayoutManager *self, + guint *network_shift, + guint *indicators_shift); G_END_DECLS diff --git a/src/top-panel.c b/src/top-panel.c index 2ee3ec9d98b62020a8d2830cac110f134f7487e7..91344ef48ca80980790fed847a473c778f55425b 100644 --- a/src/top-panel.c +++ b/src/top-panel.c @@ -101,6 +101,7 @@ typedef struct _PhoshTopPanel { GtkGesture *click_gesture; /* needed so that the gesture isn't destroyed immediately */ PhoshTopPanelBg *background; + GtkCssProvider *cutout_css_provider; } PhoshTopPanel; G_DEFINE_TYPE (PhoshTopPanel, phosh_top_panel, PHOSH_TYPE_DRAG_SURFACE) @@ -669,6 +670,7 @@ phosh_top_panel_dispose (GObject *object) self->seat = NULL; } g_clear_pointer (&self->background, phosh_cp_widget_destroy); + g_clear_object (&self->cutout_css_provider); G_OBJECT_CLASS (phosh_top_panel_parent_class)->dispose (object); } @@ -845,13 +847,29 @@ set_clock_position (PhoshTopPanel *self, PhoshLayoutManager *layout_manager) static void set_margin (PhoshTopPanel *self, PhoshLayoutManager *layout_manager) { - guint shift; + guint network_box_shift = 0, indicators_box_shift = 0; + g_autofree char *css = NULL; + g_autoptr (GtkCssProvider) provider = gtk_css_provider_new (); - shift = phosh_layout_manager_get_corner_shift (layout_manager); - g_debug ("Shifting UI elements %d pixels to center ", shift); + phosh_layout_manager_get_box_shifts (layout_manager, + &network_box_shift, + &indicators_box_shift); - gtk_widget_set_margin_start (GTK_WIDGET (self->box_top_bar), shift); - gtk_widget_set_margin_end (GTK_WIDGET (self->box_top_bar), shift); + g_debug ("Shifting UI elements %u,%u pixels to center ", + network_box_shift, + indicators_box_shift); + + css = g_strdup_printf ("#top-bar > :first-child {" + " padding-left: %dpx;" + "}" + "#top-bar > :last-child {" + " padding-right: %dpx;" + "}", network_box_shift, indicators_box_shift); + gtk_css_provider_load_from_data (provider, css, -1, NULL); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1); + g_set_object (&self->cutout_css_provider, provider); } @@ -861,8 +879,8 @@ on_layout_changed (PhoshTopPanel *self, PhoshLayoutManager *layout_manager) g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); g_return_if_fail (PHOSH_IS_LAYOUT_MANAGER (layout_manager)); - set_margin (self, layout_manager); set_clock_position (self, layout_manager); + set_margin (self, layout_manager); } diff --git a/src/top-panel.h b/src/top-panel.h index 83e8390d88bd26c0da829217db0b151041ebd174..5d8d5f9d056debad9b2f33ffaaa43bc4f48e5211 100644 --- a/src/top-panel.h +++ b/src/top-panel.h @@ -15,7 +15,10 @@ G_DECLARE_FINAL_TYPE (PhoshTopPanel, phosh_top_panel, PHOSH, TOP_PANEL, PhoshDra #define PHOSH_TOP_BAR_HEIGHT 32 #define PHOSH_TOP_BAR_ICON_SIZE GTK_ICON_SIZE_SMALL_TOOLBAR +/* Minimum padding of network and indicator box to the left / right screen edge */ #define PHOSH_TOP_BAR_MIN_PADDING 9 +/* Minimum padding of network and indicator box to the left / right display cutouts */ +#define PHOSH_TOP_BAR_CUTOUT_MIN_PADDING (PHOSH_TOP_BAR_MIN_PADDING / 2) /** * PhoshTopPanelState: