-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathextension.js
267 lines (236 loc) · 7.2 KB
/
extension.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/* You can do whatever you want with this code, but I hope that, if you want to
* improve it, you will talk to me so we can discuss and implement your idea into
* this very same extension. It's just to keep things neat and clean, instead of
* polluting EGO with plenty of similar extensions that do almost the same thing.
*
* If you want to debug this extension, open 'metadata.json' and set 'debug' to true.
* You can read the debugging messages in the terminal if you give the following:
* $ journalctl -f -o cat /usr/bin/gnome-shell
*/
import Shell from 'gi://Shell';
import St from 'gi://St';
import Meta from 'gi://Meta';
import GLib from 'gi://GLib';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
const TOGGLE_STATUS = {
UNMINIMIZE: 0,
MINIMIZE: 1,
};
let extensionName;
let toggleStatus = TOGGLE_STATUS.UNMINIMIZE;
let Settings;
let panelButton;
let ignoredWindows = [];
function logDebug(message) {
console.debug(message);
}
/* make a list of all open windows
* populate: ignoredWindows , windowsToMinimize
*/
function populateIgnoredWindows(windows) {
for (let i = 0; i < windows.length; ++i) {
let title = windows[i].title ?? '';
let focusedWindow = global.display.get_focus_window();
let window_type = windows[i].window_type ?? '';
let wm_classInitial = windows[i].wm_class ?? '';
let wm_class = wm_classInitial.toLowerCase();
logDebug(`minimize i: ${i}`);
logDebug(`\t title: ${title}`);
logDebug(`\t window_type: ${window_type}`);
logDebug(`\t wm_class: ${wm_class}`);
if (windows[i] === focusedWindow && Settings.get_boolean('keep-focused')) {
logDebug(`\t ${title} ignored: window is focused`);
ignoredWindows.push(windows[i]);
continue;
}
if (window_type === Meta.WindowType.DESKTOP) {
logDebug(`\t ${title} ignored: window_type is DESKTOP`);
ignoredWindows.push(windows[i]);
continue;
}
if (window_type === Meta.WindowType.DOCK) {
logDebug(`\t ${title} ignored: window_type is DOCK`);
ignoredWindows.push(windows[i]);
continue;
}
if (window_type === Meta.WindowType.MODAL_DIALOG) {
logDebug(`\t ${title} ignored: window_type is MODAL DIALOG`);
ignoredWindows.push(windows[i]);
continue;
}
if (title.startsWith('DING')) {
logDebug(`\t ${title} ignored: name starts with DING`);
ignoredWindows.push(windows[i]);
continue;
}
if (wm_class.endsWith('notejot')) {
logDebug(`\t ${title} ignored: name ends with notejot`);
ignoredWindows.push(windows[i]);
continue;
}
if (wm_class === 'conky') {
logDebug(`\t ${title} ignored: wm_class is conky`);
ignoredWindows.push(windows[i]);
continue;
}
if (wm_class === 'Gjs') {
logDebug(`\t ${title} ignored: wm_class is Gjs`);
ignoredWindows.push(windows[i]);
continue;
}
if (title.startsWith('@!')
&& (title.endsWith('BDH') || title.endsWith('BDHF'))) {
logDebug(`\t ${title} ignored: title starts with @! and ends with BDH or BDHF`);
ignoredWindows.push(windows[i]);
continue;
}
}
}
/* not all open windows must be touched.
* we must remove those that must be ignored (ignoredWindows)
* from the full list (windows)
*/
function pruneWindows(windows) {
for (let i = 0; i < windows.length; ++i) {
for (let j = 0; j < ignoredWindows.length; j++) {
if (ignoredWindows[j] === windows[i]) {
logDebug(`\t this was in ignoredWindows: ${windows[i].title}`);
windows.splice(i, 1);
}
}
}
}
/* if at least one window is unminimized, the button will minimize it.
* if this has to appen, toggleStatus changes to "MINIMIZE".
*/
function checkUnminimizedWindows(windows) {
toggleStatus = TOGGLE_STATUS.UNMINIMIZE;
for (let i = 0; i < windows.length; ++i) {
if (!windows[i].minimized) {
logDebug(`\t ${windows[i].title} is unminimized`);
toggleStatus = TOGGLE_STATUS.MINIMIZE;
continue;
}
}
}
/* unminimize windows
*/
function unminimizeWindows(windows) {
logDebug(`executing unminimizeWindows(windows)`);
for (let i = 0; i < windows.length; ++i) {
logDebug(`\t ${windows[i].title} is getting unminimized}`);
windows[i].unminimize();
}
}
/* minimize windows
*/
function minimizeWindows(windows) {
logDebug(`executing minimizeWindows(windows)`);
for (let i = 0; i < windows.length; i++) {
logDebug(`\t ${windows[i].title} is getting minimized}`);
windows[i].minimize();
}
}
/* toggle desktop windows
*/
function toggleDesktop() {
// do not toggle when overview is open
if (Main.overview.visible) {
return;
}
let metaWorkspace = global.workspace_manager.get_active_workspace();
let windows = metaWorkspace.list_windows();
// 1 make a list of all windows
// 2 not all windows must be touched by this extension, some must be ignored
// 3 check if there are unminimized windows in the remaining windows list
// 4 if so -> the extension minimizes them, otherwise it unminimizes them all.
populateIgnoredWindows(windows);
pruneWindows(windows);
checkUnminimizedWindows(windows);
logDebug(`toggleStatus is ${toggleStatus}`);
if (toggleStatus === TOGGLE_STATUS.UNMINIMIZE) {
logDebug(`loading unminimizeWindows(windows)`);
unminimizeWindows(windows);
} else if (toggleStatus === TOGGLE_STATUS.MINIMIZE) {
logDebug(`loading minimizeWindows(windows)`);
minimizeWindows(windows);
}
}
/* reset toggle status
*/
function resetToggleStatus() {
toggleStatus = TOGGLE_STATUS.MINIMIZE;
ignoredWindows = [];
}
/* get panel button
*/
function getPanelButton() {
panelButton = new PanelMenu.Button(0.0, `${extensionName}`, false);
let iconName = GLib.path_get_basename(Settings.get_string('indicator-icon-name'));
let icon = new St.Icon({
icon_name: iconName.slice(0, iconName.lastIndexOf('.')),
style_class: 'system-status-icon',
});
panelButton.add_child(icon);
panelButton.connect('button-press-event', toggleDesktop);
panelButton.connect('touch-event', toggleDesktop);
return panelButton;
}
/* add button to panel
*/
function addButton() {
let role = `${extensionName} Indicator`;
let position = ['left', 'left', 'center', 'center', 'right', 'right'];
let qualifier = [0, 1, 0, 1, 1, -1];
let index = Settings.get_enum('indicator-position');
Main.panel.addToStatusArea(role, getPanelButton(), qualifier[index], position[index]);
}
/* remove button from panel
*/
function removeButton() {
panelButton.destroy();
panelButton = null;
}
export default class extends Extension {
/* enable extension
*/
enable() {
extensionName = this.metadata.name;
Settings = this.getSettings();
Settings.connect('changed::keep-focused', () => {
resetToggleStatus();
removeButton();
addButton();
});
Settings.connect('changed::indicator-position', () => {
removeButton();
addButton();
});
Settings.connect('changed::indicator-icon-name', () => {
removeButton();
addButton();
});
resetToggleStatus();
addButton();
Main.wm.addKeybinding(
'shortcut',
Settings,
Meta.KeyBindingFlags.NONE,
Shell.ActionMode.ALL,
() => {
toggleDesktop();
}
);
}
/* disable extension
*/
disable() {
resetToggleStatus();
ignoredWindows = [];
Settings = null;
removeButton();
Main.wm.removeKeybinding('shortcut');
}
}