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
3 changes: 3 additions & 0 deletions workspace-indicator@benzor.hu/ATTRIBUTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Parts of the code have been adapted from the official "Workspace switcher" applet.

Icon of the applet is from the Mint-Y icon theme.
674 changes: 674 additions & 0 deletions workspace-indicator@benzor.hu/COPYING

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions workspace-indicator@benzor.hu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Workspace Indicator

This applet is a simple alternative to the default "Workspace switcher" applet that takes up minimal space on a panel.
It displays only a single button showing the number of the current workspace.

* Clicking the button triggers the Expo view (workspace grid).
* Scrolling on the button switches workspace.

Either behaviours can be turned off in the settings.
Comment thread
mtwebster marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
const Applet = imports.ui.applet;
const Main = imports.ui.main;
const Pango = imports.gi.Pango;
const Settings = imports.ui.settings;
const St = imports.gi.St;
const Tooltips = imports.ui.tooltips;

const MIN_SWITCH_INTERVAL_MS = 220;

class IndicatorButton {
constructor(applet) {
this.applet = applet;
this.actor = new St.Button(
{
name: 'indicator_button',
style_class: 'workspace-button',
reactive: true,
can_focus: true
}
);
if (applet.orientation == St.Side.TOP || applet.orientation == St.Side.BOTTOM) {
this.actor.set_height(applet._panelHeight);
} else {
this.actor.set_width(applet._panelHeight);
this.actor.add_style_class_name('vertical');
}
this.label = new St.Label({text: ''});
this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
this.actor.set_child(this.label);
this.update_signal = global.workspace_manager.connect('active-workspace-changed', () => this.update());
this.update();
}

show() {
this.actor.connect('button-release-event', (actor, event) => this.on_click(actor, event));
this.tooltip = new Tooltips.PanelItemTooltip(this, 'Current workspace', this.applet.orientation);
this.actor.add_style_pseudo_class('outlined');
}

on_click(actor, event) {
if (!this.applet.enable_expo_click)
return;
if (event.get_button() === 1 && !Main.expo.animationInProgress) // (1, 2, 3) = (left, middle, right)
Main.expo.toggle();
}

update() {
let idx = global.workspace_manager.get_active_workspace_index();
this.label.text = `${idx + 1}`;
}

destroy() {
if (this.tooltip)
this.tooltip.destroy();
global.workspace_manager.disconnect(this.update_signal);
this.actor.destroy();
}
}

class WorkspaceIndicatorApplet extends Applet.Applet {

constructor(metadata, orientation, panel_height, instance_id) {
super(orientation, panel_height, instance_id);
this.setAllowedLayout(Applet.AllowedLayout.BOTH);

this.settings = new Settings.AppletSettings(
this,
metadata.uuid,
instance_id
);

this.settings.bind(
"enable-expo-click",
"enable_expo_click"
);

this.settings.bind(
"enable-scroll-switch",
"enable_scroll_switch"
);

this.orientation = orientation;
this.button = null;

this.last_switch = 0;
this.last_switch_direction = 0;

this.scroll_signal = this.actor.connect('scroll-event', this.on_scroll_event.bind(this));
this.create_button();

this.edit_mode_signal = global.settings.connect('changed::panel-edit-mode', () => this.on_panel_edit_mode_changed());
}

create_button() {
if (this.button) {
this.button.destroy();
this.button = null;
}
this.actor.set_style_class_name('workspace-switcher');
this.button = new IndicatorButton(this);
this.actor.add_actor(this.button.actor);
this.button.show()
}

on_scroll_event(actor, event) {
if (!this.enable_scroll_switch)
return;
let direction = event.get_scroll_direction();

if (direction !== 0 && direction !== 1) return;

const now = (new Date()).getTime();

if ((now - this.last_switch) >= MIN_SWITCH_INTERVAL_MS || direction !== this.last_switch_direction) {
direction === 0 ? Main.wm.actionMoveWorkspaceLeft() : Main.wm.actionMoveWorkspaceRight();
}
Comment on lines +108 to +116
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_scroll_direction() is compared against magic numbers 0 and 1. For readability and future compatibility, prefer Clutter.ScrollDirection.UP/DOWN (and ignore SMOOTH) like other applets in this repo; this also makes the intent clearer than relying on numeric enum values.

Copilot uses AI. Check for mistakes.

this.last_switch = now;
this.last_switch_direction = direction;
}

on_applet_removed_from_panel() {
if (this.button) {
this.button.destroy();
this.button = null;
}
if (this.edit_mode_signal)
global.settings.disconnect(this.edit_mode_signal);
if (this.scroll_signal)
this.actor.disconnect(this.scroll_signal);
this.settings.finalize();
}

on_orientation_changed(neworientation) {
this.orientation = neworientation;

if (this.orientation == St.Side.TOP || this.orientation == St.Side.BOTTOM)
this.actor.set_vertical(false);
else
this.actor.set_vertical(true);

this.create_button();
}

on_panel_height_changed() {
this.create_button();
}

on_panel_edit_mode_changed() {
let reactive = !global.settings.get_boolean('panel-edit-mode');
if (this.button)
this.button.actor.reactive = reactive;
}

destroy() {
this.on_applet_removed_from_panel();
super.destroy();
}
}

function main(metadata, orientation, panel_height, instance_id) {
return new WorkspaceIndicatorApplet(
metadata,
orientation,
panel_height,
instance_id
);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"uuid": "workspace-indicator@benzor.hu",
"name": "Workspace Indicator",
"description": "Single-button workspace indicator and switcher",
"version": "1.0.0",
"max_instances": 10,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metadata.json uses max_instances, but Cinnamon applet metadata expects max-instances (hyphenated). With the underscore key, the instance limit will be ignored by Cinnamon/spices tooling. Rename the key to max-instances (and keep the numeric value).

Suggested change
"max_instances": 10,
"max-instances": 10,

Copilot uses AI. Check for mistakes.
"multiversion": true,
"author": "Benzor94"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"enable-expo-click": {
"type": "checkbox",
"default": true,
"description": "Left click opens Expo"
},

"enable-scroll-switch": {
"type": "checkbox",
"default": true,
"description": "Scroll to switch workspaces"
}
}
4 changes: 4 additions & 0 deletions workspace-indicator@benzor.hu/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"author": "Benzor94",
"license": "GPL-3.0"
}
Binary file added workspace-indicator@benzor.hu/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.