Back to index

indicator-appmenu  12.10.0
Classes | Defines | Typedefs | Functions
hudappmenuregistrar.c File Reference
#include "hudappmenuregistrar.h"
#include <gio/gio.h>

Go to the source code of this file.

Classes

struct  HudAppMenuRegistrarObserver
struct  HudAppMenuRegistrarWindow
struct  _HudAppMenuRegistrar

Defines

#define G_LOG_DOMAIN   "hudappmenuregistrar"
#define APPMENU_REGISTRAR_BUS_NAME   "com.canonical.AppMenu.Registrar"
 SECTION:hudappmenuregistrar : HudAppMenuRegistrar : client for the com.canonical.AppMenu.Registrar D-Bus service.
#define APPMENU_REGISTRAR_OBJECT_PATH   "/com/canonical/AppMenu/Registrar"
#define APPMENU_REGISTRAR_IFACE   "com.canonical.AppMenu.Registrar"

Typedefs

typedef GObjectClass HudAppMenuRegistrarClass

Functions

static void hud_app_menu_registrar_window_free (gpointer user_data)
static HudAppMenuRegistrarWindowhud_app_menu_registrar_get_window (HudAppMenuRegistrar *registrar, guint xid)
static void hud_app_menu_registrar_possibly_free_window (HudAppMenuRegistrar *registrar, HudAppMenuRegistrarWindow *window)
static void hud_app_menu_registrar_notify_window_observers (HudAppMenuRegistrar *registrar, HudAppMenuRegistrarWindow *window)
static void hud_app_menu_registrar_dbus_signal (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
static void hud_app_menu_registrar_ready (GObject *source, GAsyncResult *result, gpointer user_data)
static void hud_app_menu_registrar_name_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data)
static void hud_app_menu_registrar_name_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data)
static void hud_app_menu_registrar_finalize (GObject *object)
static void hud_app_menu_registrar_init (HudAppMenuRegistrar *registrar)
static void hud_app_menu_registrar_class_init (HudAppMenuRegistrarClass *class)
void hud_app_menu_registrar_add_observer (HudAppMenuRegistrar *registrar, guint xid, HudAppMenuRegistrarObserverFunc callback, gpointer user_data)
 HudAppMenuRegistrarObserverFunc: : the #HudAppMenuRegistrar : the xid that we are notifying about : the bus name for the dbusmenu, or NULL : the object path for the dbusmenu, or NULL : the data pointer.
void hud_app_menu_registrar_remove_observer (HudAppMenuRegistrar *registrar, guint xid, HudAppMenuRegistrarObserverFunc callback, gpointer user_data)
 hud_app_menu_registrar_remove_observer: : the #HudAppMenuRegistrar : the xid to begin observing : a HudAppMenuRegistrarObserverFunc : user data for
HudAppMenuRegistrar * hud_app_menu_registrar_get (void)
 hud_app_menu_registrar_get:

Class Documentation

struct HudAppMenuRegistrarObserver

Definition at line 63 of file hudappmenuregistrar.c.

Class Members
HudAppMenuRegistrarObserverFunc callback
gpointer user_data
struct HudAppMenuRegistrarWindow

Definition at line 69 of file hudappmenuregistrar.c.

Class Members
gchar * bus_name
gchar * object_path
GSList * observers
guint xid
struct _HudAppMenuRegistrar

Definition at line 77 of file hudappmenuregistrar.c.

Class Members
GCancellable * cancellable
gboolean notifying
GObject parent_instance
gboolean ready
guint subscription
GHashTable * windows

Define Documentation

#define APPMENU_REGISTRAR_BUS_NAME   "com.canonical.AppMenu.Registrar"

SECTION:hudappmenuregistrar : HudAppMenuRegistrar : client for the com.canonical.AppMenu.Registrar D-Bus service.

The #HudAppMenuRegistrar is a singleton object that monitors the com.canonical.AppMenu.Registrar D-Bus service.

On instantiation, a D-Bus name watch is setup for the registrar. When the registrar is found to exist, a local copy is made of the windows and menus that the registrar knows about. Change notifications are also monitored to keep the local cache in sync.

After that point, all queries for information from the registrar are satisfied from the local cache, without blocking.

Information is acquired from #HudAppMenuRegistrar by using hud_app_menu_registrar_add_observer(). This immediately calls a callback with the initial information and makes future calls to the same callback if the information is found to have changed.

If the registrar is offline or the information is not yet available at the time of the original query, the window will initially be reported as having no menu but a change notification will arrive when the proper information becomes available. HudAppMenuRegistrar:

