GtkPopover as a xfce panel plugin

For discussions about programming, and for programming questions and advice


Moderator: Forum moderators

Post Reply
User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

GtkPopover as a xfce panel plugin

Post by misko_2083 »

The Gtk3 popovers look very nice and support adding gtk box as child.
But GtkPopover does not have it's own window like GtkMenu to be used as a stand-alone. So I figured there has to be a window where popover will be drawn.
In a panel plugin there is not enough place for popover to be drawn. So, bummer.
However it will work if a new window is created. Later I can position that window next to the panel plugin. I was also able to simulate GtkMenu behaviour where standalone popover will be closed if clicked outside it.
Now the arrows.
The popovers have the arrow and, when attached to a widget, popover's arrow points in the direction of that widget.
But, in the case of panel plugins, that arrow should be pointing to a widget that is outside of the window.
I was thinking about using dummy widgets like 1x1 pixel transparent image. Put them all around the window and then when figuring out where the button is and how the panel is oriented, attach a popover to the appropriate dummy widget.
This is a stand-alone GtkPopover:

Code: Select all

#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; 
}

I also tried this with the xfce plugin.
https://m.youtube.com/watch?v=eXZzwDDQlZ8
Aligning the arrow properly with the panel plugin looks tricky right now.
Please let me know if someone has a better or easier way.

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: GtkPopover as a xfce panel plugin

Post by misko_2083 »

Ok I've figured out the placement.
Image
There are some flaws though.
There is no shadow, so I resorted to adding a style context and theme the border of the popover.
There is a bit of exposed window inside the popover because I did this:

Code: Select all

gtk_container_add(GTK_CONTAINER(dicons->window), dicons->popover); 

Clicking on that area closes the popover and exposes the window.
I can connect to the closed signal the popover emits and close the window but the next time the popover pops:
Image
Still thinking of a way to get around this.

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

Post Reply

Return to “Programming”