Compare commits

...

3 Commits

Author SHA1 Message Date
June
140c635081
other: bump to version 15 2025-10-03 17:23:05 +02:00
June
a92ef52034
feature: support GNOME Shell version 49
Checked the source of 49.0 and tested in Fedora 43 Beta and there don't
seem to be any changes relevant to the functionality of this extension.
2025-10-03 17:22:03 +02:00
June
4071b79974
docs: add newer, cut down and commented panel.js from GNOME Shell 49.0 2025-10-03 16:36:09 +02:00
2 changed files with 323 additions and 2 deletions

View File

@ -0,0 +1,321 @@
// My annotated and cut down js/ui/panel.js from gnome-shell/49.0.
// All annotations are what I guessed, interpreted and copied while reading the
// code and comparing to other panel.js versions and might be wrong. They are
// prefixed with "Annotation:" to indicate that they're my comments, not
// comments that orginally existed.
// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/49.0/js/ui/panel.js
// On: 2025-10-03
// License: This code is licensed under GPLv2.
// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/49.0/js/ui/sessionMode.js
// On: 2025-10-03
// License: This code is licensed under GPLv2.
// I'm using the word "item" to refer to the thing, which gets added to the top
// (menu)bar / panel, where an item has a role/name and an indicator.
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import Clutter from 'gi://Clutter';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import GObject from 'gi://GObject';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import St from 'gi://St';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import * as CtrlAltTab from './ctrlAltTab.js';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import * as PopupMenu from './popupMenu.js';
import * as PanelMenu from './panelMenu.js';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import * as Main from './main.js';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
import {DateMenuButton} from './dateMenu.js';
import {ATIndicator} from './status/accessibility.js';
import {InputSourceIndicator} from './status/keyboard.js';
import {DwellClickIndicator} from './status/dwellClick.js';
import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js';
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this
// Extension.
// Of note (for PANEL_ITEM_IMPLEMENTATIONS):
// const ActivitiesButton = [...]
// const QuickSettings = [...]
// Compared to panel_48.2_2025-06-08.js: AppMenuButton got removed.
// Compared to panel_48.2_2025-06-08.js: AppMenuButton got removed.
const PANEL_ITEM_IMPLEMENTATIONS = {
'activities': ActivitiesButton,
'quickSettings': QuickSettings,
'dateMenu': DateMenuButton,
'a11y': ATIndicator,
'keyboard': InputSourceIndicator,
'dwellClick': DwellClickIndicator,
'screenRecording': ScreenRecordingIndicator,
'screenSharing': ScreenSharingIndicator,
};
export const Panel = GObject.registerClass(
class Panel extends St.Widget {
// Annotation: Initializes the top (menu)bar / panel.
// Does relevant stuff like:
// - Defining this._leftBox, this._centerBox and this._rightBox.
// - Finally calling this._updatePanel().
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
_init() {
super._init({
name: 'panel',
reactive: true,
});
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._sessionStyle = null;
this.statusArea = {};
this.menuManager = new PopupMenu.PopupMenuManager(this);
this._leftBox = new St.BoxLayout({name: 'panelLeft'});
this.add_child(this._leftBox);
this._centerBox = new St.BoxLayout({name: 'panelCenter'});
this.add_child(this._centerBox);
this._rightBox = new St.BoxLayout({name: 'panelRight'});
this.add_child(this._rightBox);
this.connect('button-press-event', this._onButtonPress.bind(this));
this.connect('touch-event', this._onTouchEvent.bind(this));
Main.overview.connectObject('showing',
() => this.add_style_pseudo_class('overview'),
this);
Main.overview.connectObject('hiding',
() => this.remove_style_pseudo_class('overview'),
this);
Main.layoutManager.panelBox.add_child(this);
Main.ctrlAltTabManager.addGroup(this,
_('Top Bar'), 'shell-focus-top-bar-symbolic',
{sortGroup: CtrlAltTab.SortGroup.TOP});
Main.sessionMode.connectObject('updated',
this._updatePanel.bind(this),
this);
global.display.connectObject('workareas-changed',
() => this.queue_relayout(),
this);
this._updatePanel();
}
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for
// this Extension.
// Annotation: Gets called by this._init() to populate the top (menu)bar /
// panel initially.
//
// It does the following relevant stuff:
// - Calls this._hideIndicators()
// - Calls this._updateBox() for this._leftBox, this._centerBox and
// this._rightBox with panel.left, panel.center and panel.right to
// populate the boxes with items defined in panel.left, panel.center and
// panel.right.
//
// panel.left, panel.center and panel.right get set via the line let panel
// = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js)
// instance of SessionMode (js/ui/sessionMode.js).
//
// And in js/ui/sessionMode.js (49.0, 2025-10-03) you have different modes
// with different panel configuration. For example the "user" mode with:
// panel: {
// left: ['activities'],
// center: ['dateMenu'],
// right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'],
// }
//
// This way this function populates the top (menu)bar / panel with the
// default stuff you see on a fresh Gnome.
//
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
_updatePanel() {
let panel = Main.sessionMode.panel;
this._hideIndicators();
this._updateBox(panel.left, this._leftBox);
this._updateBox(panel.center, this._centerBox);
this._updateBox(panel.right, this._rightBox);
if (panel.left.includes('dateMenu'))
Main.messageTray.bannerAlignment = Clutter.ActorAlign.START;
else if (panel.right.includes('dateMenu'))
Main.messageTray.bannerAlignment = Clutter.ActorAlign.END;
// Default to center if there is no dateMenu
else
Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER;
if (this._sessionStyle)
this.remove_style_class_name(this._sessionStyle);
this._sessionStyle = Main.sessionMode.panelStyle;
if (this._sessionStyle)
this.add_style_class_name(this._sessionStyle);
}
// Annotation: This function hides all items, which are in the top (menu)bar
// panel and in PANEL_ITEM_IMPLEMENTATIONS.
//
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
_hideIndicators() {
for (let role in PANEL_ITEM_IMPLEMENTATIONS) {
let indicator = this.statusArea[role];
if (!indicator)
continue;
indicator.container.hide();
}
}
// Annotation: This function takes a role (of an item) and returns a
// corresponding indicator, if either of two things are true:
// - The indicator is already in this.statusArea.
// Then it just returns the indicator by using this.statusArea.
// - The role is in PANEL_ITEM_IMPLEMENTATIONS.
// Then it creates a new indicator, adds it to this.statusArea and returns
// it.
//
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
_ensureIndicator(role) {
let indicator = this.statusArea[role];
if (!indicator) {
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
if (!constructor) {
// This icon is not implemented (this is a bug)
return null;
}
indicator = new constructor(this);
this.statusArea[role] = indicator;
}
return indicator;
}
// Annotation: This function takes a list of items (or rather their roles)
// and adds the indicators of those items to a box (like this._leftBox)
// using this._ensureIndicator() to get the indicator corresponding to the
// given role.
// So only items with roles this._ensureIndicator() knows, get added.
//
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
_updateBox(elements, box) {
let nChildren = box.get_n_children();
for (let i = 0; i < elements.length; i++) {
let role = elements[i];
let indicator = this._ensureIndicator(role);
if (indicator == null)
continue;
this._addToPanelBox(role, indicator, i + nChildren, box);
}
}
// Annotation: This function adds the given item to the specified top
// (menu)bar / panel box and connects to "destroy" and "menu-set" events.
//
// It takes the following arguments:
// - role: The name of the item to add.
// - indicator: The indicator of the item to add.
// - position: Where in the box to add the item.
// - box: The box to add the item to.
// Can be one of the following:
// - this._leftBox
// - this._centerBox
// - this._rightBox
//
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
_addToPanelBox(role, indicator, position, box) {
let container = indicator.container;
container.show();
let parent = container.get_parent();
if (parent)
parent.remove_child(container);
box.insert_child_at_index(container, position);
this.statusArea[role] = indicator;
let destroyId = indicator.connect('destroy', emitter => {
delete this.statusArea[role];
emitter.disconnect(destroyId);
});
indicator.connect('menu-set', this._onMenuSet.bind(this));
this._onMenuSet(indicator);
}
// Annotation: This function allows you to add an item to the top (menu)bar
// / panel.
// While per default it adds the item to the status area (the right box of
// the top bar), you can specify the box and add the item to any of the
// three boxes of the top bar.
// To add an item to the top bar, you need to give its role and indicator.
//
// This function takes the following arguments:
// - role: A name for the item to add.
// - indicator: The indicator for the item to add (must be an instance of
// PanelMenu.Button).
// - position: Where in the box to add the item.
// - box: The box to add the item to.
// Can be one of the following:
// - "left": referring to this._leftBox
// - "center": referring to this._centerBox
// - "right": referring to this._rightBox
// These boxes are what you see in the top bar as the left, right and
// center sections.
//
// Finally this function just calls this._addToPanelBox() for the actual
// work, so it basically just makes sure the input to this._addToPanelBox()
// is correct.
//
// Compared to panel_48.2_2025-06-08.js: Nothing changed.
addToStatusArea(role, indicator, position, box) {
if (this.statusArea[role])
throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`);
if (!(indicator instanceof PanelMenu.Button))
throw new TypeError('Status indicator must be an instance of PanelMenu.Button');
position ??= 0;
let boxes = {
left: this._leftBox,
center: this._centerBox,
right: this._rightBox,
};
let boxContainer = boxes[box] || this._rightBox;
this.statusArea[role] = indicator;
this._addToPanelBox(role, indicator, position, boxContainer);
return indicator;
}
// Of note:
// _onMenuSet(indicator) { [...] }
// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for
// this Extension.
});

View File

@ -2,8 +2,8 @@
"uuid": "top-bar-organizer@julian.gse.jsts.xyz",
"name": "Top Bar Organizer",
"description": "Organize the items of the top (menu)bar.",
"version": 14,
"shell-version": [ "45", "46", "47", "48" ],
"version": 15,
"shell-version": [ "45", "46", "47", "48", "49" ],
"settings-schema": "org.gnome.shell.extensions.top-bar-organizer",
"url": "https://gitlab.gnome.org/june/top-bar-organizer"
}