GTK3 regressions from a GTK2 perspective

Iah7 Actually it's possible to have a text inside the progress bar in gtk3 but with another widget.
This is what I managed to hack today with the GtkEntry widget. :slight_smile:
Peek 2020-06-04 21-06

I did not set it to run anything it's just a proof of concept.
Will probably use it on xfce.

gcc -Wall -g timer.c -o timer $(pkg-config --libs --cflags gtk+-3.0)

#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>

GtkWidget *switch_a;
GtkWidget *switch_b;

/* Determines to continue the timer or not */
static gboolean continue_timer = FALSE;

/* Determines if the timer has started */
static gboolean start_timer = TRUE;

/* Display seconds expired */
static int sec_expired = 30;

static void
_quit_cb (GtkWidget *button, gpointer data)
{
    (void)button; (void)data; /* Avoid compiler warnings */
    printf("Canceled\n");
    gtk_main_quit();
    return;
}

static void
_check_switch ()
{
    if (gtk_switch_get_active (GTK_SWITCH(switch_a)) == 1)
        printf("no_save=on\n");
    else
        printf("no_save=off\n");
    if (gtk_switch_get_active (GTK_SWITCH(switch_b)) == 1)
        printf("reboot=on\n");
    else
        printf("reboot=off\n");
}

static void
_shutdown (GtkWidget *button, gpointer data)
{
    (void)button; (void)data; /* Avoid compiler warnings */
     _check_switch();
    gtk_main_quit();
}

static gboolean
_label_update(gpointer data)
{
    GtkEntry *label = (GtkEntry*)data;
    char buf[256];
    memset(&buf, 0x0, 256);
    snprintf(buf, 255, "Turning off computer in  %d seconds.", --sec_expired);
    if (sec_expired == 0)
        {
        _check_switch();
        gtk_main_quit();
        }

    gtk_entry_set_text(GTK_ENTRY(label), buf);
    gtk_entry_set_progress_fraction(GTK_ENTRY(label), (double)sec_expired / 30.0);
    return continue_timer;
}

int main(void)
{
    GtkWidget *window;
    GtkWidget *box;
    GtkWidget *box_a;
    GtkWidget *box_b;
    GtkWidget *boxl;
    GtkWidget *shutdown_button;
    GtkWidget *cancel_button;
    GtkWidget *label;
    GtkWidget *question;
    GtkWidget *no_save;
    GtkWidget *reboot;

    gtk_init(NULL, NULL);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request(window, 250, 120);
    gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
    gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
    gtk_window_stick (GTK_WINDOW (window));
    gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
    gtk_window_set_title (GTK_WINDOW (window), "Shutdown");
    g_signal_connect (G_OBJECT (window), "destroy", 
                    G_CALLBACK (gtk_main_quit),
                    NULL);
    box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
    box_a = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
    box_b = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
    boxl = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);

    gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
    gtk_container_add(GTK_CONTAINER(window),boxl);

    question = gtk_label_new ("\nAre you sure you want to shutdown?");
    label = gtk_entry_new ();
    gtk_entry_set_text (GTK_ENTRY(label),
                       "Turning off computer in  30 seconds.");
    gtk_entry_set_progress_fraction(GTK_ENTRY(label), 1.0);
    gtk_entry_set_has_frame (GTK_ENTRY(label), FALSE);
    gtk_entry_set_activates_default (GTK_ENTRY(label),
                                     FALSE);
    gtk_entry_set_overwrite_mode (GTK_ENTRY(label),
                                    FALSE);
    gtk_editable_set_editable (GTK_EDITABLE(label), FALSE);
    gtk_widget_set_can_focus (GTK_WIDGET(label), FALSE);
    gtk_widget_set_state_flags (GTK_WIDGET(label),
                                GTK_SELECTION_NONE, FALSE);

    no_save = gtk_label_new ("No save");
    reboot = gtk_label_new ("Reboot ");
    switch_a = gtk_switch_new ();
    switch_b = gtk_switch_new ();
    gtk_box_pack_start (GTK_BOX(box_a), no_save, FALSE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_a), switch_a, FALSE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_b), reboot, FALSE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_b), switch_b, FALSE, FALSE, 10);

    shutdown_button = gtk_button_new_with_label("Shutdown");
    g_signal_connect(G_OBJECT(shutdown_button), "clicked", G_CALLBACK(_shutdown), shutdown_button);

    cancel_button = gtk_button_new_with_label("Cancel");
    g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(_quit_cb), NULL);

    gtk_box_pack_start (GTK_BOX(boxl), question, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX(boxl), label, TRUE, TRUE, 0);

    gtk_box_pack_start (GTK_BOX(boxl), box_a, TRUE, TRUE, 10);
    gtk_box_pack_start (GTK_BOX(boxl), box_b, TRUE, TRUE, 10);
    gtk_box_pack_start (GTK_BOX (box), cancel_button, TRUE, TRUE, 10);
    gtk_box_pack_start (GTK_BOX(box), shutdown_button, TRUE, TRUE, 10);
    gtk_box_pack_start (GTK_BOX(boxl), box, TRUE, TRUE, 10);

    gtk_widget_show_all(window);

    g_timeout_add_seconds(1, _label_update, label);
    continue_timer = TRUE;
    start_timer = TRUE;

    gtk_main();
    return 0;
}

