Thread: What compilation flags should I use to upgrade from GTK2 to GTK3?

  1. #1
    Registered User
    Join Date
    Dec 2016
    Posts
    30

    What compilation flags should I use to upgrade from GTK2 to GTK3?

    Hi folks,

    Which compilation flags should I use to compile the code in https://www.cairographics.org/threaded_animation_with_cairo/ and force it to use GTK3?


    I tried
    Code:
    gcc threaded_examp.c `pkg-config --cflags --libs gtk+-3.0 --libs gthread-3.0` -Wall -o threaded_examp
    but got:

    Package gthread-3.0 was not found in the pkg-config search path.
    Perhaps you should add the directory containing `gthread-3.0.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'gthread-3.0' found
    I am using a variety of Arch Linux.

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    A logical guess.

    Code:
    `pkg-config --cflags --libs gtk+-3.0`
    NOTE: I would instead use
    Code:
    `pkg-config gtk+-3.0 --cflags --libs`
    Edit1:

    But, to convert this to GTK 3.0
    Code:
    gcc threaded_examp.c `pkg-config --cflags --libs gtk+-2.0 --libs gthread-2.0` -Wall -o threaded_examp
    It would become
    Code:
    gcc threaded_examp.c `pkg-config --cflags --libs gtk+-3.0 --libs gthread-2.0` -Wall -o threaded_examp
    But, I would instead try to use the more standard
    Code:
    gcc threaded_examp.c `pkg-config gtk+-3.0 --cflags --libs gthread-2.0` -Wall -o threaded_examp
    Tim S.
    Last edited by stahta01; 04-04-2017 at 09:49 AM.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  3. #3
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    You cannot compile that code in GTK3. GdkPixmap is deprecated along with many of the related functions. It would need to be rewritten to use a cairo surface instead.

  4. #4
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    Looking at Migrating from GTK+ 2.x to GTK+ 3: GTK+ 3 Reference Manual, also the "gdk_draw_drawable()" function cannot be used.... hum...as a beginner the conversion to GTK3+ truly is out of my reach.

    Does anyone know of a GTK3+ version of https://www.cairographics.org/thread...on_with_cairo/ ? I would need the 'alternative method using signals' part of the code.

  5. #5
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    The code would need to be rewritten almost from scratch since pretty much everything has changed.

    Are you sure you need threads for your application? They are not absolutely necessary for an animation. They just make the UI more responsive.

    What exactly are you trying to do?

  6. #6
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    I am trying to create a program that carries out animations that might change depending on the user input through the GUI buttons, so I guess treads are important!

    These animations should display a mix of pixel data and 2D or 3D lines. You have helped me creating the animations containing pixel data imagery, and I mixed that with the aforementioned threaded cairo code and boom! It was perfect until I realized it was GTK2+ and not GTK3+. Why do I care for GTK3+ so much? It is much better and more modern than GTK2+ right?

    In the past I used Qt with C++, but personally I much prefer the look and feel of GTK programs to Qt. In addition I have a preference for C (even though I am a noob). It is far less complex than C++ whilst having the same or even more power.

    So, since I realise it must be an complete pain in the rear part to adapt code written in GTK2+ to GTK3+ (LXDE indeed seems to be have abandoned GTK, GIMP is having a hard time transitioning to GTK3+, etc...) I am trying to write my program from scratch using GTK3+ ! Would it be easier to include threads in the sample program you wrote How to display a 2D array as an image using GTK3+? ? Would it be better to use cairo in this code to handle the lines and circles? Is this the best way to go? What is your opinion?

  7. #7
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    EDIT to my last answer/post: where it reads "In addition I have a preference for C (even though I am a noob). It is far less complex than C++ whilst having the same or even more power." it should have been "In addition I have a preference for C (even though I am a noob). It is far less complex than C++." Really I have no idea which of these two languages is more 'powerful' (whatever that means) and I really don't care or want to start a battle on this.
    Last edited by hikerFreak; 04-05-2017 at 06:22 PM.

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    You don't necessarily need threads. It depends on exactly what you're trying to do.
    Code:
    // gcc anim.c `pkg-config --cflags --libs gtk+-3.0` -Wall -o anim -lm
    
    #include <gtk/gtk.h>
    #include <math.h>
    
    static cairo_surface_t *surface = NULL;
    
        static gboolean
    on_configure_event(
        GtkWidget         *widget,
        GdkEventConfigure *event,
        gpointer           data)
    {
        static int save_w = 0, save_h = 0;
    
        if (save_w == event->width && save_h == event->height)
            return TRUE;
    
        save_w = event->width;
        save_h = event->height;
    
        if (surface)
            cairo_surface_destroy(surface);
    
        surface = gdk_window_create_similar_surface(
            gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR,
            save_w, save_h);
    
        cairo_t *cr = cairo_create(surface);
        cairo_set_source_rgb(cr, 1, 1, 1);
        cairo_paint(cr);
        cairo_destroy(cr);
    
        return TRUE;
    }
    
        static gboolean
    on_draw(
        GtkWidget *widget,
        cairo_t   *cr,
        gpointer   data)
    {
        cairo_set_source_surface(cr, surface, 0, 0);
        cairo_paint(cr);
        return TRUE;
    }
    
    static gboolean stop_timeout = FALSE;
    
        gboolean
    on_timeout(
        gpointer data)
    {
        if (stop_timeout) return FALSE;
    
        GtkWidget *widget = GTK_WIDGET(data);
        static int ang = 0;
    
        cairo_t *cr = cairo_create(surface);
        cairo_set_source_rgb(cr, 1, 1, 1);
        cairo_paint(cr);
    
        int width = gtk_widget_get_allocated_width(widget);
        int height = gtk_widget_get_allocated_height(widget);
        int x = (int)(width/2.0 * (cos(3.1416/180*ang) + 1));
        int y = (int)(height/2.0 * (sin(3.1416/180*ang) + 1));
        ang = (ang + 2) % 360;
    
        cairo_set_source_rgb(cr, 0, 0, 0);
        cairo_move_to(cr, width/2, height/2);
        cairo_line_to(cr, x, y);
    
        cairo_stroke(cr);
        cairo_destroy(cr);
    
        gtk_widget_queue_draw(GTK_WIDGET(data));
        return TRUE;
    }
    
        static void
    on_destroy(
        void)
    {
        if (surface) cairo_surface_destroy(surface);
    }
    
        static void
    button_clicked(
        GtkWidget *button,
        gpointer   data)
    {
        gtk_button_set_label(GTK_BUTTON(button),
            stop_timeout ? "Stop" : "Start");
        stop_timeout = !stop_timeout;
        if (!stop_timeout)
            g_timeout_add(50, (GSourceFunc)on_timeout, GTK_WINDOW(data));
    }
    
        static void
    on_activate(
        GtkApplication *app,
        gpointer        user_data)
    {
        GtkWidget *window = gtk_application_window_new(app);
        gtk_window_set_title(GTK_WINDOW(window), "Animate");
    
        g_signal_connect(window, "destroy",
            G_CALLBACK(on_destroy), NULL);
    
        GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
        gtk_container_add(GTK_CONTAINER(window), box);
    
        GtkWidget *button = gtk_button_new_with_label("Stop");
        g_signal_connect(GTK_BUTTON(button), "clicked",
            G_CALLBACK(button_clicked), window);
        gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
    
        GtkWidget *drawing_area = gtk_drawing_area_new();
        gtk_widget_set_size_request(drawing_area, 300, 300);
        gtk_box_pack_start(GTK_BOX(box), drawing_area, TRUE, TRUE, 0);
    
        g_signal_connect(drawing_area, "draw",
            G_CALLBACK(on_draw), NULL);
        g_signal_connect(drawing_area,"configure-event",
            G_CALLBACK(on_configure_event), NULL);
    
        g_timeout_add(50, (GSourceFunc)on_timeout, window);
    
        gtk_widget_show_all(window);
    }
    
        int
    main(
        int argc,
        char **argv)
    {
        GtkApplication *app = gtk_application_new("org.gtk.animate",
            G_APPLICATION_FLAGS_NONE);
        g_signal_connect(app, "activate",
            G_CALLBACK(on_activate), NULL);
        int status = g_application_run(G_APPLICATION(app), argc, argv);
        g_object_unref(app);
        return status;
    }

  9. #9
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    Thanks!

    Why is there need for the function on_activate()? I mean... since this function mostly declares widgets and connects these
    with signals, could all the stuff inside
    on_activate() not be written as part of the main() function?

  10. #10
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Possibly, but since you are trying to learn GTK+3 I thought I'd show you the modern way to do it. By doing all that in response to the "activate" event, it will all be done at a very specific time in the application code. Note that main is different from the other programs we've been playing with, e.g., instead of calling gtk_main, we call g_application_run.

    Actually, all the drawing should be done in the "draw" event and only the updating of the inforation should be done in the timer event. Here's a little rewrite.
    Code:
    // gcc anim.c `pkg-config --cflags --libs gtk+-3.0` -Wall -o anim -lm
    
    #include <gtk/gtk.h>
    #include <math.h>
    #include <string.h>
    
    #define PI 3.14159265359
    
    static cairo_surface_t *surface = NULL;
    
        static gboolean
    on_configure_event(
        GtkWidget         *widget,
        GdkEventConfigure *event,
        gpointer           data)
    {
        static int save_w = 0, save_h = 0;
    
        if (save_w == event->width && save_h == event->height)
            return TRUE;
    
        save_w = event->width;
        save_h = event->height;
    
        if (surface)
            cairo_surface_destroy(surface);
    
        surface = gdk_window_create_similar_surface(
            gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR,
            save_w, save_h);
    
        cairo_t *cr = cairo_create(surface);
        cairo_set_source_rgb(cr, 1, 1, 1);
        cairo_paint(cr);
        cairo_destroy(cr);
    
        gtk_widget_queue_draw(widget);
    
        return TRUE;
    }
    
    
    static int ang[3] = {270, 270, 270};
    static gboolean show_line[3] = {TRUE, TRUE, TRUE};
    
    
        static gboolean
    on_draw(
        GtkWidget *widget,
        cairo_t   *cr,
        gpointer   data)
    {
        int half_width = gtk_widget_get_allocated_width(widget) / 2;
        int half_height = gtk_widget_get_allocated_height(widget) / 2;
    
        cairo_t *cr2 = cairo_create(surface);
        cairo_set_source_rgb(cr2, 1, 1, 1);
        cairo_paint(cr2);
    
        for (int i = 0; i < 3; i++) {
            if (!show_line[i]) continue;
            int x = (int)(half_width  * (cos(PI/180*ang[i]) + 1));
            int y = (int)(half_height * (sin(PI/180*ang[i]) + 1));
            cairo_move_to(cr2, half_width, half_height);
            cairo_line_to(cr2, x, y);
            cairo_set_source_rgb(cr2, i==0, i==1, i==2);
            cairo_stroke(cr2);
        }
    
        cairo_destroy(cr2);
    
        cairo_set_source_surface(cr, surface, 0, 0);
        cairo_paint(cr);
    
        return TRUE;
    }
    
    
    static gboolean stop_timeout = FALSE;
    
    
        static gboolean
    on_timeout(
        gpointer data)
    {
        if (stop_timeout) return FALSE;
        for (int i = 0; i < 3; i++)
            ang[i] = (ang[i] + 2*(i+1)) % 360;
        gtk_widget_queue_draw(GTK_WIDGET(data));
        return TRUE;
    }
    
        static void
    on_destroy(
        void)
    {
        if (surface) cairo_surface_destroy(surface);
    }
    
        static void
    button_clicked(
        GtkWidget *button,
        gpointer   data)
    {
        gtk_button_set_label(GTK_BUTTON(button),
            stop_timeout ? "Stop" : "Start");
        stop_timeout = !stop_timeout;
        if (!stop_timeout)
            g_timeout_add(50, (GSourceFunc)on_timeout, GTK_WINDOW(data));
    }
    
    
    static GtkWidget *window;
    
    
        static void
    check_button_toggled(
        GtkWidget *checkbutton,
        gpointer data)
    {
        *(gboolean*)data =
            gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton));
        gtk_widget_queue_draw(GTK_WIDGET(window));
    }
    
        static void
    on_activate(
        GtkApplication *app,
        gpointer        user_data)
    {
        window = gtk_application_window_new(app);
        gtk_window_set_title(GTK_WINDOW(window), "Animate");
    
        g_signal_connect(window, "destroy",
            G_CALLBACK(on_destroy), NULL);
    
        GtkWidget *outerbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
        gtk_container_add(GTK_CONTAINER(window), outerbox);
    
        GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
        gtk_box_pack_start(GTK_BOX(outerbox), box, FALSE, FALSE, 0);
    
        GtkWidget *button = gtk_button_new_with_label("Stop");
        g_signal_connect(GTK_BUTTON(button), "clicked",
            G_CALLBACK(button_clicked), window);
        gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
    
        const gchar *s[3] = {"Red", "Green", "Blue"};
        for (int i = 0; i < 3; i++) {
            button = gtk_check_button_new_with_label(s[i]);
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
            g_signal_connect(button, "toggled",
                G_CALLBACK(check_button_toggled), &show_line[i]);
            gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(button),
                FALSE, FALSE, 0);
        }
    
        GtkWidget *drawing_area = gtk_drawing_area_new();
        gtk_widget_set_size_request(drawing_area, 300, 300);
        gtk_box_pack_start(GTK_BOX(outerbox), drawing_area, TRUE, TRUE, 0);
    
        g_signal_connect(drawing_area, "draw",
            G_CALLBACK(on_draw), NULL);
        g_signal_connect(drawing_area,"configure-event",
            G_CALLBACK(on_configure_event), NULL);
    
        g_timeout_add(50, (GSourceFunc)on_timeout, drawing_area);
    
        gtk_widget_show_all(window);
    }
    
        int
    main(
        int argc,
        char **argv)
    {
        GtkApplication *app = gtk_application_new("org.gtk.animate",
            G_APPLICATION_FLAGS_NONE);
        g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
        int status = g_application_run(G_APPLICATION(app), argc, argv);
        g_object_unref(app);
        return status;
    }

  11. #11
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    Thanks Algorism!

    Just a few more questions about the code:

    By doing all that in response to the "activate" event, it will all be done at a very specific time in the application code. Note that main is different from the other programs we've been playing with, e.g., instead of calling gtk_main, we call g_application_run.
    why is this an advantage in relation to the alternative of declaring the widgets and calling gtk_main() inside the function main()?

    In line 144, you have "g_signal_connect(GTK_BUTTON(button), "clicked",G_CALLBACK(button_clicked), window);"
    why do you call the function GTK_BUTTON() with the argument button?
    I mean, would it not be equivalent to write
    "g_signal_connect(button, "clicked",G_CALLBACK(button_clicked), window);" instead?

    Last edited by hikerFreak; 04-09-2017 at 12:30 PM.

  12. #12
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    The whole GApplication thing is a higher-level concept. It provides extra features that gtk3 has over gtk2. It calls gtk_main internally to run the event loop. Read this.

    I have no idea why I cast button from GtkWidget* to GtkButton* with GTK_BUTTON() when calling g_signal_connect. It's not necessary, but it doesn't hurt since GtkButton "is-a" GtkWidget (in the OOP sense).

  13. #13
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    Thanks

    Two questions I have for C (and C++ for that matter):

    -You have set the variable ang (which is responsible for updating the drawing) to global, using the declaration:

    Code:
    static int ang[3]
    Now...


    1. One alternative to setting it global would be to set ang local to on_activate()), and then it would be called by value or by reference by on_draw(). What are the main advantages and disadvantages of the global declaration approach you have used in comparison to the local declaration approach of ang?


    2. When the function on_draw() is called using

    Code:
    static gboolean g_signal_connect(drawing_area, "draw", G_CALLBACK(on_draw), NULL);
    no arguments are passed onto it (except the NULL pointer of course). However the function declaration accepts several arguments as can be seen in the following declaration:

    Code:
    static gboolean on_draw(GtkWidget *widget,cairo_t *cr,gpointer   data)
    We have not supplied this arguments, yet the code works, the compiler does not complain. I understand that it works since our data (the ang variable) was set to be globally accessible. However is this generally ok to do in C, declaring a function with N parameters and then specifying only part of them as arguments?
    Last edited by hikerFreak; 04-10-2017 at 01:54 AM.

  14. #14
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Firstly, undestand that this is a very quickly written program. If I was taking my time and properly designing it I would consider other possibilities. Although I would probably still use global variables (very common in event-driven non-object-oriented code), I would "hide" them better. A simple possibility is to put them all in a struct to create a pseudo-namespace. Another possibility is to split the program into multiple source files in which the "globals" being static would be hidden (similar to private member variables in a C++ object).

    If by local to on_activate you mean just int ang[3] then that won't work since you can't access a local variable after the function returns. If you mean static int ang[3] then you would have to pass it as the data parameter to both on_timeout and on_draw. Note that we are already passing something to on_timeout. To pass more than one thing, we'd have to pack them in a static struct and pass a pointer to that.

    I'm not sure what you mean by "no arguments are passed in". The function isn't being called by that statement, so there is no way to "pass in" arguments. Only a pointer to the function is being passed, and it's signature is irrelevant since it is hidden by the G_CALLBACK casting macro. However, when it is eventually called by the system, it is called with the proper parameters. The only parameter you have any control over is the data parameter.

  15. #15
    Registered User
    Join Date
    Dec 2016
    Posts
    30
    Thank you once again.

    If I was taking my time and properly designing it I would consider other possibilities. Although I would probably still use global variables (very common in event-driven non-object-oriented code), I would "hide" them better. A simple possibility is to put them all in a struct to create a pseudo-namespace. Another possibility is to split the program into multiple source files in which the "globals" being static would be hidden (similar to private member variables in a C++ object).
    My question really is very basic: why is it good to hide variables? Should programmers generally avoid global variables? If so, in which situations?

    But maybe this is out of the scope of this post!
    Last edited by hikerFreak; 04-10-2017 at 12:05 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to display a 2D array as an image using GTK3+?
    By hikerFreak in forum C Programming
    Replies: 9
    Last Post: 04-02-2017, 05:52 PM
  2. How to design a progress bar button with gtk3 c code?
    By Alireza Alipour in forum C Programming
    Replies: 0
    Last Post: 02-09-2017, 09:54 AM
  3. Which toolkit should I use: gtk2+ or gtk3+?
    By hikerFreak in forum General Discussions
    Replies: 2
    Last Post: 12-10-2016, 02:59 AM
  4. I need help with GTK3 treeviews, and paneviews
    By KoRn KloWn in forum C Programming
    Replies: 6
    Last Post: 01-18-2013, 01:31 PM
  5. linux/gcc/gtk2 programming help
    By solarwind in forum C Programming
    Replies: 0
    Last Post: 02-05-2006, 08:58 PM

Tags for this Thread