desktopIconsUtil.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /* Desktop Icons GNOME Shell extension
  2. *
  3. * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. const Gtk = imports.gi.Gtk;
  19. const Gio = imports.gi.Gio;
  20. const GLib = imports.gi.GLib;
  21. const ExtensionUtils = imports.misc.extensionUtils;
  22. const Me = ExtensionUtils.getCurrentExtension();
  23. const Prefs = Me.imports.prefs;
  24. const Main = imports.ui.main;
  25. const ShellMountOperation = imports.ui.shellMountOperation;
  26. const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
  27. const EXEC_KEY = 'exec';
  28. var DEFAULT_ATTRIBUTES = 'metadata::*,standard::*,access::*,time::modified,unix::mode';
  29. function getDesktopDir() {
  30. let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
  31. return Gio.File.new_for_commandline_arg(desktopPath);
  32. }
  33. function clamp(value, min, max) {
  34. return Math.max(Math.min(value, max), min);
  35. };
  36. function launchTerminal(workdir) {
  37. let terminalSettings = new Gio.Settings({ schema_id: TERMINAL_SCHEMA });
  38. let exec = terminalSettings.get_string(EXEC_KEY);
  39. let argv = [exec, `--working-directory=${workdir}`];
  40. /* The following code has been extracted from GNOME Shell's
  41. * source code in Misc.Util.trySpawn function and modified to
  42. * set the working directory.
  43. *
  44. * https://gitlab.gnome.org/GNOME/gnome-shell/blob/gnome-3-30/js/misc/util.js
  45. */
  46. var success, pid;
  47. try {
  48. [success, pid] = GLib.spawn_async(workdir, argv, null,
  49. GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
  50. null);
  51. } catch (err) {
  52. /* Rewrite the error in case of ENOENT */
  53. if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
  54. throw new GLib.SpawnError({ code: GLib.SpawnError.NOENT,
  55. message: _("Command not found") });
  56. } else if (err instanceof GLib.Error) {
  57. // The exception from gjs contains an error string like:
  58. // Error invoking GLib.spawn_command_line_async: Failed to
  59. // execute child process "foo" (No such file or directory)
  60. // We are only interested in the part in the parentheses. (And
  61. // we can't pattern match the text, since it gets localized.)
  62. let message = err.message.replace(/.*\((.+)\)/, '$1');
  63. throw new (err.constructor)({ code: err.code,
  64. message: message });
  65. } else {
  66. throw err;
  67. }
  68. }
  69. // Dummy child watch; we don't want to double-fork internally
  70. // because then we lose the parent-child relationship, which
  71. // can break polkit. See https://bugzilla.redhat.com//show_bug.cgi?id=819275
  72. GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, () => {});
  73. }
  74. function distanceBetweenPoints(x, y, x2, y2) {
  75. return (Math.pow(x - x2, 2) + Math.pow(y - y2, 2));
  76. }
  77. function getExtraFolders() {
  78. let extraFolders = new Array();
  79. if (Prefs.settings.get_boolean('show-home')) {
  80. extraFolders.push([Gio.File.new_for_commandline_arg(GLib.get_home_dir()), Prefs.FileType.USER_DIRECTORY_HOME]);
  81. }
  82. if (Prefs.settings.get_boolean('show-trash')) {
  83. extraFolders.push([Gio.File.new_for_uri('trash:///'), Prefs.FileType.USER_DIRECTORY_TRASH]);
  84. }
  85. return extraFolders;
  86. }
  87. function getFileExtensionOffset(filename, isDirectory) {
  88. let offset = filename.length;
  89. if (!isDirectory) {
  90. let doubleExtensions = ['.gz', '.bz2', '.sit', '.Z', '.bz', '.xz'];
  91. for (let extension of doubleExtensions) {
  92. if (filename.endsWith(extension)) {
  93. offset -= extension.length;
  94. filename = filename.substring(0, offset);
  95. break;
  96. }
  97. }
  98. let lastDot = filename.lastIndexOf('.');
  99. if (lastDot > 0)
  100. offset = lastDot;
  101. }
  102. return offset;
  103. }
  104. function getGtkClassBackgroundColor(classname, state) {
  105. let widget = new Gtk.WidgetPath();
  106. widget.append_type(Gtk.Widget);
  107. let context = new Gtk.StyleContext();
  108. context.set_path(widget);
  109. context.add_class(classname);
  110. return context.get_background_color(state);
  111. }
  112. // Reference the extension org.gnome.shell.extensions.drive-menu
  113. function eject(mount) {
  114. let unmountArgs = [
  115. Gio.MountUnmountFlags.NONE,
  116. (new ShellMountOperation.ShellMountOperation(mount)).mountOp,
  117. null, // Gio.Cancellable
  118. ];
  119. if (mount.can_eject()) {
  120. mount.eject_with_operation(...unmountArgs,
  121. _ejectFinish.bind(mount));
  122. } else {
  123. mount.unmount_with_operation(...unmountArgs,
  124. _unmountFinish.bind(mount));
  125. }
  126. }
  127. function _unmountFinish(mount, result) {
  128. try {
  129. mount.unmount_with_operation_finish(result);
  130. } catch (e) {
  131. this._reportFailure(e);
  132. }
  133. }
  134. function _ejectFinish(mount, result) {
  135. try {
  136. mount.eject_with_operation_finish(result);
  137. } catch (e) {
  138. this._reportFailure(e);
  139. }
  140. }
  141. function _reportFailure(exception) {
  142. // TRANSLATORS: %s is the filesystem name
  143. let msg = _('Ejecting drive “%s” failed:').format(this.mount.get_name());
  144. Main.notifyError(msg, exception.message);
  145. }