From b3d04cb2331d15da76f6f2fcaa14516f7736b59d Mon Sep 17 00:00:00 2001 From: Leonhard Date: Wed, 27 Sep 2023 18:09:58 +0200 Subject: [PATCH 01/31] Prototype menu --- src/WindowManager.vala | 92 +++++++++++++++++++++++------------------- src/meson.build | 1 + 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/WindowManager.vala b/src/WindowManager.vala index e872db30c..aab51102b 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -73,6 +73,7 @@ namespace Gala { private WindowSwitcher? winswitcher = null; private ActivatableComponent? window_overview = null; + private WindowMenu window_menu; public ScreenSaverManager? screensaver { get; private set; } @@ -345,6 +346,8 @@ namespace Gala { ui_group.add_child ((Clutter.Actor) window_overview); } + window_menu = new WindowMenu (this); + notification_group = new Clutter.Actor (); ui_group.add_child (notification_group); @@ -985,48 +988,53 @@ namespace Gala { public override void show_window_menu (Meta.Window window, Meta.WindowMenuType menu, int x, int y) { switch (menu) { case Meta.WindowMenuType.WM: - if (daemon_proxy == null || window.get_window_type () == Meta.WindowType.NOTIFICATION) { - return; - } - - WindowFlags flags = WindowFlags.NONE; - if (window.can_minimize ()) - flags |= WindowFlags.CAN_HIDE; - - if (window.can_maximize ()) - flags |= WindowFlags.CAN_MAXIMIZE; - - var maximize_flags = window.get_maximized (); - if (maximize_flags > 0) { - flags |= WindowFlags.IS_MAXIMIZED; - - if (Meta.MaximizeFlags.VERTICAL in maximize_flags && !(Meta.MaximizeFlags.HORIZONTAL in maximize_flags)) { - flags |= WindowFlags.IS_TILED; - } - } - - if (window.allows_move ()) - flags |= WindowFlags.ALLOWS_MOVE; - - if (window.allows_resize ()) - flags |= WindowFlags.ALLOWS_RESIZE; - - if (window.is_above ()) - flags |= WindowFlags.ALWAYS_ON_TOP; - - if (window.on_all_workspaces) - flags |= WindowFlags.ON_ALL_WORKSPACES; - - if (window.can_close ()) - flags |= WindowFlags.CAN_CLOSE; - - daemon_proxy.show_window_menu.begin (flags, x, y, (obj, res) => { - try { - ((Daemon) obj).show_window_menu.end (res); - } catch (Error e) { - message ("Error invoking MenuManager: %s", e.message); - } - }); + warning ("CREATE MENU"); + var window_menu = new WindowMenu (this); + ui_group.add_child (window_menu); + window_menu.set_position (x, y); + window_menu.handle_switch_windows (get_display () ); + // if (daemon_proxy == null || window.get_window_type () == Meta.WindowType.NOTIFICATION) { + // return; + // } + + // WindowFlags flags = WindowFlags.NONE; + // if (window.can_minimize ()) + // flags |= WindowFlags.CAN_HIDE; + + // if (window.can_maximize ()) + // flags |= WindowFlags.CAN_MAXIMIZE; + + // var maximize_flags = window.get_maximized (); + // if (maximize_flags > 0) { + // flags |= WindowFlags.IS_MAXIMIZED; + + // if (Meta.MaximizeFlags.VERTICAL in maximize_flags && !(Meta.MaximizeFlags.HORIZONTAL in maximize_flags)) { + // flags |= WindowFlags.IS_TILED; + // } + // } + + // if (window.allows_move ()) + // flags |= WindowFlags.ALLOWS_MOVE; + + // if (window.allows_resize ()) + // flags |= WindowFlags.ALLOWS_RESIZE; + + // if (window.is_above ()) + // flags |= WindowFlags.ALWAYS_ON_TOP; + + // if (window.on_all_workspaces) + // flags |= WindowFlags.ON_ALL_WORKSPACES; + + // if (window.can_close ()) + // flags |= WindowFlags.CAN_CLOSE; + + // daemon_proxy.show_window_menu.begin (flags, x, y, (obj, res) => { + // try { + // ((Daemon) obj).show_window_menu.end (res); + // } catch (Error e) { + // message ("Error invoking MenuManager: %s", e.message); + // } + // }); break; case Meta.WindowMenuType.APP: // FIXME we don't have any sort of app menus diff --git a/src/meson.build b/src/meson.build index a60a295e1..4ebd98f6b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -52,6 +52,7 @@ gala_bin_sources = files( 'Widgets/WindowClone.vala', 'Widgets/WindowCloneContainer.vala', 'Widgets/WindowIconActor.vala', + 'Widgets/WindowMenu.vala', 'Widgets/WindowOverview.vala', 'Widgets/WindowSwitcher/WindowSwitcher.vala', 'Widgets/WindowSwitcher/WindowSwitcherIcon.vala', From efe76191fb22e1f6d5e658e5a6cbf019849f7e32 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Wed, 27 Sep 2023 18:10:22 +0200 Subject: [PATCH 02/31] Add missing files --- src/Widgets/WindowMenu.vala | 517 ++++++++++++++++++++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 src/Widgets/WindowMenu.vala diff --git a/src/Widgets/WindowMenu.vala b/src/Widgets/WindowMenu.vala new file mode 100644 index 000000000..beab40546 --- /dev/null +++ b/src/Widgets/WindowMenu.vala @@ -0,0 +1,517 @@ +/* + * Copyright 2021 Aral Balkan + * Copyright 2020 Mark Story + * Copyright 2017 Popye + * Copyright 2014 Tom Beckmann + * Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +public class Gala.WindowMenu : Clutter.Actor { + public const int ICON_SIZE = 64; + public const int WRAPPER_PADDING = 12; + private const string CAPTION_FONT_NAME = "Inter"; + private const int MIN_OFFSET = 64; + private const int ANIMATION_DURATION = 200; + + public bool opened { get; private set; default = false; } + + public Gala.WindowManager? wm { get; construct; } + private Gala.ModalProxy modal_proxy = null; + + private Granite.Settings granite_settings; + private Clutter.Canvas canvas; + private Clutter.Actor container; + private Clutter.Text caption; + + private Gtk.WidgetPath widget_path; + private Gtk.StyleContext style_context; + private unowned Gtk.CssProvider? dark_style_provider = null; + + private int modifier_mask; + + private bool first_release = true; + + private WindowSwitcherIcon? _current_icon = null; + private WindowSwitcherIcon? current_icon { + get { + return _current_icon; + } + set { + if (_current_icon != null) { + _current_icon.selected = false; + } + + _current_icon = value; + if (_current_icon != null) { + _current_icon.selected = true; + } + + update_caption_text (); + } + } + + private float scaling_factor = 1.0f; + + public WindowMenu (Gala.WindowManager wm) { + Object (wm: wm); + } + + construct { + unowned var gtk_settings = Gtk.Settings.get_default (); + granite_settings = Granite.Settings.get_default (); + + unowned var display = wm.get_display (); + scaling_factor = display.get_monitor_scale (display.get_current_monitor ()); + + canvas = new Clutter.Canvas (); + canvas.scale_factor = scaling_factor; + set_content (canvas); + + opacity = 0; + + // Carry out the initial draw + create_components (); + + var effect = new ShadowEffect (40) { + shadow_opacity = 200, + css_class = "window-switcher", + scale_factor = scaling_factor + }; + add_effect (effect); + + // Redraw the components if the colour scheme changes. + granite_settings.notify["prefers-color-scheme"].connect (() => { + canvas.invalidate (); + create_components (); + }); + + gtk_settings.notify["gtk-theme-name"].connect (() => { + canvas.invalidate (); + create_components (); + }); + + unowned var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); + monitor_manager.monitors_changed.connect (() => { + var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); + if (cur_scale != scaling_factor) { + scaling_factor = cur_scale; + canvas.scale_factor = scaling_factor; + effect.scale_factor = scaling_factor; + create_components (); + } + }); + + canvas.draw.connect (draw); + } + + private bool draw (Cairo.Context ctx, int width, int height) { + if (style_context == null) { // gtk is not initialized yet + create_gtk_objects (); + } + + ctx.save (); + ctx.set_operator (Cairo.Operator.CLEAR); + ctx.paint (); + ctx.clip (); + ctx.reset_clip (); + + if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + unowned var gtksettings = Gtk.Settings.get_default (); + dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); + style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + } else if (dark_style_provider != null) { + style_context.remove_provider (dark_style_provider); + dark_style_provider = null; + } + + ctx.set_operator (Cairo.Operator.OVER); + style_context.render_background (ctx, 0, 0, width, height); + style_context.render_frame (ctx, 0, 0, width, height); + ctx.restore (); + + return true; + } + + private void create_components () { + // We've already been constructed once, start again + if (container != null) { + destroy_all_children (); + } + + var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); + var layout = new Clutter.FlowLayout (Clutter.FlowOrientation.HORIZONTAL); + container = new Clutter.Actor () { + reactive = true, + layout_manager = layout, + margin_left = margin, + margin_top = margin, + margin_right = margin, + margin_bottom = margin + }; + + container.button_release_event.connect (container_mouse_release); + container.motion_event.connect (container_motion_event); + + var caption_color = "#2e2e31"; + + if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + caption_color = "#fafafa"; + } + + caption = new Clutter.Text.full (CAPTION_FONT_NAME, "", Clutter.Color.from_string (caption_color)); + caption.set_pivot_point (0.5f, 0.5f); + caption.set_ellipsize (Pango.EllipsizeMode.END); + caption.set_line_alignment (Pango.Alignment.CENTER); + + add_child (container); + add_child (caption); + } + + private void create_gtk_objects () { + widget_path = new Gtk.WidgetPath (); + widget_path.append_type (typeof (Gtk.Window)); + widget_path.iter_set_object_name (-1, "window"); + + style_context = new Gtk.StyleContext (); + style_context.set_scale ((int)Math.round (scaling_factor)); + style_context.set_path (widget_path); + style_context.add_class ("background"); + style_context.add_class ("csd"); + style_context.add_class ("unified"); + } + + [CCode (instance_pos = -1)] + public void handle_switch_windows ( + Meta.Display display + ) { + var workspace = display.get_workspace_manager ().get_active_workspace (); + + // copied from gnome-shell, finds the primary modifier in the mask + // var mask = binding.get_mask (); + // if (mask == 0) { + // modifier_mask = 0; + // } else { + // modifier_mask = 1; + // while (mask > 1) { + // mask >>= 1; + // modifier_mask <<= 1; + // } + // } + + if (!opened) { + bool windows_exist; + // if (binding.get_name ().has_prefix ("switch-group")) { + // windows_exist = collect_current_windows (display, workspace); + // } else { + // windows_exist = collect_all_windows (display, workspace); + // } + + // if (!windows_exist) { + // return; + // } + + open_switcher (); + } + + // var binding_name = binding.get_name (); + // var backward = binding_name.has_suffix ("-backward"); + + next_window (false); + } + + private bool collect_all_windows (Meta.Display display, Meta.Workspace? workspace) { + var windows = display.get_tab_list (Meta.TabList.NORMAL, workspace); + if (windows == null) { + return false; + } + + unowned var current_window = display.get_tab_current (Meta.TabList.NORMAL, workspace); + if (current_window == null) { + current_icon = null; + } + + container.width = -1; + container.destroy_all_children (); + + foreach (unowned var window in windows) { + var icon = new WindowSwitcherIcon (window, ICON_SIZE, scaling_factor); + if (window == current_window) { + current_icon = icon; + } + + container.add_child (icon); + } + + return true; + } + + private bool collect_current_windows (Meta.Display display, Meta.Workspace? workspace) { + var windows = display.get_tab_list (Meta.TabList.NORMAL, workspace); + if (windows == null) { + return false; + } + + unowned var current_window = display.get_tab_current (Meta.TabList.NORMAL, workspace); + if (current_window == null) { + current_icon = null; + return false; + } + + container.width = -1; + container.destroy_all_children (); + + unowned var window_tracker = ((WindowManagerGala) wm).window_tracker; + var app = window_tracker.get_app_for_window (current_window); + foreach (unowned var window in windows) { + if (window_tracker.get_app_for_window (window) == app) { + var icon = new WindowSwitcherIcon (window, ICON_SIZE, scaling_factor); + if (window == current_window) { + current_icon = icon; + } + + container.add_child (icon); + } + } + + return true; + } + + private void open_switcher () { + // if (container.get_n_children () == 0) { + // Clutter.get_default_backend ().get_default_seat ().bell_notify (); + // return; + // } + + if (opened) { + return; + } + + opacity = 0; + + unowned var display = wm.get_display (); + var monitor = display.get_current_monitor (); + var geom = display.get_monitor_geometry (monitor); + + float container_width; + container.get_preferred_width ( + InternalUtils.scale_to_int (ICON_SIZE, scaling_factor) + container.margin_left + container.margin_right, + null, + out container_width + ); + if (container_width + InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2 > geom.width) { + container.width = geom.width - InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2; + } + + float nat_width, nat_height; + container.get_preferred_size (null, null, out nat_width, out nat_height); + + var switcher_height = (int) (nat_height + caption.height / 2 - container.margin_bottom + WRAPPER_PADDING * 3 * scaling_factor); + set_size ((int) nat_width, switcher_height); + canvas.set_size ((int) nat_width, switcher_height); + canvas.invalidate (); + + // container width might have changed, so we must update caption width too + update_caption_text (); + + toggle_display (true); + } + + private void toggle_display (bool show) { + if (opened == show) { + return; + } + + opened = show; + if (show) { + push_modal (); + } else { + wm.pop_modal (modal_proxy); + } + + save_easing_state (); + set_easing_duration (wm.enable_animations ? ANIMATION_DURATION : 0); + opacity = show ? 255 : 0; + restore_easing_state (); + + container.reactive = show; + } + + private void push_modal () { + modal_proxy = wm.push_modal (this); + modal_proxy.set_keybinding_filter ((binding) => { + var action = Meta.Prefs.get_keybinding_action (binding.get_name ()); + + switch (action) { + case Meta.KeyBindingAction.NONE: + case Meta.KeyBindingAction.LOCATE_POINTER_KEY: + case Meta.KeyBindingAction.SWITCH_APPLICATIONS: + case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD: + case Meta.KeyBindingAction.SWITCH_WINDOWS: + case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: + case Meta.KeyBindingAction.SWITCH_GROUP: + case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: + return false; + default: + break; + } + + return true; + }); + + } + + private void close_switcher (uint32 time, bool cancel = false) { + if (!opened) { + return; + } + + // var window = current_icon.window; + // if (window == null) { + // return; + // } + + // if (!cancel) { + // var workspace = window.get_workspace (); + // if (workspace != wm.get_display ().get_workspace_manager ().get_active_workspace ()) { + // workspace.activate_with_focus (window, time); + // } else { + // window.activate (time); + // } + // } + + toggle_display (false); + } + + private void next_window (bool backward) { + Clutter.Actor actor; + + if (container.get_n_children () == 1 && current_icon != null) { + Clutter.get_default_backend ().get_default_seat ().bell_notify (); + return; + } + + if (current_icon == null) { + actor = container.get_first_child (); + } else if (!backward) { + actor = current_icon.get_next_sibling (); + if (actor == null) { + actor = container.get_first_child (); + } + } else { + actor = current_icon.get_previous_sibling (); + if (actor == null) { + actor = container.get_last_child (); + } + } + + current_icon = (WindowSwitcherIcon) actor; + } + + private void update_caption_text () { + var current_window = current_icon != null ? current_icon.window : null; + var current_caption = current_window != null ? current_window.title : "n/a"; + caption.set_text (current_caption); + + // Make caption smaller than the wrapper, so it doesn't overflow. + caption.width = width - WRAPPER_PADDING * 2 * scaling_factor; + caption.set_position ( + InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor), + (int) (height - caption.height / 2 - InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor) * 2) + ); + } + + public override void key_focus_out () { + close_switcher (wm.get_display ().get_current_time ()); + } + + public override bool button_release_event (Clutter.ButtonEvent event) { + if (first_release) { + first_release = false; + return true; + } + + close_switcher (event.get_time ()); + first_release = true; + return true; + } + +#if HAS_MUTTER45 + private bool container_motion_event (Clutter.Event event) { +#else + private bool container_motion_event (Clutter.MotionEvent event) { +#endif + float x, y; + event.get_coords (out x, out y); + var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); + if (actor == null) { + return true; + } + + var selected = actor as WindowSwitcherIcon; + if (selected == null) { + return true; + } + + if (current_icon != selected) { + current_icon = selected; + } + + return true; + } + +#if HAS_MUTTER45 + private bool container_mouse_release (Clutter.Event event) { +#else + private bool container_mouse_release (Clutter.ButtonEvent event) { +#endif + if (opened && event.get_button () == Clutter.Button.PRIMARY) { + close_switcher (event.get_time ()); + } + + return true; + } + +#if HAS_MUTTER45 + public override bool key_release_event (Clutter.Event event) { +#else + public override bool key_release_event (Clutter.KeyEvent event) { +#endif + // if ((get_current_modifiers () & modifier_mask) == 0) { + // close_switcher (event.get_time ()); + // } + + return Clutter.EVENT_PROPAGATE; + } + +#if HAS_MUTTER45 + public override bool key_press_event (Clutter.Event event) { +#else + public override bool key_press_event (Clutter.KeyEvent event) { +#endif + switch (event.get_key_symbol ()) { + case Clutter.Key.Right: + next_window (false); + return Clutter.EVENT_STOP; + case Clutter.Key.Left: + next_window (true); + return Clutter.EVENT_STOP; + case Clutter.Key.Escape: + close_switcher (event.get_time (), true); + return Clutter.EVENT_PROPAGATE; + case Clutter.Key.Return: + close_switcher (event.get_time (), false); + return Clutter.EVENT_PROPAGATE; + } + + return Clutter.EVENT_PROPAGATE; + } + + + private inline Clutter.ModifierType get_current_modifiers () { + Clutter.ModifierType modifiers; + wm.get_display ().get_cursor_tracker ().get_pointer (null, out modifiers); + + return modifiers & Clutter.ModifierType.MODIFIER_MASK; + } +} From 88bcd6291843c8816136bd34c5448a3cef7a6ce0 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Wed, 27 Sep 2023 23:49:52 +0200 Subject: [PATCH 03/31] Add menuitems --- src/Widgets/Menu/Menu.vala | 296 +++++++++++++++++++++++++++++++++ src/Widgets/Menu/Menu.vala~ | 281 +++++++++++++++++++++++++++++++ src/Widgets/Menu/MenuItem.vala | 94 +++++++++++ src/WindowManager.vala | 3 +- src/meson.build | 4 +- 5 files changed, 676 insertions(+), 2 deletions(-) create mode 100644 src/Widgets/Menu/Menu.vala create mode 100644 src/Widgets/Menu/Menu.vala~ create mode 100644 src/Widgets/Menu/MenuItem.vala diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala new file mode 100644 index 000000000..327a4017c --- /dev/null +++ b/src/Widgets/Menu/Menu.vala @@ -0,0 +1,296 @@ +/* + * Copyright 2021 Aral Balkan + * Copyright 2020 Mark Story + * Copyright 2017 Popye + * Copyright 2014 Tom Beckmann + * Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +public class Gala.WindowMenu : Clutter.Actor { + public const int ICON_SIZE = 64; + public const int WRAPPER_PADDING = 12; + private const string CAPTION_FONT_NAME = "Inter"; + private const int MIN_OFFSET = 64; + private const int ANIMATION_DURATION = 200; + + public bool opened { get; private set; default = false; } + + public Gala.WindowManager? wm { get; construct; } + private Gala.ModalProxy modal_proxy = null; + + private Granite.Settings granite_settings; + private Clutter.Canvas canvas; + + private Gtk.WidgetPath widget_path; + private Gtk.StyleContext style_context; + private unowned Gtk.CssProvider? dark_style_provider = null; + + private bool first_release = true; + private bool drawn = false; + + private float scaling_factor = 1.0f; + + public WindowMenu (Gala.WindowManager wm) { + Object (wm: wm); + } + + construct { + unowned var gtk_settings = Gtk.Settings.get_default (); + granite_settings = Granite.Settings.get_default (); + + unowned var display = wm.get_display (); + scaling_factor = display.get_monitor_scale (display.get_current_monitor ()); + + canvas = new Clutter.Canvas (); + canvas.scale_factor = scaling_factor; + set_content (canvas); + + opacity = 0; + + layout_manager = new Clutter.BoxLayout () { + orientation = VERTICAL + }; + + // Carry out the initial draw + create_components (); + + var effect = new ShadowEffect (40) { + shadow_opacity = 200, + css_class = "window-switcher", + scale_factor = scaling_factor + }; + add_effect (effect); + + // Redraw the components if the colour scheme changes. + granite_settings.notify["prefers-color-scheme"].connect (() => { + canvas.invalidate (); + create_components (); + }); + + gtk_settings.notify["gtk-theme-name"].connect (() => { + canvas.invalidate (); + create_components (); + }); + + unowned var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); + monitor_manager.monitors_changed.connect (() => { + var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); + if (cur_scale != scaling_factor) { + scaling_factor = cur_scale; + canvas.scale_factor = scaling_factor; + effect.scale_factor = scaling_factor; + create_components (); + } + }); + + canvas.draw.connect (draw); + + motion_event.connect (on_motion_event); + + actor_added.connect (update_size); + } + + private bool draw (Cairo.Context ctx, int width, int height) { + if (style_context == null) { // gtk is not initialized yet + create_gtk_objects (); + } + + ctx.save (); + ctx.set_operator (Cairo.Operator.CLEAR); + ctx.paint (); + ctx.clip (); + ctx.reset_clip (); + + if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + unowned var gtksettings = Gtk.Settings.get_default (); + dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); + style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + } else if (dark_style_provider != null) { + style_context.remove_provider (dark_style_provider); + dark_style_provider = null; + } + + ctx.set_operator (Cairo.Operator.OVER); + style_context.render_background (ctx, 0, 0, width, height); + style_context.render_frame (ctx, 0, 0, width, height); + ctx.restore (); + + return true; + } + + private void create_components () { + // We've already been constructed once, start again + if (drawn) { + destroy_all_children (); + } + + drawn = true; + + var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); + } + + private void create_gtk_objects () { + var window = new Gtk.Window (); + + style_context = window.get_style_context (); + style_context.add_class ("csd"); + style_context.add_class ("unified"); + } + + private void update_size () { + float greatest_child_width = 10, greatest_child_height = 10; + + foreach (var child in get_children ()) { + float preferred_width, preferred_height; + child.get_preferred_size (null, null, out preferred_width, out preferred_height); + if (preferred_width > greatest_child_width) { + greatest_child_width = preferred_width; + } + + if (preferred_height > greatest_child_height) { + greatest_child_height = preferred_height; + } + } + + set_size (greatest_child_width, greatest_child_height); + canvas.set_size ((int) greatest_child_width, (int) greatest_child_height); + } + + public void open_menu () { + if (opened) { + return; + } + + opacity = 0; + + unowned var display = wm.get_display (); + var monitor = display.get_current_monitor (); + var geom = display.get_monitor_geometry (monitor); + + // float container_width; + // container.get_preferred_width ( + // InternalUtils.scale_to_int (ICON_SIZE, scaling_factor) + container.margin_left + container.margin_right, + // null, + // out container_width + // ); + // if (container_width + InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2 > geom.width) { + // container.width = geom.width - InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2; + // } + + // float nat_width, nat_height; + // container.get_preferred_size (null, null, out nat_width, out nat_height); + + // var switcher_height = (int) (nat_height + caption.height / 2 - container.margin_bottom + WRAPPER_PADDING * 3 * scaling_factor); + canvas.invalidate (); + + // container width might have changed, so we must update caption width too + // update_caption_text (); + + toggle_display (true); + } + + public void toggle_display (bool show) { + if (opened == show) { + return; + } + + opened = show; + if (show) { + push_modal (); + } else { + wm.pop_modal (modal_proxy); + } + + save_easing_state (); + set_easing_duration (wm.enable_animations ? ANIMATION_DURATION : 0); + opacity = show ? 255 : 0; + restore_easing_state (); + } + + private void push_modal () { + modal_proxy = wm.push_modal (this); + modal_proxy.set_keybinding_filter ((binding) => { + var action = Meta.Prefs.get_keybinding_action (binding.get_name ()); + + switch (action) { + case Meta.KeyBindingAction.NONE: + case Meta.KeyBindingAction.LOCATE_POINTER_KEY: + case Meta.KeyBindingAction.SWITCH_APPLICATIONS: + case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD: + case Meta.KeyBindingAction.SWITCH_WINDOWS: + case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: + case Meta.KeyBindingAction.SWITCH_GROUP: + case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: + return false; + default: + break; + } + + return true; + }); + + } + + public override void key_focus_out () { + toggle_display (false); + } + + public override bool button_release_event (Clutter.ButtonEvent event) { + if (first_release) { + first_release = false; + return true; + } + + toggle_display (false); + first_release = true; + return true; + } + +#if HAS_MUTTER45 + private bool on_motion_event (Clutter.Event event) { +#else + private bool on_motion_event (Clutter.MotionEvent event) { +#endif + // float x, y; + // event.get_coords (out x, out y); + // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); + // if (actor == null) { + // return true; + // } + + // var selected = actor as WindowSwitcherIcon; + // if (selected == null) { + // return true; + // } + + // if (current_icon != selected) { + // current_icon = selected; + // } + + return true; + } + +#if HAS_MUTTER45 + public override bool key_press_event (Clutter.Event event) { +#else + public override bool key_press_event (Clutter.KeyEvent event) { +#endif + switch (event.get_key_symbol ()) { + case Clutter.Key.Right: + // next_window (false); + return Clutter.EVENT_STOP; + case Clutter.Key.Left: + // next_window (true); + return Clutter.EVENT_STOP; + case Clutter.Key.Escape: + toggle_display (false); + return Clutter.EVENT_PROPAGATE; + case Clutter.Key.Return: + toggle_display (false); + return Clutter.EVENT_PROPAGATE; + } + + return Clutter.EVENT_PROPAGATE; + } +} diff --git a/src/Widgets/Menu/Menu.vala~ b/src/Widgets/Menu/Menu.vala~ new file mode 100644 index 000000000..1efcc088f --- /dev/null +++ b/src/Widgets/Menu/Menu.vala~ @@ -0,0 +1,281 @@ +/* + * Copyright 2021 Aral Balkan + * Copyright 2020 Mark Story + * Copyright 2017 Popye + * Copyright 2014 Tom Beckmann + * Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +public class Gala.WindowMenu : Clutter.Actor { + public const int ICON_SIZE = 64; + public const int WRAPPER_PADDING = 12; + private const string CAPTION_FONT_NAME = "Inter"; + private const int MIN_OFFSET = 64; + private const int ANIMATION_DURATION = 200; + + public bool opened { get; private set; default = false; } + + public Gala.WindowManager? wm { get; construct; } + private Gala.ModalProxy modal_proxy = null; + + private Granite.Settings granite_settings; + private Clutter.Canvas canvas; + + private Gtk.WidgetPath widget_path; + private Gtk.StyleContext style_context; + private unowned Gtk.CssProvider? dark_style_provider = null; + + private bool first_release = true; + private bool drawn = false; + + private float scaling_factor = 1.0f; + + public WindowMenu (Gala.WindowManager wm) { + Object (wm: wm); + } + + construct { + unowned var gtk_settings = Gtk.Settings.get_default (); + granite_settings = Granite.Settings.get_default (); + + unowned var display = wm.get_display (); + scaling_factor = display.get_monitor_scale (display.get_current_monitor ()); + + canvas = new Clutter.Canvas (); + canvas.scale_factor = scaling_factor; + set_content (canvas); + + opacity = 0; + + layout_manager = new Clutter.BoxLayout () { + orientation = VERTICAL + }; + + // Carry out the initial draw + create_components (); + + var effect = new ShadowEffect (40) { + shadow_opacity = 200, + css_class = "window-switcher", + scale_factor = scaling_factor + }; + add_effect (effect); + + // Redraw the components if the colour scheme changes. + granite_settings.notify["prefers-color-scheme"].connect (() => { + canvas.invalidate (); + create_components (); + }); + + gtk_settings.notify["gtk-theme-name"].connect (() => { + canvas.invalidate (); + create_components (); + }); + + unowned var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); + monitor_manager.monitors_changed.connect (() => { + var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); + if (cur_scale != scaling_factor) { + scaling_factor = cur_scale; + canvas.scale_factor = scaling_factor; + effect.scale_factor = scaling_factor; + create_components (); + } + }); + + canvas.draw.connect (draw); + + motion_event.connect (on_motion_event); + } + + private bool draw (Cairo.Context ctx, int width, int height) { + if (style_context == null) { // gtk is not initialized yet + create_gtk_objects (); + } + + ctx.save (); + ctx.set_operator (Cairo.Operator.CLEAR); + ctx.paint (); + ctx.clip (); + ctx.reset_clip (); + + if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + unowned var gtksettings = Gtk.Settings.get_default (); + dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); + style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + } else if (dark_style_provider != null) { + style_context.remove_provider (dark_style_provider); + dark_style_provider = null; + } + + ctx.set_operator (Cairo.Operator.OVER); + style_context.render_background (ctx, 0, 0, width, height); + style_context.render_frame (ctx, 0, 0, width, height); + ctx.restore (); + + return true; + } + + private void create_components () { + // We've already been constructed once, start again + if (drawn) { + destroy_all_children (); + } + + drawn = true; + + var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); + } + + private void create_gtk_objects () { + var window = new Gtk.Window (); + + style_context = window.get_style_context (); + style_context.add_class ("csd"); + style_context.add_class ("unified"); + } + + public void update_size () { + + } + + public void open_menu () { + if (opened) { + return; + } + + opacity = 0; + + unowned var display = wm.get_display (); + var monitor = display.get_current_monitor (); + var geom = display.get_monitor_geometry (monitor); + + // float container_width; + // container.get_preferred_width ( + // InternalUtils.scale_to_int (ICON_SIZE, scaling_factor) + container.margin_left + container.margin_right, + // null, + // out container_width + // ); + // if (container_width + InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2 > geom.width) { + // container.width = geom.width - InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2; + // } + + // float nat_width, nat_height; + // container.get_preferred_size (null, null, out nat_width, out nat_height); + + // var switcher_height = (int) (nat_height + caption.height / 2 - container.margin_bottom + WRAPPER_PADDING * 3 * scaling_factor); + set_size ((int) 50, 50); + canvas.set_size ((int) 50, 50); + canvas.invalidate (); + + // container width might have changed, so we must update caption width too + // update_caption_text (); + + toggle_display (true); + } + + public void toggle_display (bool show) { + if (opened == show) { + return; + } + + opened = show; + if (show) { + push_modal (); + } else { + wm.pop_modal (modal_proxy); + } + + save_easing_state (); + set_easing_duration (wm.enable_animations ? ANIMATION_DURATION : 0); + opacity = show ? 255 : 0; + restore_easing_state (); + } + + private void push_modal () { + modal_proxy = wm.push_modal (this); + modal_proxy.set_keybinding_filter ((binding) => { + var action = Meta.Prefs.get_keybinding_action (binding.get_name ()); + + switch (action) { + case Meta.KeyBindingAction.NONE: + case Meta.KeyBindingAction.LOCATE_POINTER_KEY: + case Meta.KeyBindingAction.SWITCH_APPLICATIONS: + case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD: + case Meta.KeyBindingAction.SWITCH_WINDOWS: + case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: + case Meta.KeyBindingAction.SWITCH_GROUP: + case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: + return false; + default: + break; + } + + return true; + }); + + } + + public override void key_focus_out () { + toggle_display (false); + } + + public override bool button_release_event (Clutter.ButtonEvent event) { + if (first_release) { + first_release = false; + return true; + } + + toggle_display (false); + first_release = true; + return true; + } + +#if HAS_MUTTER45 + private bool on_motion_event (Clutter.Event event) { +#else + private bool on_motion_event (Clutter.MotionEvent event) { +#endif + // float x, y; + // event.get_coords (out x, out y); + // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); + // if (actor == null) { + // return true; + // } + + // var selected = actor as WindowSwitcherIcon; + // if (selected == null) { + // return true; + // } + + // if (current_icon != selected) { + // current_icon = selected; + // } + + return true; + } + +#if HAS_MUTTER45 + public override bool key_press_event (Clutter.Event event) { +#else + public override bool key_press_event (Clutter.KeyEvent event) { +#endif + switch (event.get_key_symbol ()) { + case Clutter.Key.Right: + // next_window (false); + return Clutter.EVENT_STOP; + case Clutter.Key.Left: + // next_window (true); + return Clutter.EVENT_STOP; + case Clutter.Key.Escape: + toggle_display (false); + return Clutter.EVENT_PROPAGATE; + case Clutter.Key.Return: + toggle_display (false); + return Clutter.EVENT_PROPAGATE; + } + + return Clutter.EVENT_PROPAGATE; + } +} diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala new file mode 100644 index 000000000..334baf383 --- /dev/null +++ b/src/Widgets/Menu/MenuItem.vala @@ -0,0 +1,94 @@ +/* + * Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +public class Gala.MenuItem : Clutter.Actor { + private const int WRAPPER_BORDER_RADIUS = 3; + private const string CAPTION_FONT_NAME = "Inter"; + + private Clutter.Text text; + private Clutter.Canvas canvas; + + private Granite.Settings granite_settings; + + private bool _selected = false; + public bool selected { + get { + return _selected; + } + set { + _selected = value; + canvas.invalidate (); + } + } + + private float _scale_factor = 1.0f; + public float scale_factor { + get { + return _scale_factor; + } + set { + _scale_factor = value; + canvas.scale_factor = _scale_factor; + + update_size (); + canvas.invalidate (); + } + } + + public MenuItem (string label, float scale_factor) { + var text_color = "#2e2e31"; + + if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + text_color = "#fafafa"; + } + + text = new Clutter.Text.full (CAPTION_FONT_NAME, "Hello World!", Clutter.Color.from_string (text_color)); + text.set_pivot_point (0.5f, 0.5f); + text.set_ellipsize (Pango.EllipsizeMode.END); + text.set_line_alignment (Pango.Alignment.CENTER); + add_child (text); + + canvas = new Clutter.Canvas (); + canvas.draw.connect (draw_background); + set_content (canvas); + + this.scale_factor = scale_factor; + } + + private void update_size () { + set_size (text.width, text.height); + canvas.set_size ((int) text.width, (int) text.height); + } + + private bool draw_background (Cairo.Context ctx, int width, int height) { + ctx.save (); + ctx.set_operator (Cairo.Operator.CLEAR); + ctx.paint (); + ctx.clip (); + ctx.reset_clip (); + + if (selected) { + var rgba = InternalUtils.get_theme_accent_color (); + Clutter.Color accent_color = { + (uint8) (rgba.red * 255), + (uint8) (rgba.green * 255), + (uint8) (rgba.blue * 255), + (uint8) (rgba.alpha * 255) + }; + + var rect_radius = InternalUtils.scale_to_int (WRAPPER_BORDER_RADIUS, scale_factor); + + // draw rect + Clutter.cairo_set_source_color (ctx, accent_color); + Drawing.Utilities.cairo_rounded_rectangle (ctx, 0, 0, width, height, rect_radius); + ctx.set_operator (Cairo.Operator.SOURCE); + ctx.fill (); + + ctx.restore (); + } + + return true; + } +} diff --git a/src/WindowManager.vala b/src/WindowManager.vala index aab51102b..29d8f8b3e 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -992,7 +992,8 @@ namespace Gala { var window_menu = new WindowMenu (this); ui_group.add_child (window_menu); window_menu.set_position (x, y); - window_menu.handle_switch_windows (get_display () ); + window_menu.add_child (new MenuItem ("wow", get_display ().get_monitor_scale (get_display ().get_current_monitor ()))); + window_menu.open_menu (); // if (daemon_proxy == null || window.get_window_type () == Meta.WindowType.NOTIFICATION) { // return; // } diff --git a/src/meson.build b/src/meson.build index 4ebd98f6b..f35011530 100644 --- a/src/meson.build +++ b/src/meson.build @@ -52,7 +52,9 @@ gala_bin_sources = files( 'Widgets/WindowClone.vala', 'Widgets/WindowCloneContainer.vala', 'Widgets/WindowIconActor.vala', - 'Widgets/WindowMenu.vala', + 'Widgets/Menu/Menu.vala', + 'Widgets/Menu/MenuItem.vala', + # 'Widgets/WindowMenu.vala', 'Widgets/WindowOverview.vala', 'Widgets/WindowSwitcher/WindowSwitcher.vala', 'Widgets/WindowSwitcher/WindowSwitcherIcon.vala', From c6f73c541cd880f25ffc561e0e59287f7d0c06ca Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 28 Sep 2023 00:01:43 +0200 Subject: [PATCH 04/31] Allocate canvas size with actor size --- src/Widgets/Menu/Menu.vala | 44 ++------------------------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 327a4017c..c081f8dfa 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -84,11 +84,11 @@ public class Gala.WindowMenu : Clutter.Actor { } }); + notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); + canvas.draw.connect (draw); motion_event.connect (on_motion_event); - - actor_added.connect (update_size); } private bool draw (Cairo.Context ctx, int width, int height) { @@ -138,25 +138,6 @@ public class Gala.WindowMenu : Clutter.Actor { style_context.add_class ("unified"); } - private void update_size () { - float greatest_child_width = 10, greatest_child_height = 10; - - foreach (var child in get_children ()) { - float preferred_width, preferred_height; - child.get_preferred_size (null, null, out preferred_width, out preferred_height); - if (preferred_width > greatest_child_width) { - greatest_child_width = preferred_width; - } - - if (preferred_height > greatest_child_height) { - greatest_child_height = preferred_height; - } - } - - set_size (greatest_child_width, greatest_child_height); - canvas.set_size ((int) greatest_child_width, (int) greatest_child_height); - } - public void open_menu () { if (opened) { return; @@ -164,29 +145,8 @@ public class Gala.WindowMenu : Clutter.Actor { opacity = 0; - unowned var display = wm.get_display (); - var monitor = display.get_current_monitor (); - var geom = display.get_monitor_geometry (monitor); - - // float container_width; - // container.get_preferred_width ( - // InternalUtils.scale_to_int (ICON_SIZE, scaling_factor) + container.margin_left + container.margin_right, - // null, - // out container_width - // ); - // if (container_width + InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2 > geom.width) { - // container.width = geom.width - InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2; - // } - - // float nat_width, nat_height; - // container.get_preferred_size (null, null, out nat_width, out nat_height); - - // var switcher_height = (int) (nat_height + caption.height / 2 - container.margin_bottom + WRAPPER_PADDING * 3 * scaling_factor); canvas.invalidate (); - // container width might have changed, so we must update caption width too - // update_caption_text (); - toggle_display (true); } From b57ea7aab0993afde5fa8c4537dabf5dcaa9344a Mon Sep 17 00:00:00 2001 From: Leonhard Date: Fri, 29 Sep 2023 20:36:34 +0200 Subject: [PATCH 05/31] Make items selectable --- src/InternalUtils.vala | 20 +++++++++ src/Widgets/Menu/Menu.vala | 44 ++++++++++++++++--- src/Widgets/Menu/MenuItem.vala | 80 ++++++++++++++++++++++++++++------ src/WindowManager.vala | 1 - 4 files changed, 123 insertions(+), 22 deletions(-) diff --git a/src/InternalUtils.vala b/src/InternalUtils.vala index 6fa4b7a43..e9cf19702 100644 --- a/src/InternalUtils.vala +++ b/src/InternalUtils.vala @@ -335,6 +335,26 @@ namespace Gala { ); } + private static Gtk.StyleContext foreground_style_context = null; + private static Gtk.CssProvider dark_style_provider = null; + public static Gdk.RGBA get_foreground_color () { + if (foreground_style_context == null) { + var window = new Gtk.Window (); + foreground_style_context = window.get_style_context (); + } + + if (Granite.Settings.get_default ().prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + unowned var gtksettings = Gtk.Settings.get_default (); + dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); + foreground_style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + } else if (dark_style_provider != null) { + foreground_style_context.remove_provider (dark_style_provider); + dark_style_provider = null; + } + + return (Gdk.RGBA) foreground_style_context.get_color (NORMAL); + } + /** * Returns the workspaces geometry following the only_on_primary settings. */ diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index c081f8dfa..f9d32cb6f 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -9,7 +9,7 @@ public class Gala.WindowMenu : Clutter.Actor { public const int ICON_SIZE = 64; - public const int WRAPPER_PADDING = 12; + public const int WRAPPER_PADDING = 3; private const string CAPTION_FONT_NAME = "Inter"; private const int MIN_OFFSET = 64; private const int ANIMATION_DURATION = 200; @@ -21,6 +21,7 @@ public class Gala.WindowMenu : Clutter.Actor { private Granite.Settings granite_settings; private Clutter.Canvas canvas; + private Clutter.Actor container; private Gtk.WidgetPath widget_path; private Gtk.StyleContext style_context; @@ -31,6 +32,8 @@ public class Gala.WindowMenu : Clutter.Actor { private float scaling_factor = 1.0f; + private MenuItem menuitem; + public WindowMenu (Gala.WindowManager wm) { Object (wm: wm); } @@ -48,9 +51,7 @@ public class Gala.WindowMenu : Clutter.Actor { opacity = 0; - layout_manager = new Clutter.BoxLayout () { - orientation = VERTICAL - }; + layout_manager = new Clutter.BinLayout (); // Carry out the initial draw create_components (); @@ -89,6 +90,22 @@ public class Gala.WindowMenu : Clutter.Actor { canvas.draw.connect (draw); motion_event.connect (on_motion_event); + + var box_layout = new Clutter.BoxLayout () { + orientation = VERTICAL + }; + + container = new Clutter.Actor () { + layout_manager = box_layout + }; + add_child (container); + + var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); + container.margin_top = margin; + container.margin_bottom = margin; + + menuitem = new MenuItem ("wow", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + container.add_child (menuitem); } private bool draw (Cairo.Context ctx, int width, int height) { @@ -126,8 +143,6 @@ public class Gala.WindowMenu : Clutter.Actor { } drawn = true; - - var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); } private void create_gtk_objects () { @@ -197,21 +212,36 @@ public class Gala.WindowMenu : Clutter.Actor { } public override bool button_release_event (Clutter.ButtonEvent event) { + menuitem.selected = !menuitem.selected; if (first_release) { first_release = false; return true; } - toggle_display (false); + // toggle_display (false); first_release = true; return true; } + public override bool enter_event (Clutter.CrossingEvent event) { + return false; + } + + public override bool leave_event (Clutter.CrossingEvent event) { + // menuitem.selected = false; + return false; + } + #if HAS_MUTTER45 private bool on_motion_event (Clutter.Event event) { #else private bool on_motion_event (Clutter.MotionEvent event) { #endif + // menuitem.selected = true; + // Timeout.add (1000, () => { + // menuitem.selected = false; + // return Source.REMOVE; + // }); // float x, y; // event.get_coords (out x, out y); // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index 334baf383..b7d5f5101 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -9,6 +9,7 @@ public class Gala.MenuItem : Clutter.Actor { private Clutter.Text text; private Clutter.Canvas canvas; + private Gtk.StyleContext style_context; private Granite.Settings granite_settings; @@ -19,6 +20,13 @@ public class Gala.MenuItem : Clutter.Actor { } set { _selected = value; + if (value) { + // style_context.set_state (Gtk.StateFlags.FOCUSED); + warning ("SELECTED"); + } else { + // style_context.set_state (Gtk.StateFlags.NORMAL); + warning ("NOT ANYMORE"); + } canvas.invalidate (); } } @@ -49,6 +57,12 @@ public class Gala.MenuItem : Clutter.Actor { text.set_ellipsize (Pango.EllipsizeMode.END); text.set_line_alignment (Pango.Alignment.CENTER); add_child (text); + var window = new Gtk.Window (); + + style_context = window.get_style_context (); + style_context.add_class ("csd"); + style_context.add_class ("unified"); + style_context.add_class (Gtk.STYLE_CLASS_MENUITEM); canvas = new Clutter.Canvas (); canvas.draw.connect (draw_background); @@ -57,9 +71,22 @@ public class Gala.MenuItem : Clutter.Actor { this.scale_factor = scale_factor; } + // public override bool enter_event (Clutter.CrossingEvent event) { + // selected = true; + // warning ("SELECTED"); + // return base.enter_event (event); + // } + + // public override bool leave_event (Clutter.CrossingEvent event) { + // selected = false; + // warning ("NOT SELECTED"); + // return base.leave_event (event); + // } + private void update_size () { set_size (text.width, text.height); - canvas.set_size ((int) text.width, (int) text.height); + // canvas.set_size ((int) text.width, (int) text.height); + canvas.set_size ((int) 50, (int) 50); } private bool draw_background (Cairo.Context ctx, int width, int height) { @@ -69,25 +96,50 @@ public class Gala.MenuItem : Clutter.Actor { ctx.clip (); ctx.reset_clip (); + // if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + // unowned var gtksettings = Gtk.Settings.get_default (); + // var dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); + // style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + // } else if (dark_style_provider != null) { + // style_context.remove_provider (dark_style_provider); + // dark_style_provider = null; + // } + + // ctx.set_operator (Cairo.Operator.OVER); + // style_context.render_background (ctx, 0, 0, width, height); + // warning ("RENDER BACKGROUND"); + if (selected) { - var rgba = InternalUtils.get_theme_accent_color (); - Clutter.Color accent_color = { - (uint8) (rgba.red * 255), - (uint8) (rgba.green * 255), - (uint8) (rgba.blue * 255), - (uint8) (rgba.alpha * 255) - }; - - var rect_radius = InternalUtils.scale_to_int (WRAPPER_BORDER_RADIUS, scale_factor); - - // draw rect - Clutter.cairo_set_source_color (ctx, accent_color); - Drawing.Utilities.cairo_rounded_rectangle (ctx, 0, 0, width, height, rect_radius); + var rgba = InternalUtils.get_foreground_color (); + ctx.set_source_rgba (rgba.red, rgba.green, rgba.blue, 0.15); + ctx.rectangle (0, 0, width, height); ctx.set_operator (Cairo.Operator.SOURCE); ctx.fill (); ctx.restore (); } + // style_context.render_frame (ctx, 0, 0, width, height); + // ctx.restore (); + + // if (selected) { + // var rgba = InternalUtils.get_theme_accent_color (); + // Clutter.Color accent_color = { + // (uint8) (rgba.red * 255), + // (uint8) (rgba.green * 255), + // (uint8) (rgba.blue * 255), + // (uint8) (rgba.alpha * 255) + // }; + + // var rect_radius = InternalUtils.scale_to_int (WRAPPER_BORDER_RADIUS, scale_factor); + + // // draw rect + // Clutter.cairo_set_source_color (ctx, accent_color); + // Drawing.Utilities.cairo_rounded_rectangle (ctx, 0, 0, width, height, rect_radius); + // ctx.set_operator (Cairo.Operator.SOURCE); + // ctx.fill (); + + // ctx.restore (); + // } return true; } diff --git a/src/WindowManager.vala b/src/WindowManager.vala index 29d8f8b3e..a8218ea77 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -992,7 +992,6 @@ namespace Gala { var window_menu = new WindowMenu (this); ui_group.add_child (window_menu); window_menu.set_position (x, y); - window_menu.add_child (new MenuItem ("wow", get_display ().get_monitor_scale (get_display ().get_current_monitor ()))); window_menu.open_menu (); // if (daemon_proxy == null || window.get_window_type () == Meta.WindowType.NOTIFICATION) { // return; From b4d052176f0cbbe748cfc3181dffa16f9783f4de Mon Sep 17 00:00:00 2001 From: Leonhard Date: Fri, 29 Sep 2023 20:53:31 +0200 Subject: [PATCH 06/31] Almost finished with menuitem api --- src/Widgets/Menu/Menu.vala | 54 ++++++++++++++++------ src/Widgets/Menu/MenuItem.vala | 82 +++++++++++----------------------- 2 files changed, 65 insertions(+), 71 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index f9d32cb6f..e19a71a10 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -23,7 +23,8 @@ public class Gala.WindowMenu : Clutter.Actor { private Clutter.Canvas canvas; private Clutter.Actor container; - private Gtk.WidgetPath widget_path; + // private MenuItem selected; + private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; @@ -89,8 +90,6 @@ public class Gala.WindowMenu : Clutter.Actor { canvas.draw.connect (draw); - motion_event.connect (on_motion_event); - var box_layout = new Clutter.BoxLayout () { orientation = VERTICAL }; @@ -233,15 +232,11 @@ public class Gala.WindowMenu : Clutter.Actor { } #if HAS_MUTTER45 - private bool on_motion_event (Clutter.Event event) { + public override bool motion_event (Clutter.Event event) { #else - private bool on_motion_event (Clutter.MotionEvent event) { + public override bool motion_event (Clutter.MotionEvent event) { #endif - // menuitem.selected = true; - // Timeout.add (1000, () => { - // menuitem.selected = false; - // return Source.REMOVE; - // }); + // warning ("MOTION"); // float x, y; // event.get_coords (out x, out y); // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); @@ -249,18 +244,49 @@ public class Gala.WindowMenu : Clutter.Actor { // return true; // } - // var selected = actor as WindowSwitcherIcon; - // if (selected == null) { + // var hovered = (MenuItem) actor; + // if (hovered == null) { // return true; // } - // if (current_icon != selected) { - // current_icon = selected; + // if (hovered != selected) { + // selected.selected = false; + // hovered.selected = true; + // selected = hovered; // } return true; } +// #if HAS_MUTTER45 +// private bool on_motion_event (Clutter.Event event) { +// #else +// private bool on_motion_event (Clutter.MotionEvent event) { +// #endif +// // menuitem.selected = true; +// // Timeout.add (1000, () => { +// // menuitem.selected = false; +// // return Source.REMOVE; +// // }); +// // float x, y; +// // event.get_coords (out x, out y); +// // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); +// // if (actor == null) { +// // return true; +// // } + +// // var selected = actor as WindowSwitcherIcon; +// // if (selected == null) { +// // return true; +// // } + +// // if (current_icon != selected) { +// // current_icon = selected; +// // } + +// return true; +// } + #if HAS_MUTTER45 public override bool key_press_event (Clutter.Event event) { #else diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index b7d5f5101..9a8d844ef 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -4,6 +4,8 @@ */ public class Gala.MenuItem : Clutter.Actor { + public signal void activated (); + private const int WRAPPER_BORDER_RADIUS = 3; private const string CAPTION_FONT_NAME = "Inter"; @@ -20,13 +22,6 @@ public class Gala.MenuItem : Clutter.Actor { } set { _selected = value; - if (value) { - // style_context.set_state (Gtk.StateFlags.FOCUSED); - warning ("SELECTED"); - } else { - // style_context.set_state (Gtk.StateFlags.NORMAL); - warning ("NOT ANYMORE"); - } canvas.invalidate (); } } @@ -48,7 +43,7 @@ public class Gala.MenuItem : Clutter.Actor { public MenuItem (string label, float scale_factor) { var text_color = "#2e2e31"; - if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + if (Granite.Settings.get_default ().prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { text_color = "#fafafa"; } @@ -56,9 +51,8 @@ public class Gala.MenuItem : Clutter.Actor { text.set_pivot_point (0.5f, 0.5f); text.set_ellipsize (Pango.EllipsizeMode.END); text.set_line_alignment (Pango.Alignment.CENTER); - add_child (text); - var window = new Gtk.Window (); + var window = new Gtk.Window (); style_context = window.get_style_context (); style_context.add_class ("csd"); style_context.add_class ("unified"); @@ -66,27 +60,36 @@ public class Gala.MenuItem : Clutter.Actor { canvas = new Clutter.Canvas (); canvas.draw.connect (draw_background); + + reactive = true; + add_child (text); set_content (canvas); this.scale_factor = scale_factor; } - // public override bool enter_event (Clutter.CrossingEvent event) { - // selected = true; - // warning ("SELECTED"); - // return base.enter_event (event); - // } + public override bool enter_event (Clutter.CrossingEvent event) { + selected = true; + return false; + } + + public override bool leave_event (Clutter.CrossingEvent event) { + selected = false; + return false; + } - // public override bool leave_event (Clutter.CrossingEvent event) { - // selected = false; - // warning ("NOT SELECTED"); - // return base.leave_event (event); - // } + public override bool button_release_event (Clutter.ButtonEvent event) { + if (event.button == Clutter.Button.PRIMARY) { + activated (); + return true; + } + + return false; + } private void update_size () { set_size (text.width, text.height); - // canvas.set_size ((int) text.width, (int) text.height); - canvas.set_size ((int) 50, (int) 50); + canvas.set_size ((int) text.width, (int) text.height); } private bool draw_background (Cairo.Context ctx, int width, int height) { @@ -96,19 +99,6 @@ public class Gala.MenuItem : Clutter.Actor { ctx.clip (); ctx.reset_clip (); - // if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { - // unowned var gtksettings = Gtk.Settings.get_default (); - // var dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); - // style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - // } else if (dark_style_provider != null) { - // style_context.remove_provider (dark_style_provider); - // dark_style_provider = null; - // } - - // ctx.set_operator (Cairo.Operator.OVER); - // style_context.render_background (ctx, 0, 0, width, height); - // warning ("RENDER BACKGROUND"); - if (selected) { var rgba = InternalUtils.get_foreground_color (); ctx.set_source_rgba (rgba.red, rgba.green, rgba.blue, 0.15); @@ -118,28 +108,6 @@ public class Gala.MenuItem : Clutter.Actor { ctx.restore (); } - // style_context.render_frame (ctx, 0, 0, width, height); - // ctx.restore (); - - // if (selected) { - // var rgba = InternalUtils.get_theme_accent_color (); - // Clutter.Color accent_color = { - // (uint8) (rgba.red * 255), - // (uint8) (rgba.green * 255), - // (uint8) (rgba.blue * 255), - // (uint8) (rgba.alpha * 255) - // }; - - // var rect_radius = InternalUtils.scale_to_int (WRAPPER_BORDER_RADIUS, scale_factor); - - // // draw rect - // Clutter.cairo_set_source_color (ctx, accent_color); - // Drawing.Utilities.cairo_rounded_rectangle (ctx, 0, 0, width, height, rect_radius); - // ctx.set_operator (Cairo.Operator.SOURCE); - // ctx.fill (); - - // ctx.restore (); - // } return true; } From bf1a5831806743a901a016769ce17769b16e64d8 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Fri, 29 Sep 2023 20:59:11 +0200 Subject: [PATCH 07/31] Cleanup --- src/Widgets/Menu/Menu.vala | 85 +++------------------------------- src/Widgets/Menu/MenuItem.vala | 9 ---- 2 files changed, 6 insertions(+), 88 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index e19a71a10..4e68931a8 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -23,8 +23,6 @@ public class Gala.WindowMenu : Clutter.Actor { private Clutter.Canvas canvas; private Clutter.Actor container; - // private MenuItem selected; - private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; @@ -33,8 +31,6 @@ public class Gala.WindowMenu : Clutter.Actor { private float scaling_factor = 1.0f; - private MenuItem menuitem; - public WindowMenu (Gala.WindowManager wm) { Object (wm: wm); } @@ -103,7 +99,11 @@ public class Gala.WindowMenu : Clutter.Actor { container.margin_top = margin; container.margin_bottom = margin; - menuitem = new MenuItem ("wow", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + var menuitem = new MenuItem ("wow", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + container.add_child (menuitem); + } + + public void add_menuitem (MenuItem menuitem) { container.add_child (menuitem); } @@ -158,7 +158,6 @@ public class Gala.WindowMenu : Clutter.Actor { } opacity = 0; - canvas.invalidate (); toggle_display (true); @@ -211,94 +210,22 @@ public class Gala.WindowMenu : Clutter.Actor { } public override bool button_release_event (Clutter.ButtonEvent event) { - menuitem.selected = !menuitem.selected; if (first_release) { first_release = false; return true; } - // toggle_display (false); + toggle_display (false); first_release = true; return true; } - public override bool enter_event (Clutter.CrossingEvent event) { - return false; - } - - public override bool leave_event (Clutter.CrossingEvent event) { - // menuitem.selected = false; - return false; - } - -#if HAS_MUTTER45 - public override bool motion_event (Clutter.Event event) { -#else - public override bool motion_event (Clutter.MotionEvent event) { -#endif - // warning ("MOTION"); - // float x, y; - // event.get_coords (out x, out y); - // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); - // if (actor == null) { - // return true; - // } - - // var hovered = (MenuItem) actor; - // if (hovered == null) { - // return true; - // } - - // if (hovered != selected) { - // selected.selected = false; - // hovered.selected = true; - // selected = hovered; - // } - - return true; - } - -// #if HAS_MUTTER45 -// private bool on_motion_event (Clutter.Event event) { -// #else -// private bool on_motion_event (Clutter.MotionEvent event) { -// #endif -// // menuitem.selected = true; -// // Timeout.add (1000, () => { -// // menuitem.selected = false; -// // return Source.REMOVE; -// // }); -// // float x, y; -// // event.get_coords (out x, out y); -// // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); -// // if (actor == null) { -// // return true; -// // } - -// // var selected = actor as WindowSwitcherIcon; -// // if (selected == null) { -// // return true; -// // } - -// // if (current_icon != selected) { -// // current_icon = selected; -// // } - -// return true; -// } - #if HAS_MUTTER45 public override bool key_press_event (Clutter.Event event) { #else public override bool key_press_event (Clutter.KeyEvent event) { #endif switch (event.get_key_symbol ()) { - case Clutter.Key.Right: - // next_window (false); - return Clutter.EVENT_STOP; - case Clutter.Key.Left: - // next_window (true); - return Clutter.EVENT_STOP; case Clutter.Key.Escape: toggle_display (false); return Clutter.EVENT_PROPAGATE; diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index 9a8d844ef..caf5f851b 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -11,9 +11,6 @@ public class Gala.MenuItem : Clutter.Actor { private Clutter.Text text; private Clutter.Canvas canvas; - private Gtk.StyleContext style_context; - - private Granite.Settings granite_settings; private bool _selected = false; public bool selected { @@ -52,12 +49,6 @@ public class Gala.MenuItem : Clutter.Actor { text.set_ellipsize (Pango.EllipsizeMode.END); text.set_line_alignment (Pango.Alignment.CENTER); - var window = new Gtk.Window (); - style_context = window.get_style_context (); - style_context.add_class ("csd"); - style_context.add_class ("unified"); - style_context.add_class (Gtk.STYLE_CLASS_MENUITEM); - canvas = new Clutter.Canvas (); canvas.draw.connect (draw_background); From 1e52803539eac2ac9ab75d6b2d4dd4acd350d2fa Mon Sep 17 00:00:00 2001 From: Leonhard Date: Fri, 29 Sep 2023 21:14:10 +0200 Subject: [PATCH 08/31] Use correct font --- src/Widgets/Menu/MenuItem.vala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index caf5f851b..cc7ba6c79 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -44,7 +44,15 @@ public class Gala.MenuItem : Clutter.Actor { text_color = "#fafafa"; } - text = new Clutter.Text.full (CAPTION_FONT_NAME, "Hello World!", Clutter.Color.from_string (text_color)); + var widget = new Gtk.Grid (); + + var pango_context = widget.create_pango_context (); + var font_desc = pango_context.get_font_description (); + + text = new Clutter.Text.with_text (null, "Hello World!") { + color = Clutter.Color.from_string (text_color), + font_description = font_desc + }; text.set_pivot_point (0.5f, 0.5f); text.set_ellipsize (Pango.EllipsizeMode.END); text.set_line_alignment (Pango.Alignment.CENTER); From bf661041584f1183e39f207ce7b5d54c2b21aa63 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Fri, 29 Sep 2023 23:56:25 +0200 Subject: [PATCH 09/31] Add separatormenuitem --- src/Widgets/Menu/Menu.vala | 4 ++ src/Widgets/Menu/MenuItem.vala | 6 ++- src/Widgets/Menu/SeparatorMenuItem.vala | 56 +++++++++++++++++++++++++ src/meson.build | 1 + 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/Widgets/Menu/SeparatorMenuItem.vala diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 4e68931a8..9a639331d 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -31,6 +31,8 @@ public class Gala.WindowMenu : Clutter.Actor { private float scaling_factor = 1.0f; + private Clutter.Actor separator; + public WindowMenu (Gala.WindowManager wm) { Object (wm: wm); } @@ -101,6 +103,8 @@ public class Gala.WindowMenu : Clutter.Actor { var menuitem = new MenuItem ("wow", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); container.add_child (menuitem); + container.add_child (new SeparatorMenuItem (scaling_factor)); + container.add_child (new MenuItem ("Another", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); } public void add_menuitem (MenuItem menuitem) { diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index cc7ba6c79..04c7d3195 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -51,7 +51,11 @@ public class Gala.MenuItem : Clutter.Actor { text = new Clutter.Text.with_text (null, "Hello World!") { color = Clutter.Color.from_string (text_color), - font_description = font_desc + font_description = font_desc, + margin_left = 12, + margin_right = 12, + margin_top = 6, + margin_bottom = 6 }; text.set_pivot_point (0.5f, 0.5f); text.set_ellipsize (Pango.EllipsizeMode.END); diff --git a/src/Widgets/Menu/SeparatorMenuItem.vala b/src/Widgets/Menu/SeparatorMenuItem.vala new file mode 100644 index 000000000..e5c2f1d87 --- /dev/null +++ b/src/Widgets/Menu/SeparatorMenuItem.vala @@ -0,0 +1,56 @@ +/* + * Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +public class Gala.SeparatorMenuItem : Clutter.Actor { + private Clutter.Canvas canvas; + + private float _scale_factor = 1.0f; + public float scale_factor { + get { + return _scale_factor; + } + set { + _scale_factor = value; + canvas.scale_factor = _scale_factor; + + canvas.invalidate (); + } + } + + public SeparatorMenuItem (float scale_factor) { + canvas = new Clutter.Canvas (); + canvas.draw.connect (draw_background); + + set_content (canvas); + + set_size (1, 1); + canvas.set_size (1, 1); + + this.scale_factor = scale_factor; + } + + private bool draw_background (Cairo.Context ctx, int width, int height) { + ctx.save (); + ctx.set_operator (Cairo.Operator.OVER); + ctx.paint (); + ctx.clip (); + ctx.reset_clip (); + + var separator = new Gtk.Separator (HORIZONTAL) { + visible = true + }; + Gtk.Allocation alloc = { + 0, + 0, + width, + height + }; + separator.size_allocate (alloc); + separator.draw (ctx); + ctx.restore (); + + return true; + } +} diff --git a/src/meson.build b/src/meson.build index f35011530..e4871cdd2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -54,6 +54,7 @@ gala_bin_sources = files( 'Widgets/WindowIconActor.vala', 'Widgets/Menu/Menu.vala', 'Widgets/Menu/MenuItem.vala', + 'Widgets/Menu/SeparatorMenuItem.vala', # 'Widgets/WindowMenu.vala', 'Widgets/WindowOverview.vala', 'Widgets/WindowSwitcher/WindowSwitcher.vala', From dcef4f4a638db9782ee6fcce9be00df789ddc655 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sat, 30 Sep 2023 12:09:16 +0200 Subject: [PATCH 10/31] Make separator look right --- src/Widgets/Menu/Menu.vala | 6 +- src/Widgets/Menu/Menu.vala~ | 281 ------------------------ src/Widgets/Menu/MenuItem.vala | 12 +- src/Widgets/Menu/SeparatorMenuItem.vala | 40 ++-- 4 files changed, 35 insertions(+), 304 deletions(-) delete mode 100644 src/Widgets/Menu/Menu.vala~ diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 9a639331d..9cf4503ae 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -101,10 +101,10 @@ public class Gala.WindowMenu : Clutter.Actor { container.margin_top = margin; container.margin_bottom = margin; - var menuitem = new MenuItem ("wow", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); - container.add_child (menuitem); + container.add_child (new MenuItem ("Change Wallpaper...", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); + container.add_child (new MenuItem ("Display Settings...", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); container.add_child (new SeparatorMenuItem (scaling_factor)); - container.add_child (new MenuItem ("Another", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); + container.add_child (new MenuItem ("System Settings...", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); } public void add_menuitem (MenuItem menuitem) { diff --git a/src/Widgets/Menu/Menu.vala~ b/src/Widgets/Menu/Menu.vala~ deleted file mode 100644 index 1efcc088f..000000000 --- a/src/Widgets/Menu/Menu.vala~ +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2021 Aral Balkan - * Copyright 2020 Mark Story - * Copyright 2017 Popye - * Copyright 2014 Tom Beckmann - * Copyright 2023 elementary, Inc. - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -public class Gala.WindowMenu : Clutter.Actor { - public const int ICON_SIZE = 64; - public const int WRAPPER_PADDING = 12; - private const string CAPTION_FONT_NAME = "Inter"; - private const int MIN_OFFSET = 64; - private const int ANIMATION_DURATION = 200; - - public bool opened { get; private set; default = false; } - - public Gala.WindowManager? wm { get; construct; } - private Gala.ModalProxy modal_proxy = null; - - private Granite.Settings granite_settings; - private Clutter.Canvas canvas; - - private Gtk.WidgetPath widget_path; - private Gtk.StyleContext style_context; - private unowned Gtk.CssProvider? dark_style_provider = null; - - private bool first_release = true; - private bool drawn = false; - - private float scaling_factor = 1.0f; - - public WindowMenu (Gala.WindowManager wm) { - Object (wm: wm); - } - - construct { - unowned var gtk_settings = Gtk.Settings.get_default (); - granite_settings = Granite.Settings.get_default (); - - unowned var display = wm.get_display (); - scaling_factor = display.get_monitor_scale (display.get_current_monitor ()); - - canvas = new Clutter.Canvas (); - canvas.scale_factor = scaling_factor; - set_content (canvas); - - opacity = 0; - - layout_manager = new Clutter.BoxLayout () { - orientation = VERTICAL - }; - - // Carry out the initial draw - create_components (); - - var effect = new ShadowEffect (40) { - shadow_opacity = 200, - css_class = "window-switcher", - scale_factor = scaling_factor - }; - add_effect (effect); - - // Redraw the components if the colour scheme changes. - granite_settings.notify["prefers-color-scheme"].connect (() => { - canvas.invalidate (); - create_components (); - }); - - gtk_settings.notify["gtk-theme-name"].connect (() => { - canvas.invalidate (); - create_components (); - }); - - unowned var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); - monitor_manager.monitors_changed.connect (() => { - var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); - if (cur_scale != scaling_factor) { - scaling_factor = cur_scale; - canvas.scale_factor = scaling_factor; - effect.scale_factor = scaling_factor; - create_components (); - } - }); - - canvas.draw.connect (draw); - - motion_event.connect (on_motion_event); - } - - private bool draw (Cairo.Context ctx, int width, int height) { - if (style_context == null) { // gtk is not initialized yet - create_gtk_objects (); - } - - ctx.save (); - ctx.set_operator (Cairo.Operator.CLEAR); - ctx.paint (); - ctx.clip (); - ctx.reset_clip (); - - if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { - unowned var gtksettings = Gtk.Settings.get_default (); - dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); - style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - } else if (dark_style_provider != null) { - style_context.remove_provider (dark_style_provider); - dark_style_provider = null; - } - - ctx.set_operator (Cairo.Operator.OVER); - style_context.render_background (ctx, 0, 0, width, height); - style_context.render_frame (ctx, 0, 0, width, height); - ctx.restore (); - - return true; - } - - private void create_components () { - // We've already been constructed once, start again - if (drawn) { - destroy_all_children (); - } - - drawn = true; - - var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); - } - - private void create_gtk_objects () { - var window = new Gtk.Window (); - - style_context = window.get_style_context (); - style_context.add_class ("csd"); - style_context.add_class ("unified"); - } - - public void update_size () { - - } - - public void open_menu () { - if (opened) { - return; - } - - opacity = 0; - - unowned var display = wm.get_display (); - var monitor = display.get_current_monitor (); - var geom = display.get_monitor_geometry (monitor); - - // float container_width; - // container.get_preferred_width ( - // InternalUtils.scale_to_int (ICON_SIZE, scaling_factor) + container.margin_left + container.margin_right, - // null, - // out container_width - // ); - // if (container_width + InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2 > geom.width) { - // container.width = geom.width - InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2; - // } - - // float nat_width, nat_height; - // container.get_preferred_size (null, null, out nat_width, out nat_height); - - // var switcher_height = (int) (nat_height + caption.height / 2 - container.margin_bottom + WRAPPER_PADDING * 3 * scaling_factor); - set_size ((int) 50, 50); - canvas.set_size ((int) 50, 50); - canvas.invalidate (); - - // container width might have changed, so we must update caption width too - // update_caption_text (); - - toggle_display (true); - } - - public void toggle_display (bool show) { - if (opened == show) { - return; - } - - opened = show; - if (show) { - push_modal (); - } else { - wm.pop_modal (modal_proxy); - } - - save_easing_state (); - set_easing_duration (wm.enable_animations ? ANIMATION_DURATION : 0); - opacity = show ? 255 : 0; - restore_easing_state (); - } - - private void push_modal () { - modal_proxy = wm.push_modal (this); - modal_proxy.set_keybinding_filter ((binding) => { - var action = Meta.Prefs.get_keybinding_action (binding.get_name ()); - - switch (action) { - case Meta.KeyBindingAction.NONE: - case Meta.KeyBindingAction.LOCATE_POINTER_KEY: - case Meta.KeyBindingAction.SWITCH_APPLICATIONS: - case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD: - case Meta.KeyBindingAction.SWITCH_WINDOWS: - case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: - case Meta.KeyBindingAction.SWITCH_GROUP: - case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: - return false; - default: - break; - } - - return true; - }); - - } - - public override void key_focus_out () { - toggle_display (false); - } - - public override bool button_release_event (Clutter.ButtonEvent event) { - if (first_release) { - first_release = false; - return true; - } - - toggle_display (false); - first_release = true; - return true; - } - -#if HAS_MUTTER45 - private bool on_motion_event (Clutter.Event event) { -#else - private bool on_motion_event (Clutter.MotionEvent event) { -#endif - // float x, y; - // event.get_coords (out x, out y); - // var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); - // if (actor == null) { - // return true; - // } - - // var selected = actor as WindowSwitcherIcon; - // if (selected == null) { - // return true; - // } - - // if (current_icon != selected) { - // current_icon = selected; - // } - - return true; - } - -#if HAS_MUTTER45 - public override bool key_press_event (Clutter.Event event) { -#else - public override bool key_press_event (Clutter.KeyEvent event) { -#endif - switch (event.get_key_symbol ()) { - case Clutter.Key.Right: - // next_window (false); - return Clutter.EVENT_STOP; - case Clutter.Key.Left: - // next_window (true); - return Clutter.EVENT_STOP; - case Clutter.Key.Escape: - toggle_display (false); - return Clutter.EVENT_PROPAGATE; - case Clutter.Key.Return: - toggle_display (false); - return Clutter.EVENT_PROPAGATE; - } - - return Clutter.EVENT_PROPAGATE; - } -} diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index 04c7d3195..f688c08e4 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -40,7 +40,7 @@ public class Gala.MenuItem : Clutter.Actor { public MenuItem (string label, float scale_factor) { var text_color = "#2e2e31"; - if (Granite.Settings.get_default ().prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { text_color = "#fafafa"; } @@ -49,11 +49,11 @@ public class Gala.MenuItem : Clutter.Actor { var pango_context = widget.create_pango_context (); var font_desc = pango_context.get_font_description (); - text = new Clutter.Text.with_text (null, "Hello World!") { + text = new Clutter.Text.with_text (null, label) { color = Clutter.Color.from_string (text_color), font_description = font_desc, - margin_left = 12, - margin_right = 12, + margin_left = 24, + margin_right = 24, margin_top = 6, margin_bottom = 6 }; @@ -91,8 +91,8 @@ public class Gala.MenuItem : Clutter.Actor { } private void update_size () { - set_size (text.width, text.height); - canvas.set_size ((int) text.width, (int) text.height); + set_size (text.width > 150 ? text.width : 150, text.height); + canvas.set_size ((int) (text.width > 150 ? text.width : 150), (int) text.height); } private bool draw_background (Cairo.Context ctx, int width, int height) { diff --git a/src/Widgets/Menu/SeparatorMenuItem.vala b/src/Widgets/Menu/SeparatorMenuItem.vala index e5c2f1d87..d89125b3b 100644 --- a/src/Widgets/Menu/SeparatorMenuItem.vala +++ b/src/Widgets/Menu/SeparatorMenuItem.vala @@ -25,30 +25,42 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { set_content (canvas); - set_size (1, 1); - canvas.set_size (1, 1); + set_size (1, 2); + canvas.set_size (1, 2); + + margin_top = 3; + margin_bottom = 3; this.scale_factor = scale_factor; } private bool draw_background (Cairo.Context ctx, int width, int height) { ctx.save (); - ctx.set_operator (Cairo.Operator.OVER); + ctx.set_operator (Cairo.Operator.CLEAR); ctx.paint (); ctx.clip (); ctx.reset_clip (); - var separator = new Gtk.Separator (HORIZONTAL) { - visible = true - }; - Gtk.Allocation alloc = { - 0, - 0, - width, - height - }; - separator.size_allocate (alloc); - separator.draw (ctx); + ctx.set_operator (Cairo.Operator.SOURCE); + + double top_alpha, bottom_alpha; + + if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { + top_alpha = 0.35; + bottom_alpha = 0.05; + } else { + top_alpha = 0.15; + bottom_alpha = 0.8; + } + + ctx.set_source_rgba (0, 0, 0, top_alpha); + ctx.rectangle (0, 0, width, 1); + ctx.fill (); + + ctx.set_source_rgba (255, 255, 255, bottom_alpha); + ctx.rectangle (0, 1, width, 1); + ctx.fill (); + ctx.restore (); return true; From 8fa585518eb47cf07e66ef83d5a235ad76c7ccd2 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sat, 30 Sep 2023 15:04:00 +0200 Subject: [PATCH 11/31] Scaling works --- src/Widgets/Menu/Menu.vala | 103 +++++++++++------------- src/Widgets/Menu/MenuItem.vala | 37 +++------ src/Widgets/Menu/SeparatorMenuItem.vala | 30 ++----- 3 files changed, 66 insertions(+), 104 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 9cf4503ae..3eda38504 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -9,7 +9,7 @@ public class Gala.WindowMenu : Clutter.Actor { public const int ICON_SIZE = 64; - public const int WRAPPER_PADDING = 3; + public const int WRAPPER_PADDING = 5; private const string CAPTION_FONT_NAME = "Inter"; private const int MIN_OFFSET = 64; private const int ANIMATION_DURATION = 200; @@ -22,16 +22,12 @@ public class Gala.WindowMenu : Clutter.Actor { private Granite.Settings granite_settings; private Clutter.Canvas canvas; private Clutter.Actor container; + private ShadowEffect shadow_effect; private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; private bool first_release = true; - private bool drawn = false; - - private float scaling_factor = 1.0f; - - private Clutter.Actor separator; public WindowMenu (Gala.WindowManager wm) { Object (wm: wm); @@ -41,74 +37,78 @@ public class Gala.WindowMenu : Clutter.Actor { unowned var gtk_settings = Gtk.Settings.get_default (); granite_settings = Granite.Settings.get_default (); - unowned var display = wm.get_display (); - scaling_factor = display.get_monitor_scale (display.get_current_monitor ()); - canvas = new Clutter.Canvas (); - canvas.scale_factor = scaling_factor; - set_content (canvas); - - opacity = 0; - layout_manager = new Clutter.BinLayout (); + shadow_effect = new ShadowEffect (40) { + shadow_opacity = 200, + css_class = "window-switcher" + }; + add_effect (shadow_effect); - // Carry out the initial draw - create_components (); + var box_layout = new Clutter.BoxLayout () { + orientation = VERTICAL + }; - var effect = new ShadowEffect (40) { - shadow_opacity = 200, - css_class = "window-switcher", - scale_factor = scaling_factor + container = new Clutter.Actor () { + layout_manager = box_layout }; - add_effect (effect); + + layout_manager = new Clutter.BinLayout (); + opacity = 0; + add_child (container); + set_content (canvas); // Redraw the components if the colour scheme changes. granite_settings.notify["prefers-color-scheme"].connect (() => { canvas.invalidate (); - create_components (); }); gtk_settings.notify["gtk-theme-name"].connect (() => { canvas.invalidate (); - create_components (); }); - unowned var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); + unowned var display = wm.get_display (); + unowned var monitor_manager = display.get_context ().get_backend ().get_monitor_manager (); monitor_manager.monitors_changed.connect (() => { var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); - if (cur_scale != scaling_factor) { - scaling_factor = cur_scale; - canvas.scale_factor = scaling_factor; - effect.scale_factor = scaling_factor; - create_components (); - } + scale (cur_scale); }); + scale (display.get_monitor_scale (display.get_current_monitor ())); notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); canvas.draw.connect (draw); - var box_layout = new Clutter.BoxLayout () { - orientation = VERTICAL - }; - - container = new Clutter.Actor () { - layout_manager = box_layout - }; - add_child (container); - - var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); - container.margin_top = margin; - container.margin_bottom = margin; - - container.add_child (new MenuItem ("Change Wallpaper...", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); - container.add_child (new MenuItem ("Display Settings...", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); - container.add_child (new SeparatorMenuItem (scaling_factor)); - container.add_child (new MenuItem ("System Settings...", wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ()))); + add_menuitem (new MenuItem ("Change Wallpaper...")); + add_menuitem (new MenuItem ("Display Settings...")); + var sep = new SeparatorMenuItem (); + container.add_child (sep); + sep.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + add_menuitem (new MenuItem ("System Settings...")); } public void add_menuitem (MenuItem menuitem) { container.add_child (menuitem); + menuitem.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + } + + public void scale (float scale_factor) { + canvas.scale_factor = scale_factor; + shadow_effect.scale_factor = scale_factor; + + container.margin_top = container.margin_bottom = InternalUtils.scale_to_int (6, scale_factor); + + foreach (var child in get_children ()) { + if (child is MenuItem) { + ((MenuItem) child).scale (scale_factor); + continue; + } + + if (child is SeparatorMenuItem) { + ((SeparatorMenuItem) child).scale (scale_factor); + continue; + } + } } private bool draw (Cairo.Context ctx, int width, int height) { @@ -139,15 +139,6 @@ public class Gala.WindowMenu : Clutter.Actor { return true; } - private void create_components () { - // We've already been constructed once, start again - if (drawn) { - destroy_all_children (); - } - - drawn = true; - } - private void create_gtk_objects () { var window = new Gtk.Window (); diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index f688c08e4..f7ffbc27c 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -6,9 +6,6 @@ public class Gala.MenuItem : Clutter.Actor { public signal void activated (); - private const int WRAPPER_BORDER_RADIUS = 3; - private const string CAPTION_FONT_NAME = "Inter"; - private Clutter.Text text; private Clutter.Canvas canvas; @@ -23,21 +20,7 @@ public class Gala.MenuItem : Clutter.Actor { } } - private float _scale_factor = 1.0f; - public float scale_factor { - get { - return _scale_factor; - } - set { - _scale_factor = value; - canvas.scale_factor = _scale_factor; - - update_size (); - canvas.invalidate (); - } - } - - public MenuItem (string label, float scale_factor) { + public MenuItem (string label) { var text_color = "#2e2e31"; if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { @@ -55,10 +38,10 @@ public class Gala.MenuItem : Clutter.Actor { margin_left = 24, margin_right = 24, margin_top = 6, - margin_bottom = 6 + margin_bottom = 6, + ellipsize = END }; text.set_pivot_point (0.5f, 0.5f); - text.set_ellipsize (Pango.EllipsizeMode.END); text.set_line_alignment (Pango.Alignment.CENTER); canvas = new Clutter.Canvas (); @@ -68,7 +51,14 @@ public class Gala.MenuItem : Clutter.Actor { add_child (text); set_content (canvas); - this.scale_factor = scale_factor; + notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); + } + + public void scale (float scale_factor) { + canvas.scale_factor = scale_factor; + text.margin_left = text.margin_right = InternalUtils.scale_to_int (24, scale_factor); + text.margin_top = text.margin_bottom = InternalUtils.scale_to_int (6, scale_factor); + canvas.set_size ((int) width, (int) height); } public override bool enter_event (Clutter.CrossingEvent event) { @@ -90,11 +80,6 @@ public class Gala.MenuItem : Clutter.Actor { return false; } - private void update_size () { - set_size (text.width > 150 ? text.width : 150, text.height); - canvas.set_size ((int) (text.width > 150 ? text.width : 150), (int) text.height); - } - private bool draw_background (Cairo.Context ctx, int width, int height) { ctx.save (); ctx.set_operator (Cairo.Operator.CLEAR); diff --git a/src/Widgets/Menu/SeparatorMenuItem.vala b/src/Widgets/Menu/SeparatorMenuItem.vala index d89125b3b..e856672de 100644 --- a/src/Widgets/Menu/SeparatorMenuItem.vala +++ b/src/Widgets/Menu/SeparatorMenuItem.vala @@ -6,32 +6,18 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { private Clutter.Canvas canvas; - private float _scale_factor = 1.0f; - public float scale_factor { - get { - return _scale_factor; - } - set { - _scale_factor = value; - canvas.scale_factor = _scale_factor; - - canvas.invalidate (); - } - } - - public SeparatorMenuItem (float scale_factor) { + public SeparatorMenuItem () { canvas = new Clutter.Canvas (); canvas.draw.connect (draw_background); set_content (canvas); - set_size (1, 2); - canvas.set_size (1, 2); - - margin_top = 3; - margin_bottom = 3; + notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); + } - this.scale_factor = scale_factor; + public void scale (float scale_factor) { + height = InternalUtils.scale_to_int (2, scale_factor); + margin_top = margin_bottom = InternalUtils.scale_to_int (3, scale_factor); } private bool draw_background (Cairo.Context ctx, int width, int height) { @@ -54,11 +40,11 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { } ctx.set_source_rgba (0, 0, 0, top_alpha); - ctx.rectangle (0, 0, width, 1); + ctx.rectangle (0, 0, width, height / 2); ctx.fill (); ctx.set_source_rgba (255, 255, 255, bottom_alpha); - ctx.rectangle (0, 1, width, 1); + ctx.rectangle (0, height / 2, width, height / 2); ctx.fill (); ctx.restore (); From e9c695631d086c108b373fb05b0660c97a37e77d Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sat, 30 Sep 2023 15:08:04 +0200 Subject: [PATCH 12/31] Cleanup --- src/Widgets/Menu/Menu.vala | 20 - src/Widgets/Menu/SeparatorMenuItem.vala | 3 +- src/Widgets/WindowMenu.vala | 517 ------------------------ 3 files changed, 2 insertions(+), 538 deletions(-) delete mode 100644 src/Widgets/WindowMenu.vala diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 3eda38504..d86624235 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -178,26 +178,6 @@ public class Gala.WindowMenu : Clutter.Actor { private void push_modal () { modal_proxy = wm.push_modal (this); - modal_proxy.set_keybinding_filter ((binding) => { - var action = Meta.Prefs.get_keybinding_action (binding.get_name ()); - - switch (action) { - case Meta.KeyBindingAction.NONE: - case Meta.KeyBindingAction.LOCATE_POINTER_KEY: - case Meta.KeyBindingAction.SWITCH_APPLICATIONS: - case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD: - case Meta.KeyBindingAction.SWITCH_WINDOWS: - case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: - case Meta.KeyBindingAction.SWITCH_GROUP: - case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: - return false; - default: - break; - } - - return true; - }); - } public override void key_focus_out () { diff --git a/src/Widgets/Menu/SeparatorMenuItem.vala b/src/Widgets/Menu/SeparatorMenuItem.vala index e856672de..a82454b0e 100644 --- a/src/Widgets/Menu/SeparatorMenuItem.vala +++ b/src/Widgets/Menu/SeparatorMenuItem.vala @@ -6,7 +6,7 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { private Clutter.Canvas canvas; - public SeparatorMenuItem () { + construct { canvas = new Clutter.Canvas (); canvas.draw.connect (draw_background); @@ -18,6 +18,7 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { public void scale (float scale_factor) { height = InternalUtils.scale_to_int (2, scale_factor); margin_top = margin_bottom = InternalUtils.scale_to_int (3, scale_factor); + canvas.scale_factor = scale_factor; } private bool draw_background (Cairo.Context ctx, int width, int height) { diff --git a/src/Widgets/WindowMenu.vala b/src/Widgets/WindowMenu.vala deleted file mode 100644 index beab40546..000000000 --- a/src/Widgets/WindowMenu.vala +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright 2021 Aral Balkan - * Copyright 2020 Mark Story - * Copyright 2017 Popye - * Copyright 2014 Tom Beckmann - * Copyright 2023 elementary, Inc. - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -public class Gala.WindowMenu : Clutter.Actor { - public const int ICON_SIZE = 64; - public const int WRAPPER_PADDING = 12; - private const string CAPTION_FONT_NAME = "Inter"; - private const int MIN_OFFSET = 64; - private const int ANIMATION_DURATION = 200; - - public bool opened { get; private set; default = false; } - - public Gala.WindowManager? wm { get; construct; } - private Gala.ModalProxy modal_proxy = null; - - private Granite.Settings granite_settings; - private Clutter.Canvas canvas; - private Clutter.Actor container; - private Clutter.Text caption; - - private Gtk.WidgetPath widget_path; - private Gtk.StyleContext style_context; - private unowned Gtk.CssProvider? dark_style_provider = null; - - private int modifier_mask; - - private bool first_release = true; - - private WindowSwitcherIcon? _current_icon = null; - private WindowSwitcherIcon? current_icon { - get { - return _current_icon; - } - set { - if (_current_icon != null) { - _current_icon.selected = false; - } - - _current_icon = value; - if (_current_icon != null) { - _current_icon.selected = true; - } - - update_caption_text (); - } - } - - private float scaling_factor = 1.0f; - - public WindowMenu (Gala.WindowManager wm) { - Object (wm: wm); - } - - construct { - unowned var gtk_settings = Gtk.Settings.get_default (); - granite_settings = Granite.Settings.get_default (); - - unowned var display = wm.get_display (); - scaling_factor = display.get_monitor_scale (display.get_current_monitor ()); - - canvas = new Clutter.Canvas (); - canvas.scale_factor = scaling_factor; - set_content (canvas); - - opacity = 0; - - // Carry out the initial draw - create_components (); - - var effect = new ShadowEffect (40) { - shadow_opacity = 200, - css_class = "window-switcher", - scale_factor = scaling_factor - }; - add_effect (effect); - - // Redraw the components if the colour scheme changes. - granite_settings.notify["prefers-color-scheme"].connect (() => { - canvas.invalidate (); - create_components (); - }); - - gtk_settings.notify["gtk-theme-name"].connect (() => { - canvas.invalidate (); - create_components (); - }); - - unowned var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); - monitor_manager.monitors_changed.connect (() => { - var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); - if (cur_scale != scaling_factor) { - scaling_factor = cur_scale; - canvas.scale_factor = scaling_factor; - effect.scale_factor = scaling_factor; - create_components (); - } - }); - - canvas.draw.connect (draw); - } - - private bool draw (Cairo.Context ctx, int width, int height) { - if (style_context == null) { // gtk is not initialized yet - create_gtk_objects (); - } - - ctx.save (); - ctx.set_operator (Cairo.Operator.CLEAR); - ctx.paint (); - ctx.clip (); - ctx.reset_clip (); - - if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { - unowned var gtksettings = Gtk.Settings.get_default (); - dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); - style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - } else if (dark_style_provider != null) { - style_context.remove_provider (dark_style_provider); - dark_style_provider = null; - } - - ctx.set_operator (Cairo.Operator.OVER); - style_context.render_background (ctx, 0, 0, width, height); - style_context.render_frame (ctx, 0, 0, width, height); - ctx.restore (); - - return true; - } - - private void create_components () { - // We've already been constructed once, start again - if (container != null) { - destroy_all_children (); - } - - var margin = InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor); - var layout = new Clutter.FlowLayout (Clutter.FlowOrientation.HORIZONTAL); - container = new Clutter.Actor () { - reactive = true, - layout_manager = layout, - margin_left = margin, - margin_top = margin, - margin_right = margin, - margin_bottom = margin - }; - - container.button_release_event.connect (container_mouse_release); - container.motion_event.connect (container_motion_event); - - var caption_color = "#2e2e31"; - - if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { - caption_color = "#fafafa"; - } - - caption = new Clutter.Text.full (CAPTION_FONT_NAME, "", Clutter.Color.from_string (caption_color)); - caption.set_pivot_point (0.5f, 0.5f); - caption.set_ellipsize (Pango.EllipsizeMode.END); - caption.set_line_alignment (Pango.Alignment.CENTER); - - add_child (container); - add_child (caption); - } - - private void create_gtk_objects () { - widget_path = new Gtk.WidgetPath (); - widget_path.append_type (typeof (Gtk.Window)); - widget_path.iter_set_object_name (-1, "window"); - - style_context = new Gtk.StyleContext (); - style_context.set_scale ((int)Math.round (scaling_factor)); - style_context.set_path (widget_path); - style_context.add_class ("background"); - style_context.add_class ("csd"); - style_context.add_class ("unified"); - } - - [CCode (instance_pos = -1)] - public void handle_switch_windows ( - Meta.Display display - ) { - var workspace = display.get_workspace_manager ().get_active_workspace (); - - // copied from gnome-shell, finds the primary modifier in the mask - // var mask = binding.get_mask (); - // if (mask == 0) { - // modifier_mask = 0; - // } else { - // modifier_mask = 1; - // while (mask > 1) { - // mask >>= 1; - // modifier_mask <<= 1; - // } - // } - - if (!opened) { - bool windows_exist; - // if (binding.get_name ().has_prefix ("switch-group")) { - // windows_exist = collect_current_windows (display, workspace); - // } else { - // windows_exist = collect_all_windows (display, workspace); - // } - - // if (!windows_exist) { - // return; - // } - - open_switcher (); - } - - // var binding_name = binding.get_name (); - // var backward = binding_name.has_suffix ("-backward"); - - next_window (false); - } - - private bool collect_all_windows (Meta.Display display, Meta.Workspace? workspace) { - var windows = display.get_tab_list (Meta.TabList.NORMAL, workspace); - if (windows == null) { - return false; - } - - unowned var current_window = display.get_tab_current (Meta.TabList.NORMAL, workspace); - if (current_window == null) { - current_icon = null; - } - - container.width = -1; - container.destroy_all_children (); - - foreach (unowned var window in windows) { - var icon = new WindowSwitcherIcon (window, ICON_SIZE, scaling_factor); - if (window == current_window) { - current_icon = icon; - } - - container.add_child (icon); - } - - return true; - } - - private bool collect_current_windows (Meta.Display display, Meta.Workspace? workspace) { - var windows = display.get_tab_list (Meta.TabList.NORMAL, workspace); - if (windows == null) { - return false; - } - - unowned var current_window = display.get_tab_current (Meta.TabList.NORMAL, workspace); - if (current_window == null) { - current_icon = null; - return false; - } - - container.width = -1; - container.destroy_all_children (); - - unowned var window_tracker = ((WindowManagerGala) wm).window_tracker; - var app = window_tracker.get_app_for_window (current_window); - foreach (unowned var window in windows) { - if (window_tracker.get_app_for_window (window) == app) { - var icon = new WindowSwitcherIcon (window, ICON_SIZE, scaling_factor); - if (window == current_window) { - current_icon = icon; - } - - container.add_child (icon); - } - } - - return true; - } - - private void open_switcher () { - // if (container.get_n_children () == 0) { - // Clutter.get_default_backend ().get_default_seat ().bell_notify (); - // return; - // } - - if (opened) { - return; - } - - opacity = 0; - - unowned var display = wm.get_display (); - var monitor = display.get_current_monitor (); - var geom = display.get_monitor_geometry (monitor); - - float container_width; - container.get_preferred_width ( - InternalUtils.scale_to_int (ICON_SIZE, scaling_factor) + container.margin_left + container.margin_right, - null, - out container_width - ); - if (container_width + InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2 > geom.width) { - container.width = geom.width - InternalUtils.scale_to_int (MIN_OFFSET, scaling_factor) * 2; - } - - float nat_width, nat_height; - container.get_preferred_size (null, null, out nat_width, out nat_height); - - var switcher_height = (int) (nat_height + caption.height / 2 - container.margin_bottom + WRAPPER_PADDING * 3 * scaling_factor); - set_size ((int) nat_width, switcher_height); - canvas.set_size ((int) nat_width, switcher_height); - canvas.invalidate (); - - // container width might have changed, so we must update caption width too - update_caption_text (); - - toggle_display (true); - } - - private void toggle_display (bool show) { - if (opened == show) { - return; - } - - opened = show; - if (show) { - push_modal (); - } else { - wm.pop_modal (modal_proxy); - } - - save_easing_state (); - set_easing_duration (wm.enable_animations ? ANIMATION_DURATION : 0); - opacity = show ? 255 : 0; - restore_easing_state (); - - container.reactive = show; - } - - private void push_modal () { - modal_proxy = wm.push_modal (this); - modal_proxy.set_keybinding_filter ((binding) => { - var action = Meta.Prefs.get_keybinding_action (binding.get_name ()); - - switch (action) { - case Meta.KeyBindingAction.NONE: - case Meta.KeyBindingAction.LOCATE_POINTER_KEY: - case Meta.KeyBindingAction.SWITCH_APPLICATIONS: - case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD: - case Meta.KeyBindingAction.SWITCH_WINDOWS: - case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: - case Meta.KeyBindingAction.SWITCH_GROUP: - case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: - return false; - default: - break; - } - - return true; - }); - - } - - private void close_switcher (uint32 time, bool cancel = false) { - if (!opened) { - return; - } - - // var window = current_icon.window; - // if (window == null) { - // return; - // } - - // if (!cancel) { - // var workspace = window.get_workspace (); - // if (workspace != wm.get_display ().get_workspace_manager ().get_active_workspace ()) { - // workspace.activate_with_focus (window, time); - // } else { - // window.activate (time); - // } - // } - - toggle_display (false); - } - - private void next_window (bool backward) { - Clutter.Actor actor; - - if (container.get_n_children () == 1 && current_icon != null) { - Clutter.get_default_backend ().get_default_seat ().bell_notify (); - return; - } - - if (current_icon == null) { - actor = container.get_first_child (); - } else if (!backward) { - actor = current_icon.get_next_sibling (); - if (actor == null) { - actor = container.get_first_child (); - } - } else { - actor = current_icon.get_previous_sibling (); - if (actor == null) { - actor = container.get_last_child (); - } - } - - current_icon = (WindowSwitcherIcon) actor; - } - - private void update_caption_text () { - var current_window = current_icon != null ? current_icon.window : null; - var current_caption = current_window != null ? current_window.title : "n/a"; - caption.set_text (current_caption); - - // Make caption smaller than the wrapper, so it doesn't overflow. - caption.width = width - WRAPPER_PADDING * 2 * scaling_factor; - caption.set_position ( - InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor), - (int) (height - caption.height / 2 - InternalUtils.scale_to_int (WRAPPER_PADDING, scaling_factor) * 2) - ); - } - - public override void key_focus_out () { - close_switcher (wm.get_display ().get_current_time ()); - } - - public override bool button_release_event (Clutter.ButtonEvent event) { - if (first_release) { - first_release = false; - return true; - } - - close_switcher (event.get_time ()); - first_release = true; - return true; - } - -#if HAS_MUTTER45 - private bool container_motion_event (Clutter.Event event) { -#else - private bool container_motion_event (Clutter.MotionEvent event) { -#endif - float x, y; - event.get_coords (out x, out y); - var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y); - if (actor == null) { - return true; - } - - var selected = actor as WindowSwitcherIcon; - if (selected == null) { - return true; - } - - if (current_icon != selected) { - current_icon = selected; - } - - return true; - } - -#if HAS_MUTTER45 - private bool container_mouse_release (Clutter.Event event) { -#else - private bool container_mouse_release (Clutter.ButtonEvent event) { -#endif - if (opened && event.get_button () == Clutter.Button.PRIMARY) { - close_switcher (event.get_time ()); - } - - return true; - } - -#if HAS_MUTTER45 - public override bool key_release_event (Clutter.Event event) { -#else - public override bool key_release_event (Clutter.KeyEvent event) { -#endif - // if ((get_current_modifiers () & modifier_mask) == 0) { - // close_switcher (event.get_time ()); - // } - - return Clutter.EVENT_PROPAGATE; - } - -#if HAS_MUTTER45 - public override bool key_press_event (Clutter.Event event) { -#else - public override bool key_press_event (Clutter.KeyEvent event) { -#endif - switch (event.get_key_symbol ()) { - case Clutter.Key.Right: - next_window (false); - return Clutter.EVENT_STOP; - case Clutter.Key.Left: - next_window (true); - return Clutter.EVENT_STOP; - case Clutter.Key.Escape: - close_switcher (event.get_time (), true); - return Clutter.EVENT_PROPAGATE; - case Clutter.Key.Return: - close_switcher (event.get_time (), false); - return Clutter.EVENT_PROPAGATE; - } - - return Clutter.EVENT_PROPAGATE; - } - - - private inline Clutter.ModifierType get_current_modifiers () { - Clutter.ModifierType modifiers; - wm.get_display ().get_cursor_tracker ().get_pointer (null, out modifiers); - - return modifiers & Clutter.ModifierType.MODIFIER_MASK; - } -} From c499ef00df6f328609085378e63c919164f6fb2b Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sat, 30 Sep 2023 15:11:17 +0200 Subject: [PATCH 13/31] Add add_separator --- src/Widgets/Menu/Menu.vala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index d86624235..eaf8e828a 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -8,10 +8,6 @@ */ public class Gala.WindowMenu : Clutter.Actor { - public const int ICON_SIZE = 64; - public const int WRAPPER_PADDING = 5; - private const string CAPTION_FONT_NAME = "Inter"; - private const int MIN_OFFSET = 64; private const int ANIMATION_DURATION = 200; public bool opened { get; private set; default = false; } @@ -81,9 +77,7 @@ public class Gala.WindowMenu : Clutter.Actor { add_menuitem (new MenuItem ("Change Wallpaper...")); add_menuitem (new MenuItem ("Display Settings...")); - var sep = new SeparatorMenuItem (); - container.add_child (sep); - sep.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + add_separator (); add_menuitem (new MenuItem ("System Settings...")); } @@ -92,7 +86,13 @@ public class Gala.WindowMenu : Clutter.Actor { menuitem.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); } - public void scale (float scale_factor) { + public void add_separator () { + var separator = new SeparatorMenuItem (); + container.add_child (separator); + separator.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + } + + private void scale (float scale_factor) { canvas.scale_factor = scale_factor; shadow_effect.scale_factor = scale_factor; From 5742055d4b6dbed7ab5c7697e28f4cb302a71092 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sat, 30 Sep 2023 15:46:20 +0200 Subject: [PATCH 14/31] Finish background menu --- src/Widgets/BackgroundMenu.vala | 68 +++++++++++++++++++++++++++++++++ src/Widgets/Menu/Menu.vala | 18 ++------- src/WindowManager.vala | 24 +++++------- src/meson.build | 1 + 4 files changed, 81 insertions(+), 30 deletions(-) create mode 100644 src/Widgets/BackgroundMenu.vala diff --git a/src/Widgets/BackgroundMenu.vala b/src/Widgets/BackgroundMenu.vala new file mode 100644 index 000000000..e64f188c9 --- /dev/null +++ b/src/Widgets/BackgroundMenu.vala @@ -0,0 +1,68 @@ +/* + * Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +public class Gala.BackgroundMenu : Menu { + public BackgroundMenu (Gala.WindowManager wm) { + Object (wm: wm); + } + + construct { + var change_wallpaper = new MenuItem (_("Change Wallpaper…")); + change_wallpaper.activated.connect (() => { + try { + AppInfo.launch_default_for_uri ("settings://desktop/appearance/wallpaper", null); + } catch (Error e) { + var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( + "Failed to Open Wallpaper Settings", + "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", + "dialog-error", + Gtk.ButtonsType.CLOSE + ); + message_dialog.show_error_details (e.message); + message_dialog.run (); + message_dialog.destroy (); + } + }); + + var display_settings = new MenuItem (_("Display Settings…")); + display_settings.activated.connect (() => { + try { + AppInfo.launch_default_for_uri ("settings://display", null); + } catch (Error e) { + var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( + "Failed to Open Display Settings", + "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", + "dialog-warning", + Gtk.ButtonsType.CLOSE + ); + message_dialog.show_error_details (e.message); + message_dialog.run (); + message_dialog.destroy (); + } + }); + + var system_settings = new MenuItem (_("System Settings…")); + system_settings.activated.connect (() => { + try { + AppInfo.launch_default_for_uri ("settings://", null); + } catch (Error e) { + var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( + "Failed to Open System Settings", + "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", + "dialog-warning", + Gtk.ButtonsType.CLOSE + ); + message_dialog.show_error_details (e.message); + message_dialog.run (); + message_dialog.destroy (); + } + }); + + add_menuitem (change_wallpaper); + add_menuitem (display_settings); + add_separator (); + add_menuitem (system_settings); + } +} diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index eaf8e828a..27f0f08df 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -7,7 +7,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -public class Gala.WindowMenu : Clutter.Actor { +public class Gala.Menu : Clutter.Actor { private const int ANIMATION_DURATION = 200; public bool opened { get; private set; default = false; } @@ -23,9 +23,7 @@ public class Gala.WindowMenu : Clutter.Actor { private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; - private bool first_release = true; - - public WindowMenu (Gala.WindowManager wm) { + public Menu (Gala.WindowManager wm) { Object (wm: wm); } @@ -74,16 +72,12 @@ public class Gala.WindowMenu : Clutter.Actor { notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); canvas.draw.connect (draw); - - add_menuitem (new MenuItem ("Change Wallpaper...")); - add_menuitem (new MenuItem ("Display Settings...")); - add_separator (); - add_menuitem (new MenuItem ("System Settings...")); } public void add_menuitem (MenuItem menuitem) { container.add_child (menuitem); menuitem.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); + menuitem.activated.connect (() => toggle_display (false)); } public void add_separator () { @@ -185,13 +179,7 @@ public class Gala.WindowMenu : Clutter.Actor { } public override bool button_release_event (Clutter.ButtonEvent event) { - if (first_release) { - first_release = false; - return true; - } - toggle_display (false); - first_release = true; return true; } diff --git a/src/WindowManager.vala b/src/WindowManager.vala index a8218ea77..3008c6241 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -73,7 +73,8 @@ namespace Gala { private WindowSwitcher? winswitcher = null; private ActivatableComponent? window_overview = null; - private WindowMenu window_menu; + + private BackgroundMenu background_menu; public ScreenSaverManager? screensaver { get; private set; } @@ -231,6 +232,7 @@ namespace Gala { Clutter.BindCoordinate.ALL, 0)); stage.insert_child_below (system_background.background_actor, null); + ui_group = new Clutter.Actor (); ui_group.reactive = true; stage.add_child (ui_group); @@ -248,6 +250,9 @@ namespace Gala { stage.remove_child (top_window_group); ui_group.add_child (top_window_group); + background_menu = new BackgroundMenu (this); + ui_group.add_child (background_menu); + FilterManager.init (this); /*keybindings*/ @@ -346,8 +351,6 @@ namespace Gala { ui_group.add_child ((Clutter.Actor) window_overview); } - window_menu = new WindowMenu (this); - notification_group = new Clutter.Actor (); ui_group.add_child (notification_group); @@ -408,17 +411,8 @@ namespace Gala { } private void on_show_background_menu (int x, int y) { - if (daemon_proxy == null) { - return; - } - - daemon_proxy.show_desktop_menu.begin (x, y, (obj, res) => { - try { - ((Daemon) obj).show_desktop_menu.end (res); - } catch (Error e) { - message ("Error invoking MenuManager: %s", e.message); - } - }); + background_menu.set_position (x, y); + background_menu.open_menu (); } private void on_monitors_changed () { @@ -989,7 +983,7 @@ namespace Gala { switch (menu) { case Meta.WindowMenuType.WM: warning ("CREATE MENU"); - var window_menu = new WindowMenu (this); + var window_menu = new BackgroundMenu (this); ui_group.add_child (window_menu); window_menu.set_position (x, y); window_menu.open_menu (); diff --git a/src/meson.build b/src/meson.build index e4871cdd2..b5fe04538 100644 --- a/src/meson.build +++ b/src/meson.build @@ -38,6 +38,7 @@ gala_bin_sources = files( 'Gestures/ToucheggBackend.vala', 'HotCorners/HotCorner.vala', 'HotCorners/HotCornerManager.vala', + 'Widgets/BackgroundMenu.vala', 'Widgets/DwellClickTimer.vala', 'Widgets/IconGroup.vala', 'Widgets/IconGroupContainer.vala', From 8a8cb84fdb99c2a9a62c72fc79d6613bc6076706 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sat, 30 Sep 2023 15:51:44 +0200 Subject: [PATCH 15/31] Fix scale + cleanup --- daemon/MenuDaemon.vala | 74 ------------------------------- src/Widgets/Menu/Menu.vala | 2 +- src/WindowManager.vala | 90 ++++++++++++++++++-------------------- 3 files changed, 43 insertions(+), 123 deletions(-) diff --git a/daemon/MenuDaemon.vala b/daemon/MenuDaemon.vala index 5029aab46..71b757895 100644 --- a/daemon/MenuDaemon.vala +++ b/daemon/MenuDaemon.vala @@ -51,9 +51,6 @@ namespace Gala { private Gtk.MenuItem close; private Gtk.MenuItem screenshot; - // Desktop Menu - private Gtk.Menu? desktop_menu = null; - private WMDBus? wm_proxy = null; private ulong always_on_top_sid = 0U; @@ -292,76 +289,5 @@ namespace Gala { return opened ? Source.REMOVE : Source.CONTINUE; }); } - - public void show_desktop_menu (int x, int y) throws DBusError, IOError { - if (desktop_menu == null) { - var change_wallpaper = new Gtk.MenuItem.with_label (_("Change Wallpaper…")); - change_wallpaper.activate.connect (() => { - try { - AppInfo.launch_default_for_uri ("settings://desktop/appearance/wallpaper", null); - } catch (Error e) { - var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( - "Failed to Open Wallpaper Settings", - "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", - "dialog-error", - Gtk.ButtonsType.CLOSE - ); - message_dialog.show_error_details (e.message); - message_dialog.run (); - message_dialog.destroy (); - } - }); - - var display_settings = new Gtk.MenuItem.with_label (_("Display Settings…")); - display_settings.activate.connect (() => { - try { - AppInfo.launch_default_for_uri ("settings://display", null); - } catch (Error e) { - var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( - "Failed to Open Display Settings", - "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", - "dialog-warning", - Gtk.ButtonsType.CLOSE - ); - message_dialog.show_error_details (e.message); - message_dialog.run (); - message_dialog.destroy (); - } - }); - - var system_settings = new Gtk.MenuItem.with_label (_("System Settings…")); - system_settings.activate.connect (() => { - try { - AppInfo.launch_default_for_uri ("settings://", null); - } catch (Error e) { - var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( - "Failed to Open System Settings", - "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", - "dialog-warning", - Gtk.ButtonsType.CLOSE - ); - message_dialog.show_error_details (e.message); - message_dialog.run (); - message_dialog.destroy (); - } - }); - - desktop_menu = new Gtk.Menu (); - desktop_menu.append (change_wallpaper); - desktop_menu.append (display_settings); - desktop_menu.append (new Gtk.SeparatorMenuItem ()); - desktop_menu.append (system_settings); - desktop_menu.show_all (); - } - - desktop_menu.popup (null, null, (m, ref px, ref py, out push_in) => { - var scale = m.scale_factor; - px = x / scale; - // Move the menu 1 pixel outside of the pointer or else it closes instantly - // on the mouse up event - py = (y / scale) + 1; - push_in = false; - }, Gdk.BUTTON_SECONDARY, Gdk.CURRENT_TIME); - } } } diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 27f0f08df..607afc50d 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -92,7 +92,7 @@ public class Gala.Menu : Clutter.Actor { container.margin_top = container.margin_bottom = InternalUtils.scale_to_int (6, scale_factor); - foreach (var child in get_children ()) { + foreach (var child in container.get_children ()) { if (child is MenuItem) { ((MenuItem) child).scale (scale_factor); continue; diff --git a/src/WindowManager.vala b/src/WindowManager.vala index 3008c6241..495970520 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -22,7 +22,6 @@ namespace Gala { [DBus (name = "org.pantheon.gala.daemon")] public interface Daemon: GLib.Object { public abstract async void show_window_menu (WindowFlags flags, int x, int y) throws Error; - public abstract async void show_desktop_menu (int x, int y) throws Error; } public class WindowManagerGala : Meta.Plugin, WindowManager { @@ -982,53 +981,48 @@ namespace Gala { public override void show_window_menu (Meta.Window window, Meta.WindowMenuType menu, int x, int y) { switch (menu) { case Meta.WindowMenuType.WM: - warning ("CREATE MENU"); - var window_menu = new BackgroundMenu (this); - ui_group.add_child (window_menu); - window_menu.set_position (x, y); - window_menu.open_menu (); - // if (daemon_proxy == null || window.get_window_type () == Meta.WindowType.NOTIFICATION) { - // return; - // } - - // WindowFlags flags = WindowFlags.NONE; - // if (window.can_minimize ()) - // flags |= WindowFlags.CAN_HIDE; - - // if (window.can_maximize ()) - // flags |= WindowFlags.CAN_MAXIMIZE; - - // var maximize_flags = window.get_maximized (); - // if (maximize_flags > 0) { - // flags |= WindowFlags.IS_MAXIMIZED; - - // if (Meta.MaximizeFlags.VERTICAL in maximize_flags && !(Meta.MaximizeFlags.HORIZONTAL in maximize_flags)) { - // flags |= WindowFlags.IS_TILED; - // } - // } - - // if (window.allows_move ()) - // flags |= WindowFlags.ALLOWS_MOVE; - - // if (window.allows_resize ()) - // flags |= WindowFlags.ALLOWS_RESIZE; - - // if (window.is_above ()) - // flags |= WindowFlags.ALWAYS_ON_TOP; - - // if (window.on_all_workspaces) - // flags |= WindowFlags.ON_ALL_WORKSPACES; - - // if (window.can_close ()) - // flags |= WindowFlags.CAN_CLOSE; - - // daemon_proxy.show_window_menu.begin (flags, x, y, (obj, res) => { - // try { - // ((Daemon) obj).show_window_menu.end (res); - // } catch (Error e) { - // message ("Error invoking MenuManager: %s", e.message); - // } - // }); + if (daemon_proxy == null || window.get_window_type () == Meta.WindowType.NOTIFICATION) { + return; + } + + WindowFlags flags = WindowFlags.NONE; + if (window.can_minimize ()) + flags |= WindowFlags.CAN_HIDE; + + if (window.can_maximize ()) + flags |= WindowFlags.CAN_MAXIMIZE; + + var maximize_flags = window.get_maximized (); + if (maximize_flags > 0) { + flags |= WindowFlags.IS_MAXIMIZED; + + if (Meta.MaximizeFlags.VERTICAL in maximize_flags && !(Meta.MaximizeFlags.HORIZONTAL in maximize_flags)) { + flags |= WindowFlags.IS_TILED; + } + } + + if (window.allows_move ()) + flags |= WindowFlags.ALLOWS_MOVE; + + if (window.allows_resize ()) + flags |= WindowFlags.ALLOWS_RESIZE; + + if (window.is_above ()) + flags |= WindowFlags.ALWAYS_ON_TOP; + + if (window.on_all_workspaces) + flags |= WindowFlags.ON_ALL_WORKSPACES; + + if (window.can_close ()) + flags |= WindowFlags.CAN_CLOSE; + + daemon_proxy.show_window_menu.begin (flags, x, y, (obj, res) => { + try { + ((Daemon) obj).show_window_menu.end (res); + } catch (Error e) { + message ("Error invoking MenuManager: %s", e.message); + } + }); break; case Meta.WindowMenuType.APP: // FIXME we don't have any sort of app menus From ad17b0cf8b710df26959fd7c859eac024a136b77 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 13:06:25 +0200 Subject: [PATCH 16/31] Use actor background color --- src/Widgets/Menu/MenuItem.vala | 43 ++++++++++------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index f7ffbc27c..f790df0ad 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -7,7 +7,6 @@ public class Gala.MenuItem : Clutter.Actor { public signal void activated (); private Clutter.Text text; - private Clutter.Canvas canvas; private bool _selected = false; public bool selected { @@ -16,7 +15,18 @@ public class Gala.MenuItem : Clutter.Actor { } set { _selected = value; - canvas.invalidate (); + if (_selected) { + var rgba = InternalUtils.get_foreground_color (); + Clutter.Color foreground_color = { + (uint8) (rgba.red * 255), + (uint8) (rgba.green * 255), + (uint8) (rgba.blue * 255), + (uint8) (0.15 * 255) + }; + set_background_color (foreground_color); + } else { + set_background_color (null); + } } } @@ -44,21 +54,14 @@ public class Gala.MenuItem : Clutter.Actor { text.set_pivot_point (0.5f, 0.5f); text.set_line_alignment (Pango.Alignment.CENTER); - canvas = new Clutter.Canvas (); - canvas.draw.connect (draw_background); - + min_width = 150; reactive = true; add_child (text); - set_content (canvas); - - notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); } public void scale (float scale_factor) { - canvas.scale_factor = scale_factor; text.margin_left = text.margin_right = InternalUtils.scale_to_int (24, scale_factor); text.margin_top = text.margin_bottom = InternalUtils.scale_to_int (6, scale_factor); - canvas.set_size ((int) width, (int) height); } public override bool enter_event (Clutter.CrossingEvent event) { @@ -79,24 +82,4 @@ public class Gala.MenuItem : Clutter.Actor { return false; } - - private bool draw_background (Cairo.Context ctx, int width, int height) { - ctx.save (); - ctx.set_operator (Cairo.Operator.CLEAR); - ctx.paint (); - ctx.clip (); - ctx.reset_clip (); - - if (selected) { - var rgba = InternalUtils.get_foreground_color (); - ctx.set_source_rgba (rgba.red, rgba.green, rgba.blue, 0.15); - ctx.rectangle (0, 0, width, height); - ctx.set_operator (Cairo.Operator.SOURCE); - ctx.fill (); - - ctx.restore (); - } - - return true; - } } From e20c35e3642a38774a6a3ea0a6019119f640761c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 13:41:47 +0200 Subject: [PATCH 17/31] Add keyboard navigation --- src/Widgets/Menu/Menu.vala | 50 ++++++++++++++++++++++++++++++++++ src/Widgets/Menu/MenuItem.vala | 15 ++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 607afc50d..2be3578df 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -23,6 +23,8 @@ public class Gala.Menu : Clutter.Actor { private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; + private MenuItem? selected = null; + public Menu (Gala.WindowManager wm) { Object (wm: wm); } @@ -78,6 +80,21 @@ public class Gala.Menu : Clutter.Actor { container.add_child (menuitem); menuitem.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); menuitem.activated.connect (() => toggle_display (false)); + menuitem.notify["selected"].connect (() => { + if (selected != null) { + if (!menuitem.selected && selected == menuitem) { + selected = null; + } else { + selected.selected = false; + selected = menuitem; + } + return; + } + + if (menuitem.selected) { + selected = menuitem; + } + }); } public void add_separator () { @@ -189,14 +206,47 @@ public class Gala.Menu : Clutter.Actor { public override bool key_press_event (Clutter.KeyEvent event) { #endif switch (event.get_key_symbol ()) { + case Clutter.Key.Up: + cycle_menuitems (true); + return Clutter.EVENT_STOP; + case Clutter.Key.Down: + cycle_menuitems (false); + return Clutter.EVENT_STOP; case Clutter.Key.Escape: toggle_display (false); return Clutter.EVENT_PROPAGATE; case Clutter.Key.Return: + if (selected != null) { + selected.activated (); + } toggle_display (false); return Clutter.EVENT_PROPAGATE; } return Clutter.EVENT_PROPAGATE; } + + private void cycle_menuitems (bool backwards) { + Clutter.Actor child; + if (selected != null) { + if (backwards) { + child = selected.get_previous_sibling () != null ? selected.get_previous_sibling () : container.last_child; + } else { + child = selected.get_next_sibling () != null ? selected.get_next_sibling () : container.first_child; + } + } else { + child = backwards ? container.last_child : container.first_child; + } + + while (child != null) { + if (child is MenuItem) { + var menuitem = (MenuItem) child; + menuitem.selected = true; + selected = menuitem; + break; + } + + child = backwards ? child.get_previous_sibling () : child.get_next_sibling (); + } + } } diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index f790df0ad..62e404f55 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -82,4 +82,19 @@ public class Gala.MenuItem : Clutter.Actor { return false; } + +#if HAS_MUTTER45 + public override bool key_press_event (Clutter.Event event) { +#else + public override bool key_press_event (Clutter.KeyEvent event) { +#endif + switch (event.get_key_symbol ()) { + case Clutter.Key.Return: + print ("RETURN PRESSED"); + // toggle_display (false); + return Clutter.EVENT_PROPAGATE; + } + + return Clutter.EVENT_PROPAGATE; + } } From 4de20e7bc9b31f0eb096a4eaf7ff1f94eb1bc139 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 13:52:14 +0200 Subject: [PATCH 18/31] Add keyboard navigation --- src/Widgets/Menu/Menu.vala | 42 ++++++++++++++++++++-------------- src/Widgets/Menu/MenuItem.vala | 25 -------------------- 2 files changed, 25 insertions(+), 42 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 2be3578df..b17b1e524 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -23,7 +23,22 @@ public class Gala.Menu : Clutter.Actor { private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; - private MenuItem? selected = null; + private MenuItem? _selected = null; + private MenuItem? selected { + get { + return _selected; + } + set { + if (_selected != null) { + _selected.selected = false; + } + + _selected = value; + if (_selected != null) { + _selected.selected = true; + } + } + } public Menu (Gala.WindowManager wm) { Object (wm: wm); @@ -80,20 +95,15 @@ public class Gala.Menu : Clutter.Actor { container.add_child (menuitem); menuitem.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); menuitem.activated.connect (() => toggle_display (false)); - menuitem.notify["selected"].connect (() => { - if (selected != null) { - if (!menuitem.selected && selected == menuitem) { - selected = null; - } else { - selected.selected = false; - selected = menuitem; - } - return; - } - if (menuitem.selected) { - selected = menuitem; - } + menuitem.enter_event.connect (() => { + selected = menuitem; + return false; + }); + + menuitem.leave_event.connect (() => { + selected = null; + return false; }); } @@ -240,9 +250,7 @@ public class Gala.Menu : Clutter.Actor { while (child != null) { if (child is MenuItem) { - var menuitem = (MenuItem) child; - menuitem.selected = true; - selected = menuitem; + selected = (MenuItem) child;; break; } diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index 62e404f55..ad8dab0f6 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -64,16 +64,6 @@ public class Gala.MenuItem : Clutter.Actor { text.margin_top = text.margin_bottom = InternalUtils.scale_to_int (6, scale_factor); } - public override bool enter_event (Clutter.CrossingEvent event) { - selected = true; - return false; - } - - public override bool leave_event (Clutter.CrossingEvent event) { - selected = false; - return false; - } - public override bool button_release_event (Clutter.ButtonEvent event) { if (event.button == Clutter.Button.PRIMARY) { activated (); @@ -82,19 +72,4 @@ public class Gala.MenuItem : Clutter.Actor { return false; } - -#if HAS_MUTTER45 - public override bool key_press_event (Clutter.Event event) { -#else - public override bool key_press_event (Clutter.KeyEvent event) { -#endif - switch (event.get_key_symbol ()) { - case Clutter.Key.Return: - print ("RETURN PRESSED"); - // toggle_display (false); - return Clutter.EVENT_PROPAGATE; - } - - return Clutter.EVENT_PROPAGATE; - } } From d5fb1cdc90a2481eaf84958be32e1758faea6e68 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 13:54:04 +0200 Subject: [PATCH 19/31] Fix small issue --- src/Widgets/Menu/Menu.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index b17b1e524..5af115af6 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -189,6 +189,7 @@ public class Gala.Menu : Clutter.Actor { push_modal (); } else { wm.pop_modal (modal_proxy); + selected = null } save_easing_state (); From cc25b6aaf59056b70260c8c7243c88ea31fd2e52 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 13:57:42 +0200 Subject: [PATCH 20/31] Use MenuItem.with_label --- src/Widgets/BackgroundMenu.vala | 6 +++--- src/Widgets/Menu/Menu.vala | 2 +- src/Widgets/Menu/MenuItem.vala | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Widgets/BackgroundMenu.vala b/src/Widgets/BackgroundMenu.vala index e64f188c9..7dca584c7 100644 --- a/src/Widgets/BackgroundMenu.vala +++ b/src/Widgets/BackgroundMenu.vala @@ -9,7 +9,7 @@ public class Gala.BackgroundMenu : Menu { } construct { - var change_wallpaper = new MenuItem (_("Change Wallpaper…")); + var change_wallpaper = new MenuItem.with_label (_("Change Wallpaper…")); change_wallpaper.activated.connect (() => { try { AppInfo.launch_default_for_uri ("settings://desktop/appearance/wallpaper", null); @@ -26,7 +26,7 @@ public class Gala.BackgroundMenu : Menu { } }); - var display_settings = new MenuItem (_("Display Settings…")); + var display_settings = new MenuItem.with_label (_("Display Settings…")); display_settings.activated.connect (() => { try { AppInfo.launch_default_for_uri ("settings://display", null); @@ -43,7 +43,7 @@ public class Gala.BackgroundMenu : Menu { } }); - var system_settings = new MenuItem (_("System Settings…")); + var system_settings = new MenuItem.with_label (_("System Settings…")); system_settings.activated.connect (() => { try { AppInfo.launch_default_for_uri ("settings://", null); diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 5af115af6..e6c4d603e 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -188,8 +188,8 @@ public class Gala.Menu : Clutter.Actor { if (show) { push_modal (); } else { + selected = null; wm.pop_modal (modal_proxy); - selected = null } save_easing_state (); diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index ad8dab0f6..021a35f9b 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -30,7 +30,12 @@ public class Gala.MenuItem : Clutter.Actor { } } - public MenuItem (string label) { + construct { + min_width = 150; + reactive = true; + } + + public MenuItem.with_label (string label) { var text_color = "#2e2e31"; if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { @@ -53,9 +58,6 @@ public class Gala.MenuItem : Clutter.Actor { }; text.set_pivot_point (0.5f, 0.5f); text.set_line_alignment (Pango.Alignment.CENTER); - - min_width = 150; - reactive = true; add_child (text); } From a36329d3674cfec88262d4d0e0226aece344b11c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 13:59:22 +0200 Subject: [PATCH 21/31] Don't use error dialogs --- src/Widgets/BackgroundMenu.vala | 30 +++--------------------------- src/Widgets/Menu/Menu.vala | 4 ---- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/src/Widgets/BackgroundMenu.vala b/src/Widgets/BackgroundMenu.vala index 7dca584c7..7069b5c7e 100644 --- a/src/Widgets/BackgroundMenu.vala +++ b/src/Widgets/BackgroundMenu.vala @@ -14,15 +14,7 @@ public class Gala.BackgroundMenu : Menu { try { AppInfo.launch_default_for_uri ("settings://desktop/appearance/wallpaper", null); } catch (Error e) { - var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( - "Failed to Open Wallpaper Settings", - "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", - "dialog-error", - Gtk.ButtonsType.CLOSE - ); - message_dialog.show_error_details (e.message); - message_dialog.run (); - message_dialog.destroy (); + warning ("Failed to open Wallpaper Settings: %s", e.message); } }); @@ -31,15 +23,7 @@ public class Gala.BackgroundMenu : Menu { try { AppInfo.launch_default_for_uri ("settings://display", null); } catch (Error e) { - var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( - "Failed to Open Display Settings", - "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", - "dialog-warning", - Gtk.ButtonsType.CLOSE - ); - message_dialog.show_error_details (e.message); - message_dialog.run (); - message_dialog.destroy (); + warning ("Failed to open Display Settings: %s", e.message); } }); @@ -48,15 +32,7 @@ public class Gala.BackgroundMenu : Menu { try { AppInfo.launch_default_for_uri ("settings://", null); } catch (Error e) { - var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( - "Failed to Open System Settings", - "Unable to open System Settings. A handler for the `settings://` URI scheme must be installed.", - "dialog-warning", - Gtk.ButtonsType.CLOSE - ); - message_dialog.show_error_details (e.message); - message_dialog.run (); - message_dialog.destroy (); + warning ("Failed to open System Settings: %s", e.message); } }); diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index e6c4d603e..2fabba7a1 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -1,8 +1,4 @@ /* - * Copyright 2021 Aral Balkan - * Copyright 2020 Mark Story - * Copyright 2017 Popye - * Copyright 2014 Tom Beckmann * Copyright 2023 elementary, Inc. * SPDX-License-Identifier: GPL-3.0-or-later */ From e5f8c798fe9250df30c33ba63f4efb6c78c6088f Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 14:01:02 +0200 Subject: [PATCH 22/31] Fix lint --- src/Widgets/Menu/Menu.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 2fabba7a1..f32f2dfb1 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -247,7 +247,7 @@ public class Gala.Menu : Clutter.Actor { while (child != null) { if (child is MenuItem) { - selected = (MenuItem) child;; + selected = (MenuItem) child; break; } From f0b5fc933e3c8c4b21f845760feaed75994f08dd Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 14:27:26 +0200 Subject: [PATCH 23/31] Lookup colors --- src/InternalUtils.vala | 20 +++++++++++--------- src/Widgets/Menu/MenuItem.vala | 2 +- src/Widgets/Menu/SeparatorMenuItem.vala | 15 ++++----------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/InternalUtils.vala b/src/InternalUtils.vala index e9cf19702..4ddcd95e4 100644 --- a/src/InternalUtils.vala +++ b/src/InternalUtils.vala @@ -335,24 +335,26 @@ namespace Gala { ); } - private static Gtk.StyleContext foreground_style_context = null; + private static Gtk.StyleContext color_style_context = null; private static Gtk.CssProvider dark_style_provider = null; - public static Gdk.RGBA get_foreground_color () { - if (foreground_style_context == null) { - var window = new Gtk.Window (); - foreground_style_context = window.get_style_context (); + public static Gdk.RGBA lookup_color (string color_name) { + if (color_style_context == null) { + color_style_context = new Gtk.StyleContext (); } - if (Granite.Settings.get_default ().prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { unowned var gtksettings = Gtk.Settings.get_default (); dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); - foreground_style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + color_style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); } else if (dark_style_provider != null) { - foreground_style_context.remove_provider (dark_style_provider); + color_style_context.remove_provider (dark_style_provider); dark_style_provider = null; } - return (Gdk.RGBA) foreground_style_context.get_color (NORMAL); + Gdk.RGBA rgba; + color_style_context.lookup_color (color_name, out rgba); + + return rgba; } /** diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index 021a35f9b..cc8748c0e 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -16,7 +16,7 @@ public class Gala.MenuItem : Clutter.Actor { set { _selected = value; if (_selected) { - var rgba = InternalUtils.get_foreground_color (); + var rgba = InternalUtils.lookup_color ("theme_fg_color"); Clutter.Color foreground_color = { (uint8) (rgba.red * 255), (uint8) (rgba.green * 255), diff --git a/src/Widgets/Menu/SeparatorMenuItem.vala b/src/Widgets/Menu/SeparatorMenuItem.vala index a82454b0e..7c40dc3df 100644 --- a/src/Widgets/Menu/SeparatorMenuItem.vala +++ b/src/Widgets/Menu/SeparatorMenuItem.vala @@ -30,21 +30,14 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { ctx.set_operator (Cairo.Operator.SOURCE); - double top_alpha, bottom_alpha; + var rgba = InternalUtils.lookup_color ("menu_separator"); + var shadow_rgba = InternalUtils.lookup_color ("menu_separator_shadow"); - if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { - top_alpha = 0.35; - bottom_alpha = 0.05; - } else { - top_alpha = 0.15; - bottom_alpha = 0.8; - } - - ctx.set_source_rgba (0, 0, 0, top_alpha); + ctx.set_source_rgba (rgba.red, rgba.green, rgba.blue, rgba.alpha); ctx.rectangle (0, 0, width, height / 2); ctx.fill (); - ctx.set_source_rgba (255, 255, 255, bottom_alpha); + ctx.set_source_rgba (shadow_rgba.red, shadow_rgba.green, shadow_rgba.blue, shadow_rgba.alpha); ctx.rectangle (0, height / 2, width, height / 2); ctx.fill (); From d6318c69f956201de8b5fcb46da6bb304aa7275a Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 14:38:05 +0200 Subject: [PATCH 24/31] Update with theme --- src/Widgets/Menu/MenuItem.vala | 11 ++++++----- src/Widgets/Menu/SeparatorMenuItem.vala | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index cc8748c0e..5be677a60 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -36,11 +36,7 @@ public class Gala.MenuItem : Clutter.Actor { } public MenuItem.with_label (string label) { - var text_color = "#2e2e31"; - - if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { - text_color = "#fafafa"; - } + var text_color = Granite.Settings.get_default ().prefers_color_scheme == DARK ? "#fafafa" : "#2e2e31"; var widget = new Gtk.Grid (); @@ -59,6 +55,11 @@ public class Gala.MenuItem : Clutter.Actor { text.set_pivot_point (0.5f, 0.5f); text.set_line_alignment (Pango.Alignment.CENTER); add_child (text); + + Granite.Settings.get_default ().notify["prefers-color-scheme"].connect (() => { + var new_text_color = Granite.Settings.get_default ().prefers_color_scheme == DARK ? "#fafafa" : "#2e2e31"; + text.color = Clutter.Color.from_string (new_text_color); + }); } public void scale (float scale_factor) { diff --git a/src/Widgets/Menu/SeparatorMenuItem.vala b/src/Widgets/Menu/SeparatorMenuItem.vala index 7c40dc3df..952611f35 100644 --- a/src/Widgets/Menu/SeparatorMenuItem.vala +++ b/src/Widgets/Menu/SeparatorMenuItem.vala @@ -13,6 +13,8 @@ public class Gala.SeparatorMenuItem : Clutter.Actor { set_content (canvas); notify["allocation"].connect (() => canvas.set_size ((int) width, (int) height)); + + Granite.Settings.get_default ().notify["prefers-color-scheme"].connect (() => canvas.invalidate ()); } public void scale (float scale_factor) { From bd817700881520baefcc957417f646625ff61db7 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 14:44:59 +0200 Subject: [PATCH 25/31] Lookup color for text color --- src/Widgets/Menu/MenuItem.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widgets/Menu/MenuItem.vala b/src/Widgets/Menu/MenuItem.vala index 5be677a60..f5f9d8c4e 100644 --- a/src/Widgets/Menu/MenuItem.vala +++ b/src/Widgets/Menu/MenuItem.vala @@ -36,7 +36,7 @@ public class Gala.MenuItem : Clutter.Actor { } public MenuItem.with_label (string label) { - var text_color = Granite.Settings.get_default ().prefers_color_scheme == DARK ? "#fafafa" : "#2e2e31"; + var text_color = InternalUtils.lookup_color ("theme_fg_color").to_string (); var widget = new Gtk.Grid (); @@ -57,7 +57,7 @@ public class Gala.MenuItem : Clutter.Actor { add_child (text); Granite.Settings.get_default ().notify["prefers-color-scheme"].connect (() => { - var new_text_color = Granite.Settings.get_default ().prefers_color_scheme == DARK ? "#fafafa" : "#2e2e31"; + var new_text_color = InternalUtils.lookup_color ("theme_fg_color").to_string (); text.color = Clutter.Color.from_string (new_text_color); }); } From 8250879b20d5860a4d45ffcfc9057370a2e52c33 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 15:22:48 +0200 Subject: [PATCH 26/31] Fix wayland --- src/WindowManager.vala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/WindowManager.vala b/src/WindowManager.vala index b54c6ca2a..d892bd8c9 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -73,7 +73,7 @@ namespace Gala { private WindowSwitcher? winswitcher = null; private ActivatableComponent? window_overview = null; - private BackgroundMenu background_menu; + private BackgroundMenu? background_menu = null; public ScreenSaverManager? screensaver { get; private set; } @@ -249,9 +249,6 @@ namespace Gala { stage.remove_child (top_window_group); ui_group.add_child (top_window_group); - background_menu = new BackgroundMenu (this); - ui_group.add_child (background_menu); - FilterManager.init (this); /*keybindings*/ @@ -406,6 +403,11 @@ namespace Gala { } private void on_show_background_menu (int x, int y) { + if (background_menu == null) { + background_menu = new BackgroundMenu (this); + ui_group.add_child (background_menu); + } + background_menu.set_position (x, y); background_menu.open_menu (); } From f6340a403276763ed53b24af851f9e13ae9369d4 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 15:30:32 +0200 Subject: [PATCH 27/31] Cleanup --- src/Widgets/Menu/Menu.vala | 27 +++------------------------ src/WindowManager.vala | 2 +- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index f32f2dfb1..e7818c62c 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -11,7 +11,6 @@ public class Gala.Menu : Clutter.Actor { public Gala.WindowManager? wm { get; construct; } private Gala.ModalProxy modal_proxy = null; - private Granite.Settings granite_settings; private Clutter.Canvas canvas; private Clutter.Actor container; private ShadowEffect shadow_effect; @@ -41,9 +40,6 @@ public class Gala.Menu : Clutter.Actor { } construct { - unowned var gtk_settings = Gtk.Settings.get_default (); - granite_settings = Granite.Settings.get_default (); - canvas = new Clutter.Canvas (); shadow_effect = new ShadowEffect (40) { @@ -65,14 +61,8 @@ public class Gala.Menu : Clutter.Actor { add_child (container); set_content (canvas); - // Redraw the components if the colour scheme changes. - granite_settings.notify["prefers-color-scheme"].connect (() => { - canvas.invalidate (); - }); - - gtk_settings.notify["gtk-theme-name"].connect (() => { - canvas.invalidate (); - }); + Granite.Settings.get_default ().notify["prefers-color-scheme"].connect (() => canvas.invalidate ()); + Gtk.Settings.get_default ().notify["gtk-theme-name"].connect (() => canvas.invalidate ()); unowned var display = wm.get_display (); unowned var monitor_manager = display.get_context ().get_backend ().get_monitor_manager (); @@ -139,7 +129,7 @@ public class Gala.Menu : Clutter.Actor { ctx.clip (); ctx.reset_clip (); - if (granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK) { + if (Granite.Settings.get_default ().prefers_color_scheme == DARK) { unowned var gtksettings = Gtk.Settings.get_default (); dark_style_provider = Gtk.CssProvider.get_named (gtksettings.gtk_theme_name, "dark"); style_context.add_provider (dark_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); @@ -164,17 +154,6 @@ public class Gala.Menu : Clutter.Actor { style_context.add_class ("unified"); } - public void open_menu () { - if (opened) { - return; - } - - opacity = 0; - canvas.invalidate (); - - toggle_display (true); - } - public void toggle_display (bool show) { if (opened == show) { return; diff --git a/src/WindowManager.vala b/src/WindowManager.vala index d892bd8c9..e0cba816f 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -409,7 +409,7 @@ namespace Gala { } background_menu.set_position (x, y); - background_menu.open_menu (); + background_menu.toggle_display (true); } private void on_monitors_changed () { From dd188aa387baaff4dde3de6c70f27bd267cf610a Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 15:32:37 +0200 Subject: [PATCH 28/31] More cleanup --- src/Widgets/Menu/Menu.vala | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index e7818c62c..4a41fdefd 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -161,7 +161,7 @@ public class Gala.Menu : Clutter.Actor { opened = show; if (show) { - push_modal (); + modal_proxy = wm.push_modal (this); } else { selected = null; wm.pop_modal (modal_proxy); @@ -173,14 +173,6 @@ public class Gala.Menu : Clutter.Actor { restore_easing_state (); } - private void push_modal () { - modal_proxy = wm.push_modal (this); - } - - public override void key_focus_out () { - toggle_display (false); - } - public override bool button_release_event (Clutter.ButtonEvent event) { toggle_display (false); return true; From fc7f5d6d502fd5ee2c2b6b2da4231877c44bed9c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 15:35:20 +0200 Subject: [PATCH 29/31] Update meson.build order --- src/meson.build | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/meson.build b/src/meson.build index b5fe04538..ae8fd2255 100644 --- a/src/meson.build +++ b/src/meson.build @@ -42,6 +42,9 @@ gala_bin_sources = files( 'Widgets/DwellClickTimer.vala', 'Widgets/IconGroup.vala', 'Widgets/IconGroupContainer.vala', + 'Widgets/Menu/Menu.vala', + 'Widgets/Menu/MenuItem.vala', + 'Widgets/Menu/SeparatorMenuItem.vala', 'Widgets/MonitorClone.vala', 'Widgets/MultitaskingView.vala', 'Widgets/PixelPicker.vala', @@ -53,10 +56,6 @@ gala_bin_sources = files( 'Widgets/WindowClone.vala', 'Widgets/WindowCloneContainer.vala', 'Widgets/WindowIconActor.vala', - 'Widgets/Menu/Menu.vala', - 'Widgets/Menu/MenuItem.vala', - 'Widgets/Menu/SeparatorMenuItem.vala', - # 'Widgets/WindowMenu.vala', 'Widgets/WindowOverview.vala', 'Widgets/WindowSwitcher/WindowSwitcher.vala', 'Widgets/WindowSwitcher/WindowSwitcherIcon.vala', From 121cae043f2387faed056e685464c92f6f116038 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 18:24:44 +0200 Subject: [PATCH 30/31] Fix menu position when close to monitor edges --- src/Widgets/Menu/Menu.vala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 4a41fdefd..62dd84575 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -162,6 +162,20 @@ public class Gala.Menu : Clutter.Actor { opened = show; if (show) { modal_proxy = wm.push_modal (this); + +#if HAS_MUTTER45 + Mtk.Rectangle rect; //TODO: I think that's correct but didn't test it + wm.get_display ().get_monitor_geometry (wm.get_display ().get_current_monitor (), out rect); +#else + var rect = wm.get_display ().get_monitor_geometry (wm.get_display ().get_current_monitor ()); +#endif + if (width + x > rect.x + rect.width) { + x = rect.x + rect.width - width; + } + + if (height + y > rect.y + rect.height) { + y = rect.y + rect.height - height; + } } else { selected = null; wm.pop_modal (modal_proxy); From cae29e34c57b1564ab5f7ace28aff92cfd0409af Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 1 Oct 2023 18:52:07 +0200 Subject: [PATCH 31/31] Fix not correctly hiding the menu --- src/Widgets/Menu/Menu.vala | 97 +++++++++++++++++--------------------- src/WindowManager.vala | 2 +- 2 files changed, 45 insertions(+), 54 deletions(-) diff --git a/src/Widgets/Menu/Menu.vala b/src/Widgets/Menu/Menu.vala index 62dd84575..ddfa1b617 100644 --- a/src/Widgets/Menu/Menu.vala +++ b/src/Widgets/Menu/Menu.vala @@ -4,16 +4,13 @@ */ public class Gala.Menu : Clutter.Actor { - private const int ANIMATION_DURATION = 200; - - public bool opened { get; private set; default = false; } - public Gala.WindowManager? wm { get; construct; } + private Gala.ModalProxy modal_proxy = null; - private Clutter.Canvas canvas; private Clutter.Actor container; private ShadowEffect shadow_effect; + private Clutter.Canvas canvas; private Gtk.StyleContext style_context; private unowned Gtk.CssProvider? dark_style_provider = null; @@ -40,14 +37,6 @@ public class Gala.Menu : Clutter.Actor { } construct { - canvas = new Clutter.Canvas (); - - shadow_effect = new ShadowEffect (40) { - shadow_opacity = 200, - css_class = "window-switcher" - }; - add_effect (shadow_effect); - var box_layout = new Clutter.BoxLayout () { orientation = VERTICAL }; @@ -56,9 +45,16 @@ public class Gala.Menu : Clutter.Actor { layout_manager = box_layout }; + shadow_effect = new ShadowEffect (40) { + shadow_opacity = 200, + css_class = "window-switcher" + }; + + canvas = new Clutter.Canvas (); + layout_manager = new Clutter.BinLayout (); - opacity = 0; add_child (container); + add_effect (shadow_effect); set_content (canvas); Granite.Settings.get_default ().notify["prefers-color-scheme"].connect (() => canvas.invalidate ()); @@ -67,8 +63,7 @@ public class Gala.Menu : Clutter.Actor { unowned var display = wm.get_display (); unowned var monitor_manager = display.get_context ().get_backend ().get_monitor_manager (); monitor_manager.monitors_changed.connect (() => { - var cur_scale = display.get_monitor_scale (display.get_current_monitor ()); - scale (cur_scale); + scale (display.get_monitor_scale (display.get_current_monitor ())); }); scale (display.get_monitor_scale (display.get_current_monitor ())); @@ -80,7 +75,7 @@ public class Gala.Menu : Clutter.Actor { public void add_menuitem (MenuItem menuitem) { container.add_child (menuitem); menuitem.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); - menuitem.activated.connect (() => toggle_display (false)); + menuitem.activated.connect (() => close_menu ()); menuitem.enter_event.connect (() => { selected = menuitem; @@ -99,6 +94,35 @@ public class Gala.Menu : Clutter.Actor { separator.scale (wm.get_display ().get_monitor_scale (wm.get_display ().get_current_monitor ())); } + public void open_menu () { + base.show (); + +#if HAS_MUTTER45 + //TODO: I think that's correct but didn't test it + Mtk.Rectangle rect; + wm.get_display ().get_monitor_geometry (wm.get_display ().get_current_monitor (), out rect); +#else + var rect = wm.get_display ().get_monitor_geometry (wm.get_display ().get_current_monitor ()); +#endif + + if (width + x > rect.x + rect.width) { + x = rect.x + rect.width - width; + } + + if (height + y > rect.y + rect.height) { + y = rect.y + rect.height - height; + } + + modal_proxy = wm.push_modal (this); + } + + public void close_menu () { + selected = null; + wm.pop_modal (modal_proxy); + + base.hide (); + } + private void scale (float scale_factor) { canvas.scale_factor = scale_factor; shadow_effect.scale_factor = scale_factor; @@ -154,41 +178,8 @@ public class Gala.Menu : Clutter.Actor { style_context.add_class ("unified"); } - public void toggle_display (bool show) { - if (opened == show) { - return; - } - - opened = show; - if (show) { - modal_proxy = wm.push_modal (this); - -#if HAS_MUTTER45 - Mtk.Rectangle rect; //TODO: I think that's correct but didn't test it - wm.get_display ().get_monitor_geometry (wm.get_display ().get_current_monitor (), out rect); -#else - var rect = wm.get_display ().get_monitor_geometry (wm.get_display ().get_current_monitor ()); -#endif - if (width + x > rect.x + rect.width) { - x = rect.x + rect.width - width; - } - - if (height + y > rect.y + rect.height) { - y = rect.y + rect.height - height; - } - } else { - selected = null; - wm.pop_modal (modal_proxy); - } - - save_easing_state (); - set_easing_duration (wm.enable_animations ? ANIMATION_DURATION : 0); - opacity = show ? 255 : 0; - restore_easing_state (); - } - public override bool button_release_event (Clutter.ButtonEvent event) { - toggle_display (false); + close_menu (); return true; } @@ -205,13 +196,13 @@ public class Gala.Menu : Clutter.Actor { cycle_menuitems (false); return Clutter.EVENT_STOP; case Clutter.Key.Escape: - toggle_display (false); + close_menu (); return Clutter.EVENT_PROPAGATE; case Clutter.Key.Return: if (selected != null) { selected.activated (); } - toggle_display (false); + close_menu (); return Clutter.EVENT_PROPAGATE; } diff --git a/src/WindowManager.vala b/src/WindowManager.vala index e0cba816f..d892bd8c9 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -409,7 +409,7 @@ namespace Gala { } background_menu.set_position (x, y); - background_menu.toggle_display (true); + background_menu.open_menu (); } private void on_monitors_changed () {