overview.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. import Shell from 'gi://Shell';
  2. import Meta from 'gi://Meta';
  3. import * as Main from 'resource:///org/gnome/shell/ui/main.js';
  4. import { WorkspaceAnimationController } from 'resource:///org/gnome/shell/ui/workspaceAnimation.js';
  5. const wac_proto = WorkspaceAnimationController.prototype;
  6. const OVERVIEW_COMPONENTS_STYLE = [
  7. "overview-components-light",
  8. "overview-components-dark",
  9. "overview-components-transparent"
  10. ];
  11. export const OverviewBlur = class OverviewBlur {
  12. constructor(connections, settings, effects_manager) {
  13. this.connections = connections;
  14. this.effects = [];
  15. this.settings = settings;
  16. this.effects_manager = effects_manager;
  17. this._workspace_switch_bg_actors = [];
  18. this.enabled = false;
  19. }
  20. enable() {
  21. this._log("blurring overview");
  22. // connect to every background change (even without changing image)
  23. // FIXME this signal is fired very often, so we should find another one
  24. // fired only when necessary (but that still catches all cases)
  25. this.connections.connect(
  26. Main.layoutManager._backgroundGroup,
  27. 'notify',
  28. _ => {
  29. this._log("updated background");
  30. this.update_backgrounds();
  31. }
  32. );
  33. // connect to monitors change
  34. this.connections.connect(
  35. Main.layoutManager,
  36. 'monitors-changed',
  37. _ => {
  38. if (Main.screenShield && !Main.screenShield.locked) {
  39. this._log("changed monitors");
  40. this.update_backgrounds();
  41. }
  42. }
  43. );
  44. // add css class name for workspace-switch background
  45. Main.uiGroup.add_style_class_name("blurred-overview");
  46. // add css class name to make components semi-transparent if wanted
  47. this.update_components_classname();
  48. // update backgrounds when the component is enabled
  49. this.update_backgrounds();
  50. // part for the workspace animation switch
  51. // make sure not to do this part if the extension was enabled prior, as
  52. // the functions would call themselves and cause infinite recursion
  53. if (!this.enabled) {
  54. // store original workspace switching methods for restoring them on
  55. // disable()
  56. this._original_PrepareSwitch = wac_proto._prepareWorkspaceSwitch;
  57. this._original_FinishSwitch = wac_proto._finishWorkspaceSwitch;
  58. const w_m = global.workspace_manager;
  59. const outer_this = this;
  60. // create a blurred background actor for each monitor during a
  61. // workspace switch
  62. wac_proto._prepareWorkspaceSwitch = function (...params) {
  63. outer_this._log("prepare workspace switch");
  64. outer_this._original_PrepareSwitch.apply(this, params);
  65. // this permits to show the blur behind windows that are on
  66. // workspaces on the left and right
  67. if (
  68. outer_this.settings.applications.BLUR
  69. ) {
  70. let ws_index = w_m.get_active_workspace_index();
  71. [ws_index - 1, ws_index + 1].forEach(
  72. i => w_m.get_workspace_by_index(i)?.list_windows().forEach(
  73. window => window.get_compositor_private().show()
  74. )
  75. );
  76. }
  77. Main.layoutManager.monitors.forEach(monitor => {
  78. if (
  79. !(
  80. Meta.prefs_get_workspaces_only_on_primary() &&
  81. (monitor !== Main.layoutManager.primaryMonitor)
  82. )
  83. ) {
  84. const bg_actor = outer_this.create_background_actor(
  85. monitor, true
  86. );
  87. Main.uiGroup.insert_child_above(
  88. bg_actor,
  89. global.window_group
  90. );
  91. // store the actors so that we can delete them later
  92. outer_this._workspace_switch_bg_actors.push(bg_actor);
  93. }
  94. });
  95. };
  96. // remove the workspace-switch actors when the switch is done
  97. wac_proto._finishWorkspaceSwitch = function (...params) {
  98. outer_this._log("finish workspace switch");
  99. outer_this._original_FinishSwitch.apply(this, params);
  100. // this hides windows that are not on the current workspace
  101. if (
  102. outer_this.settings.applications.BLUR
  103. )
  104. for (let i = 0; i < w_m.get_n_workspaces(); i++) {
  105. if (i != w_m.get_active_workspace_index())
  106. w_m.get_workspace_by_index(i)?.list_windows().forEach(
  107. window => window.get_compositor_private().hide()
  108. );
  109. }
  110. outer_this.effects = outer_this.effects.filter(
  111. effects_group => !effects_group.is_transition
  112. );
  113. outer_this._workspace_switch_bg_actors.forEach(actor => {
  114. actor.destroy();
  115. });
  116. outer_this._workspace_switch_bg_actors = [];
  117. };
  118. }
  119. this.enabled = true;
  120. }
  121. update_backgrounds() {
  122. // remove every old background
  123. this.remove_background_actors();
  124. // add new backgrounds
  125. Main.layoutManager.monitors.forEach(monitor => {
  126. const bg_actor = this.create_background_actor(monitor, false);
  127. Main.layoutManager.overviewGroup.insert_child_at_index(
  128. bg_actor,
  129. monitor.index
  130. );
  131. });
  132. }
  133. create_background_actor(monitor, is_transition) {
  134. let bg_actor = new Meta.BackgroundActor({
  135. meta_display: global.display,
  136. monitor: monitor.index
  137. });
  138. let background_group = Main.layoutManager._backgroundGroup
  139. .get_children()
  140. .filter((child) => child instanceof Meta.BackgroundActor);
  141. let background =
  142. background_group[
  143. Main.layoutManager.monitors.length - monitor.index - 1
  144. ];
  145. if (!background) {
  146. this._warn("could not get background for overview");
  147. return bg_actor;
  148. }
  149. bg_actor.content.set({
  150. background: background.get_content().background
  151. });
  152. let blur_effect = new Shell.BlurEffect({
  153. brightness: this.settings.overview.CUSTOMIZE
  154. ? this.settings.overview.BRIGHTNESS
  155. : this.settings.BRIGHTNESS,
  156. sigma: this.settings.overview.CUSTOMIZE
  157. ? this.settings.overview.SIGMA
  158. : this.settings.SIGMA
  159. * monitor.geometry_scale,
  160. mode: Shell.BlurMode.ACTOR
  161. });
  162. // store the scale in the effect in order to retrieve it in set_sigma
  163. blur_effect.scale = monitor.geometry_scale;
  164. let color_effect = this.effects_manager.new_color_effect({
  165. color: this.settings.overview.CUSTOMIZE
  166. ? this.settings.overview.COLOR
  167. : this.settings.COLOR
  168. }, this.settings);
  169. let noise_effect = this.effects_manager.new_noise_effect({
  170. noise: this.settings.overview.CUSTOMIZE
  171. ? this.settings.overview.NOISE_AMOUNT
  172. : this.settings.NOISE_AMOUNT,
  173. lightness: this.settings.overview.CUSTOMIZE
  174. ? this.settings.overview.NOISE_LIGHTNESS
  175. : this.settings.NOISE_LIGHTNESS
  176. }, this.settings);
  177. bg_actor.add_effect(color_effect);
  178. bg_actor.add_effect(noise_effect);
  179. bg_actor.add_effect(blur_effect);
  180. this.effects.push({ blur_effect, color_effect, noise_effect, is_transition });
  181. bg_actor.set_x(monitor.x);
  182. bg_actor.set_y(monitor.y);
  183. return bg_actor;
  184. }
  185. /// Updates the classname to style overview components with semi-transparent
  186. /// backgrounds.
  187. update_components_classname() {
  188. OVERVIEW_COMPONENTS_STYLE.forEach(
  189. style => Main.uiGroup.remove_style_class_name(style)
  190. );
  191. if (this.settings.overview.STYLE_COMPONENTS > 0)
  192. Main.uiGroup.add_style_class_name(
  193. OVERVIEW_COMPONENTS_STYLE[this.settings.overview.STYLE_COMPONENTS - 1]
  194. );
  195. }
  196. set_sigma(s) {
  197. this.effects.forEach(effect => {
  198. effect.blur_effect.sigma = s * effect.blur_effect.scale;
  199. });
  200. }
  201. set_brightness(b) {
  202. this.effects.forEach(effect => {
  203. effect.blur_effect.brightness = b;
  204. });
  205. }
  206. set_color(c) {
  207. this.effects.forEach(effect => {
  208. effect.color_effect.color = c;
  209. });
  210. }
  211. set_noise_amount(n) {
  212. this.effects.forEach(effect => {
  213. effect.noise_effect.noise = n;
  214. });
  215. }
  216. set_noise_lightness(l) {
  217. this.effects.forEach(effect => {
  218. effect.noise_effect.lightness = l;
  219. });
  220. }
  221. remove_background_actors() {
  222. Main.layoutManager.overviewGroup.get_children().forEach(actor => {
  223. if (actor.constructor.name === 'Meta_BackgroundActor') {
  224. actor.get_effects().forEach(effect => {
  225. this.effects_manager.remove(effect);
  226. });
  227. Main.layoutManager.overviewGroup.remove_child(actor);
  228. actor.destroy();
  229. }
  230. });
  231. this.effects = [];
  232. }
  233. disable() {
  234. this._log("removing blur from overview");
  235. this.remove_background_actors();
  236. Main.uiGroup.remove_style_class_name("blurred-overview");
  237. OVERVIEW_COMPONENTS_STYLE.forEach(
  238. style => Main.uiGroup.remove_style_class_name(style)
  239. );
  240. // make sure to absolutely not do this if the component was not enabled
  241. // prior, as this would cause infinite recursion
  242. if (this.enabled) {
  243. // restore original behavior
  244. if (this._original_PrepareSwitch)
  245. wac_proto._prepareWorkspaceSwitch = this._original_PrepareSwitch;
  246. if (this._original_FinishSwitch)
  247. wac_proto._finishWorkspaceSwitch = this._original_FinishSwitch;
  248. }
  249. this.connections.disconnect_all();
  250. this.enabled = false;
  251. }
  252. _log(str) {
  253. if (this.settings.DEBUG)
  254. console.log(`[Blur my Shell > overview] ${str}`);
  255. }
  256. _warn(str) {
  257. console.warn(`[Blur my Shell > overview] ${str}`);
  258. }
  259. };