This is an opaque structure type.

Definition at line 59 of file hudappmenuregistrar.c.

#define APPMENU_REGISTRAR_IFACE   "com.canonical.AppMenu.Registrar"

Definition at line 61 of file hudappmenuregistrar.c.

#define APPMENU_REGISTRAR_OBJECT_PATH   "/com/canonical/AppMenu/Registrar"

Definition at line 60 of file hudappmenuregistrar.c.

#define G_LOG_DOMAIN   "hudappmenuregistrar"

Definition at line 19 of file hudappmenuregistrar.c.


Typedef Documentation

typedef GObjectClass HudAppMenuRegistrarClass

Definition at line 88 of file hudappmenuregistrar.c.


Function Documentation

void hud_app_menu_registrar_add_observer ( HudAppMenuRegistrar *  registrar,
guint  xid,
HudAppMenuRegistrarObserverFunc  callback,
gpointer  user_data 
)

HudAppMenuRegistrarObserverFunc: : the #HudAppMenuRegistrar : the xid that we are notifying about : the bus name for the dbusmenu, or NULL : the object path for the dbusmenu, or NULL : the data pointer.

Notifies about the initial values for or changes to the bus name and object path at which to find the dbusmenu for .

You should pass the values of and to dbusmenu_client_new() to get started.

If no menu is available then and will both be given as NULL. hud_app_menu_registrar_add_observer: : the #HudAppMenuRegistrar : the xid to begin observing : a HudAppMenuRegistrarObserverFunc : user data for

Begins observing .

will be called exactly once before the function returns with a set of initial values (the bus name and object path at which to find the menu for the window).

If the location of the menu for changes (including being created or destroyed) then will be called each time an update is required.

It is possible that the values are not initially known because they have not yet been retreived from the registrar or because the registrar is not running. In this case, NULL values will be provided initially and will be invoked again when the real values are known.

Call hud_app_menu_registrar_remove_observer() to when you are no longer interested in .

Definition at line 418 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrarObserver *observer;
  HudAppMenuRegistrarWindow *window;

  g_return_if_fail (xid != 0);
  g_return_if_fail (callback != NULL);
  g_return_if_fail (!registrar->notifying);

  g_debug ("observer added for xid %u (%p)", xid, user_data);

  observer = g_slice_new (HudAppMenuRegistrarObserver);
  observer->callback = callback;
  observer->user_data = user_data;

  window = hud_app_menu_registrar_get_window (registrar, xid);
  window->observers = g_slist_prepend (window->observers, observer);

  /* send the first update */
  (* callback) (registrar, xid, window->bus_name, window->object_path, user_data);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 368 of file hudappmenuregistrar.c.

{
  class->finalize = hud_app_menu_registrar_finalize;
}

Here is the call graph for this function:

static void hud_app_menu_registrar_dbus_signal ( GDBusConnection *  connection,
const gchar *  sender_name,
const gchar *  object_path,
const gchar *  interface_name,
const gchar *  signal_name,
GVariant *  parameters,
gpointer  user_data 
) [static]

