Back to index

indicator-appmenu  12.10.0
Classes | Defines | Typedefs | Functions
window-menu-model.c File Reference
#include <libbamf/libbamf.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gio/gdesktopappinfo.h>
#include "window-menu-model.h"
#include "gactionmuxer.h"
#include "gtkmodelmenu.h"

Go to the source code of this file.

Classes

struct  _WindowMenuModelPrivate
struct  _WindowMenuEntry

Defines

#define WINDOW_MENU_MODEL_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), WINDOW_MENU_MODEL_TYPE, WindowMenuModelPrivate))
#define ACTION_MUX_PREFIX_WIN   "win"
#define ACTION_MUX_PREFIX_APP   "app"
#define ENTRY_DATA   "window-menu-model-menuitem-entry"

Typedefs

typedef struct _WindowMenuEntry

Functions

static void window_menu_model_class_init (WindowMenuModelClass *klass)
static void window_menu_model_init (WindowMenuModel *self)
static void window_menu_model_dispose (GObject *object)
static void window_menu_model_finalize (GObject *object)
static GList * get_entries (WindowMenu *wm)
static guint get_location (WindowMenu *wm, IndicatorObjectEntry *entry)
static WindowMenuStatus get_status (WindowMenu *wm)
static gboolean get_error_state (WindowMenu *wm)
static guint get_xid (WindowMenu *wm)
 G_DEFINE_TYPE (WindowMenuModel, window_menu_model, WINDOW_MENU_TYPE)
static void add_application_menu (WindowMenuModel *menu, const gchar *appname, GMenuModel *model)
GtkLabel * mi_find_label (GtkWidget *mi)
GtkImage * mi_find_icon (GtkWidget *mi)
GtkMenu * mi_find_menu (GtkMenuItem *mi)
static void entry_object_free (gpointer inentry)
static void entry_label_notify (GObject *obj, GParamSpec *pspec, gpointer user_data)
static void entry_visible_notify (GObject *obj, GParamSpec *pspec, gpointer user_data)
static void entry_sensitive_notify (GObject *obj, GParamSpec *pspec, gpointer user_data)
static void entry_on_menuitem (WindowMenuModel *menu, GtkMenuItem *gmi)
static void item_inserted_cb (GtkContainer *menu, GtkWidget *widget, gint position, gpointer data)
static void item_removed_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
static void add_window_menu (WindowMenuModel *menu, GMenuModel *model)
WindowMenuModel * window_menu_model_new (BamfApplication *app, BamfWindow *window)

Class Documentation

struct _WindowMenuModelPrivate

Definition at line 34 of file window-menu-model.c.

Class Members
GtkAccelGroup * accel_group
GActionMuxer * action_mux
GDBusMenuModel * app_menu_model
IndicatorObjectEntry application_menu
gboolean has_application_menu
GtkMenu * win_menu
gulong win_menu_insert
GDBusMenuModel * win_menu_model
gulong win_menu_remove
guint xid
struct _WindowMenuEntry

Definition at line 246 of file window-menu-model.c.

Class Members
IndicatorObjectEntry entry
GtkMenuItem * gmi
gulong label_sig
gulong sensitive_sig
gulong visible_sig

Define Documentation

#define ACTION_MUX_PREFIX_APP   "app"

Definition at line 75 of file window-menu-model.c.

#define ACTION_MUX_PREFIX_WIN   "win"

Definition at line 74 of file window-menu-model.c.

#define ENTRY_DATA   "window-menu-model-menuitem-entry"

Definition at line 78 of file window-menu-model.c.

#define WINDOW_MENU_MODEL_GET_PRIVATE (   o)    (G_TYPE_INSTANCE_GET_PRIVATE ((o), WINDOW_MENU_MODEL_TYPE, WindowMenuModelPrivate))

Definition at line 53 of file window-menu-model.c.


Typedef Documentation

typedef struct _WindowMenuEntry

Definition at line 245 of file window-menu-model.c.


Function Documentation

static void add_application_menu ( WindowMenuModel *  menu,
const gchar *  appname,
GMenuModel *  model 
) [static]

Definition at line 154 of file window-menu-model.c.

{
       g_return_if_fail(G_IS_MENU_MODEL(model));

       menu->priv->app_menu_model = g_object_ref(model);

       if (appname != NULL) {
              menu->priv->application_menu.label = GTK_LABEL(gtk_label_new(appname));
       } else {
              menu->priv->application_menu.label = GTK_LABEL(gtk_label_new(_("Unknown Application Name")));
       }
       g_object_ref_sink(menu->priv->application_menu.label);
       gtk_widget_show(GTK_WIDGET(menu->priv->application_menu.label));

       menu->priv->application_menu.menu = GTK_MENU(gtk_model_menu_create_menu(model, G_ACTION_OBSERVABLE(menu->priv->action_mux), menu->priv->accel_group));

       gtk_widget_show(GTK_WIDGET(menu->priv->application_menu.menu));
       g_object_ref_sink(menu->priv->application_menu.menu);

       menu->priv->has_application_menu = TRUE;

       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_window_menu ( WindowMenuModel *  menu,
GMenuModel *  model 
) [static]

Definition at line 414 of file window-menu-model.c.

{
       menu->priv->win_menu_model = g_object_ref(model);

       menu->priv->win_menu = GTK_MENU(gtk_model_menu_create_menu(model, G_ACTION_OBSERVABLE(menu->priv->action_mux), menu->priv->accel_group));
       g_assert(menu->priv->win_menu != NULL);
       g_object_ref_sink(menu->priv->win_menu);

       menu->priv->win_menu_insert = g_signal_connect(G_OBJECT (menu->priv->win_menu),
              "insert",
              G_CALLBACK (item_inserted_cb),
              menu);
       menu->priv->win_menu_remove = g_signal_connect (G_OBJECT (menu->priv->win_menu),
              "remove",
              G_CALLBACK (item_removed_cb),
              menu);

       GList * children = gtk_container_get_children(GTK_CONTAINER(menu->priv->win_menu));
       GList * child;
       for (child = children; child != NULL; child = g_list_next(child)) {
              GtkMenuItem * gmi = GTK_MENU_ITEM(child->data);

              if (gmi == NULL) {
                     continue;
              }

              entry_on_menuitem(menu, gmi);
       }
       g_list_free(children);

       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void entry_label_notify ( GObject *  obj,
GParamSpec *  pspec,
gpointer  user_data 
) [static]

Definition at line 284 of file window-menu-model.c.

{
       g_return_if_fail(GTK_IS_MENU_ITEM(obj));

       GtkMenuItem * gmi = GTK_MENU_ITEM(obj);
       WindowMenuEntry * entry = (WindowMenuEntry *)user_data;

       if (entry->entry.label != NULL) {
              const gchar * label = gtk_menu_item_get_label(gmi);
              gtk_label_set_label(entry->entry.label, label);
       }

       return;
}

Here is the caller graph for this function:

static void entry_object_free ( gpointer  inentry) [static]

Definition at line 258 of file window-menu-model.c.

{
       WindowMenuEntry * entry = (WindowMenuEntry *)inentry;

       if (entry->label_sig != 0) {
              g_signal_handler_disconnect(entry->gmi, entry->label_sig);
       }

       if (entry->sensitive_sig != 0) {
              g_signal_handler_disconnect(entry->gmi, entry->sensitive_sig);
       }

       if (entry->visible_sig != 0) {
              g_signal_handler_disconnect(entry->gmi, entry->visible_sig);
       }

       g_clear_object(&entry->entry.label);
       g_clear_object(&entry->entry.image);
       g_clear_object(&entry->entry.menu);

       g_free(entry);
       return;
}

Here is the caller graph for this function:

static void entry_on_menuitem ( WindowMenuModel *  menu,
GtkMenuItem *  gmi 
) [static]

Definition at line 343 of file window-menu-model.c.

{
       WindowMenuEntry * entry = g_new0(WindowMenuEntry, 1);

       entry->gmi = gmi;

       entry->entry.label = mi_find_label(GTK_WIDGET(gmi));
       entry->entry.image = mi_find_icon(GTK_WIDGET(gmi));
       entry->entry.menu = mi_find_menu(gmi);

       if (entry->entry.label == NULL && entry->entry.image == NULL) {
              const gchar * label = gtk_menu_item_get_label(gmi);
              if (label == NULL) {
                     g_warning("Item doesn't have a label or an image, aborting");
                     return;
              }

              entry->entry.label = GTK_LABEL(gtk_label_new(label));
              gtk_widget_show(GTK_WIDGET(entry->entry.label));
              entry->label_sig = g_signal_connect(G_OBJECT(gmi), "notify::label", G_CALLBACK(entry_label_notify), entry->entry.label);
       }

       if (entry->entry.label != NULL) {
              g_object_ref_sink(entry->entry.label);
       }

       if (entry->entry.image != NULL) {
              g_object_ref_sink(entry->entry.image);
       }

       if (entry->entry.menu != NULL) {
              g_object_ref_sink(entry->entry.menu);
       }

       entry->sensitive_sig = g_signal_connect(G_OBJECT(gmi), "notify::sensitive", G_CALLBACK(entry_sensitive_notify), entry);
       entry->visible_sig = g_signal_connect(G_OBJECT(gmi), "notify::visible", G_CALLBACK(entry_visible_notify), entry);

       g_object_set_data_full(G_OBJECT(gmi), ENTRY_DATA, entry, entry_object_free);

       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void entry_sensitive_notify ( GObject *  obj,
GParamSpec *  pspec,
gpointer  user_data 
) [static]

Definition at line 323 of file window-menu-model.c.

{
       g_return_if_fail(GTK_IS_WIDGET(obj));
       GtkWidget * widget = GTK_WIDGET(obj);
       WindowMenuEntry * entry = (WindowMenuEntry *)user_data;
       gboolean sensitive = gtk_widget_get_sensitive(widget);

       if (entry->entry.label != NULL) {
              gtk_widget_set_sensitive(GTK_WIDGET(entry->entry.label), sensitive);
       }

       if (entry->entry.image != NULL) {
              gtk_widget_set_sensitive(GTK_WIDGET(entry->entry.image), sensitive);
       }

       return;
}

Here is the caller graph for this function:

static void entry_visible_notify ( GObject *  obj,
GParamSpec *  pspec,
gpointer  user_data 
) [static]

Definition at line 302 of file window-menu-model.c.

{
       g_return_if_fail(GTK_IS_WIDGET(obj));
       GtkWidget * widget = GTK_WIDGET(obj);
       WindowMenuEntry * entry = (WindowMenuEntry *)user_data;
       gboolean visible = gtk_widget_get_visible(widget);

       if (entry->entry.label != NULL) {
              gtk_widget_set_visible(GTK_WIDGET(entry->entry.label), visible);
       }

       if (entry->entry.image != NULL) {
              gtk_widget_set_visible(GTK_WIDGET(entry->entry.image), visible);
       }

       return;
}

Here is the caller graph for this function:

G_DEFINE_TYPE ( WindowMenuModel  ,
window_menu_model  ,
WINDOW_MENU_TYPE   
)
static GList * get_entries ( WindowMenu *  wm) [static]

Definition at line 536 of file window-menu-model.c.

{
       g_return_val_if_fail(IS_WINDOW_MENU_MODEL(wm), NULL);
       WindowMenuModel * menu = WINDOW_MENU_MODEL(wm);

       GList * ret = NULL;

       if (menu->priv->has_application_menu) {
              ret = g_list_append(ret, &menu->priv->application_menu);
       }

       if (menu->priv->win_menu != NULL) {
              GList * children = gtk_container_get_children(GTK_CONTAINER(menu->priv->win_menu));
              GList * child;
              for (child = children; child != NULL; child = g_list_next(child)) {
                     gpointer entry = g_object_get_data(child->data, ENTRY_DATA);

                     if (entry == NULL) {
                            /* Try to build the entry, it is possible (but unlikely) that
                               we could beat the signal that this isn't created.  So we'll
                               just handle that race here */
                            entry_on_menuitem(menu, GTK_MENU_ITEM(child->data));
                            entry = g_object_get_data(child->data, ENTRY_DATA);
                     }

                     if (entry != NULL) {
                            ret = g_list_append(ret, entry);
                     }
              }

              g_list_free(children);
       }

       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static gboolean get_error_state ( WindowMenu *  wm) [static]

Definition at line 629 of file window-menu-model.c.

{
       return FALSE;
}

Here is the caller graph for this function:

static guint get_location ( WindowMenu *  wm,
IndicatorObjectEntry *  entry 
) [static]

Definition at line 574 of file window-menu-model.c.

{
       g_return_val_if_fail(IS_WINDOW_MENU_MODEL(wm), 0);
       WindowMenuModel * menu = WINDOW_MENU_MODEL(wm);

       gboolean found = FALSE;
       guint pos = 0;

       if (menu->priv->has_application_menu) {
              if (entry == &menu->priv->application_menu) {
                     pos = 0;
                     found = TRUE;
              } else {
                     /* We need to put a shift in if there is an application
                        menu and we're not looking for that one */
                     pos = 1;
              }
       }

       if (menu->priv->win_menu != NULL) {
              GList * children = gtk_container_get_children(GTK_CONTAINER(menu->priv->win_menu));
              GList * child;
              for (child = children; child != NULL; child = g_list_next(child), pos++) {
                     gpointer lentry = g_object_get_data(child->data, ENTRY_DATA);

                     if (entry == lentry) {
                            found = TRUE;
                            break;
                     }
              }

              g_list_free(children);
       }

       if (!found) {
              /* NOTE: Not printing any of the values here because there's
                 a pretty good chance that they're not valid.  Let's not crash
                 things here. */
              g_warning("Unable to find entry: %p", entry);
       }

       return pos;
}

Here is the caller graph for this function:

static WindowMenuStatus get_status ( WindowMenu *  wm) [static]

Definition at line 621 of file window-menu-model.c.

{
       return WINDOW_MENU_STATUS_NORMAL;
}

Here is the caller graph for this function:

static guint get_xid ( WindowMenu *  wm) [static]

Definition at line 636 of file window-menu-model.c.

{
       g_return_val_if_fail(IS_WINDOW_MENU_MODEL(wm), 0);
       return WINDOW_MENU_MODEL(wm)->priv->xid;
}

Here is the caller graph for this function:

static void item_inserted_cb ( GtkContainer *  menu,
GtkWidget *  widget,
gint  position,
gpointer  data 
) [static]

Definition at line 387 of file window-menu-model.c.

{
       if (g_object_get_data(G_OBJECT(widget), ENTRY_DATA) == NULL) {
              entry_on_menuitem(WINDOW_MENU_MODEL(data), GTK_MENU_ITEM(widget));
       }

       if (g_object_get_data(G_OBJECT(widget), ENTRY_DATA) != NULL) {
              g_signal_emit_by_name(data, WINDOW_MENU_SIGNAL_ENTRY_ADDED, g_object_get_data(G_OBJECT(widget), ENTRY_DATA));
       }

       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void item_removed_cb ( GtkContainer *  menu,
GtkWidget *  widget,
gpointer  data 
) [static]

Definition at line 405 of file window-menu-model.c.

{
       g_signal_emit_by_name(data, WINDOW_MENU_SIGNAL_ENTRY_REMOVED, g_object_get_data(G_OBJECT(widget), ENTRY_DATA));
       return;
}

Here is the caller graph for this function:

GtkImage* mi_find_icon ( GtkWidget *  mi)

Definition at line 207 of file window-menu-model.c.

{
       if (GTK_IS_IMAGE(mi)) {
              return GTK_IMAGE(mi);
       }

       GtkImage * retval = NULL;

       if (GTK_IS_CONTAINER(mi)) {
              GList * children = gtk_container_get_children(GTK_CONTAINER(mi));
              GList * child = children;

              while (child != NULL && retval == NULL) {
                     if (GTK_IS_WIDGET(child->data)) {
                            retval = mi_find_icon(GTK_WIDGET(child->data));
                     }
                     child = g_list_next(child);
              }

              g_list_free(children);
       }

       return retval;
}

Here is the caller graph for this function:

GtkLabel* mi_find_label ( GtkWidget *  mi)

Definition at line 180 of file window-menu-model.c.

{
       if (GTK_IS_LABEL(mi)) {
              return GTK_LABEL(mi);
       }

       GtkLabel * retval = NULL;

       if (GTK_IS_CONTAINER(mi)) {
              GList * children = gtk_container_get_children(GTK_CONTAINER(mi));
              GList * child = children;

              while (child != NULL && retval == NULL) {
                     if (GTK_IS_WIDGET(child->data)) {
                            retval = mi_find_label(GTK_WIDGET(child->data));
                     }
                     child = g_list_next(child);
              }

              g_list_free(children);
       }

       return retval;
}

Here is the caller graph for this function:

GtkMenu* mi_find_menu ( GtkMenuItem *  mi)

Definition at line 235 of file window-menu-model.c.

{
       GtkWidget * retval = gtk_menu_item_get_submenu(mi);
       if (GTK_IS_MENU(retval)) {
              return GTK_MENU(retval);
       } else {
              return NULL;
       }
}

Here is the caller graph for this function:

static void window_menu_model_class_init ( WindowMenuModelClass *  klass) [static]

Definition at line 81 of file window-menu-model.c.

{
       GObjectClass *object_class = G_OBJECT_CLASS (klass);

       g_type_class_add_private (klass, sizeof (WindowMenuModelPrivate));

       object_class->dispose = window_menu_model_dispose;
       object_class->finalize = window_menu_model_finalize;

       WindowMenuClass * wm_class = WINDOW_MENU_CLASS(klass);

       wm_class->get_entries = get_entries;
       wm_class->get_location = get_location;
       wm_class->get_status = get_status;
       wm_class->get_error_state = get_error_state;
       wm_class->get_xid = get_xid;

       return;
}

Here is the call graph for this function:

static void window_menu_model_dispose ( GObject *  object) [static]

Definition at line 113 of file window-menu-model.c.

{
       WindowMenuModel * menu = WINDOW_MENU_MODEL(object);

       g_clear_object(&menu->priv->action_mux);
       g_clear_object(&menu->priv->accel_group);

       /* Application Menu */
       g_clear_object(&menu->priv->app_menu_model);
       g_clear_object(&menu->priv->application_menu.label);
       g_clear_object(&menu->priv->application_menu.menu);

       /* Window Menus */
       if (menu->priv->win_menu_insert != 0) {
              g_signal_handler_disconnect(menu->priv->win_menu, menu->priv->win_menu_insert);
              menu->priv->win_menu_insert = 0;
       }

       if (menu->priv->win_menu_remove != 0) {
              g_signal_handler_disconnect(menu->priv->win_menu, menu->priv->win_menu_remove);
              menu->priv->win_menu_remove = 0;
       }

       g_clear_object(&menu->priv->win_menu_model);
       g_clear_object(&menu->priv->win_menu);

       G_OBJECT_CLASS (window_menu_model_parent_class)->dispose (object);
       return;
}

Here is the caller graph for this function:

static void window_menu_model_finalize ( GObject *  object) [static]

Definition at line 144 of file window-menu-model.c.

{

       G_OBJECT_CLASS (window_menu_model_parent_class)->finalize (object);
       return;
}

Here is the caller graph for this function:

static void window_menu_model_init ( WindowMenuModel *  self) [static]

Definition at line 102 of file window-menu-model.c.

{
       self->priv = WINDOW_MENU_MODEL_GET_PRIVATE(self);

       self->priv->action_mux = g_action_muxer_new();
       self->priv->accel_group = gtk_accel_group_new();

       return;
}

Here is the call graph for this function:

WindowMenuModel* window_menu_model_new ( BamfApplication *  app,
BamfWindow *  window 
)

Definition at line 449 of file window-menu-model.c.

{
       g_return_val_if_fail(BAMF_IS_APPLICATION(app), NULL);
       g_return_val_if_fail(BAMF_IS_WINDOW(window), NULL);

       WindowMenuModel * menu = g_object_new(WINDOW_MENU_MODEL_TYPE, NULL);

       menu->priv->xid = bamf_window_get_xid(window);

       gchar *unique_bus_name;
       gchar *app_menu_object_path;
       gchar *menubar_object_path;
       gchar *application_object_path;
       gchar *window_object_path;
       GDBusConnection *session;

       unique_bus_name = bamf_window_get_utf8_prop (window, "_GTK_UNIQUE_BUS_NAME");

       if (unique_bus_name == NULL) {
              /* If this isn't set, we won't get very far... */
              return NULL;
       }

       app_menu_object_path = bamf_window_get_utf8_prop (window, "_GTK_APP_MENU_OBJECT_PATH");
       menubar_object_path = bamf_window_get_utf8_prop (window, "_GTK_MENUBAR_OBJECT_PATH");
       application_object_path = bamf_window_get_utf8_prop (window, "_GTK_APPLICATION_OBJECT_PATH");
       window_object_path = bamf_window_get_utf8_prop (window, "_GTK_WINDOW_OBJECT_PATH");

       session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);

       /* Setup actions */
       if (application_object_path != NULL) {
              g_action_muxer_insert(menu->priv->action_mux, ACTION_MUX_PREFIX_APP, G_ACTION_GROUP(g_dbus_action_group_get (session, unique_bus_name, application_object_path)));
       }

       if (window_object_path != NULL) {
              g_action_muxer_insert(menu->priv->action_mux, ACTION_MUX_PREFIX_WIN, G_ACTION_GROUP(g_dbus_action_group_get (session, unique_bus_name, window_object_path)));
       }

       /* Build us some menus */
       if (app_menu_object_path != NULL) {
              const gchar * desktop_path = bamf_application_get_desktop_file(app);
              gchar * app_name = NULL;

              if (desktop_path != NULL) {
                     GDesktopAppInfo * desktop = g_desktop_app_info_new_from_filename(desktop_path);

                     if (desktop != NULL) {
                            app_name = g_strdup(g_app_info_get_name(G_APP_INFO(desktop)));

                            g_object_unref(desktop);
                     }
              }

              GMenuModel * model = G_MENU_MODEL(g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path));

              add_application_menu(menu, app_name, model);

              g_object_unref(model);
              g_free(app_name);
       }

       if (menubar_object_path != NULL) {
              GMenuModel * model = G_MENU_MODEL(g_dbus_menu_model_get (session, unique_bus_name, menubar_object_path));

              add_window_menu(menu, model);

              g_object_unref(model);
       }

       /* when the action groups change, we could end up having items
        * enabled/disabled.  how to deal with that?
        */

       g_free (unique_bus_name);
       g_free (app_menu_object_path);
       g_free (menubar_object_path);
       g_free (application_object_path);
       g_free (window_object_path);

       g_object_unref (session);

       return menu;
}

Here is the call graph for this function: