Skip to content

Commit 69eca61

Browse files
authored
fix: Update version-name to 50.5 and refactor clipboard loading (#43)
* feat(metadata): update version-name to 50.4 * feat(clipboard): refactor loading mechanism to use async methods for clipboard store * feat(metadata): update version-name to 50.5
1 parent 44e005b commit 69eca61

7 files changed

Lines changed: 107 additions & 75 deletions

File tree

metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Aurora Shell",
33
"description": "A customizable GNOME Shell extension that enhances the user experience with various modules and features. The optional Clipboard History module reads and stores clipboard text locally so it can be browsed and restored; no clipboard data is shared with third parties, and its open shortcut is unset by default.",
4-
"version-name": "50.2",
4+
"version-name": "50.5",
55
"uuid": "aurora-shell@luminusos.github.io",
66
"url": "https://github.com/luminusOS/aurora-shell",
77
"settings-schema": "org.gnome.shell.extensions.aurora-shell",

src/modules/clipboardHistory/clipboardHistory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export class ClipboardHistory extends Module {
3939
const pollMs = rawSettings.get_int('clipboard-history-poll-interval');
4040

4141
this._store = new ClipboardStore(filePath, maxItems);
42-
this._store.load();
4342

4443
this._panel = new (ClipboardPanel as unknown as new (
4544
store: ClipboardStore,
@@ -56,6 +55,8 @@ export class ClipboardHistory extends Module {
5655

5756
this._monitor = new ClipboardMonitor(pollMs, (text) => this.addText(text));
5857

58+
void this._store.load().then(() => this._panel?.refresh());
59+
5960
this._startupIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
6061
this._startupIdleId = 0;
6162
this._monitor?.start();

src/modules/clipboardHistory/clipboardStore.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import Gio from '@girs/gio-2.0';
55

66
import { logger } from '~/core/logger.ts';
77

8+
// @ts-ignore - _promisify is a GJS extension not reflected in .d.ts
9+
Gio._promisify(Gio.File.prototype, 'load_contents_async');
10+
811
const LOG_PREFIX = 'ClipboardHistory';
912

1013
export type ClipboardEntry = {
@@ -31,12 +34,11 @@ export class ClipboardStore {
3134
this._maxItems = maxItems;
3235
}
3336

34-
load(): void {
37+
async load(): Promise<void> {
3538
try {
3639
const file = Gio.File.new_for_path(this._filePath);
37-
const [ok, contents] = file.load_contents(null);
38-
if (!ok) return;
39-
const decoded = new TextDecoder().decode(contents as unknown as Uint8Array);
40+
const [contents] = await file.load_contents_async(null);
41+
const decoded = new TextDecoder().decode(contents);
4042
const parsed = JSON.parse(decoded) as StorageFormat;
4143
if (parsed.version !== 1 || !Array.isArray(parsed.entries)) return;
4244
this._pinned = parsed.entries.filter((e) => e.pinned);

src/modules/trayIcons/trayContainer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class TrayContainer extends PanelMenu.Button {
155155
declare private _limit: number;
156156
declare private _items: Map<string, TrayIconItem>;
157157
declare private _chevron: St.Button;
158-
declare private _chevronIcon: St.Icon;
158+
declare private _chevronIcon: St.Icon | null;
159159
declare private _clipArea: TrayClipArea;
160160
declare private _iconRow: St.BoxLayout;
161161
declare private _outerBox: St.BoxLayout;
@@ -495,7 +495,7 @@ export class TrayContainer extends PanelMenu.Button {
495495
this._chevron.visible = hasOverflow;
496496

497497
// Chevron rotation: 0° = expanded (points right), 180° = collapsed (points left).
498-
this._chevronIcon.ease({
498+
this._chevronIcon?.ease({
499499
rotationAngleZ: this._state.collapsed ? 180 : 0,
500500
duration: animated ? ANIM_DURATION : 0,
501501
mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
@@ -648,6 +648,8 @@ export class TrayContainer extends PanelMenu.Button {
648648
destroyTooltip();
649649
for (const widget of this._items.values()) widget.destroy();
650650
this._items.clear();
651+
this._chevronIcon?.destroy();
652+
this._chevronIcon = null;
651653
super.destroy();
652654
}
653655
}

src/modules/trayIcons/trayIcons.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import type { Button as PanelMenuButton } from '@girs/gnome-shell/ui/panelMenu';
99

1010
// @ts-ignore
1111
Gio._promisify(Gio.DBusConnection.prototype, 'call');
12+
// @ts-ignore - _promisify is a GJS extension not reflected in .d.ts
13+
Gio._promisify(Gio.File.prototype, 'load_contents_async');
1214

1315
import type { ExtensionContext } from '~/core/context.ts';
1416
import { logger } from '~/core/logger.ts';
@@ -268,9 +270,9 @@ export class TrayIcons extends Module {
268270
if (!sniPid) continue;
269271

270272
const directMatch = appPidSet.has(sniPid);
271-
const ancestorMatch = directMatch ? true : this._pidHasAncestor(sniPid, appPidSet);
273+
const ancestorMatch = directMatch ? true : await this._pidHasAncestor(sniPid, appPidSet);
272274
const trackerMatch = this._trackedPidMatchesApp(sniPid, appId, app);
273-
const flatpakAppId = this._getFlatpakAppId(sniPid);
275+
const flatpakAppId = await this._getFlatpakAppId(sniPid);
274276
const flatpakMatch = flatpakAppId ? appIdCandidates.has(flatpakAppId.toLowerCase()) : false;
275277
const covered = ancestorMatch || trackerMatch || flatpakMatch;
276278
logger.log(
@@ -283,13 +285,19 @@ export class TrayIcons extends Module {
283285
return false;
284286
}
285287

286-
private _getFlatpakAppId(pid: number): string | null {
288+
private async _getFlatpakAppId(pid: number): Promise<string | null> {
289+
const text = await this._readProcText(`/proc/${pid}/root/.flatpak-info`);
290+
if (!text) return null;
291+
const match = /^name=(.+)$/m.exec(text);
292+
return match?.[1]?.trim() || null;
293+
}
294+
295+
// Async /proc read (EGO-X-004: no synchronous file IO in shell code).
296+
private async _readProcText(path: string): Promise<string | null> {
287297
try {
288-
const [ok, bytes] = GLib.file_get_contents(`/proc/${pid}/root/.flatpak-info`);
289-
if (!ok) return null;
290-
const text = new TextDecoder().decode(bytes);
291-
const match = /^name=(.+)$/m.exec(text);
292-
return match?.[1]?.trim() || null;
298+
const file = Gio.File.new_for_path(path);
299+
const [contents] = await file.load_contents_async(null);
300+
return new TextDecoder().decode(contents);
293301
} catch {
294302
return null;
295303
}
@@ -306,13 +314,13 @@ export class TrayIcons extends Module {
306314
}
307315
}
308316

309-
private _pidHasAncestor(pid: number, candidateAncestors: Set<number>): boolean {
317+
private async _pidHasAncestor(pid: number, candidateAncestors: Set<number>): Promise<boolean> {
310318
let currentPid = pid;
311319
const seen = new Set<number>();
312320

313321
while (currentPid > 1 && !seen.has(currentPid)) {
314322
seen.add(currentPid);
315-
const parentPid = this._getParentPid(currentPid);
323+
const parentPid = await this._getParentPid(currentPid);
316324
if (!parentPid) return false;
317325
if (candidateAncestors.has(parentPid)) return true;
318326
currentPid = parentPid;
@@ -321,17 +329,12 @@ export class TrayIcons extends Module {
321329
return false;
322330
}
323331

324-
private _getParentPid(pid: number): number | null {
325-
try {
326-
const [ok, bytes] = GLib.file_get_contents(`/proc/${pid}/status`);
327-
if (!ok) return null;
328-
const text = new TextDecoder().decode(bytes);
329-
const match = /^PPid:\s+(\d+)$/m.exec(text);
330-
if (!match) return null;
331-
return Number.parseInt(match[1]!, 10);
332-
} catch {
333-
return null;
334-
}
332+
private async _getParentPid(pid: number): Promise<number | null> {
333+
const text = await this._readProcText(`/proc/${pid}/status`);
334+
if (!text) return null;
335+
const match = /^PPid:\s+(\d+)$/m.exec(text);
336+
if (!match) return null;
337+
return Number.parseInt(match[1]!, 10);
335338
}
336339

337340
private _appIdCandidates(appId: string, app: Shell.App): Set<string> {

src/modules/volumeMixer/mixerPanel.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,6 @@ export class VolumeMixerPanel extends St.BoxLayout {
6666
this._emptyLabel.visible = !hasStreams;
6767
}
6868

69-
override vfunc_destroy(): void {
70-
this._scroll = null;
71-
super.vfunc_destroy();
72-
}
73-
7469
override vfunc_get_preferred_height(forWidth: number): [number, number] {
7570
if (!this.get_stage()) return [0, 0];
7671

src/shared/ui/dash.ts

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,17 @@ export class AuroraDash extends Dash {
209209
}
210210

211211
private _syncLabelFlushMode(): void {
212-
const items: any[] = [
213-
...((this as any)._box?.get_children?.() ?? []),
214-
(this as any)._showAppsIcon,
215-
];
212+
const items: any[] = [...this._getDashChildren(), (this as any)._showAppsIcon];
216213
for (const item of items) {
217-
if (!item?.label) continue;
218-
if (this._flushMode) {
219-
item.label.add_style_class_name('flush-mode');
220-
} else {
221-
item.label.remove_style_class_name('flush-mode');
214+
try {
215+
if (!item?.label) continue;
216+
if (this._flushMode) {
217+
item.label.add_style_class_name('flush-mode');
218+
} else {
219+
item.label.remove_style_class_name('flush-mode');
220+
}
221+
} catch {
222+
// Ignore children disposed during shell shutdown.
222223
}
223224
}
224225
}
@@ -340,10 +341,15 @@ export class AuroraDash extends Dash {
340341

341342
private _isMenuOpen(): boolean {
342343
const dashAny = this as any;
343-
const children = dashAny._box?.get_children?.() ?? [];
344+
const children = this._getDashChildren();
344345

345346
for (const child of children) {
346-
const appIcon = child.child?._delegate;
347+
let appIcon: any;
348+
try {
349+
appIcon = child.child?._delegate;
350+
} catch {
351+
continue;
352+
}
347353

348354
if (appIcon?._menu?.isOpen) {
349355
return true;
@@ -499,11 +505,15 @@ export class AuroraDash extends Dash {
499505
// Snapshot existing (non-animating-out) apps so we can detect newly added
500506
// items after stock _redisplay and animate them in ourselves.
501507
const isFirstDisplay = !dashAny._shownInitially;
502-
const existingApps = new Set<any>(
503-
((this as any)._box?.get_children?.() ?? [])
504-
.filter((c: any) => c.child?._delegate?.app && !c.animatingOut)
505-
.map((c: any) => c.child._delegate.app),
506-
);
508+
const existingApps = new Set<any>();
509+
for (const child of this._getDashChildren()) {
510+
try {
511+
const app = child.child?._delegate?.app;
512+
if (app && !child.animatingOut) existingApps.add(app);
513+
} catch {
514+
// Ignore children disposed during shell shutdown.
515+
}
516+
}
507517

508518
// Temporarily patch get_running() so the base Dash only sees apps with
509519
// windows on this monitor and active workspace. _globallyRunningIds is set
@@ -557,21 +567,24 @@ export class AuroraDash extends Dash {
557567
// (instant) when overview.visible is false, leaving new items at scale=1.
558568
// We detect them via the pre-redisplay snapshot and replay the animation.
559569
if (shouldAnimate && !isFirstDisplay) {
560-
const children = (this as any)._box?.get_children?.() ?? [];
561-
for (const child of children) {
562-
const childApp = child.child?._delegate?.app;
563-
if (childApp && !existingApps.has(childApp) && !child.animatingOut) {
564-
child.remove_all_transitions();
565-
child.scale_x = 0;
566-
child.scale_y = 0;
567-
child.opacity = 0;
568-
child.ease({
569-
scale_x: 1,
570-
scale_y: 1,
571-
opacity: 255,
572-
duration: ANIMATION_TIME,
573-
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
574-
});
570+
for (const child of this._getDashChildren()) {
571+
try {
572+
const childApp = child.child?._delegate?.app;
573+
if (childApp && !existingApps.has(childApp) && !child.animatingOut) {
574+
child.remove_all_transitions();
575+
child.scale_x = 0;
576+
child.scale_y = 0;
577+
child.opacity = 0;
578+
child.ease({
579+
scale_x: 1,
580+
scale_y: 1,
581+
opacity: 255,
582+
duration: ANIMATION_TIME,
583+
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
584+
});
585+
}
586+
} catch {
587+
// Ignore children disposed during shell shutdown.
575588
}
576589
}
577590
}
@@ -605,13 +618,16 @@ export class AuroraDash extends Dash {
605618
}
606619

607620
private _updatePerMonitorRunningDots(): void {
608-
const children = (this as any)._box?.get_children?.() ?? [];
609-
for (const child of children) {
610-
const icon = child.child?._delegate;
611-
if (!icon?.app) continue;
612-
const hasWindowHere = icon.app.get_windows().some((w: any) => this._isWindowRelevant(w));
613-
const dot = icon._dot;
614-
if (dot) dot.visible = hasWindowHere;
621+
for (const child of this._getDashChildren()) {
622+
try {
623+
const icon = child.child?._delegate;
624+
if (!icon?.app) continue;
625+
const hasWindowHere = icon.app.get_windows().some((w: any) => this._isWindowRelevant(w));
626+
const dot = icon._dot;
627+
if (dot) dot.visible = hasWindowHere;
628+
} catch {
629+
// Ignore children disposed during shell shutdown.
630+
}
615631
}
616632
}
617633

@@ -625,9 +641,13 @@ export class AuroraDash extends Dash {
625641
* clicked a window directly or switched apps).
626642
*/
627643
private _overrideIconActivation(): void {
628-
const children = (this as any)._box?.get_children?.() ?? [];
629-
for (const child of children) {
630-
const appIcon = child.child?._delegate;
644+
for (const child of this._getDashChildren()) {
645+
let appIcon: any;
646+
try {
647+
appIcon = child.child?._delegate;
648+
} catch {
649+
continue;
650+
}
631651
if (!appIcon?.app || appIcon._auroraActivatePatched) continue;
632652

633653
appIcon._auroraActivatePatched = true;
@@ -720,6 +740,15 @@ export class AuroraDash extends Dash {
720740
}
721741
}
722742

743+
private _getDashChildren(): any[] {
744+
if (this._isDestroyed) return [];
745+
try {
746+
return (this as any)._box?.get_children?.() ?? [];
747+
} catch {
748+
return [];
749+
}
750+
}
751+
723752
private _setupSpringLoadMonitor(): void {
724753
this._springLoadDragMonitor = {
725754
dragMotion: (dragEvent: any) => {

0 commit comments

Comments
 (0)