Perhaps @vkareh has an idea about how to prevent text selection inside GtkEntry. :slight_smile:

Is anybody still interested in the classic-style Log Out and Shut Down dialogs?

I ask this because I actually whipped up a solution which looks almost identical to the GTK+ 2 dialogs, but the solution is kind of messy, at least on the progress bar front. To wit, I had to pack a GtkLabel and a GtkProgressBar into an overlay container (GtkOverlay) so that the label text would be drawn over the top of the progress bar. To make things messier, I used a size group to ensure the progress bar did not cut the text off (the text should dictate the size of the progress bar, not vice versa). Furthermore, I also had to connect to the label's size-allocate signal so that whenever the label was resized (e.g., the text size was increased), the progress bar trough and progress "gadgets" would increase in height. Without the last step, the result was a big gap at the top of the progress bar, meaning roughly half the text may be drawn over the progress bar and half is drawn above the progress bar. Annoying!

Anyway, I personally use my version exclusively now. Here's the fruits of my labors:
new-log-out

new-shut-down

In short, I want to know if anyone else thinks it's a good idea for me to start a pull request for this. I can only imagine it'll first make light in MATE 1.26.

4 Likes

Good idea Gordon.
I think you covered all of the cases, the text size/font and theme switching.

1 Like

I just started a pull request for this at: https://github.com/mate-desktop/mate-session-manager/pull/261.

My fingers are crossed and we shall see how it works out.

3 Likes

Your knowledge of Gtk is impressive.
Do you know if GtkPopovers can be used to create mate-panel plugin menus?
I like how they look and how other widgets can be inside them.

Edit:
Let's forget that I asked. It looks too tricky.
Especially the arrows. Popover is not designed to work as a standalone widget, it has no own window.
It needs a window and a few dummy widgets (1x1 transparent png) to set arrows pointing to.
It would need a lot of them for all the corners. :slight_smile:
I've tried to emulate a standalone menu-like behavior which closes popover if it is unfocused.

#include <gtk/gtk.h> 
  
/*   save this file as standalone-popover.c
     create a 1x1 pixel transparent png image in the same folder
     and name it dummy.png
     compile with:
          gcc standalone-popover.c -o standalone-popover  `pkg-config --cflags --libs gtk+-3.0`
*/

#define DUMMY_PNG "dummy.png"

void destroy(GtkWidget* widget, gpointer data) 
{ 
    gtk_main_quit(); 
} 
  
int main(int argc, char* argv[]) 
{ 
  
    GtkWidget  *window; 
    GtkWidget  *popover;
    GtkWidget  *dummy_png_top_left;
    GtkWidget  *dummy_png_top_center;
    GtkWidget  *dummy_png_top_right;
    GtkWidget  *box;
    GtkWidget  *dummy_box_top;
    GtkWidget  *label;
    GtkWidget  *button;
    gtk_init(&argc, &argv); 
  
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
    gtk_window_set_type_hint (GTK_WINDOW(window),
                              GDK_WINDOW_TYPE_HINT_POPUP_MENU);
    gtk_widget_set_size_request(window, 250, 220);
    gtk_window_set_resizable (GTK_WINDOW(window), TRUE);
    gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
    gtk_window_stick (GTK_WINDOW (window));
    gtk_window_set_decorated (GTK_WINDOW(window), FALSE);
    gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);

    gtk_widget_set_events (window, GDK_FOCUS_CHANGE_MASK);

    g_signal_connect(window, "destroy", 
                     G_CALLBACK(destroy), NULL);
    g_signal_connect (G_OBJECT (GTK_WINDOW (window)),
                    "focus-out-event",
                    G_CALLBACK (destroy),
                    NULL);
    gtk_window_present (GTK_WINDOW(window));
    gtk_container_set_border_width(GTK_CONTAINER(window), 20); 
  

    dummy_png_top_left   =  gtk_image_new_from_file (DUMMY_PNG);
    dummy_png_top_center =  gtk_image_new_from_file (DUMMY_PNG);
    dummy_png_top_right  =  gtk_image_new_from_file (DUMMY_PNG);

    dummy_box_top = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_box_set_homogeneous (GTK_BOX (dummy_box_top), TRUE);
    gtk_box_pack_start (GTK_BOX(dummy_box_top), dummy_png_top_left, TRUE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX(dummy_box_top), dummy_png_top_center, TRUE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX(dummy_box_top), dummy_png_top_right, TRUE, FALSE, 0);

    box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
    gtk_box_set_homogeneous (GTK_BOX (box), TRUE);

    gtk_widget_show(dummy_png_top_left);
    gtk_widget_show(dummy_png_top_center);
    gtk_widget_show(dummy_png_top_right);

    label = gtk_label_new ("Standalone GtkPopover");
    button = gtk_button_new_with_label("OK");
    gtk_box_pack_start (GTK_BOX(box), dummy_box_top, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX(box), label, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box), button, TRUE, FALSE, 10);

    /* here we use the dummy widget to position the popover arrows */
    popover = gtk_popover_new(dummy_png_top_center);

    gtk_container_add(GTK_CONTAINER(window), popover); 
    gtk_container_add(GTK_CONTAINER(popover), box); 
    gtk_popover_set_modal(GTK_POPOVER(popover), FALSE);

    g_signal_connect(G_OBJECT(button),
                     "clicked",
                     G_CALLBACK(destroy),
                     window);
    gtk_widget_show_all(window);

    /* need this to focus a window */
    gtk_window_present_with_time(GTK_WINDOW(window),GDK_CURRENT_TIME);
    gtk_window_activate_focus (GTK_WINDOW (window));
    gtk_widget_grab_focus(GTK_WIDGET(window));
    gtk_main(); 
  
    return 0; 
} 

