clinuxgtkgtk3

GtkTreeStore Subclass, Error When Reloading Plugin


I am working on a plugin written in C using Gtk for a Linux application. I only get errors when attempting to reload the plugin.

So here are the step:

  1. Load plugin - no error
  2. Unload plugin - no error
  3. Load plugin again - errors in console

Here is what I see in the console

(:121962): GLib-GObject-CRITICAL **: 00:16:43.621: cannot register existing type 'ProjectViewTreeStore'

(:121962): GLib-GObject-CRITICAL **: 00:16:43.643: g_type_add_interface_static: assertion 'G_TYPE_IS_INSTANTIATABLE (instance_type)' failed

(:121962): GLib-CRITICAL **: 00:16:43.643: g_once_init_leave_pointer: assertion 'result != 0' failed

(:121962): GLib-GObject-CRITICAL **: 00:16:43.644: g_object_new_with_properties: assertion 'G_TYPE_IS_OBJECT (object_type)' failed

(:121962): Gtk-CRITICAL **: 00:16:43.644: gtk_tree_store_set_column_types: assertion 'GTK_IS_TREE_STORE (tree_store)' failed

Here is the code for the GtkTreeStore subclass:

#pragma once

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define PROJECT_VIEW_TYPE_TREE_STORE                  (project_view_tree_store_get_type())
#define PROJECT_VIEW_TREE_STORE(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PROJECT_VIEW_TYPE_TREE_STORE, ProjectViewTreeStore))
#define PROJECT_VIEW_TREE_STORE_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), PROJECT_VIEW_TYPE_TREE_STORE, ProjectViewTreeStoreClass))
#define PROJECT_VIEW_IS_TREE_STORE(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PROJECT_VIEW_TYPE_TREE_STORE))
#define PROJECT_VIEW_IS_TREE_STORE_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), PROJECT_VIEW_TYPE_TREE_STORE))
#define PROJECT_VIEW_TREE_STORE_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), PROJECT_VIEW_TYPE_TREE_STORE, ProjectViewTreeStoreClass))


typedef struct _ProjectViewTreeStore ProjectViewTreeStore;
typedef struct _ProjectViewTreeStoreClass ProjectViewTreeStoreClass;
typedef struct _ProjectViewTreeStorePrivate ProjectViewTreeStorePrivate;


struct _ProjectViewTreeStore {
    GtkTreeStore parent_instance;
    ProjectViewTreeStorePrivate* priv;
};

struct _ProjectViewTreeStoreClass {
    GtkTreeStoreClass parent_class;
};

ProjectViewTreeStore* project_view_tree_store_new(gint num_cols, GType* types);

void project_view_tree_store_disable_drag_first_row(ProjectViewTreeStore* store, gboolean flag);

G_END_DECLS

Source file:

#include <gtk/gtk.h>
#include "project-view-tree-store.h"

struct _ProjectViewTreeStorePrivate {
    gboolean no_drag_first_row_;
};

static gboolean row_draggable(GtkTreeDragSource* drag_source, GtkTreePath* path);
static gboolean drag_data_get(GtkTreeDragSource* drag_source, GtkTreePath* path, GtkSelectionData* selection_data);
static gboolean drag_data_delete(GtkTreeDragSource* drag_source, GtkTreePath* path);
static void project_view_tree_store_dispose(GObject* object);
static void project_view_tree_store_finalize(GObject* object);

static void gtk_tree_drag_source_interface_init(GtkTreeDragSourceIface* iface) {
    iface->drag_data_delete = drag_data_delete;
    iface->drag_data_get = drag_data_get;
    iface->row_draggable = row_draggable;
}

G_DEFINE_TYPE_WITH_CODE(ProjectViewTreeStore, project_view_tree_store, GTK_TYPE_TREE_STORE, 
    G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_DRAG_SOURCE, gtk_tree_drag_source_interface_init));

