[gnome-shell-extensions] apps-menu: Allow creating desktop launchers via DND
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell-extensions] apps-menu: Allow creating desktop launchers via DND
- Date: Wed, 22 Mar 2017 18:33:27 +0000 (UTC)
commit 243f700fa22ee6d2f3a46308a2b94b686641b32a
Author: Florian Müllner <fmuellner gnome org>
Date: Wed Mar 15 01:30:53 2017 +0100
apps-menu: Allow creating desktop launchers via DND
Back in the olden days, it used to be possible to drag items from
the application menu to the desktop to create a launcher shortcut.
Reimplement that "classic" functionality in the apps menu extension.
https://bugzilla.gnome.org/show_bug.cgi?id=780371
extensions/apps-menu/extension.js | 118 ++++++++++++++++++++++++++++++++++++-
1 files changed, 117 insertions(+), 1 deletions(-)
---
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index ced236c..404548d 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -1,16 +1,19 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Atk = imports.gi.Atk;
+const DND = imports.ui.dnd;
const GMenu = imports.gi.GMenu;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Clutter = imports.gi.Clutter;
const Main = imports.ui.main;
+const Meta = imports.gi.Meta;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Gtk = imports.gi.Gtk;
const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
const Signals = imports.signals;
const Pango = imports.gi.Pango;
@@ -70,6 +73,16 @@ const ApplicationMenuItem = new Lang.Class({
textureCache.disconnect(iconThemeChangedId);
}));
this._updateIcon();
+
+ this.actor._delegate = this;
+ let draggable = DND.makeDraggable(this.actor);
+
+ draggable.connect('drag-begin', () => {
+ Shell.util_set_hidden_from_pick(Main.legacyTray.actor, true);
+ });
+ draggable.connect('drag-end', () => {
+ Shell.util_set_hidden_from_pick(Main.legacyTray.actor, false);
+ });
},
activate: function(event) {
@@ -85,8 +98,16 @@ const ApplicationMenuItem = new Lang.Class({
this.parent(active, params);
},
+ getDragActor: function() {
+ return this._app.create_icon_texture(APPLICATION_ICON_SIZE);
+ },
+
+ getDragActorSource: function() {
+ return this._iconBin;
+ },
+
_updateIcon: function() {
- this._iconBin.set_child(this._app.create_icon_texture(APPLICATION_ICON_SIZE));
+ this._iconBin.set_child(this.getDragActor());
}
});
@@ -246,6 +267,94 @@ const ApplicationsMenu = new Lang.Class({
}
});
+const DesktopTarget = new Lang.Class({
+ Name: 'DesktopTarget',
+
+ _init: function() {
+ this._desktop = null;
+ this._desktopDestroyedId = 0;
+
+ this._windowAddedId =
+ global.window_group.connect('actor-added',
+ Lang.bind(this, this._onWindowAdded));
+
+ global.get_window_actors().forEach(a => {
+ this._onWindowAdded(a.get_parent(), a);
+ });
+ },
+
+ _onWindowAdded: function(group, actor) {
+ if (!(actor instanceof Meta.WindowActor))
+ return;
+
+ if (actor.meta_window.get_window_type() == Meta.WindowType.DESKTOP)
+ this._setDesktop(actor);
+ },
+
+ _setDesktop: function(desktop) {
+ if (this._desktop) {
+ this._desktop.disconnect(this._desktopDestroyedId);
+ this._desktopDestroyedId = 0;
+
+ delete this._desktop._delegate;
+ }
+
+ this._desktop = desktop;
+
+ if (this._desktop) {
+ this._desktopDestroyedId = this._desktop.connect('destroy', () => {
+ this._setDesktop(null);
+ });
+ this._desktop._delegate = this;
+ }
+ },
+
+ _getSourceAppInfo: function(source) {
+ if (!(source instanceof ApplicationMenuItem))
+ return null;
+ return source._app.app_info;
+ },
+
+ destroy: function() {
+ if (this._windowAddedId)
+ global.window_group.disconnect(this._windowAddedId);
+ this._windowAddedId = 0;
+
+ this._setDesktop(null);
+ },
+
+ handleDragOver: function(source, actor, x, y, time) {
+ let appInfo = this._getSourceAppInfo(source);
+ if (!appInfo)
+ return DND.DragMotionResult.CONTINUE;
+
+ return DND.DragMotionResult.COPY_DROP;
+ },
+
+ acceptDrop: function(source, actor, x, y, time) {
+ let appInfo = this._getSourceAppInfo(source);
+ if (!appInfo)
+ return false;
+
+ this.emit('app-dropped');
+
+ let desktop = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
+
+ let src = Gio.File.new_for_path(appInfo.get_filename());
+ let dst = Gio.File.new_for_path(GLib.build_filenamev([desktop, src.get_basename()]));
+
+ try {
+ // copy_async() isn't introspectable :-(
+ src.copy(dst, Gio.FileCopyFlags.OVERWRITE, null, null);
+ } catch(e) {
+ log('Failed to copy to desktop: ' + e.message);
+ }
+
+ return true;
+ }
+});
+Signals.addSignalMethods(DesktopTarget.prototype);
+
const ApplicationsButton = new Lang.Class({
Name: 'ApplicationsButton',
Extends: PanelMenu.Button,
@@ -286,6 +395,11 @@ const ApplicationsButton = new Lang.Class({
Lang.bind(this, this._setKeybinding));
this._setKeybinding();
+ this._desktopTarget = new DesktopTarget();
+ this._desktopTarget.connect('app-dropped', () => {
+ this.menu.close();
+ });
+
this._applicationsButtons = new Map();
this.reloadFlag = false;
this._createLayout();
@@ -330,6 +444,8 @@ const ApplicationsButton = new Lang.Class({
Main.sessionMode.hasOverview ?
Lang.bind(Main.overview, Main.overview.toggle) :
null);
+
+ this._desktopTarget.destroy();
},
_onCapturedEvent: function(actor, event) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]