window-list: Use InjectionManager instead of custom classes
Once the shell is ported to ESM, it will no longer be possible
to replace entire classes (even when imported). Prepare for that
by overriding methods of the regular WorkspaceBackground class
instead.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/268>
Florian Müllner
9 months ago
2 | 2 | import Shell from 'gi://Shell'; |
3 | 3 | import St from 'gi://St'; |
4 | 4 | |
5 | import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js'; | |
5 | import {Extension, InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js'; | |
6 | 6 | |
7 | 7 | const Layout = imports.ui.layout; |
8 | 8 | const Main = imports.ui.main; |
76 | 76 | } |
77 | 77 | } |
78 | 78 | |
79 | class MyWorkspace extends Workspace.Workspace { | |
80 | static { | |
81 | GObject.registerClass(this); | |
82 | } | |
83 | ||
84 | constructor(...args) { | |
85 | super(...args); | |
86 | ||
87 | this._overviewAdjustment.connectObject('notify::value', () => { | |
88 | const {value: progress} = this._overviewAdjustment; | |
89 | const brightness = 1 - (1 - VIGNETTE_BRIGHTNESS) * progress; | |
90 | for (const bg of this._background?._backgroundGroup ?? []) { | |
91 | bg.content.set({ | |
92 | vignette: true, | |
93 | brightness, | |
94 | }); | |
95 | } | |
96 | }, this); | |
97 | } | |
98 | } | |
99 | ||
100 | class MyWorkspaceBackground extends Workspace.WorkspaceBackground { | |
101 | static { | |
102 | GObject.registerClass(this); | |
103 | } | |
104 | ||
105 | _updateBorderRadius() { | |
106 | } | |
107 | ||
108 | vfunc_allocate(box) { | |
109 | this.set_allocation(box); | |
110 | ||
111 | const themeNode = this.get_theme_node(); | |
112 | const contentBox = themeNode.get_content_box(box); | |
113 | ||
114 | this._bin.allocate(contentBox); | |
115 | ||
116 | const [contentWidth, contentHeight] = contentBox.get_size(); | |
117 | const monitor = Main.layoutManager.monitors[this._monitorIndex]; | |
118 | const xRatio = contentWidth / this._workarea.width; | |
119 | const yRatio = contentHeight / this._workarea.height; | |
120 | ||
121 | const right = area => area.x + area.width; | |
122 | const bottom = area => area.y + area.height; | |
123 | ||
124 | const offsets = { | |
125 | left: xRatio * (this._workarea.x - monitor.x), | |
126 | right: xRatio * (right(monitor) - right(this._workarea)), | |
127 | top: yRatio * (this._workarea.y - monitor.y), | |
128 | bottom: yRatio * (bottom(monitor) - bottom(this._workarea)), | |
129 | }; | |
130 | ||
131 | contentBox.set_origin(-offsets.left, -offsets.top); | |
132 | contentBox.set_size( | |
133 | offsets.left + contentWidth + offsets.right, | |
134 | offsets.top + contentHeight + offsets.bottom); | |
135 | this._backgroundGroup.allocate(contentBox); | |
136 | } | |
137 | } | |
138 | ||
139 | 79 | export class WindowPicker extends Clutter.Actor { |
140 | 80 | static [GObject.signals] = { |
141 | 81 | 'open-state-changed': {param_types: [GObject.TYPE_BOOLEAN]}, |
155 | 95 | |
156 | 96 | this._adjustment = new OverviewAdjustment(this); |
157 | 97 | |
98 | this._injectionManager = new InjectionManager(); | |
158 | 99 | this.connect('destroy', this._onDestroy.bind(this)); |
159 | 100 | |
160 | 101 | global.bind_property('screen-width', |
182 | 123 | } |
183 | 124 | |
184 | 125 | _injectBackgroundShade() { |
185 | this._origWorkspace = Workspace.Workspace; | |
186 | this._origWorkspaceBackground = Workspace.WorkspaceBackground; | |
187 | ||
188 | Workspace.Workspace = MyWorkspace; | |
189 | Workspace.WorkspaceBackground = MyWorkspaceBackground; | |
126 | const backgroundProto = Workspace.WorkspaceBackground.prototype; | |
127 | this._injectionManager.overrideMethod(backgroundProto, '_updateBorderRadius', | |
128 | () => { | |
129 | return function () {}; | |
130 | }); | |
131 | this._injectionManager.overrideMethod(backgroundProto, 'vfunc_allocate', | |
132 | () => { | |
133 | /* eslint-disable no-invalid-this */ | |
134 | return function (box) { | |
135 | this.set_allocation(box); | |
136 | ||
137 | const themeNode = this.get_theme_node(); | |
138 | const contentBox = themeNode.get_content_box(box); | |
139 | ||
140 | this._bin.allocate(contentBox); | |
141 | ||
142 | const [contentWidth, contentHeight] = contentBox.get_size(); | |
143 | const monitor = Main.layoutManager.monitors[this._monitorIndex]; | |
144 | const xRatio = contentWidth / this._workarea.width; | |
145 | const yRatio = contentHeight / this._workarea.height; | |
146 | ||
147 | const right = area => area.x + area.width; | |
148 | const bottom = area => area.y + area.height; | |
149 | ||
150 | const offsets = { | |
151 | left: xRatio * (this._workarea.x - monitor.x), | |
152 | right: xRatio * (right(monitor) - right(this._workarea)), | |
153 | top: yRatio * (this._workarea.y - monitor.y), | |
154 | bottom: yRatio * (bottom(monitor) - bottom(this._workarea)), | |
155 | }; | |
156 | ||
157 | contentBox.set_origin(-offsets.left, -offsets.top); | |
158 | contentBox.set_size( | |
159 | offsets.left + contentWidth + offsets.right, | |
160 | offsets.top + contentHeight + offsets.bottom); | |
161 | this._backgroundGroup.allocate(contentBox); | |
162 | }; | |
163 | /* eslint-enable */ | |
164 | }); | |
165 | this._injectionManager.overrideMethod(backgroundProto, 'vfunc_parent_set', | |
166 | () => { | |
167 | /* eslint-disable no-invalid-this */ | |
168 | return function () { | |
169 | setTimeout(() => { | |
170 | const parent = this.get_parent(); | |
171 | if (!parent) | |
172 | return; | |
173 | ||
174 | parent._overviewAdjustment.connectObject('notify::value', () => { | |
175 | const {value: progress} = parent._overviewAdjustment; | |
176 | const brightness = 1 - (1 - VIGNETTE_BRIGHTNESS) * progress; | |
177 | for (const bg of this._backgroundGroup ?? []) { | |
178 | bg.content.set({ | |
179 | vignette: true, | |
180 | brightness, | |
181 | }); | |
182 | } | |
183 | }, this); | |
184 | }); | |
185 | }; | |
186 | /* eslint-enable */ | |
187 | }); | |
190 | 188 | } |
191 | 189 | |
192 | 190 | get visible() { |
292 | 290 | } |
293 | 291 | |
294 | 292 | _onDestroy() { |
295 | if (this._origWorkspace) | |
296 | Workspace.Workspace = this._origWorkspace; | |
297 | ||
298 | if (this._origWorkspaceBackground) | |
299 | Workspace.WorkspaceBackground = this._origWorkspaceBackground; | |
293 | this._injectionManager.clear(); | |
300 | 294 | |
301 | 295 | if (this._stageKeyPressId) |
302 | 296 | global.stage.disconnect(this._stageKeyPressId); |