So far the PR has gotten mixed responses. Some of us here really disliked the "spreading" of the dialog buttons; turns out @raveit65 likes the spreading and says no to the lack of spreading I (unintentionally) whipped up. I wrote back a response which details the advantages and disadvantages of both methods, and strongly urged @raveit65 to not include the expanding buttons.

We'll have to see what happens. Personally I don't care about the buttons, but enabling the expanded buttons also means using a deprecated function in GTK+ 3. As far as I can tell, there's no way around the use of the deprecated feature -- @raveit65 claims applying a style class would do the trick, but the result still doesn't look right.

I defended our position by showing that in MATE, the old-style button layout is more common than the new-style layout. I hope we can come to an agreement on this issue.

Spread buttons require a deprecated function!? I thought this was a new GTK misfeature. How is it deprecated?

Good question, but it requires a little background.

When a feature is "deprecated" in GTK, that only means that the feature is deprecated for use by applications; the feature may be used within the GTK library itself for as long as the feature exists. Heck, the use of the feature in the GTK does not even throw up a warning under most circumstances.

The old style of logout dialog used a GtkMessageDialog, which is derived from a more generic GtkDialog. Since GtkMessageDialog is implemented inside of GTK, the usage of the deprecated function in question does not throw up a warning; if there even was a warning, it was when GTK was compiled. GtkDialog actually has more conservative button layouts than GtkMessageDialog, apparently. (An oversight on the part of the GTK team, perhaps?) My proposed logout dialog uses the generic GtkDialog instead of GtkMessageDialog so that I can insert an image on the left and stuff. In other words, I did it for extra flexibility -- not really for the buttons, but that was a side benefit.

Honestly, I don't see what anyone's complaining about. The majority of dialogs in MATE use the old style, and the GTK+ 2 version of MATE had a log out dialog which looked practically identical to this one. But it looks like I'm going to have to partly concede here if I want to push this patch through. Oh well.

I've been spectating the pull request from afar - thank you for working on improving this! :+1:

I think there's two visual concepts being mixing up in those reviews - I know the combine/linked style button look can certainly be influenced by the theme. Ambiant-MATE (our default) doesn't make them "stick" together anywhere:

Screenshot at 2020-11-07 11-38-01
Screenshot at 2020-11-07 11-38-18
Screenshot at 2020-11-07 11-38-12

Presumably, the first two screenshots are using GtkMessageBox, causing buttons to stretch and space out to the full width of the window, as well as the center text alignment (yuck...). Definitely can see how GTK3 is influenced by GNOME 3's design guidelines there.

Whereas the third screenshot is closer to GTK2's traditional placement by placing buttons on the far right, similar to how Qt/KDE (and Windows/macOS) continues today and GTK2 did back then:

Screenshot at 2020-11-07 12-39-54

Please stop posting FAKE-NEWS under my name!
I never told you to add a deprecated function.
Only Mr. Trump is allowed to post fake news :stuck_out_tongue:
Again,
Adding the .linked style class to GtkButtonBox , which is the parent of the buttons, with gtk_style_context_add_class isn't deprecated.
That means themes like MATE default Menta or gtk default Adwaita use the .linked button style.
Other gtk themes like Mate-Ubuntu themes doesn't use that settings in their gtk-widget.css.

It looks like that most people of the MATE team, apart from me, doesn't like the change, because you add accessibility problems with readability of the progress text.
And there are other problems, see last post https://github.com/mate-desktop/mate-session-manager/pull/261#issuecomment-723419348

