Skip to content

Instantly share code, notes, and snippets.

@andreldm
Last active June 30, 2020 00:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreldm/83c9b99e7aa133c924fb4165acc8427a to your computer and use it in GitHub Desktop.
Save andreldm/83c9b99e7aa133c924fb4165acc8427a to your computer and use it in GitHub Desktop.
GTK Popover sample
/*
* Build:
* gcc $(pkg-config --cflags gtk+-3.0) popover_sample.c -o popover_sample $(pkg-config --libs gtk+-3.0)
*/
#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button, *popover, *vbox;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
button = gtk_menu_button_new ();
gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("open-menu-symbolic", GTK_ICON_SIZE_BUTTON));
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (window), button);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Hello World 1"), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Hello World 2"), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Hello World 3"), FALSE, FALSE, 0);
popover = gtk_popover_new (button);
gtk_container_add (GTK_CONTAINER (popover), vbox);
gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover);
gtk_widget_show_all (popover);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
diff --git a/panel-plugin/sample.c b/panel-plugin/sample.c
index 97a0cc6..8927da2 100644
--- a/panel-plugin/sample.c
+++ b/panel-plugin/sample.c
@@ -135,7 +135,7 @@ sample_new (XfcePanelPlugin *plugin)
{
SamplePlugin *sample;
GtkOrientation orientation;
- GtkWidget *label;
+ GtkWidget *button, *popover, *vbox;
/* allocate memory for the plugin structure */
sample = g_slice_new0 (SamplePlugin);
@@ -158,13 +158,22 @@ sample_new (XfcePanelPlugin *plugin)
gtk_container_add (GTK_CONTAINER (sample->ebox), sample->hvbox);
/* some sample widgets */
- label = gtk_label_new (_("Sample"));
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (sample->hvbox), label, FALSE, FALSE, 0);
+ button = gtk_menu_button_new ();
+ gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("open-menu-symbolic", GTK_ICON_SIZE_BUTTON));
+ gtk_box_pack_start (GTK_BOX (sample->hvbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
- label = gtk_label_new (_("Plugin"));
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (sample->hvbox), label, FALSE, FALSE, 0);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Hello World 1"), FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Hello World 2"), FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Hello World 3"), FALSE, FALSE, 0);
+
+ popover = gtk_popover_new (button);
+ gtk_container_add (GTK_CONTAINER (popover), vbox);
+
+ gtk_widget_show_all (popover);
+
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover);
return sample;
}
@Misko-2083
Copy link

Misko-2083 commented Jun 19, 2020

https://stackoverflow.com/questions/60337910/is-it-possible-to-use-gtkpopover-while-writing-a-xfce4-panel-plugin/60867221#60867221
That would be tricky. 😄
Would have to have a transparent window behind the popover before attaching it to xfce panel button..

Tried that in python before (but that would depend on compositing):

#!/usr/bin/env python3

import gi
import cairo
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk



class Popover(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, Gtk.WindowType.TOPLEVEL)
        self.set_title("Popover")
        self.set_default_size(190, 75)
        self.connect("destroy", Gtk.main_quit)

        self.screen = self.get_screen()
        self.visual = self.screen.get_rgba_visual()
        if self.visual != None and self.screen.is_composited():
            print ("Composited")
            self.set_visual(self.visual)
        self.set_app_paintable(True)
        self.connect("draw", self.area_draw)

        box = Gtk.Box()
        box.set_spacing(5)
        box.set_orientation(Gtk.Orientation.VERTICAL)
        self.add(box)

        self.popover = Gtk.Popover()
        self.popover.set_position(Gtk.PositionType.TOP)
        self.popover.set_relative_to(box)

        box = Gtk.Box()
        box.set_spacing(5)
        box.set_orientation(Gtk.Orientation.VERTICAL)

        self.popover.add(box)

        button = Gtk.Button("Close")
        button.connect("button-press-event", Gtk.main_quit)

        label = Gtk.Label("Click this to close")
        box.add(button)

        checkbutton = Gtk.CheckButton("A CheckButton widget")
        box.add(checkbutton)
        self.popover.show_all()

    def area_draw(self, widget, cr):
        cr.set_source_rgba(0, 0, 0, 0)
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.paint()
        cr.set_operator(cairo.OPERATOR_OVER)

w2 = Popover()
w2.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
w2.connect("button-press-event", Gtk.main_quit)

w2.connect("destroy", Gtk.main_quit)
w2.connect("focus-out-event", Gtk.main_quit)
w2.set_position(Gtk.WindowPosition.MOUSE)
w2.set_decorated(False)

w2.show()

Gtk.main()

@Misko-2083
Copy link

Peek 2020-06-19 17-07

@andreldm
Copy link
Author

Yes, I think that could "work" for a plugin, although positioning the window relative to the panel button could be a bit tricky and as you mentioned this doesn't look nice when compositing is disabled:
image

All in all, it's hack and that only breeds bugs 😄

@Misko-2083
Copy link

Misko-2083 commented Jun 21, 2020

Positioning the window next to the panel button is not that hard.
https://youtu.be/82bCIkLWsd0
I even added a remote-event 🤣
If you whish to try out, https://github.com/Misko-2083/desktop-icons-applet
I even added a remote-event to call the window from command line:

xfce4-panel --plugin-event=desktop-icons-applet-X:popup:bool:false
xfce4-panel --plugin-event=desktop-icons-applet-X:popup:bool:true

P.S. popover is out of the picture 😄

./autogen.sh --prefix=usr

@andreldm
Copy link
Author

Nice, but that's not a popover, that's a regular window, that's the same approach adopted by whiskermenu. You still need to make it transparent and fill it with a popover. Not hard, but doesn't seem worth the trouble IHMO.

@Misko-2083
Copy link

Well, if there is a window already, there is no need for a popover.
If only Xfdesktop could display a popover from data received via inter-process communication. 🤣

Speaking of IPC, I written a panel plugin for jgmenu that sets some TINT2 variables...
https://github.com/johanmalm/jgmenu/blob/master/contrib/xfce4-panel/jgmenu-applet.c#L217
... that jgmenu reads and based on them knows where the panel and the button are positioned.
https://github.com/johanmalm/jgmenu/blob/master/src/ipc.c#L185
And then calculates the best position next to the button.

Jgmenu doesn't even use gtk or qt, just xlib, cairo and pango.
https://youtu.be/rsK-H7seyJw?t=51

@Misko-2083
Copy link

I have an update on popover. I managed to make a popover without the transparency involved.
Still needs a full gtk window behind to draw the popup.
https://www.youtube.com/watch?v=eXZzwDDQlZ8
Now I'm struggling with positioning the popover arrows and a window.
It's harder than I thought. Should have listened to you when you said. :)
I'm using some dummy widgets, 1 pixel transparent png images to set popover pointing to.
I see no other way to "inform" popover where the toggle button is.
I've sent the code to ToZ to have a look here https://forum.xfce.org/viewtopic.php?pid=58793#p58793

@andreldm
Copy link
Author

I still don't understand what you really want to accomplish, seems like you want to replicate Cinnamon menu or Elementary OS' app launcher. If that's the case you can take a look at their code, but I'll be surprised if that's easily supported by GTK, perhaps it's a popover that belongs to the panel itself, not a plugin in its own process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment