c48330a986
It makes sure we do not forget to zero the id and lets us avoid zero checks before. We use it for all new code, lets clean up the existing code base. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/845
299 lines
7.6 KiB
C
299 lines
7.6 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
/*
|
|
* Copyright (C) 2011 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors: David Zeuthen <davidz@redhat.com>
|
|
* Cosimo Cecchi <cosimoc@redhat.com>
|
|
*
|
|
*/
|
|
|
|
#include "shell-mime-sniffer.h"
|
|
#include "hotplug-mimetypes.h"
|
|
|
|
/* Set the environment variable HOTPLUG_SNIFFER_DEBUG to show debug */
|
|
static void print_debug (const gchar *str, ...);
|
|
|
|
#define BUS_NAME "org.gnome.Shell.HotplugSniffer"
|
|
#define AUTOQUIT_TIMEOUT 5
|
|
|
|
static const gchar introspection_xml[] =
|
|
"<node>"
|
|
" <interface name='org.gnome.Shell.HotplugSniffer'>"
|
|
" <method name='SniffURI'>"
|
|
" <arg type='s' name='uri' direction='in'/>"
|
|
" <arg type='as' name='content_types' direction='out'/>"
|
|
" </method>"
|
|
" </interface>"
|
|
"</node>";
|
|
|
|
static GDBusNodeInfo *introspection_data = NULL;
|
|
static GMainLoop *loop = NULL;
|
|
static guint autoquit_id = 0;
|
|
|
|
static gboolean
|
|
autoquit_timeout_cb (gpointer _unused)
|
|
{
|
|
print_debug ("Timeout reached, quitting...");
|
|
|
|
autoquit_id = 0;
|
|
g_main_loop_quit (loop);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
ensure_autoquit_off (void)
|
|
{
|
|
if (g_getenv ("HOTPLUG_SNIFFER_PERSIST") != NULL)
|
|
return;
|
|
|
|
g_clear_handle_id (&autoquit_id, g_source_remove);
|
|
}
|
|
|
|
static void
|
|
ensure_autoquit_on (void)
|
|
{
|
|
if (g_getenv ("HOTPLUG_SNIFFER_PERSIST") != NULL)
|
|
return;
|
|
|
|
autoquit_id =
|
|
g_timeout_add_seconds (AUTOQUIT_TIMEOUT,
|
|
autoquit_timeout_cb, NULL);
|
|
g_source_set_name_by_id (autoquit_id, "[gnome-shell] autoquit_timeout_cb");
|
|
}
|
|
|
|
typedef struct {
|
|
GVariant *parameters;
|
|
GDBusMethodInvocation *invocation;
|
|
} InvocationData;
|
|
|
|
static InvocationData *
|
|
invocation_data_new (GVariant *params,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
InvocationData *ret;
|
|
|
|
ret = g_slice_new0 (InvocationData);
|
|
ret->parameters = g_variant_ref (params);
|
|
ret->invocation = g_object_ref (invocation);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
invocation_data_free (InvocationData *data)
|
|
{
|
|
g_variant_unref (data->parameters);
|
|
g_clear_object (&data->invocation);
|
|
|
|
g_slice_free (InvocationData, data);
|
|
}
|
|
|
|
static void
|
|
sniff_async_ready_cb (GObject *source,
|
|
GAsyncResult *res,
|
|
gpointer user_data)
|
|
{
|
|
InvocationData *data = user_data;
|
|
gchar **types;
|
|
GError *error = NULL;
|
|
|
|
types = shell_mime_sniffer_sniff_finish (SHELL_MIME_SNIFFER (source),
|
|
res, &error);
|
|
|
|
if (error != NULL)
|
|
{
|
|
g_dbus_method_invocation_return_gerror (data->invocation, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
g_dbus_method_invocation_return_value (data->invocation,
|
|
g_variant_new ("(^as)", types));
|
|
g_strfreev (types);
|
|
|
|
out:
|
|
invocation_data_free (data);
|
|
ensure_autoquit_on ();
|
|
}
|
|
|
|
static void
|
|
handle_sniff_uri (InvocationData *data)
|
|
{
|
|
ShellMimeSniffer *sniffer;
|
|
const gchar *uri;
|
|
GFile *file;
|
|
|
|
ensure_autoquit_off ();
|
|
|
|
g_variant_get (data->parameters,
|
|
"(&s)", &uri,
|
|
NULL);
|
|
file = g_file_new_for_uri (uri);
|
|
|
|
print_debug ("Initiating sniff for uri %s", uri);
|
|
|
|
sniffer = shell_mime_sniffer_new (file);
|
|
shell_mime_sniffer_sniff_async (sniffer,
|
|
sniff_async_ready_cb,
|
|
data);
|
|
|
|
g_object_unref (sniffer);
|
|
g_object_unref (file);
|
|
}
|
|
|
|
static void
|
|
handle_method_call (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *method_name,
|
|
GVariant *parameters,
|
|
GDBusMethodInvocation *invocation,
|
|
gpointer user_data)
|
|
{
|
|
InvocationData *data;
|
|
|
|
data = invocation_data_new (parameters, invocation);
|
|
|
|
if (g_strcmp0 (method_name, "SniffURI") == 0)
|
|
handle_sniff_uri (data);
|
|
else
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static const GDBusInterfaceVTable interface_vtable =
|
|
{
|
|
handle_method_call,
|
|
NULL, /* get_property */
|
|
NULL, /* set_property */
|
|
};
|
|
|
|
static void
|
|
on_bus_acquired (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
print_debug ("Connected to the session bus: %s", name);
|
|
|
|
g_dbus_connection_register_object (connection,
|
|
"/org/gnome/Shell/HotplugSniffer",
|
|
introspection_data->interfaces[0],
|
|
&interface_vtable,
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
|
|
if (error != NULL)
|
|
{
|
|
g_printerr ("Error exporting object on the session bus: %s",
|
|
error->message);
|
|
g_error_free (error);
|
|
|
|
_exit(1);
|
|
}
|
|
|
|
print_debug ("Object exported on the session bus");
|
|
}
|
|
|
|
static void
|
|
on_name_lost (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
print_debug ("Lost bus name: %s, exiting", name);
|
|
|
|
g_main_loop_quit (loop);
|
|
}
|
|
|
|
static void
|
|
on_name_acquired (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
print_debug ("Acquired bus name: %s", name);
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
guint name_owner_id;
|
|
|
|
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
|
g_assert (introspection_data != NULL);
|
|
|
|
ensure_autoquit_on ();
|
|
loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
|
BUS_NAME, 0,
|
|
on_bus_acquired,
|
|
on_name_acquired,
|
|
on_name_lost,
|
|
NULL,
|
|
NULL);
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
if (name_owner_id != 0)
|
|
g_bus_unown_name (name_owner_id);
|
|
|
|
if (loop != NULL)
|
|
g_main_loop_unref (loop);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
static void __attribute__((format(printf, 1, 0)))
|
|
print_debug (const gchar *format, ...)
|
|
{
|
|
g_autofree char *s = NULL;
|
|
g_autofree char *timestamp = NULL;
|
|
va_list ap;
|
|
g_autoptr (GDateTime) now = NULL;
|
|
static volatile gsize once_init_value = 0;
|
|
static gboolean show_debug = FALSE;
|
|
static guint pid = 0;
|
|
|
|
if (g_once_init_enter (&once_init_value))
|
|
{
|
|
show_debug = (g_getenv ("HOTPLUG_SNIFFER_DEBUG") != NULL);
|
|
pid = getpid ();
|
|
g_once_init_leave (&once_init_value, 1);
|
|
}
|
|
|
|
if (!show_debug)
|
|
goto out;
|
|
|
|
now = g_date_time_new_now_local ();
|
|
timestamp = g_date_time_format (now, "%H:%M:%S");
|
|
|
|
va_start (ap, format);
|
|
s = g_strdup_vprintf (format, ap);
|
|
va_end (ap);
|
|
|
|
g_print ("gnome-shell-hotplug-sniffer[%d]: %s.%03d: %s\n",
|
|
pid, timestamp, g_date_time_get_microsecond (now), s);
|
|
out:
|
|
;
|
|
}
|
|
|