Definition at line 154 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrar *registrar = user_data;

  g_debug ("got signal");

  if (!registrar->ready)
    {
      g_debug ("not ready, so ignoring signal");
      return;
    }

  if (g_str_equal (signal_name, "WindowRegistered"))
    {
      HudAppMenuRegistrarWindow *window;
      guint xid;

      if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uso)")))
          return;

      g_variant_get_child (parameters, 0, "u", &xid);
      window = hud_app_menu_registrar_get_window (registrar, xid);

      g_free (window->bus_name);
      g_variant_get_child (parameters, 1, "s", &window->bus_name);
      g_free (window->object_path);
      g_variant_get_child (parameters, 2, "o", &window->object_path);

      g_debug ("xid %u is now at (%s, %s)", xid, window->bus_name, window->object_path);

      hud_app_menu_registrar_notify_window_observers (registrar, window);
    }

  else if (g_str_equal (signal_name, "WindowUnregistered"))
    {
      HudAppMenuRegistrarWindow *window;
      guint xid;

      if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(u)")))
        return;

      g_variant_get (parameters, 0, "u", &xid);

      g_debug ("xid %u disappeared", xid);

      window = hud_app_menu_registrar_get_window (registrar, xid);

      g_free (window->bus_name);
      window->bus_name = NULL;
      g_free (window->object_path);
      window->object_path = NULL;

      hud_app_menu_registrar_notify_window_observers (registrar, window);

      hud_app_menu_registrar_possibly_free_window (registrar, window);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hud_app_menu_registrar_finalize ( GObject *  object) [static]

Definition at line 350 of file hudappmenuregistrar.c.

{
  /* This is an immortal singleton.  If we're here, we have trouble. */
  g_assert_not_reached ();
}

Here is the caller graph for this function:

HudAppMenuRegistrar* hud_app_menu_registrar_get ( void  )

hud_app_menu_registrar_get:

Gets the singleton instance of #HudAppMenuRegistrar.

Returns: (transfer none): the instance

Definition at line 499 of file hudappmenuregistrar.c.

{
  static HudAppMenuRegistrar *singleton;

  if (!singleton)
    singleton = g_object_new (HUD_TYPE_APP_MENU_REGISTRAR, NULL);

  return singleton;
}

Here is the caller graph for this function:

static HudAppMenuRegistrarWindow* hud_app_menu_registrar_get_window ( HudAppMenuRegistrar *  registrar,
guint  xid 
) [static]

Definition at line 107 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrarWindow *window;

  window = g_hash_table_lookup (registrar->windows, GINT_TO_POINTER (xid));

  if (!window)
    {
      window = g_slice_new0 (HudAppMenuRegistrarWindow);
      window->xid = xid;

      g_debug ("create window instance for %u", xid);
      g_hash_table_insert (registrar->windows, GINT_TO_POINTER (xid), window);
    }

  return window;
}

Here is the caller graph for this function:

static void hud_app_menu_registrar_init ( HudAppMenuRegistrar *  registrar) [static]

Definition at line 357 of file hudappmenuregistrar.c.

{
  g_debug ("online");

  registrar->windows = g_hash_table_new_full (NULL, NULL, NULL, hud_app_menu_registrar_window_free);
  g_bus_watch_name (G_BUS_TYPE_SESSION, APPMENU_REGISTRAR_BUS_NAME, G_BUS_NAME_WATCHER_FLAGS_NONE,
                    hud_app_menu_registrar_name_appeared, hud_app_menu_registrar_name_vanished,
                    g_object_ref (registrar), g_object_unref);
}

Here is the call graph for this function:

static void hud_app_menu_registrar_name_appeared ( GDBusConnection *  connection,
const gchar *  name,
const gchar *  name_owner,
gpointer  user_data 
) [static]

Definition at line 277 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrar *registrar = user_data;

  g_debug ("name appeared (owner is %s)", name_owner);

  g_assert (registrar->subscription == 0);
  registrar->subscription = g_dbus_connection_signal_subscribe (connection, name_owner,
                                                                APPMENU_REGISTRAR_IFACE, NULL,
                                                                APPMENU_REGISTRAR_OBJECT_PATH, NULL,
                                                                G_DBUS_SIGNAL_FLAGS_NONE,
                                                                hud_app_menu_registrar_dbus_signal,
                                                                registrar, NULL);

  g_assert (registrar->cancellable == NULL);
  registrar->cancellable = g_cancellable_new ();
  g_dbus_connection_call (connection, name_owner, APPMENU_REGISTRAR_OBJECT_PATH,
                          APPMENU_REGISTRAR_IFACE, "GetMenus", NULL, G_VARIANT_TYPE ("(a(uso))"),
                          G_DBUS_CALL_FLAGS_NONE, -1, registrar->cancellable,
                          hud_app_menu_registrar_ready, g_object_ref (registrar));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hud_app_menu_registrar_name_vanished ( GDBusConnection *  connection,
const gchar *  name,
gpointer  user_data 
) [static]

