/*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Pawel Stolowski
*/
[CCode (gir_namespace = "UnityExtras", gir_version = "1.0")]
namespace Unity.Extras
{
private static const string FILE_MANAGER_DBUS_NAME = "org.freedesktop.FileManager1";
private static const string FILE_MANAGER_DBUS_PATH = "/org/freedesktop/FileManager1";
public delegate void CreateScopeCallback ();
[DBus (name = "org.freedesktop.FileManager1")]
internal interface FileManagerInterface: GLib.Object
{
public abstract async void show_items (string[] uris, string startup_id) throws Error;
/* These methods are currently unused
public abstract async void show_folders (string[] uris, string startup_id) throws Error;
public abstract async void show_item_properties (string[] uris, string startup_id) throws Error;*/
}
/**
* Opens file manager showing given uri in its parent folder.
* It tries to activate file manager using org.freedesktop.FileManager1 interface first and if it fails,
* uses GLib.AppInfo.launch_default_for_uri.
*/
public async void show_in_folder (string uri) throws Error
{
string[] uris = {uri};
var file = File.new_for_uri (uri);
if (file != null)
{
File? parent_dir = file.get_parent ();
if (parent_dir != null)
{
// try to launch file manager via dbus interface first
try
{
FileManagerInterface service = yield Bus.get_proxy (BusType.SESSION, FILE_MANAGER_DBUS_NAME, FILE_MANAGER_DBUS_PATH);
yield service.show_items (uris, "");
return;
}
catch (GLib.Error e)
{
warning ("Failed to activate file manager via dbus: '%s', uri '%s'", e.message, uri);
}
// fallback
GLib.AppInfo.launch_default_for_uri (parent_dir.get_uri (), null); // may throw
return;
}
else
{
throw new GLib.IOError.FAILED ("Failed to get parent dir for uri: '%s'".printf (uri));
}
}
else
{
throw new GLib.IOError.FAILED ("Failed to create file object for uri: '%s'".printf (uri));
}
}
/**
* Check if a given well known DBus is owned. Failure (exception) means ownership couldn't be determined.
* WARNING: This does sync IO!
*
* @param name DBus name to test for availability
* @return true if name is available
*/
public static bool dbus_name_has_owner (string name) throws Error
{
bool has_owner;
DBusConnection bus = Bus.get_sync (BusType.SESSION);
Variant result = bus.call_sync ("org.freedesktop.DBus",
"/org/freedesktop/dbus",
"org.freedesktop.DBus",
"NameHasOwner",
new Variant ("(s)", name),
new VariantType ("(b)"),
DBusCallFlags.NO_AUTO_START,
-1);
result.get ("(b)", out has_owner);
return has_owner;
}
/**
* Attempts to own DBus name (calls dbus_name_has_owner first). CreateScopeCallback should create Lens/Scope object -
* it will be called after initial dbus name availability check, but before acquiring the name, so this function may
* still fail even after executing the callback.
*
* @param name DBus name to own
* @param scope_creation_cb callback that creates Lens/Scope object
* @return application instance (on success)
*/
public static GLib.Application? dbus_own_name (string name, CreateScopeCallback scope_creation_cb) throws Error
{
GLib.Application? app = null;
if (!dbus_name_has_owner (name))
{
scope_creation_cb ();
app = new Application (name, ApplicationFlags.IS_SERVICE);
app.register ();
if (app.get_is_remote ())
{
app = null;
}
else
{
/* Hold()ing the app makes sure the GApplication doesn't exit */
app.hold ();
}
}
return app;
}
}