void eom_plugin_engine_update_plugins_ui (EomWindow *window, gboolean new_window) { GList *pl; eom_debug (DEBUG_PLUGINS); g_return_if_fail (EOM_IS_WINDOW (window)); if (new_window) reactivate_all (window); /* Updated ui of all the plugins that implement update_ui */ for (pl = eom_plugins_list; pl; pl = pl->next) { EomPluginInfo *info = (EomPluginInfo*)pl->data; if (!info->available || !info->active) continue; eom_debug_message (DEBUG_PLUGINS, "Updating UI of %s", info->name); eom_plugin_update_ui (info->plugin, window); } }
const GList * eom_plugin_engine_get_plugins_list (void) { eom_debug (DEBUG_PLUGINS); return eom_plugins_list; }
static void reactivate_all (EomWindow *window) { GList *pl; eom_debug (DEBUG_PLUGINS); for (pl = eom_plugins_list; pl; pl = pl->next) { gboolean res = TRUE; EomPluginInfo *info = (EomPluginInfo*)pl->data; /* If plugin is not available, don't try to activate/load it */ if (info->available && info->active) { if (info->plugin == NULL) res = load_plugin_module (info); if (res) eom_plugin_activate (info->plugin, window); } } eom_debug_message (DEBUG_PLUGINS, "End"); }
gboolean eom_plugin_engine_init (void) { eom_debug (DEBUG_PLUGINS); g_return_val_if_fail (eom_plugins_list == NULL, FALSE); if (!g_module_supported ()) { g_warning ("eom is not able to initialize the plugins engine."); return FALSE; } eom_plugin_engine_settings = g_settings_new (EOM_CONF_PLUGINS); g_signal_connect (eom_plugin_engine_settings, "changed::" EOM_CONF_PLUGINS_ACTIVE_PLUGINS, G_CALLBACK (eom_plugin_engine_active_plugins_changed), NULL); eom_plugin_engine_get_active_plugins (); eom_plugin_engine_load_all (); return TRUE; }
static void free_window_data(WindowData* data) { g_return_if_fail(data != NULL); eom_debug(DEBUG_PLUGINS); g_free(data); }
gboolean eom_plugin_engine_plugin_is_configurable (EomPluginInfo *info) { eom_debug (DEBUG_PLUGINS); g_return_val_if_fail (info != NULL, FALSE); if ((info->plugin == NULL) || !info->active || !info->available) return FALSE; return eom_plugin_is_configurable (info->plugin); }
static void plugin_manager_toggle_active (GtkTreeIter *iter, GtkTreeModel *model) { gboolean active; eom_debug (DEBUG_PLUGINS); gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1); active ^= 1; plugin_manager_set_active (iter, model, active); }
gboolean eom_plugin_engine_deactivate_plugin (EomPluginInfo *info) { gboolean res; GSList *list; eom_debug (DEBUG_PLUGINS); g_return_val_if_fail (info != NULL, FALSE); if (!info->active || !info->available) return TRUE; eom_plugin_engine_deactivate_plugin_real (info); /* Update plugin state */ info->active = FALSE; list = active_plugins; res = (list == NULL); while (list != NULL) { if (strcmp (info->location, (gchar *)list->data) == 0) { g_free (list->data); active_plugins = g_slist_delete_link (active_plugins, list); list = NULL; res = TRUE; } else { list = g_slist_next (list); } } if (!res) { g_warning ("Plugin '%s' is already deactivated.", info->name); return TRUE; } GArray *array; GSList *l; array = g_array_new (TRUE, TRUE, sizeof (gchar *)); for (l = active_plugins; l; l = l->next) { array = g_array_append_val (array, l->data); } g_settings_set_strv (eom_plugin_engine_settings, EOM_CONF_PLUGINS_ACTIVE_PLUGINS, (const gchar **) array->data); g_array_free (array, TRUE); return TRUE; }
gboolean eom_plugin_engine_activate_plugin (EomPluginInfo *info) { eom_debug (DEBUG_PLUGINS); g_return_val_if_fail (info != NULL, FALSE); if (!info->available) return FALSE; if (info->active) return TRUE; if (eom_plugin_engine_activate_plugin_real (info)) { GSList *list; /* Update plugin state */ info->active = TRUE; list = active_plugins; while (list != NULL) { if (strcmp (info->location, (gchar *)list->data) == 0) { g_warning ("Plugin '%s' is already active.", info->name); return TRUE; } list = g_slist_next (list); } active_plugins = g_slist_insert_sorted (active_plugins, g_strdup (info->location), (GCompareFunc)strcmp); GArray *array; GSList *l; array = g_array_new (TRUE, TRUE, sizeof (gchar *)); for (l = active_plugins; l; l = l->next) { array = g_array_append_val (array, l->data); } g_settings_set_strv (eom_plugin_engine_settings, EOM_CONF_PLUGINS_ACTIVE_PLUGINS, (const gchar **) array->data); g_array_free (array, TRUE); return TRUE; } return FALSE; }
static void cursor_changed_cb (GtkTreeView *view, gpointer data) { EomPluginManager *pm = data; EomPluginInfo *info; eom_debug (DEBUG_PLUGINS); info = plugin_manager_get_selected_plugin (pm); gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->about_button), info != NULL); gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button), (info != NULL) && eom_plugin_engine_plugin_is_configurable (info)); }
static void plugin_manager_populate_lists (EomPluginManager *pm) { const GList *plugins; GtkListStore *model; GtkTreeIter iter; eom_debug (DEBUG_PLUGINS); plugins = pm->priv->plugins; model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree))); while (plugins) { EomPluginInfo *info; info = (EomPluginInfo *)plugins->data; gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, ACTIVE_COLUMN, eom_plugin_engine_plugin_is_active (info), AVAILABLE_COLUMN, eom_plugin_engine_plugin_is_available (info), INFO_COLUMN, info, -1); plugins = plugins->next; } if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) { GtkTreeSelection *selection; EomPluginInfo* info; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree)); g_return_if_fail (selection != NULL); gtk_tree_selection_select_iter (selection, &iter); gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, INFO_COLUMN, &info, -1); gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button), eom_plugin_engine_plugin_is_configurable (info)); } }
static void plugin_manager_set_active_all (EomPluginManager *pm, gboolean active) { GtkTreeModel *model; GtkTreeIter iter; eom_debug (DEBUG_PLUGINS); model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)); g_return_if_fail (model != NULL); gtk_tree_model_get_iter_first (model, &iter); do { plugin_manager_set_active (&iter, model, active); } while (gtk_tree_model_iter_next (model, &iter)); }
static void about_button_cb (GtkWidget *button, EomPluginManager *pm) { EomPluginInfo *info; eom_debug (DEBUG_PLUGINS); info = plugin_manager_get_selected_plugin (pm); g_return_if_fail (info != NULL); /* If there is another about dialog already open destroy it */ if (pm->priv->about) gtk_widget_destroy (pm->priv->about); pm->priv->about = g_object_new (GTK_TYPE_ABOUT_DIALOG, "program-name" , eom_plugin_engine_get_plugin_name (info), "copyright", eom_plugin_engine_get_plugin_copyright (info), "authors", eom_plugin_engine_get_plugin_authors (info), "comments", eom_plugin_engine_get_plugin_description (info), "website", eom_plugin_engine_get_plugin_website (info), "logo-icon-name", eom_plugin_engine_get_plugin_icon_name (info), NULL); gtk_window_set_destroy_with_parent (GTK_WINDOW (pm->priv->about), TRUE); g_signal_connect (pm->priv->about, "response", G_CALLBACK (gtk_widget_destroy), NULL); g_signal_connect (pm->priv->about, "destroy", G_CALLBACK (gtk_widget_destroyed), &pm->priv->about); gtk_window_set_transient_for (GTK_WINDOW (pm->priv->about), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm)))); gtk_widget_show (pm->priv->about); }
static gboolean plugin_manager_set_active (GtkTreeIter *iter, GtkTreeModel *model, gboolean active) { EomPluginInfo *info; gboolean res = TRUE; eom_debug (DEBUG_PLUGINS); gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1); g_return_val_if_fail (info != NULL, FALSE); if (active) { /* Activate the plugin */ if (!eom_plugin_engine_activate_plugin (info)) { eom_debug_message (DEBUG_PLUGINS, "Could not activate %s.\n", eom_plugin_engine_get_plugin_name (info)); res = FALSE; } } else { /* Deactivate the plugin */ if (!eom_plugin_engine_deactivate_plugin (info)) { eom_debug_message (DEBUG_PLUGINS, "Could not deactivate %s.\n", eom_plugin_engine_get_plugin_name (info)); res = FALSE; } } /* Set new value */ gtk_list_store_set (GTK_LIST_STORE (model), iter, ACTIVE_COLUMN, eom_plugin_engine_plugin_is_active (info), AVAILABLE_COLUMN, eom_plugin_engine_plugin_is_available (info), -1); return res; }
static void eom_plugin_engine_active_plugins_changed (GSettings *settings, gchar *key, gpointer user_data) { GList *pl; gboolean to_activate; eom_debug (DEBUG_PLUGINS); g_return_if_fail (settings != NULL); g_return_if_fail (key != NULL); eom_plugin_engine_get_active_plugins (); for (pl = eom_plugins_list; pl; pl = pl->next) { EomPluginInfo *info = (EomPluginInfo*)pl->data; if (!info->available) continue; to_activate = (g_slist_find_custom (active_plugins, info->location, (GCompareFunc)strcmp) != NULL); if (!info->active && to_activate) { /* Activate plugin */ if (eom_plugin_engine_activate_plugin_real (info)) /* Update plugin state */ info->active = TRUE; } else { if (info->active && !to_activate) { eom_plugin_engine_deactivate_plugin_real (info); /* Update plugin state */ info->active = FALSE; } } } }
static void row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) { EomPluginManager *pm = data; GtkTreeIter iter; GtkTreeModel *model; eom_debug (DEBUG_PLUGINS); model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)); g_return_if_fail (model != NULL); gtk_tree_model_get_iter (model, &iter, path); g_return_if_fail (&iter != NULL); plugin_manager_toggle_active (&iter, model); }
static void eom_statusbar_date_plugin_activate (EomWindowActivatable *activatable) { EomStatusbarDatePlugin *plugin = EOM_STATUSBAR_DATE_PLUGIN (activatable); EomWindow *window = plugin->window; GtkWidget *statusbar = eom_window_get_statusbar (window); GtkWidget *thumbview = eom_window_get_thumb_view (window); eom_debug (DEBUG_PLUGINS); plugin->statusbar_date = gtk_statusbar_new (); gtk_widget_set_size_request (plugin->statusbar_date, 200, 10); gtk_widget_set_margin_top (GTK_WIDGET (plugin->statusbar_date), 0); gtk_widget_set_margin_bottom (GTK_WIDGET (plugin->statusbar_date), 0); gtk_box_pack_end (GTK_BOX (statusbar), plugin->statusbar_date, FALSE, FALSE, 0); plugin->signal_id = g_signal_connect_after (G_OBJECT (thumbview), "selection_changed", G_CALLBACK (selection_changed_cb), plugin); statusbar_set_date (GTK_STATUSBAR (plugin->statusbar_date), EOM_THUMB_VIEW (eom_window_get_thumb_view (window))); }
static void configure_button_cb (GtkWidget *button, EomPluginManager *pm) { EomPluginInfo *info; GtkWindow *toplevel; eom_debug (DEBUG_PLUGINS); info = plugin_manager_get_selected_plugin (pm); g_return_if_fail (info != NULL); eom_debug_message (DEBUG_PLUGINS, "Configuring: %s\n", eom_plugin_engine_get_plugin_name (info)); toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm))); eom_plugin_engine_configure_plugin (info, toplevel); eom_debug_message (DEBUG_PLUGINS, "Done"); }
static void impl_activate(EomPlugin* plugin, EomWindow* window) { GtkWidget* statusbar = eom_window_get_statusbar(window); GtkWidget* thumbview = eom_window_get_thumb_view(window); WindowData* data; eom_debug(DEBUG_PLUGINS); data = g_new(WindowData, 1); data->statusbar_date = gtk_statusbar_new(); gtk_widget_set_size_request(data->statusbar_date, 200, 10); #if GTK_CHECK_VERSION (3, 0, 0) gtk_widget_set_margin_top (GTK_WIDGET (data->statusbar_date), 0); gtk_widget_set_margin_bottom (GTK_WIDGET (data->statusbar_date), 0); #endif gtk_box_pack_end(GTK_BOX(statusbar), data->statusbar_date, FALSE, FALSE, 0); data->signal_id = g_signal_connect_after(G_OBJECT(thumbview), "selection_changed", G_CALLBACK(selection_changed_cb), data); statusbar_set_date(GTK_STATUSBAR(data->statusbar_date), EOM_THUMB_VIEW(eom_window_get_thumb_view(window))); g_object_set_data_full(G_OBJECT(window), WINDOW_DATA_KEY, data, (GDestroyNotify) free_window_data); }
void eom_plugin_engine_configure_plugin (EomPluginInfo *info, GtkWindow *parent) { GtkWidget *conf_dlg; GtkWindowGroup *wg; eom_debug (DEBUG_PLUGINS); g_return_if_fail (info != NULL); conf_dlg = eom_plugin_create_configure_dialog (info->plugin); g_return_if_fail (conf_dlg != NULL); gtk_window_set_transient_for (GTK_WINDOW (conf_dlg), parent); // Will return a default group if no group is set wg = gtk_window_get_group (parent); // For now assign a dedicated window group if it is // the default one until we know if this is really needed if (wg == gtk_window_get_group (NULL)) { wg = gtk_window_group_new (); gtk_window_group_add_window (wg, parent); } gtk_window_group_add_window (wg, GTK_WINDOW (conf_dlg)); gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE); gtk_widget_show (conf_dlg); }
static EomPluginInfo * plugin_manager_get_selected_plugin (EomPluginManager *pm) { EomPluginInfo *info = NULL; GtkTreeModel *model; GtkTreeIter iter; GtkTreeSelection *selection; eom_debug (DEBUG_PLUGINS); model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)); g_return_val_if_fail (model != NULL, NULL); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree)); g_return_val_if_fail (selection != NULL, NULL); if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1); } return info; }
void eom_plugin_engine_shutdown (void) { GList *pl; eom_debug (DEBUG_PLUGINS); #ifdef ENABLE_PYTHON /* Note: that this may cause finalization of objects (typically * the EomWindow) by running the garbage collector. Since some * of the plugin may have installed callbacks upon object * finalization (typically they need to free the WindowData) * it must run before we get rid of the plugins. */ eom_python_shutdown (); #endif g_return_if_fail (eom_plugin_engine_settings != NULL); for (pl = eom_plugins_list; pl; pl = pl->next) { EomPluginInfo *info = (EomPluginInfo*) pl->data; eom_plugin_info_free (info); } g_slist_foreach (active_plugins, (GFunc)g_free, NULL); g_slist_free (active_plugins); active_plugins = NULL; g_list_free (eom_plugins_list); eom_plugins_list = NULL; g_object_unref (eom_plugin_engine_settings); eom_plugin_engine_settings = NULL; }
static void active_toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, EomPluginManager *pm) { GtkTreeIter iter; GtkTreePath *path; GtkTreeModel *model; eom_debug (DEBUG_PLUGINS); path = gtk_tree_path_new_from_string (path_str); model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)); g_return_if_fail (model != NULL); gtk_tree_model_get_iter (model, &iter, path); if (&iter != NULL) plugin_manager_toggle_active (&iter, model); gtk_tree_path_free (path); }
static void eom_plugin_manager_init (EomPluginManager *pm) { GtkWidget *label; GtkWidget *viewport; GtkWidget *hbuttonbox; eom_debug (DEBUG_PLUGINS); pm->priv = EOM_PLUGIN_MANAGER_GET_PRIVATE (pm); gtk_box_set_spacing (GTK_BOX (pm), 6); label = gtk_label_new_with_mnemonic (_("Active _Plugins:")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (pm), label, FALSE, TRUE, 0); viewport = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport), GTK_SHADOW_IN); gtk_box_pack_start (GTK_BOX (pm), viewport, TRUE, TRUE, 0); pm->priv->tree = gtk_tree_view_new (); gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree); gtk_label_set_mnemonic_widget (GTK_LABEL (label), pm->priv->tree); hbuttonbox = gtk_hbutton_box_new (); gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END); gtk_box_set_spacing (GTK_BOX (hbuttonbox), 8); pm->priv->about_button = gtk_button_new_with_mnemonic (_("_About Plugin")); gtk_button_set_image (GTK_BUTTON (pm->priv->about_button), gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_BUTTON)); gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->about_button); pm->priv->configure_button = gtk_button_new_with_mnemonic (_("C_onfigure Plugin")); gtk_button_set_image (GTK_BUTTON (pm->priv->configure_button), gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_BUTTON)); gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button); gtk_widget_set_size_request (GTK_WIDGET (viewport), 270, 100); g_signal_connect (pm->priv->about_button, "clicked", G_CALLBACK (about_button_cb), pm); g_signal_connect (pm->priv->configure_button, "clicked", G_CALLBACK (configure_button_cb), pm); plugin_manager_construct_tree (pm); /* Get the list of available plugins (or installed) */ pm->priv->plugins = eom_plugin_engine_get_plugins_list (); if (pm->priv->plugins != NULL) { plugin_manager_populate_lists (pm); } else { gtk_widget_set_sensitive (pm->priv->about_button, FALSE); gtk_widget_set_sensitive (pm->priv->configure_button, FALSE); } }
static gboolean load_plugin_module (EomPluginInfo *info) { gchar *path; gchar *dirname; eom_debug (DEBUG_PLUGINS); g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (info->file != NULL, FALSE); g_return_val_if_fail (info->location != NULL, FALSE); g_return_val_if_fail (info->plugin == NULL, FALSE); g_return_val_if_fail (info->available, FALSE); switch (info->loader) { case EOM_PLUGIN_LOADER_C: dirname = g_path_get_dirname (info->file); g_return_val_if_fail (dirname != NULL, FALSE); path = g_module_build_path (dirname, info->location); g_free (dirname); g_return_val_if_fail (path != NULL, FALSE); info->module = G_TYPE_MODULE (eom_module_new (path)); g_free (path); break; #ifdef ENABLE_PYTHON case EOM_PLUGIN_LOADER_PY: { gchar *dir; if (!eom_python_init ()) { /* Mark plugin as unavailable and fails */ info->available = FALSE; g_warning ("Cannot load Python plugin '%s' since eom " "was not able to initialize the Python interpreter.", info->name); return FALSE; } g_return_val_if_fail ((info->location != NULL) && (info->location[0] != '\0'), FALSE); dir = g_path_get_dirname (info->file); info->module = G_TYPE_MODULE ( eom_python_module_new (dir, info->location)); g_free (dir); break; } #endif default: g_return_val_if_reached (FALSE); } if (!g_type_module_use (info->module)) { switch (info->loader) { case EOM_PLUGIN_LOADER_C: g_warning ("Cannot load plugin '%s' since file '%s' cannot be read.", info->name, eom_module_get_path (EOM_MODULE (info->module))); break; case EOM_PLUGIN_LOADER_PY: g_warning ("Cannot load Python plugin '%s' since file '%s' cannot be read.", info->name, info->location); break; default: g_return_val_if_reached (FALSE); } g_object_unref (G_OBJECT (info->module)); info->module = NULL; /* Mark plugin as unavailable and fails */ info->available = FALSE; return FALSE; } switch (info->loader) { case EOM_PLUGIN_LOADER_C: info->plugin = EOM_PLUGIN (eom_module_new_object (EOM_MODULE (info->module))); break; #ifdef ENABLE_PYTHON case EOM_PLUGIN_LOADER_PY: info->plugin = EOM_PLUGIN (eom_python_module_new_object (EOM_PYTHON_MODULE (info->module))); break; #endif default: g_return_val_if_reached (FALSE); } g_type_module_unuse (info->module); eom_debug_message (DEBUG_PLUGINS, "End"); return TRUE; }
static void plugin_manager_construct_tree (EomPluginManager *pm) { GtkTreeViewColumn *column; GtkCellRenderer *cell; GtkListStore *model; eom_debug (DEBUG_PLUGINS); model = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER); gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree), GTK_TREE_MODEL (model)); g_object_unref (model); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pm->priv->tree), FALSE); /* First column */ cell = gtk_cell_renderer_toggle_new (); g_object_set (cell, "xpad", 6, NULL); g_signal_connect (cell, "toggled", G_CALLBACK (active_toggled_cb), pm); column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE, cell, "active", ACTIVE_COLUMN, "activatable", AVAILABLE_COLUMN, "sensitive", AVAILABLE_COLUMN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column); /* Second column */ column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, PLUGIN_MANAGER_NAME_TITLE); gtk_tree_view_column_set_resizable (column, TRUE); cell = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, cell, FALSE); g_object_set (cell, "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR, NULL); gtk_tree_view_column_set_cell_data_func (column, cell, plugin_manager_view_icon_cell_cb, pm, NULL); cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, cell, TRUE); g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); gtk_tree_view_column_set_cell_data_func (column, cell, plugin_manager_view_info_cell_cb, pm, NULL); gtk_tree_view_column_set_spacing (column, 6); gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column); /* Sort on the plugin names */ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), model_name_sort_func, NULL, NULL); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); /* Enable search for our non-string column */ gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree), INFO_COLUMN); gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree), name_search_cb, NULL, NULL); g_signal_connect (pm->priv->tree, "cursor_changed", G_CALLBACK (cursor_changed_cb), pm); g_signal_connect (pm->priv->tree, "row_activated", G_CALLBACK (row_activated_cb), pm); g_signal_connect (pm->priv->tree, "button-press-event", G_CALLBACK (button_press_event_cb), pm); g_signal_connect (pm->priv->tree, "popup-menu", G_CALLBACK (popup_menu_cb), pm); gtk_widget_show (pm->priv->tree); }