Definition at line 303 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrar *registrar = user_data;

  g_debug ("name vanished");

  if (registrar->subscription > 0)
    {
      g_dbus_connection_signal_unsubscribe (connection, registrar->subscription);
      registrar->subscription = 0;
    }

  if (registrar->cancellable)
    {
      g_cancellable_cancel (registrar->cancellable);
      g_clear_object (&registrar->cancellable);
    }

  if (registrar->ready)
    {
      GHashTableIter iter;
      gpointer value;

      registrar->ready = FALSE;

      g_hash_table_iter_init (&iter, registrar->windows);
      while (g_hash_table_iter_next (&iter, NULL, &value))
        {
          HudAppMenuRegistrarWindow *window = value;

          g_free (window->bus_name);
          window->bus_name = NULL;
          g_free (window->object_path);
          window->object_path = NULL;

          hud_app_menu_registrar_notify_window_observers (registrar, window);

          /* Cannot go the normal route here because we are iterating... */
          if (window->observers == NULL)
            g_hash_table_iter_remove (&iter);
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hud_app_menu_registrar_notify_window_observers ( HudAppMenuRegistrar *  registrar,
HudAppMenuRegistrarWindow window 
) [static]

Definition at line 135 of file hudappmenuregistrar.c.

{
  GSList *node;

  registrar->notifying = TRUE;

  for (node = window->observers; node; node = node->next)
    {
      HudAppMenuRegistrarObserver *observer = node->data;

      g_debug ("notifying %p about %u", observer->user_data, window->xid);
      (* observer->callback) (registrar, window->xid, window->bus_name, window->object_path, observer->user_data);
    }

  registrar->notifying = FALSE;
}

Here is the caller graph for this function:

static void hud_app_menu_registrar_possibly_free_window ( HudAppMenuRegistrar *  registrar,
HudAppMenuRegistrarWindow window 
) [static]

Definition at line 127 of file hudappmenuregistrar.c.

{
  if (window->bus_name == NULL && window->observers == NULL)
    g_hash_table_remove (registrar->windows, GINT_TO_POINTER (window->xid));
}

Here is the caller graph for this function:

static void hud_app_menu_registrar_ready ( GObject *  source,
GAsyncResult *  result,
gpointer  user_data 
) [static]

Definition at line 219 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrar *registrar = user_data;
  GError *error = NULL;
  GVariant *reply;

  g_debug ("GetMenus returned");

  g_clear_object (&registrar->cancellable);

  reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);

  if (reply)
    {
      GVariantIter *iter;
      const gchar *bus_name;
      const gchar *object_path;
      guint xid;

      g_assert (!registrar->ready);
      registrar->ready = TRUE;

      g_debug ("going ready");

      g_variant_get (reply, "(a(uso))", &iter);

      while (g_variant_iter_next (iter, "(u&s&o)", &xid, &bus_name, &object_path))
        {
          HudAppMenuRegistrarWindow *window;

          window = hud_app_menu_registrar_get_window (registrar, xid);

          /* we were not ready until now, so we expect this to be unset */
          g_assert (window->bus_name == NULL);

          window->bus_name = g_strdup (bus_name);
          window->object_path = g_strdup (object_path);

          hud_app_menu_registrar_notify_window_observers (registrar, window);
        }

      g_variant_iter_free (iter);
      g_variant_unref (reply);
    }
  else
    {
      g_warning ("GetMenus returned an error: %s", error->message);
      g_error_free (error);
    }

  g_object_unref (registrar);

  g_debug ("done handling GetMenus reply");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void hud_app_menu_registrar_remove_observer ( HudAppMenuRegistrar *  registrar,
guint  xid,
HudAppMenuRegistrarObserverFunc  callback,
gpointer  user_data 
)

hud_app_menu_registrar_remove_observer: : the #HudAppMenuRegistrar : the xid to begin observing : a HudAppMenuRegistrarObserverFunc : user data for

Reverses the effect of a previous call to hud_app_menu_registrar_add_observer().

and must be exactly equal to the values passed to that function.

One call does not remove all instances of and . You need to call this function the same number of times that you called hud_app_menu_registrar_add_observer().

Definition at line 461 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrarWindow *window;
  GSList **node;

  g_return_if_fail (xid != 0);
  g_return_if_fail (callback != NULL);
  g_return_if_fail (!registrar->notifying);

  g_debug ("observer removed for xid %u (%p)", xid, user_data);

  window = hud_app_menu_registrar_get_window (registrar, xid);
  for (node = &window->observers; *node; node = &(*node)->next)
    {
      HudAppMenuRegistrarObserver *observer = (*node)->data;

      if (observer->callback == callback && observer->user_data == user_data)
        {
          g_slice_free (HudAppMenuRegistrarObserver, observer);
          *node = g_slist_delete_link (*node, *node);
          break;
        }
    }

  hud_app_menu_registrar_possibly_free_window (registrar, window);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hud_app_menu_registrar_window_free ( gpointer  user_data) [static]

Definition at line 93 of file hudappmenuregistrar.c.

{
  HudAppMenuRegistrarWindow *window = user_data;

  g_assert (window->bus_name == NULL);
  g_assert (window->object_path == NULL);
  g_assert (window->observers == NULL);

  g_debug ("free window instance for %u", window->xid);

  g_slice_free (HudAppMenuRegistrarWindow, window);
}

Here is the caller graph for this function: