How to copy a widget?

Is it possible to copy a widget, that is, given a widget, can I get a completely new widget with same properties as that of the given widget?

My use case is, I have a GtkImage and want to get a copy of it. How can I achieve it?

You can’t copy a widget in the way you’re thinking. Just do it manually, since that’s all that would happen with a “copy” function anyways.

Could you elaborate more with an example of what exactly are trying to achieve?

Yep sure. I have a GtkImage. It is returned by a function and has to be added at two places at the same time.
I can make the function return two copies of the image, but to remain consistent (in my program, all the other programs return only one widget, and the requirement of two copies, is a special case), I don’t want to change the pattern to return two widgets. So I wonder if there is any method to copy the properties of a GtkImage (only visible properties, like image, size etc. and not programmable properties like signals, name, parent etc.)

Well I am not an expert of understanding (probably because I speak daily 4 Languages), but I came up with a CRAZY example which probably can help you to give you an Idea.

The following program creates a Window, puts a grid inside it.
The grid adds two Objects, a Button and a Label.

With the Help of GQuark and g_object_set|get_qdata() functions I create a connection of the Label with the Button and the Window, but not with the Grid.

Now we have 4 funcitons.

The function clicked_callback gets only the Button, and extracts the information (the Label in this case, but it can be a GtkImage) from it with the help of the GQuark and apply some changes on the Label (sets the label tex and angle property ) and print those changes to the console.
In other words, click the Button and see the Changes.

Next function “function_foo_1()” Gets the Label with the help of the buffer used for the Quark KEY from the Window Object and monitors the “copy-clipboard” signal and calls the copy_callback() function.

The next function “function_foo_2()” takes only one argument and does not care about buffer identifier of the key set on Quark and does the whole work inside it.

This implies that it needs to iterate all its children to find if one of them has a Label, if found checks if the label holds he Quark and if it has that Quark…well you have access to the Label :).
At this point the angle property will be set to 180.0.

Here is the Whole program, just comment out those functions and see it how it works.
and of course use right click and copy in the label to monitor that Signal.

#include <gtk/gtk.h>

void copy_callback( GtkLabel *label );
void clicked_callback ( GtkButton *button );
void function_foo_1( GtkWidget *window, const gchar *const data );
void function_foo_2( GtkWidget *grid );

int main ( void )
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *button;
    GtkWidget *label;

    /// ***
    gtk_init ( NULL, NULL );

    /// *** Create a Window
    window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
    gtk_window_set_default_size ( GTK_WINDOW ( window ), 250, 150 );

    /// Create a Grid
    grid = gtk_grid_new();
    gtk_grid_set_column_homogeneous( GTK_GRID( grid ), TRUE );
    gtk_container_add( GTK_CONTAINER( window ), grid );

    /// create a Button
    button  = gtk_button_new_with_mnemonic( "Click Me!" );
    g_signal_connect_swapped ( button, "clicked", G_CALLBACK ( clicked_callback ), button );
    g_object_set ( button, "margin", 25, NULL );

    /// *** Create a Label for the Button
    label = gtk_label_new_with_mnemonic( "Hello There" );
    g_object_set( label, "selectable", TRUE, NULL );

    /// *** Attach the Button and the Label to the Grid
    gtk_grid_attach( GTK_GRID( grid ), button, 0, 0, 1, 1 );
    gtk_grid_attach( GTK_GRID( grid ), label,  0, 1, 1, 1 );

    /// Create a Quark and use "label_data" as KEY
    GQuark quark;
    const gchar *const buffer = "label_data";

    quark = g_quark_from_string( buffer );
    g_object_set_qdata( G_OBJECT( window ), quark, label );
    g_object_set_qdata( G_OBJECT( button ), quark, label );

    /// *** Function to modify the label properties
    /// comment it out to see its work
    ///function_foo_1 ( window, buffer );

    /// *** Function to modify the label properties
    /// comment it out to see its work
    ///function_foo_2 ( grid );

    gtk_widget_show_all ( window );
    gtk_main ();
}

void clicked_callback ( GtkButton *button )
{
    g_return_if_fail( button );
    GQuark quark;
    static gboolean flag = FALSE;
    quark = g_quark_from_string ("label_data" );

    GtkLabel *label = g_object_get_qdata (G_OBJECT ( button ), quark );

    if ( flag == FALSE )
    {
        gtk_label_set_label( label, "Have a nice day" );
        g_object_set( label, "angle", 0, NULL );
        g_print( "Now the label Text is: %s\n", gtk_label_get_label( label ) );

        flag = TRUE;
    }
    else
    {
        gtk_label_set_label( label, "Welcome to the GTK+ World" );
        g_print( "Now the label Text is: %s\n", gtk_label_get_label( label ) );
        flag = FALSE;
    }
}

void function_foo_1( GtkWidget *window, const gchar *const data )
{
    g_return_if_fail( GTK_IS_WINDOW( window ) );

    GQuark quark;
    GtkLabel *label = NULL;

    quark = g_quark_from_string( data );
    label = g_object_get_qdata( G_OBJECT( window ), quark );

    if ( label )
    {
        g_signal_connect_swapped( label, "copy-clipboard", G_CALLBACK( copy_callback ), label );
    }
}

void copy_callback( GtkLabel *label )
{
    g_return_if_fail( GTK_IS_LABEL( label ) );
    g_print( "the Copy-clicpboard signal was chatched\n" );

}

void function_foo_2( GtkWidget *grid )
{
    g_return_if_fail( GTK_IS_GRID( grid ) );
    GQuark quark;
    quark = g_quark_from_string( "label_data" );

    GList *children;
    children = gtk_container_get_children( GTK_CONTAINER( grid ) );

    GtkLabel *label = NULL;

    while ( children )
    {
        /// I know one Buttoon has the information I need
        /// Is this Button the right one?
        if ( GTK_IS_BUTTON( children->data ) )
        {
            /// If we found the Button
            /// Does this Button holds the needed Information I need?
            label = g_object_get_qdata( G_OBJECT( children->data ), quark );
            if ( label )
            {
                g_object_set( label, "angle", 180.0, NULL );
                g_print( "You just changed the angle propertys\n" );
            }
        }
        children = children->next;
    }

    g_free( children );
}

If you need to more informations aboutt GQaurk I have a playlist on my Channel for it.

As you can see none of those functions (except the callback one) takes a label as argument.
Happy Coding!

1 Like

This is definitely pretty amazing! I’ll run the code and see. Maybe, I think, I should drop the idea of “copying”, I thought of a few look-around, for the issue. Thanks again :slight_smile:

1 Like