The use of GtkTargetEntry's target value

I took a look in a lot of projects where GtkTargetEntry is involved

struct GtkTargetEntry
{
    gchar *target;
    guint  flags;
    guint  info;
};

and noticed something strange that almost all programmers took this approach in their applications:

static GtkTargetEntry row_targets[] =
{
    { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW }
};

But this is not right, not as approach ( the target variable is of type char* and not const gchar *) and not from the compiler view as well:

error: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]

I noticed also that some of them just cast it away ( gchar* ) "GTK_TREE_MODEL_ROW".

How should one treat this case? its usage is in this case together with gtk_tree_view_enable_model_drag_source and gtk_tree_view_enable_model_drag_dest.

Something like:

static GtkTargetEntry row_targets[] =
{
    { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW }
};


gint main ( ... )
{
    gtk_tree_view_enable_model_drag_source ( GTK_TREE_VIEW ( treeview ),
            GDK_BUTTON1_MASK,
            row_targets,
            G_N_ELEMENTS ( row_targets ),
            GDK_ACTION_MOVE | GDK_ACTION_COPY );
    gtk_tree_view_enable_model_drag_dest ( GTK_TREE_VIEW ( treeview ),
                                           row_targets,
                                           G_N_ELEMENTS ( row_targets ),
                                           GDK_ACTION_MOVE | GDK_ACTION_COPY );
}

But like is said, the compiler is not happy about it:

error: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]

The GtkTargetEntry structure is an old part of the API, and the meaning of const in C has always been a lot less strict than const in C++. The structure also caters to both static storage allocation and heap allocation, which means it needs to own the data, so that it can free it later on.

In general, if you’re using static strings, you can safely cast away their constness. GTK won’t modify the contents of the GtkTargetEntry structure, anyway.

The alternative is to always allocate GtkTargetEntry structures with gtk_target_entry_new(), and free them when not needed any more with gtk_target_entry_free().

1 Like

This means that this approach is OK?:

gint main ( void )
{
    GtkWidget      *textview;
    GtkTargetEntry *row_targets;
    
    /// ***
    row_targets = gtk_target_entry_new ( "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, 0 );
    
    /// ***
    treeview = gtk_tree_view_new ();
    
    /// ***
    gtk_tree_view_enable_model_drag_source ( GTK_TREE_VIEW ( treeview ),
                                            GDK_BUTTON1_MASK,
                                            row_targets,
                                            sizeof ( GtkTargetEntry ) / sizeof ( *row_targets ),
                                            GDK_ACTION_MOVE | GDK_ACTION_COPY );
            
    /// ***
    gtk_tree_view_enable_model_drag_dest ( GTK_TREE_VIEW ( treeview ),
                                           row_targets,
                                           sizeof ( GtkTargetEntry ) / sizeof ( *row_targets ),
                                           GDK_ACTION_MOVE | GDK_ACTION_COPY );
                                           
    /// ***
    gtk_target_entry_free ( row_targets );
}

I also had to change G_N_ELEMENTS ( row_targets ) because of:

error: division ‘sizeof (GtkTargetEntry * {aka struct _GtkTargetEntry *}) / sizeof (GtkTargetEntry {aka struct _GtkTargetEntry})’ does not compute the number of array elements [-Werror=sizeof-pointer-div]

to:
sizeof ( GtkTargetEntry ) / sizeof ( *row_targets ),
and I hope that is fine.

“Hope” is a bit too thin a thing to rely on, when dealing with C. :wink:

All functions that ask for a GtkTargetEntry in GTK are really asking for an array of GtkTargetEntry; if you allocate a pointer, you’re really allocating an array of 1 element.

If you want to allocate more than one target entry in order to pass it to the GTK API, you will need to do the allocation and freeing yourself:

// Allocate the targets array
GtkTargetEntry *targets = g_new0 (GtkTargetEntry, n_targets)

// Initialize each target
targets[0].target = g_strdup ("foo");
targets[0].flags = ...
targets[0].info = ...

targets[1].target = g_strdup ("bar");
targets[1].flags = ...
targets[1].info = ...

...

// Set the targets
gtk_tree_view_enable_model_drag_dest (treeview, targets, n_targets, action_flags);

 // Free the copied "target" string
for (guint i = 0; i < n_targets; i++)
  g_free (targets[i].target);

// Free the target array
g_free (targets);
1 Like

[quote=“ebassi, post:4, topic:4586”]
“Hope” is a bit too thin a thing to rely on, when dealing with C.
[/quote].
You are definitely right on that one :slight_smile: Thank you.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.