diff --git a/js/misc/docInfo.js b/js/misc/docInfo.js index a9332d91c..8ec375aa9 100644 --- a/js/misc/docInfo.js +++ b/js/misc/docInfo.js @@ -29,8 +29,8 @@ DocInfo.prototype = { return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo); }, - launch : function() { - Shell.DocSystem.get_default().open(this.recentInfo); + launch : function(workspaceIndex) { + Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex); }, matchTerms: function(terms) { diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 43720303d..3df634f76 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -223,14 +223,20 @@ BaseAppSearchProvider.prototype = { 'icon': app.create_icon_texture(Search.RESULT_ICON_SIZE)}; }, - activateResult: function(id) { + activateResult: function(id, params) { + params = Params.parse(params, { workspace: null, + timestamp: null }); + let app = this._appSys.get_app(id); - app.activate(); + app.activate(params.workspace ? params.workspace.index() : -1); }, - dragActivateResult: function(id) { + dragActivateResult: function(id, params) { + params = Params.parse(params, { workspace: null, + timestamp: null }); + let app = this._appSys.get_app(id); - app.open_new_window(); + app.open_new_window(params.workspace ? params.workspace.get_index() : -1); } }; @@ -401,7 +407,7 @@ AppWellIcon.prototype = { let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1); launchWorkspace.activate(global.get_current_time()); this.emit('launching'); - this.app.open_new_window(); + this.app.open_new_window(-1); Main.overview.hide(); } return false; @@ -486,9 +492,9 @@ AppWellIcon.prototype = { if (modifiers & Clutter.ModifierType.CONTROL_MASK && this.app.state == Shell.AppState.RUNNING) { - this.app.open_new_window(); + this.app.open_new_window(-1); } else { - this.app.activate(); + this.app.activate(-1); } Main.overview.hide(); }, @@ -498,8 +504,11 @@ AppWellIcon.prototype = { return this._menu.menuEventFilter(event); }, - shellWorkspaceLaunch : function() { - this.app.open_new_window(); + shellWorkspaceLaunch : function(params) { + params = Params.parse(params, { workspace: null, + timestamp: null }); + + this.app.open_new_window(params.workspace ? params.workspace.index() : -1); }, getDragActor: function() { @@ -668,7 +677,7 @@ AppIconMenu.prototype = { let metaWindow = child._window; this.emit('activate-window', metaWindow); } else if (child == this._newWindowMenuItem) { - this._source.app.open_new_window(); + this._source.app.open_new_window(-1); this.emit('activate-window', null); } else if (child == this._toggleFavoriteMenuItem) { let favs = AppFavorites.getAppFavorites(); diff --git a/js/ui/docDisplay.js b/js/ui/docDisplay.js index d2afe04f6..2e77f8c77 100644 --- a/js/ui/docDisplay.js +++ b/js/ui/docDisplay.js @@ -4,6 +4,7 @@ const Gettext = imports.gettext.domain('gnome-shell'); const _ = Gettext.gettext; const DocInfo = imports.misc.docInfo; +const Params = imports.misc.params; const Search = imports.ui.search; @@ -28,9 +29,12 @@ DocSearchProvider.prototype = { 'icon': docInfo.createIcon(Search.RESULT_ICON_SIZE)}; }, - activateResult: function(id) { + activateResult: function(id, params) { + params = Params.parse(params, { workspace: null, + timestamp: null }); + let docInfo = this._docManager.lookupByUri(id); - docInfo.launch(); + docInfo.launch(params.workspace ? params.workspace.index() : -1); }, getInitialResultSet: function(terms) { diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index 6b85bd87f..be64427e0 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -171,7 +171,7 @@ ListItem.prototype = { _onClicked: function() { this.emit('activate'); - this._app.activate(); + this._app.activate(-1); } }; Signals.addSignalMethods(ListItem.prototype); diff --git a/js/ui/placeDisplay.js b/js/ui/placeDisplay.js index b8745b21f..04ce63c62 100644 --- a/js/ui/placeDisplay.js +++ b/js/ui/placeDisplay.js @@ -12,6 +12,7 @@ const _ = Gettext.gettext; const DND = imports.ui.dnd; const Main = imports.ui.main; +const Params = imports.misc.params; const Search = imports.ui.search; const Util = imports.misc.util; @@ -58,6 +59,21 @@ PlaceInfo.prototype = { } }; +// Helper function to translate launch parameters into a GAppLaunchContext +function _makeLaunchContext(params) +{ + params = Params.parse(params, { workspace: null, + timestamp: null }); + + let launchContext = global.create_app_launch_context(); + if (params.workspace != null) + launchContext.set_desktop(params.workspace.index()); + if (params.timestamp != null) + launchContext.set_timestamp(params.timestamp); + + return launchContext; +} + function PlaceDeviceInfo(mount) { this._init(mount); } @@ -77,9 +93,9 @@ PlaceDeviceInfo.prototype = { return St.TextureCache.get_default().load_gicon(null, icon, size); }, - launch: function() { + launch: function(param) { Gio.app_info_launch_default_for_uri(this._mount.get_root().get_uri(), - global.create_app_launch_context()); + _makeLaunchContex(params)); }, isRemovable: function() { @@ -111,7 +127,6 @@ PlaceDeviceInfo.prototype = { } }; - function PlacesManager() { this._init(); } @@ -130,8 +145,8 @@ PlacesManager.prototype = { function(size) { return St.TextureCache.get_default().load_gicon(null, homeIcon, size); }, - function() { - Gio.app_info_launch_default_for_uri(homeUri, global.create_app_launch_context()); + function(params) { + Gio.app_info_launch_default_for_uri(homeUri, _makeLaunchContext(params)); }); let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP); @@ -143,8 +158,8 @@ PlacesManager.prototype = { function(size) { return St.TextureCache.get_default().load_gicon(null, desktopIcon, size); }, - function() { - Gio.app_info_launch_default_for_uri(desktopUri, global.create_app_launch_context()); + function(params) { + Gio.app_info_launch_default_for_uri(desktopUri, _makeLaunchContext(params)); }); this._connect = new PlaceInfo('special:connect', _("Connect to..."), @@ -153,7 +168,11 @@ PlacesManager.prototype = { icon_type: St.IconType.FULLCOLOR, icon_size: size }); }, - function () { + function (params) { + // BUG: nautilus-connect-server doesn't have a desktop file, so we can't + // launch it with the workspace from params. It's probably pretty rare + // and odd to drag this place onto a workspace in any case + Util.spawn(['nautilus-connect-server']); }); @@ -173,8 +192,12 @@ PlacesManager.prototype = { function(size) { return networkApp.create_icon_texture(size); }, - function () { - networkApp.launch(); + function (params) { + params = Params.parse(params, { workspace: null, + timestamp: 0 }); + + networkApp.launch_full(params.timestamp, [], + params.workspace ? params.workspace.index() : -1); }); } @@ -314,8 +337,8 @@ PlacesManager.prototype = { function(size) { return St.TextureCache.get_default().load_gicon(null, icon, size); }, - function() { - Gio.app_info_launch_default_for_uri(bookmark, global.create_app_launch_context()); + function(params) { + Gio.app_info_launch_default_for_uri(bookmark, _makeLaunchContext(params)); }); this._bookmarks.push(item); } @@ -395,9 +418,9 @@ PlaceSearchProvider.prototype = { 'icon': placeInfo.iconFactory(Search.RESULT_ICON_SIZE) }; }, - activateResult: function(id) { + activateResult: function(id, params) { let placeInfo = Main.placesManager.lookupPlaceById(id); - placeInfo.launch(); + placeInfo.launch(params); }, _compareResultMeta: function (idA, idB) { diff --git a/js/ui/search.js b/js/ui/search.js index 24b411ab6..d1fa925c8 100644 --- a/js/ui/search.js +++ b/js/ui/search.js @@ -267,7 +267,7 @@ OpenSearchSystem.prototype = { return lang != null; }, - activateResult: function(id) { + activateResult: function(id, params) { let searchTerms = this._terms.join(' '); let url = this._providers[id].url.replace('{searchTerms}', encodeURIComponent(searchTerms)); diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js index 44794f6a9..7e9ba7a7d 100644 --- a/js/ui/searchDisplay.js +++ b/js/ui/searchDisplay.js @@ -81,11 +81,11 @@ SearchResult.prototype = { return new Clutter.Clone({ source: this.metaInfo['icon'] }); }, - shellWorkspaceLaunch: function() { + shellWorkspaceLaunch: function(params) { if (this.provider.dragActivateResult) - this.provider.dragActivateResult(this.metaInfo.id); + this.provider.dragActivateResult(this.metaInfo.id, params); else - this.provider.activateResult(this.metaInfo.id); + this.provider.activateResult(this.metaInfo.id, params); } }; diff --git a/js/ui/workspace.js b/js/ui/workspace.js index 0241213c1..3e76d717b 100644 --- a/js/ui/workspace.js +++ b/js/ui/workspace.js @@ -1431,8 +1431,8 @@ Workspace.prototype = { time); return true; } else if (source.shellWorkspaceLaunch) { - this.metaWorkspace.activate(time); - source.shellWorkspaceLaunch(); + source.shellWorkspaceLaunch({ workspace: this.metaWorkspace, + timestamp: time }); return true; } diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js index 8f8586b9d..e4bd6bbff 100644 --- a/js/ui/workspaceThumbnail.js +++ b/js/ui/workspaceThumbnail.js @@ -283,8 +283,8 @@ WorkspaceThumbnail.prototype = { time); return true; } else if (source.shellWorkspaceLaunch) { - this.metaWorkspace.activate(time); - source.shellWorkspaceLaunch(); + source.shellWorkspaceLaunch({ workspace: this.metaWorkspace, + timestamp: time }); return true; } diff --git a/src/shell-app.c b/src/shell-app.c index 0f733a429..74b72fb33 100644 --- a/src/shell-app.c +++ b/src/shell-app.c @@ -411,6 +411,8 @@ shell_app_activate_window (ShellApp *app, /** * shell_app_activate: * @app: a #ShellApp + * @workspace: launch on this workspace, or -1 for default. Ignored if + * activating an existing window * * Perform an appropriate default action for operating on this application, * dependent on its current state. For example, if the application is not @@ -419,13 +421,19 @@ shell_app_activate_window (ShellApp *app, * recently used transient for that window). */ void -shell_app_activate (ShellApp *app) +shell_app_activate (ShellApp *app, + int workspace) { switch (app->state) { case SHELL_APP_STATE_STOPPED: /* TODO sensibly handle this error */ - shell_app_info_launch (app->info, NULL); + shell_app_info_launch_full (app->info, + 0, + NULL, + workspace, + NULL, + NULL); break; case SHELL_APP_STATE_STARTING: break; @@ -438,11 +446,13 @@ shell_app_activate (ShellApp *app) /** * shell_app_open_new_window: * @app: a #ShellApp + * @workspace: open on this workspace, or -1 for default * * Request that the application create a new window. */ void -shell_app_open_new_window (ShellApp *app) +shell_app_open_new_window (ShellApp *app, + int workspace) { /* Here we just always launch the application again, even if we know * it was already running. For most applications this @@ -452,7 +462,12 @@ shell_app_open_new_window (ShellApp *app) * as say Pidgin. Ideally, we have the application express to us * that it supports an explicit new-window action. */ - shell_app_info_launch (app->info, NULL); + shell_app_info_launch_full (app->info, + 0, + NULL, + workspace, + NULL, + NULL); } /** diff --git a/src/shell-app.h b/src/shell-app.h index ce222374b..78b61f5ad 100644 --- a/src/shell-app.h +++ b/src/shell-app.h @@ -44,9 +44,11 @@ gboolean shell_app_is_transient (ShellApp *app); void shell_app_activate_window (ShellApp *app, MetaWindow *window, guint32 timestamp); -void shell_app_activate (ShellApp *app); +void shell_app_activate (ShellApp *app, + int workspace); -void shell_app_open_new_window (ShellApp *app); +void shell_app_open_new_window (ShellApp *app, + int workspace); ShellAppState shell_app_get_state (ShellApp *app); diff --git a/src/shell-doc-system.c b/src/shell-doc-system.c index 3ee51e6ba..a80e816d0 100644 --- a/src/shell-doc-system.c +++ b/src/shell-doc-system.c @@ -227,17 +227,24 @@ shell_doc_system_on_recent_changed (GtkRecentManager *manager, * shell_doc_system_open: * @system: A #ShellDocSystem * @info: A #GtkRecentInfo + * @workspace: Open on this workspace, or -1 for default * * Launch the default application associated with the mime type of * @info, using its uri. */ void shell_doc_system_open (ShellDocSystem *system, - GtkRecentInfo *info) + GtkRecentInfo *info, + int workspace) { GFile *file; GAppInfo *app_info; gboolean needs_uri; + GAppLaunchContext *context; + + context = shell_global_create_app_launch_context (shell_global_get ()); + if (workspace != -1) + gdk_app_launch_context_set_desktop ((GdkAppLaunchContext *)context, workspace); file = g_file_new_for_uri (gtk_recent_info_get_uri (info)); needs_uri = g_file_get_path (file) == NULL; @@ -248,7 +255,7 @@ shell_doc_system_open (ShellDocSystem *system, { GList *uris; uris = g_list_prepend (NULL, (gpointer)gtk_recent_info_get_uri (info)); - g_app_info_launch_uris (app_info, uris, shell_global_create_app_launch_context (shell_global_get ()), NULL); + g_app_info_launch_uris (app_info, uris, context, NULL); g_list_free (uris); } else @@ -267,7 +274,6 @@ shell_doc_system_open (ShellDocSystem *system, if (gtk_recent_info_get_application_info (info, app_name, &app_exec, &count, &time)) { GRegex *regex; - GAppLaunchContext *context; /* TODO: Change this once better support for creating GAppInfo is added to GtkRecentInfo, as right now @@ -298,13 +304,13 @@ shell_doc_system_open (ShellDocSystem *system, despite passing the app launch context, no startup notification occurs. */ - context = shell_global_create_app_launch_context (shell_global_get ()); g_app_info_launch (app_info, NULL, context, NULL); - g_object_unref (context); } g_free (app_name); } + + g_object_unref (context); } static void diff --git a/src/shell-doc-system.h b/src/shell-doc-system.h index 95ffb6c2f..077bc1a6c 100644 --- a/src/shell-doc-system.h +++ b/src/shell-doc-system.h @@ -41,6 +41,7 @@ void shell_doc_system_queue_existence_check (ShellDocSystem *system, guint n_items); void shell_doc_system_open (ShellDocSystem *system, - GtkRecentInfo *info); + GtkRecentInfo *info, + int workspace); #endif /* __SHELL_DOC_SYSTEM_H__ */