static void project_view_tree_store_class_init( ProjectViewTreeStoreClass* klass) {
    printf("%s\n", __func__);
    GObjectClass* obj_class = G_OBJECT_CLASS(klass);
    obj_class->dispose = project_view_tree_store_dispose;
    obj_class->finalize = project_view_tree_store_finalize;
}

static void project_view_tree_store_init(ProjectViewTreeStore* self) {
    printf("%s\n", __func__);
    ProjectViewTreeStorePrivate* priv = project_view_tree_store_get_instance_private(self);
    self->priv = priv;
    self->priv->no_drag_first_row_ = FALSE;
}

ProjectViewTreeStore* project_view_tree_store_new(gint num_cols, GType* types) {
    printf("%s\n", __func__);
    ProjectViewTreeStore* store;
    store = g_object_new(PROJECT_VIEW_TYPE_TREE_STORE, NULL);
    
    gtk_tree_store_set_column_types(&store->parent_instance, num_cols, types);
    return store;
}

void project_view_tree_store_disable_drag_first_row(ProjectViewTreeStore* self, gboolean flag) {
    printf("%s\n", __func__);
    g_return_if_fail(PROJECT_VIEW_IS_TREE_STORE(self));
    self->priv->no_drag_first_row_ = flag;
}

static gboolean row_draggable(GtkTreeDragSource* drag_source, GtkTreePath* path) {
    
    ProjectViewTreeStore* store = PROJECT_VIEW_TREE_STORE(drag_source);
    
    if (store->priv->no_drag_first_row_ && (gtk_tree_path_get_depth(path) == 1)) {
        return FALSE;
    }
    
    return TRUE;
}
  
static gboolean drag_data_get(GtkTreeDragSource* drag_source, GtkTreePath* path, GtkSelectionData* selection_data) {

    ProjectViewTreeStore* store = PROJECT_VIEW_TREE_STORE(drag_source);
    return gtk_tree_drag_source_drag_data_get(GTK_TREE_DRAG_SOURCE(&store->parent_instance), path, selection_data);
}
  
static gboolean drag_data_delete(GtkTreeDragSource* drag_source, GtkTreePath* path) {
    
    ProjectViewTreeStore* store = PROJECT_VIEW_TREE_STORE(drag_source);
    return gtk_tree_drag_source_drag_data_delete(GTK_TREE_DRAG_SOURCE(&store->parent_instance), path);
}

static void project_view_tree_store_dispose(GObject* object) {
    printf("%s\n", __func__);
    G_OBJECT_CLASS(project_view_tree_store_parent_class)->dispose(object);
}

static void project_view_tree_store_finalize(GObject* object) {
    printf("%s\n", __func__);
    G_OBJECT_CLASS(project_view_tree_store_parent_class)->finalize(object);
}

Why is it that no error occurs on the first load? Am I missing something in the subclass?

It appears that maybe my subclass is not 100% right but I really do not know, there really isn't a good A-to-Z tutorial on subclassing Gtk widgets and even the Gtk demo code is not consistent.


Solution

  • Found the solution after so long. I needed the following function call

    plugin_module_make_resident
    

    in my module load function:

    G_MODULE_EXPORT void geany_load_module(GeanyPlugin* plugin) {
        // Step 1: set meta-data
        // <snip>
    
        // Step 2: set functions
        plugin->funcs->init = projectview_v2_init;
        plugin->funcs->cleanup = projectview_v2_cleanup;
        plugin->funcs->configure = NULL;
        plugin->funcs->help = NULL;
        
        // Prevent segfault in plugin when it registers GTypes and gets unloaded
        // and when reloaded tries to re-register the GTypes.
        plugin_module_make_resident(plugin); // <-- needed this call
    
        // Step 3: register
        GEANY_PLUGIN_REGISTER(plugin, 248);
    }
    

    https://www.geany.org/manual/reference/pluginutils_8h.html#ac402e1d165036aaeb5ae1e176e536c36