appfolders.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import Shell from 'gi://Shell';
  2. import Clutter from 'gi://Clutter';
  3. import Cogl from 'gi://Cogl';
  4. import * as Main from 'resource:///org/gnome/shell/ui/main.js';
  5. import { adjustAnimationTime } from 'resource:///org/gnome/shell/misc/animationUtils.js';
  6. import { PaintSignals } from '../conveniences/paint_signals.js';
  7. // TODO drop Tweener in favour of Clutter's `ease` (will need to extend the blur effect for it)
  8. const Tweener = imports.tweener.tweener;
  9. // TODO: Drop GNOME 46 backwards compatibility
  10. const transparent = Clutter.Color ?
  11. Clutter.Color.from_pixel(0x00000000) :
  12. new Cogl.Color({
  13. red: 0,
  14. green: 0,
  15. blue: 0,
  16. alpha: 0
  17. });
  18. const FOLDER_DIALOG_ANIMATION_TIME = 200;
  19. const DIALOGS_STYLES = [
  20. "appfolder-dialogs-transparent",
  21. "appfolder-dialogs-light",
  22. "appfolder-dialogs-dark"
  23. ];
  24. let original_zoomAndFadeIn = null;
  25. let original_zoomAndFadeOut = null;
  26. let sigma;
  27. let brightness;
  28. let _zoomAndFadeIn = function () {
  29. let [sourceX, sourceY] =
  30. this._source.get_transformed_position();
  31. let [dialogX, dialogY] =
  32. this.child.get_transformed_position();
  33. this.child.set({
  34. translation_x: sourceX - dialogX,
  35. translation_y: sourceY - dialogY,
  36. scale_x: this._source.width / this.child.width,
  37. scale_y: this._source.height / this.child.height,
  38. opacity: 0,
  39. });
  40. this.set_background_color(transparent);
  41. let blur_effect = this.get_effect("appfolder-blur");
  42. blur_effect.radius = 0;
  43. blur_effect.brightness = 1.0;
  44. Tweener.addTween(blur_effect,
  45. {
  46. radius: sigma * 2,
  47. brightness: brightness,
  48. time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
  49. transition: 'easeOutQuad'
  50. }
  51. );
  52. this.child.ease({
  53. translation_x: 0,
  54. translation_y: 0,
  55. scale_x: 1,
  56. scale_y: 1,
  57. opacity: 255,
  58. duration: FOLDER_DIALOG_ANIMATION_TIME,
  59. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  60. });
  61. this._needsZoomAndFade = false;
  62. if (this._sourceMappedId === 0) {
  63. this._sourceMappedId = this._source.connect(
  64. 'notify::mapped', this._zoomAndFadeOut.bind(this));
  65. }
  66. };
  67. let _zoomAndFadeOut = function () {
  68. if (!this._isOpen)
  69. return;
  70. if (!this._source.mapped) {
  71. this.hide();
  72. return;
  73. }
  74. let [sourceX, sourceY] =
  75. this._source.get_transformed_position();
  76. let [dialogX, dialogY] =
  77. this.child.get_transformed_position();
  78. this.set_background_color(transparent);
  79. let blur_effect = this.get_effect("appfolder-blur");
  80. Tweener.addTween(blur_effect,
  81. {
  82. radius: 0,
  83. brightness: 1.0,
  84. time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
  85. transition: 'easeInQuad'
  86. }
  87. );
  88. this.child.ease({
  89. translation_x: sourceX - dialogX,
  90. translation_y: sourceY - dialogY,
  91. scale_x: this._source.width / this.child.width,
  92. scale_y: this._source.height / this.child.height,
  93. opacity: 0,
  94. duration: FOLDER_DIALOG_ANIMATION_TIME,
  95. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  96. onComplete: () => {
  97. this.child.set({
  98. translation_x: 0,
  99. translation_y: 0,
  100. scale_x: 1,
  101. scale_y: 1,
  102. opacity: 255,
  103. });
  104. this.hide();
  105. this._popdownCallbacks.forEach(func => func());
  106. this._popdownCallbacks = [];
  107. },
  108. });
  109. this._needsZoomAndFade = false;
  110. };
  111. export const AppFoldersBlur = class AppFoldersBlur {
  112. // we do not use the effects manager and dummy pipelines here because we
  113. // really want to manage our sigma value ourself during the transition
  114. constructor(connections, settings, _) {
  115. this.connections = connections;
  116. this.paint_signals = new PaintSignals(connections);
  117. this.settings = settings;
  118. }
  119. enable() {
  120. this._log("blurring appfolders");
  121. brightness = this.settings.appfolder.BRIGHTNESS;
  122. sigma = this.settings.appfolder.SIGMA;
  123. let appDisplay = Main.overview._overview.controls._appDisplay;
  124. if (appDisplay._folderIcons.length > 0) {
  125. this.blur_appfolders();
  126. }
  127. this.connections.connect(
  128. appDisplay, 'view-loaded', _ => this.blur_appfolders()
  129. );
  130. }
  131. blur_appfolders() {
  132. let appDisplay = Main.overview._overview.controls._appDisplay;
  133. if (this.settings.HACKS_LEVEL === 1)
  134. this._log("appfolders hack level 1");
  135. appDisplay._folderIcons.forEach(icon => {
  136. icon._ensureFolderDialog();
  137. if (original_zoomAndFadeIn == null) {
  138. original_zoomAndFadeIn = icon._dialog._zoomAndFadeIn;
  139. }
  140. if (original_zoomAndFadeOut == null) {
  141. original_zoomAndFadeOut = icon._dialog._zoomAndFadeOut;
  142. }
  143. let blur_effect = new Shell.BlurEffect({
  144. name: "appfolder-blur",
  145. radius: sigma * 2,
  146. brightness: brightness,
  147. mode: Shell.BlurMode.BACKGROUND
  148. });
  149. icon._dialog.remove_effect_by_name("appfolder-blur");
  150. icon._dialog.add_effect(blur_effect);
  151. DIALOGS_STYLES.forEach(
  152. style => icon._dialog._viewBox.remove_style_class_name(style)
  153. );
  154. if (this.settings.appfolder.STYLE_DIALOGS > 0)
  155. icon._dialog._viewBox.add_style_class_name(
  156. DIALOGS_STYLES[this.settings.appfolder.STYLE_DIALOGS - 1]
  157. );
  158. // finally override the builtin functions
  159. icon._dialog._zoomAndFadeIn = _zoomAndFadeIn;
  160. icon._dialog._zoomAndFadeOut = _zoomAndFadeOut;
  161. // HACK
  162. //
  163. //`Shell.BlurEffect` does not repaint when shadows are under it. [1]
  164. //
  165. // This does not entirely fix this bug (shadows caused by windows
  166. // still cause artifacts), but it prevents the shadows of the panel
  167. // buttons to cause artifacts on the panel itself
  168. //
  169. // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
  170. if (this.settings.HACKS_LEVEL === 1) {
  171. this.paint_signals.disconnect_all_for_actor(icon._dialog);
  172. this.paint_signals.connect(icon._dialog, blur_effect);
  173. } else {
  174. this.paint_signals.disconnect_all();
  175. }
  176. });
  177. };
  178. set_sigma(s) {
  179. sigma = s;
  180. if (this.settings.appfolder.BLUR)
  181. this.blur_appfolders();
  182. }
  183. set_brightness(b) {
  184. brightness = b;
  185. if (this.settings.appfolder.BLUR)
  186. this.blur_appfolders();
  187. }
  188. disable() {
  189. this._log("removing blur from appfolders");
  190. let appDisplay = Main.overview._overview.controls._appDisplay;
  191. if (original_zoomAndFadeIn != null) {
  192. appDisplay._folderIcons.forEach(icon => {
  193. if (icon._dialog)
  194. icon._dialog._zoomAndFadeIn = original_zoomAndFadeIn;
  195. });
  196. }
  197. if (original_zoomAndFadeOut != null) {
  198. appDisplay._folderIcons.forEach(icon => {
  199. if (icon._dialog)
  200. icon._dialog._zoomAndFadeOut = original_zoomAndFadeOut;
  201. });
  202. }
  203. appDisplay._folderIcons.forEach(icon => {
  204. if (icon._dialog) {
  205. icon._dialog.remove_effect_by_name("appfolder-blur");
  206. DIALOGS_STYLES.forEach(
  207. s => icon._dialog._viewBox.remove_style_class_name(s)
  208. );
  209. }
  210. });
  211. this.connections.disconnect_all();
  212. }
  213. _log(str) {
  214. if (this.settings.DEBUG)
  215. console.log(`[Blur my Shell > appfolders] ${str}`);
  216. }
  217. };