Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions data/Application.css
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,9 @@ backgrounditem .close-button {
.running-indicator:disabled {
color: @fg_color;
}

dock-button:focus-visible {
background: alpha(@accent_color, 0.5);
border-radius: 6px;
outline: 1px solid alpha(@accent_color, 0.8);
}
2 changes: 1 addition & 1 deletion src/AppSystem/Background/BackgroundItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public class Dock.BackgroundItem : BaseIconGroup {
}
});

gesture_click.released.connect (popover_menu.popup);
button.clicked.connect (popover_menu.popup);
}

private Gtk.Widget create_widget_func (Object obj) {
Expand Down
26 changes: 15 additions & 11 deletions src/AppSystem/Launcher.vala
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,14 @@ public class Dock.Launcher : BaseItem {
transition_type = CROSSFADE
};

overlay.child = image;
var overlay = new Gtk.Overlay () {
child = image
};
overlay.add_overlay (badge_container);
overlay.add_overlay (progress_revealer);

button.child = overlay;

var running_indicator = new Gtk.Image.from_icon_name ("pager-checked-symbolic");
running_indicator.add_css_class ("running-indicator");

Expand Down Expand Up @@ -240,8 +244,8 @@ public class Dock.Launcher : BaseItem {
easing = EASE_IN_OUT_QUAD
};

gesture_click.button = 0;
gesture_click.released.connect (on_click_released);
button.mouse_button = 0;
button.clicked.connect (on_clicked);

var long_press = new Gtk.GestureLongPress () {
touch_only = true
Expand Down Expand Up @@ -320,12 +324,12 @@ public class Dock.Launcher : BaseItem {
remove_dnd_cycle ();
}

private void on_click_released (int n_press, double x, double y) {
var event_display = gesture_click.get_current_event ().get_display ();
var context = event_display.get_app_launch_context ();
context.set_timestamp (gesture_click.get_current_event_time ());
private void on_clicked (uint button, uint32 timestamp) {
unowned var display = Gdk.Display.get_default ();
var context = display.get_app_launch_context ();
context.set_timestamp (timestamp);

switch (gesture_click.get_current_button ()) {
switch (button) {
case Gdk.BUTTON_PRIMARY:
app.launch (context);
break;
Expand All @@ -334,7 +338,7 @@ public class Dock.Launcher : BaseItem {
animate_launch ();
} else {
animate_shake ();
event_display.beep ();
display.beep ();
}
break;
case Gdk.BUTTON_SECONDARY:
Expand All @@ -349,7 +353,7 @@ public class Dock.Launcher : BaseItem {
return;
}

bounce_up.value_to = -0.5 * overlay.get_height ();
bounce_up.value_to = -0.5 * button.get_height ();
bounce_down.value_from = bounce_up.value_to;

bounce_up.play ();
Expand All @@ -360,7 +364,7 @@ public class Dock.Launcher : BaseItem {
return;
}

shake.value_to = -0.1 * overlay.get_width ();
shake.value_to = -0.1 * button.get_width ();
shake.play ();

int repeat_count = 0;
Expand Down
1 change: 1 addition & 0 deletions src/BaseIconGroup.vala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public abstract class Dock.BaseIconGroup : ContainerItem {
selection_mode = NONE,
halign = CENTER,
valign = CENTER,
can_focus = false,
};
flow_box.bind_model (slice, create_flow_box_child);

Expand Down
20 changes: 10 additions & 10 deletions src/BaseItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class Dock.BaseItem : Gtk.Box {
bin.height_request = -1;
}

overlay.visible = !value;
button.visible = !value;
}
}

Expand All @@ -70,8 +70,7 @@ public class Dock.BaseItem : Gtk.Box {
* It's needed because top margin messes with dnd offsets and gsk transform.
*/
protected Gtk.Box actionable_box;
protected Gtk.Overlay overlay;
protected Gtk.GestureClick gesture_click;
protected Button button;

protected Granite.Bin bin { get; private set; }

Expand All @@ -92,11 +91,11 @@ public class Dock.BaseItem : Gtk.Box {
construct {
orientation = VERTICAL;

overlay = new Gtk.Overlay ();
button = new Button ();

// We need the bin because we need the animation to run even if the overlay is not visible
// We need the bin because we need the animation to run even if the button is not visible
bin = new Granite.Bin () {
child = overlay
child = button
};

actionable_box = new Gtk.Box (VERTICAL, 0);
Expand Down Expand Up @@ -185,9 +184,6 @@ public class Dock.BaseItem : Gtk.Box {

add_controller (motion_controller);

gesture_click = new Gtk.GestureClick ();
add_controller (gesture_click);

if (group == NONE) {
return;
}
Expand All @@ -214,6 +210,10 @@ public class Dock.BaseItem : Gtk.Box {
popover_tooltip.dispose ();
}

public override bool grab_focus () {
return button.grab_focus ();
}

public void set_revealed (bool revealed) {
fade.skip ();
reveal.skip ();
Expand Down Expand Up @@ -281,7 +281,7 @@ public class Dock.BaseItem : Gtk.Box {
}

private void on_drag_begin (Gtk.DragSource drag_source, Gdk.Drag drag) {
var paintable = new Gtk.WidgetPaintable (overlay);
var paintable = new Gtk.WidgetPaintable (button);
drag_source.set_icon (paintable.get_current_image (), drag_offset_x, drag_offset_y);

moving = true;
Expand Down
46 changes: 46 additions & 0 deletions src/Button.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: GPL-3.0
* SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io)
*/

public class Dock.Button : Granite.Bin {
Comment thread
lenemter marked this conversation as resolved.
public signal void clicked (uint button, uint32 timestamp);

public uint mouse_button { get; set; default = 1; }

class construct {
set_accessible_role (BUTTON);
set_css_name ("dock-button");
}

construct {
focusable = true;

var gesture_click = new Gtk.GestureClick ();
bind_property ("mouse-button", gesture_click, "button", SYNC_CREATE);
gesture_click.released.connect (on_released);
add_controller (gesture_click);

var key_controller = new Gtk.EventControllerKey ();
key_controller.key_pressed.connect (on_key_pressed);
add_controller (key_controller);
}

private void on_released (Gtk.GestureClick gesture_click, int n_press, double x, double y) {
clicked (gesture_click.get_current_button (), gesture_click.get_current_event_time ());
}

private bool on_key_pressed (
Gtk.EventControllerKey key_controller,
uint keyval,
uint keycode,
Gdk.ModifierType state
) {
if (keyval == Gdk.Key.space || keyval == Gdk.Key.Return || keyval == Gdk.Key.KP_Enter) {
clicked (Gdk.BUTTON_PRIMARY, key_controller.get_current_event_time ());
return true;
}

return false;
}
}
2 changes: 1 addition & 1 deletion src/ContainerItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public abstract class Dock.ContainerItem : BaseItem {
bind_property ("icon-size", container, "width-request", SYNC_CREATE);
bind_property ("icon-size", container, "height-request", SYNC_CREATE);

overlay.child = container;
button.child = container;

notify["state"].connect (() => {
if ((state != HIDDEN) && !moving) {
Expand Down
4 changes: 4 additions & 0 deletions src/ItemGroup.vala
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@
}
}

public BaseItem? get_first_item () {
return (BaseItem?) current_children.get_item (0);
}

public uint get_index_for_item (BaseItem item) {
uint index;
if (current_children.find (item, out index)) {
Expand Down
37 changes: 34 additions & 3 deletions src/ItemManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@

public Launcher? added_launcher { get; set; default = null; }

private ItemGroup app_group;
private ItemGroup background_group;
#if WORKSPACE_SWITCHER
private Gtk.Separator separator;
private ItemGroup workspaces_group;
private DynamicWorkspaceIcon dynamic_workspace_item;
#endif
private bool focus_was_moved = false;

static construct {
settings = new Settings ("io.elementary.dock");
}

construct {
var app_group = new ItemGroup (AppSystem.get_default ().apps, (obj) => new Launcher ((App) obj));
app_group = new ItemGroup (AppSystem.get_default ().apps, (obj) => new Launcher ((App) obj));

var background_item = new BackgroundItem ();
var background_group = new ItemGroup (background_item.group_model, (obj) => (BackgroundItem) obj);
background_group = new ItemGroup (background_item.group_model, (obj) => (BackgroundItem) obj);

#if WORKSPACE_SWITCHER
separator = new Gtk.Separator (VERTICAL) {
Expand All @@ -33,18 +37,24 @@
separator_box.append (new TopMargin ());
separator_box.append (separator);

workspaces_group = new ItemGroup (WorkspaceSystem.get_default ().workspaces, (obj) => new WorkspaceIconGroup ((Workspace) obj));

dynamic_workspace_item = new DynamicWorkspaceIcon ();
#endif

append (app_group);
append (background_group);
#if WORKSPACE_SWITCHER
append (separator_box);
append (new ItemGroup (WorkspaceSystem.get_default ().workspaces, (obj) => new WorkspaceIconGroup ((Workspace) obj)));
append (workspaces_group);
append (dynamic_workspace_item);
#endif
overflow = VISIBLE;

app_group.items.items_changed.connect (on_group_items_changed);
background_group.items.items_changed.connect (on_group_items_changed);
workspaces_group.items.items_changed.connect (on_group_items_changed);

var drop_target_file = new Gtk.DropTarget (typeof (File), COPY) {
preload = true
};
Expand Down Expand Up @@ -151,6 +161,27 @@
});
}

private void on_group_items_changed () {
if (focus_was_moved) {
return;
}

var item_to_focus = (BaseItem) (
app_group.get_first_item () ??
background_group.get_first_item () ??
workspaces_group.get_first_item () ??
dynamic_workspace_item
);

item_to_focus.grab_focus ();
}

public override bool focus (Gtk.DirectionType direction) {
focus_was_moved = true;

return base.focus (direction);
}

public void move_launcher_after (BaseItem source, int target_index) {
if (source is Launcher) {
AppSystem.get_default ().reorder_app (source.app, target_index);
Expand Down
4 changes: 2 additions & 2 deletions src/WorkspaceSystem/DynamicWorkspaceItem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public class Dock.DynamicWorkspaceIcon : ContainerItem, WorkspaceItem {
null, null
);

gesture_click.button = Gdk.BUTTON_PRIMARY;
gesture_click.released.connect (switch_to_new_workspace);
button.mouse_button = Gdk.BUTTON_PRIMARY;
button.clicked.connect (switch_to_new_workspace);
}

private void update_active_state () {
Expand Down
4 changes: 2 additions & 2 deletions src/WorkspaceSystem/WorkspaceIconGroup.vala
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public class Dock.WorkspaceIconGroup : BaseIconGroup, WorkspaceItem {
return true;
});

gesture_click.button = Gdk.BUTTON_PRIMARY;
gesture_click.released.connect (workspace.activate);
button.mouse_button = Gdk.BUTTON_PRIMARY;
button.clicked.connect (workspace.activate);
}

public void window_entered (Window window) {
Expand Down
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ sources = [
'BaseIconGroup.vala',
'BaseItem.vala',
'BottomMargin.vala',
'Button.vala',
'ContainerItem.vala',
'ItemGroup.vala',
'ItemManager.vala',
Expand Down