Personally i like to add the icons to the dialog, but that's all and i am sure this can be done with actual gtk3 dialog of this application.

PS:
I am i doubt that the few users here of ubuntu-mate channel are the majority of MATE users all over other distros.

1 Like

Sorry everyone -- I had to close that pull request. I never was super gung-ho about the addition, and if @raveit65 doesn't really want it, then frankly I think it's not worth pushing forward on this. I'm also already adding more gray hair to my (already slightly graying) head. :face_with_hand_over_mouth:

So sorry but I hope everyone can live without this change a little longer.

Are there plans to tackle GTK4 or let MATE ride into the sunset on the GTK3 horse?
It seems GTK devs broke the future for traditional GTK desktops.
MATE will be appreciated as long as it is around. Thanks for the work you do.

2 Likes

I guess I've regained some of my colored hair, so I'll return to the "good fight" (TM) and resume (trying to) figure out what @56tievar is talking about.

BTW, what "fake news"? I don't get it.

@lah7:

By the way, how did you get the icon next to the first dialog in your post there? It seems to be GTK+ 3, and that dialog is indeed powered by GtkMessageDialog, and GtkMessageDialog actually lacks any code to display icons (I'm pretty sure). I was unable to replicate that dialog appearance using my stock MATE and GTK:

caja

Are you using gtk-mushrooms or something? Just curious.

Nothing special, it's the default in Ubuntu MATE. I genuinely don't know if it's a setting or something patched at distro level. A quick look in dconf/gconf editor didn't reveal anything. Doesn't seem to be an icon/theme thing either. :confused:

Which distro and version are you using?

I no longer use MATE myself, but I do have gtk-mushrooms (AUR) installed which did restored the dialogs for those few GTK applications.

I wish I could use Ubuntu MATE, but I only rarely can use it, as most of my machines are 32-bit capable only. As such I use (hopefully) Ubuntu MATE's closest relative, Debian, most of the time, and Debian is the system I was using when I took that screenshot. For whatever it's worth, I use Debian 10.6 (Buster) because Bullseye isn't stable yet, and also because of some LibreOffice GTK+ 2 foibles. Thus the MATE version I have is 1.20.4 and the GTK version is 3.24.5.

Weird. I guess the Debian version of GTK or Caja is not the same as the Ubuntu / Ubuntu MATE version -- most likely Caja was patched, because no icon appears next to the Log Out dialog anymore no matter what, and the Log Out dialog always uses GtkMessageDialog too.

OK. I guess it goes without saying that Ubuntu MATE is not based on Debian 10 -- if anything it's probably closer to Debian 11, at least in terms of package versions. But Gentoo, which ships with the newer MATE 1.24 and GTK 3.24.22, also displays the Caja prompt without an icon. Odd.

Well, it's not too interesting after all.

1 Like

Hey Gordon how come no one got an idea to place the pause button on that shutdown dialog? :smiley:


Text inside the progress bar is less readable.

What kind of elaborate joke is that?!? I really don't get it. What's with the STLWRT donkey on the progress bar? What pause button?

Oh wait. You mean you want something which pauses the shutdown delay?

Still, I don't get the joke program.

(BTW, care to share that code for making the donkey move over when pushed by the progress indicator? :slight_smile: )

Also, why are you covering up errors produced by your program using 2>/dev/null? :confused:

(Furthermore, that's the funniest demo I've seen all week!)

The progress is similar to Nyan Cat.
I did not put the rainbow in the progress bar, although it's doable with CSS.

It looks better when switched to dark theme because of your profile picture.
Gtk spills some warnings over the dark theme used, so 2>/dev/null.

Here's the app


There are two threads one to set the progress bar and one to animate gif.
The one that sets the progress also sets the left margin of the image:
  gtk_widget_set_margin_start(widgets->progress_image,
                              alloc->width);

But first gets the progress bar's allocation->width. :slight_smile:

I don't know how to make animations from images, (probably can but looks like too much work) so I uploaded gordon.png to one website that creates animated gif from static image. https://www.kapwing.com/studio/editor

It's been nearly 2 years since this topic was created, and now I maintain a series of patches called gtk3-classic ... previously known as gtk3-mushrooms.

Even though my C isn't great, I have managed a couple of fixes - including the ability to scroll over tabs like we could do in GTK2.

It is packaged for Arch (which is pretty straight forward, actually), but I haven't forgot about Ubuntu MATE! At some point I will have another go at creating a PPA / Debian package so you can enjoy classic features of GTK2 in GTK3. I just need to figure out how to "turn off" tests for the Ubuntu gtk+3.0 package.

I think patching GTK3's quirks is a good workaround until STLWRT enters the scene as a possible GTK "slot in" replacement. :slightly_smiling_face:

5 Likes