Xfce Forum

Sub domains
 

You are not logged in.

#1 2022-05-19 11:31:44

Misko_2083
Member
Registered: 2015-10-13
Posts: 191
Website

Theme weirdness

I've returned to making a standalone popovers with GTK3 after some time.
This time with Xlib as a window.
I know this is hack but I don't understand why one theme works and the other glitches.

It's best noticed on a random video.
With Orchis gtk theme it works fine.
Fg764Cg.png
With Adwaita it's drawing a light show, sometimes it's painted black.
9TIIuAO.png

From theme to theme, some work fine some don't.
I just can't figure out why.

If I can only find out what line is causing this I would override it with CSS. big_smile
And use it as a panel plugin.

code:

// gcc test.c `pkg-config --cflags --libs gtk+-3.0 gdk-3.0 glib-2.0` -lX11 && ./a.out

#include <X11/Xlib.h>
#include <unistd.h>
#include <stdio.h>

#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <glib.h>


static void my_gtk_realize(GtkWidget* widget, gpointer data)
{
    gtk_widget_set_window(widget, (GdkWindow*)data);
}

static void file_quit(GtkWidget* widget, gpointer data)
{
    gboolean* running = (gboolean*)data;
    *running = FALSE;
}

int main(int argc, char** argv)
{
    gtk_init(&argc, &argv);

    XVisualInfo vinfo;

    GdkDisplay* gd = gdk_display_get_default();
    Display* d = GDK_DISPLAY_XDISPLAY(gd);
    cairo_rectangle_int_t    rect;

    XMatchVisualInfo(d, DefaultScreen(d), 32, TrueColor, &vinfo);

    XSetWindowAttributes attr;

    attr.colormap = XCreateColormap(d, DefaultRootWindow(d), vinfo.visual, AllocNone);
    attr.border_pixel = 0;
    attr.background_pixel = 0;

    Screen *scr = DefaultScreenOfDisplay(d);

    Window w = XCreateWindow(d, RootWindowOfScreen(scr), 0, 0, 300, 300, 0, vinfo.depth,
                             InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr);

    XSelectInput(d, w, StructureNotifyMask);
    GC gc = XCreateGC(d, w, 0, 0);

    Atom wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", 0);
    XSetWMProtocols(d, w, &wm_delete_window, 1);

    Atom WM_HINTS;

    WM_HINTS = XInternAtom(d, "_MOTIF_WM_HINTS", True);

    if ( WM_HINTS != None ) {
        #define MWM_DECOR_NONE          0
        #define MWM_HINTS_DECORATIONS   (1L << 1)
        struct {
          unsigned long flags;
          unsigned long functions;
          unsigned long decorations;
                   long input_mode;
          unsigned long status;
        } MWMHints = { MWM_HINTS_DECORATIONS, 0,
            MWM_DECOR_NONE, 0, 0 };
        XChangeProperty(d, w, WM_HINTS, WM_HINTS, 32,
                        PropModeReplace, (unsigned char *)&MWMHints,
                        sizeof(MWMHints)/4);
    }

    XMapRaised(d, w);

    GdkWindow* gw = gdk_x11_window_foreign_new_for_display(gd, w);

    gdk_window_set_pass_through (gw, TRUE);
    gdk_window_set_type_hint (gw, GDK_WINDOW_TYPE_HINT_POPUP_MENU);

    GtkWidget* gtk = gtk_widget_new(GTK_TYPE_WINDOW, NULL);

    GtkWidget        *close_button;
    GtkWidget        *box;
    GtkStyleProvider *style_provider;

    g_signal_connect(gtk, "realize", G_CALLBACK(my_gtk_realize), gw);
    gtk_widget_set_has_window(gtk, TRUE);
    gtk_widget_realize(gtk);

    GtkWidget* popover = gtk_popover_new(gtk);

    gtk_popover_set_constrain_to(GTK_POPOVER(popover),
                                 GTK_POPOVER_CONSTRAINT_NONE);
    rect.x = 5;
    rect.y = 500;
    rect.height = 35;
    rect.width = 35;

    gtk_popover_set_pointing_to(GTK_POPOVER(popover), &rect);
    gtk_popover_set_position(GTK_POPOVER(popover), GTK_POS_TOP);

    gtk_popover_set_modal(GTK_POPOVER(popover), FALSE);

    style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());

    gtk_style_context_add_provider (gtk_widget_get_style_context (popover),
                                  style_provider,
                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

    char *css_text;

    css_text = g_strdup_printf ("popover.background {\n"
                                " border: solid 2px;\n"
                                "}\n");

    gtk_css_provider_load_from_data (GTK_CSS_PROVIDER
                                   (style_provider),
                                   css_text, -1, NULL);
    g_free (css_text);


    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
    close_button = gtk_button_new_with_label("Close");
    gtk_widget_set_sensitive (close_button, TRUE);

    gtk_box_pack_start (GTK_BOX(box), close_button, TRUE, FALSE, 10);

    gtk_container_add(GTK_CONTAINER(popover), box);

    gtk_container_add(GTK_CONTAINER(gtk), popover);
    gtk_container_set_border_width (GTK_CONTAINER(gtk),
                                     0);
    gboolean running = TRUE;

    g_signal_connect(G_OBJECT(popover), "closed", G_CALLBACK(file_quit), &running);

    g_signal_connect(G_OBJECT(close_button), "clicked", G_CALLBACK(file_quit), &running);

    gtk_widget_show_all(gtk);

    while (running)
    {
        Window focus;
        int revert_to;
        XGetInputFocus(d, &focus, &revert_to);
        if (focus != w)
           running = FALSE;

        while (g_main_context_pending(NULL))
        {
            g_main_context_iteration(NULL,FALSE);
        }
    }

    XDestroyWindow(d, w);
    XCloseDisplay(d);
}

The window closes when it looses focus or on Close button.
MOTIF_WM_HINTS are set to make the Xwindow undecorated.

Next lines in the code above set the arrow position:

    rect.x = 5;
    rect.y = 500;
    rect.height = 35;
    rect.width = 35;

    gtk_popover_set_pointing_to(GTK_POPOVER(popover), &rect);
    gtk_popover_set_position(GTK_POPOVER(popover), GTK_POS_TOP);

GTK_POS_TOP is bottom GTK_POS_LEFT is right, so it's opposite.


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

Offline

#2 2022-05-19 23:28:22

ToZ
Administrator
From: Canada
Registered: 2011-06-02
Posts: 10,948

Re: Theme weirdness

Misko_2083 wrote:

It's best noticed on a random video.
With Orchis gtk theme it works fine.
https://imgur.com/Fg764Cg.png
With Adwaita it's drawing a light show, sometimes it's painted black.
https://imgur.com/9TIIuAO.png

Did you intend to post a video or some images to show the issue?

BTW, welcome back.


Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki  |  Community | Contribute ---

Offline

#3 2022-05-20 08:24:03

Misko_2083
Member
Registered: 2015-10-13
Posts: 191
Website

Re: Theme weirdness

ToZ wrote:
Misko_2083 wrote:

It's best noticed on a random video.
With Orchis gtk theme it works fine.
https://imgur.com/Fg764Cg.png
With Adwaita it's drawing a light show, sometimes it's painted black.
https://imgur.com/9TIIuAO.png

Did you intend to post a video or some images to show the issue?

BTW, welcome back.

Images, but here is video if it helps: https://youtu.be/B2QT-HmGH5U

xfwm4 --version
	This is xfwm4 version 4.16.1 (revision 5f61a84ad) for Xfce 4.16
	Released under the terms of the GNU General Public License.
	Compiled against GTK+-3.24.24, using GTK+-3.24.24.

	Build configuration and supported features:
	- Startup notification support:                 Yes
	- XSync support:                                Yes
	- Render support:                               Yes
	- Xrandr support:                               Yes
	- Xpresent support:                             Yes
	- X Input 2 support:                            No
	- Embedded compositor:                          Yes
	- Epoxy support:                                Yes
	- KDE systray proxy (deprecated):               No
ToZ wrote:

BTW, welcome back.

Thank you Tony. It's good to be back.


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

Offline

#4 2022-05-20 23:47:40

ToZ
Administrator
From: Canada
Registered: 2011-06-02
Posts: 10,948

Re: Theme weirdness

I've tested your code on two separate computers. One the first one (long time install), I can see the artifacts - but not with Orchis theme. On the second one (new fresh install), I don't see any artifacts using the built-in adwaita theme (haven't tried any other themes yet).

Can you try with the built in adwaita theme?

xfconf-query -c xsettings -p /Net/ThemeName -s ""

Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki  |  Community | Contribute ---

Offline

#5 2022-05-22 19:02:33

Misko_2083
Member
Registered: 2015-10-13
Posts: 191
Website

Re: Theme weirdness

ToZ wrote:

I've tested your code on two separate computers. One the first one (long time install), I can see the artifacts - but not with Orchis theme. On the second one (new fresh install), I don't see any artifacts using the built-in adwaita theme (haven't tried any other themes yet).

Can you try with the built in adwaita theme?

xfconf-query -c xsettings -p /Net/ThemeName -s ""

Just tried and it still exists.

----

Finally, I think I got it. Need to tell GTK+ that we want to draw the window's background ourselfs.
https://docs.gtk.org/gtk3/method.Widget … table.html

After this line:

GtkWidget* gtk = gtk_widget_new(GTK_TYPE_WINDOW, NULL);

add next line:

gtk_widget_set_app_paintable(gtk, TRUE);

Now it doesn't appear with Adwaita for me.


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

Offline

#6 2022-05-23 18:29:48

ToZ
Administrator
From: Canada
Registered: 2011-06-02
Posts: 10,948

Re: Theme weirdness

Interesting. Thanks for sharing the solution - though I don't understand why I wasn't experiencing the issue on my new laptop build.


Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki  |  Community | Contribute ---

Offline

#7 2022-05-25 13:26:32

Misko_2083
Member
Registered: 2015-10-13
Posts: 191
Website

Re: Theme weirdness

^It happens if it's spawned very fast.
Although this with Xlib works very well I would prefer it with Gtk window.
That way it would work without the compositor. However that creates other issues.

If you wan't to try out here it is.

Create /usr/share/xfce4/panel/plugins/desktop-icons-applet.desktop
with next content:

[Xfce Panel]
Type=X-XFCE-PanelPlugin
Encoding=UTF-8
Name=Desktop Icons
Comment=Show and Hide desktop icons
Icon=emblem-desktop
X-XFCE-Module=dicons
X-XFCE-Internal=true
X-XFCE-Unique=false
X-XFCE-API=2.0

Save this as desktop-icons-plugin.c

/*
* Copyright © 2022 misko_2083
*
* Distributed under terms of the GPL2 license.
* 
* compile
* gcc -Wall -s -shared -fPIC -g desktop-icons-plugin.c -o libdicons.so $(pkg-config --libs --cflags gtk+-3.0 libxfce4util-1.0 libxfce4panel-2.0 libxfconf-0)
* move to libdir (debian 64bit)
* sudo mv libdicons.so $(pkg-config --variable=libdir libxfce4panel-2.0)/xfce4/panel/plugins/libdicons.so
*/

#include <gtk/gtk.h>
#include <libxfce4util/libxfce4util.h>
#include <libxfce4panel/libxfce4panel.h>
#include <xfconf/xfconf.h>

#define DEFAULT_ICON_NAME "emblem-desktop"
#define DEFAULT_TOOLTIP_MESSAGE "Show/Hide Desktop Icons"
#define DEFAULT_TITLE "dicons"
#define XFCE_PLUGIN_VERSION "0.3"

/* prototypes */
static void
dicons_construct   (XfcePanelPlugin *plugin);

/* register the plugin */
XFCE_PANEL_PLUGIN_REGISTER (dicons_construct);

typedef struct _DiconsPlugin {
    XfcePanelPlugin *plugin;
    GtkWidget        *ebox;
    GtkWidget        *hvbox;
    GtkWidget        *button;
    gchar            *icon_name;
    GtkWidget        *icon;
    GtkWidget        *window;
    GtkWidget        *popover;
} DiconsPlugin;

struct icon {
	char home[42];
	char trash[42];
	char filesystem[42];
	char removable[42];
};

static const struct icon icon = {
	.home = "/desktop-icons/file-icons/show-home",
	.trash = "/desktop-icons/file-icons/show-trash",
	.filesystem = "/desktop-icons/file-icons/show-filesystem",
	.removable = "/desktop-icons/file-icons/show-removable"
};

static void
button_clicked_cb     (GtkWidget *button,
                    DiconsPlugin    *dicons);
static gboolean
on_popup_focus_out (GtkWidget *widget,
                    GdkEventFocus *event,
                    gpointer data);                    
static gboolean
on_key_pressed     (GtkWidget *widget,
                    GdkEventKey *event,
                    gpointer data);

static const char dicons_plugin_copyright[] =
"Copyright \xc2\xa9 2020 Miloš Pavlović\n";

static void dicons_about(XfcePanelPlugin *plugin)
{
    const gchar *auth[] = { "Miloš Pavlović", NULL };
    GdkPixbuf *ico;

    ico = xfce_panel_pixbuf_from_source("emblem-desktop", NULL, 32);
    gtk_show_about_dialog(NULL,
                  "logo", ico,
                  "license", xfce_get_license_text(XFCE_LICENSE_TEXT_GPL),
                  "version", XFCE_PLUGIN_VERSION,
                  "program-name", "dicons-applet",
                  "comments", _("Opens a configuration menu for desktop icons"),
                  "website", "https://github.com/Misko-2083",
                  "copyright", _(dicons_plugin_copyright),
                  "authors", auth,
                  NULL);
    if (ico)
        g_object_unref(G_OBJECT(ico));
}

static void
_quit_cb (GtkWidget *button, GtkWidget *window, gpointer data)
{
    gtk_window_close (GTK_WINDOW (window));
    
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
    
    return;
}

static gboolean
on_popup_focus_out (GtkWidget *widget,
                    GdkEventFocus *event,
                    gpointer data)
{
  DiconsPlugin *dicons = (DiconsPlugin *) data;
  gtk_window_close (GTK_WINDOW (dicons->window));

  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dicons->button), FALSE);
  
  return TRUE;
}

static gboolean
on_key_pressed    (GtkWidget *widget,
                   GdkEventKey *event,
                   gpointer data)
{
    if (event->keyval == GDK_KEY_Escape){
        gtk_window_close (GTK_WINDOW (widget));
        
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), FALSE);
        
        return TRUE;
    }
    return FALSE;
}


static gboolean
on_switch         (GtkWidget *widget,
                   gboolean *state,
                   gpointer user_data)
{
    XfconfChannel    *channel;

    xfconf_init(NULL);
    
    channel = xfconf_channel_get("xfce4-desktop");
    
    if (state)
        xfconf_channel_set_bool(channel, user_data, TRUE);
    else
        xfconf_channel_set_bool(channel, user_data, FALSE);
        
    xfconf_shutdown();
        
    return FALSE;
}

static gboolean
dicons_size_changed (XfcePanelPlugin *plugin,
                     gint             size,
                     DiconsPlugin    *dicons)
{
    gint              icon_size;

    /* The plugin only occupies a single row */
    size /= xfce_panel_plugin_get_nrows(plugin);

#if LIBXFCE4PANEL_CHECK_VERSION (4, 13, 0)
    icon_size = xfce_panel_plugin_get_icon_size (plugin);
#else
    // fall-back for older panel versions
    icon_size = size;
    icon_size -= 4;
    if (icon_size < 24)
        icon_size = 16;
    else if (icon_size < 32)
        icon_size = 24;
    else if (icon_size < 36)
        icon_size = 32;
#endif
    gtk_widget_set_size_request (GTK_WIDGET (dicons->button),  size, icon_size);

    return TRUE;
}

static void popover_size_changed (DiconsPlugin    *dicons)
{
    /*here react to size change*/
    g_print("size changed\n");
}

static void button_clicked_cb(GtkWidget *button,
                           DiconsPlugin    *dicons)
{
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dicons->button)))
  {       
    GtkWidget        *cancel_button;
    GtkStyleProvider *style_provider;
    GtkWidget        *box;
    GtkWidget        *box_a;
    GtkWidget        *box_b;
    GtkWidget        *boxl;
    GtkWidget        *scrolled_window;
    GtkWidget        *about_button;
    GtkWidget        *question;
    GtkWidget        *label_home;
    GtkWidget        *label_trash;
    GtkWidget        *label_filesystem;
    GtkWidget        *label_removable;
    GtkWidget        *image;
    GtkWidget        *switch_home;
    GtkWidget        *switch_trash;
    GtkWidget        *switch_filesystem;
    GtkWidget        *switch_removable;
    XfconfChannel    *channel;

    gint                     x, y;
    gint                     wx, wy, offset_x, offset_y, win_x, win_y;
    XfceScreenPosition       position;
    cairo_rectangle_int_t    rect;
    gint                     width, height;

    GdkDisplay *display = gdk_display_get_default();  
    GdkSeat *seat = gdk_display_get_default_seat(display);
    GdkDevice *device = gdk_seat_get_pointer(seat);

    gtk_init(NULL, NULL);

    dicons->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    dicons->popover = gtk_popover_new(dicons->window);

    gtk_window_set_type_hint (GTK_WINDOW(dicons->window),
                              GDK_WINDOW_TYPE_HINT_POPUP_MENU);
    gtk_widget_set_app_paintable (GTK_WIDGET(dicons->window), TRUE); //must be set to true
    gtk_widget_set_size_request(dicons->window, 400, 250);
    gtk_window_set_resizable (GTK_WINDOW(dicons->window), TRUE);
    gtk_window_set_keep_above (GTK_WINDOW (dicons->window), TRUE);
    gtk_window_set_decorated (GTK_WINDOW (dicons->window), FALSE);
    gtk_window_stick (GTK_WINDOW (dicons->window));
    gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dicons->window), TRUE);
    gtk_window_set_title (GTK_WINDOW (dicons->window), "Xfce Desktop Icons");
    gtk_widget_set_events (dicons->window, GDK_FOCUS_CHANGE_MASK);
    gtk_widget_set_events (GTK_WIDGET(dicons->window), GDK_KEY_PRESS_MASK);

    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);

    image = gtk_image_new_from_icon_name (dicons->icon_name,
                                          GTK_ICON_SIZE_BUTTON);
    question = gtk_label_new ("Desktop Icons");

    label_home = gtk_label_new ("Home");
    label_trash = gtk_label_new ("Trash");
    label_filesystem = gtk_label_new ("Filesystem");
    label_removable = gtk_label_new ("Removable");
    switch_home = gtk_switch_new ();
    switch_trash = gtk_switch_new ();
    switch_filesystem = gtk_switch_new ();
    switch_removable = gtk_switch_new ();
                      
    xfconf_init(NULL);
    
    channel = xfconf_channel_get("xfce4-desktop");

    /*  set initial switches */
    if (xfconf_channel_get_bool(channel, icon.home, TRUE))
        gtk_switch_set_state (GTK_SWITCH(switch_home), TRUE);
    else
        gtk_switch_set_state (GTK_SWITCH(switch_home), FALSE);
        
    if (xfconf_channel_get_bool(channel, icon.trash, TRUE))
        gtk_switch_set_state (GTK_SWITCH(switch_trash), TRUE);
    else
        gtk_switch_set_state (GTK_SWITCH(switch_trash), FALSE);
        
    if (xfconf_channel_get_bool(channel, icon.filesystem, TRUE))
        gtk_switch_set_state (GTK_SWITCH(switch_filesystem), TRUE);
    else
        gtk_switch_set_state (GTK_SWITCH(switch_filesystem), FALSE);

    if (xfconf_channel_get_bool(channel, icon.removable, TRUE))
        gtk_switch_set_state (GTK_SWITCH(switch_removable), TRUE);
    else
        gtk_switch_set_state (GTK_SWITCH(switch_removable), FALSE);

    xfconf_shutdown();

    gtk_popover_set_constrain_to (GTK_POPOVER (dicons->popover),
                                  GTK_POPOVER_CONSTRAINT_NONE);
    /* modal blocks the panel preferences process,
     *  it needs to be set to FALSE */
    gtk_popover_set_modal (GTK_POPOVER (dicons->popover), FALSE);

    style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
    gtk_style_context_add_provider (gtk_widget_get_style_context (dicons->popover),
                                  style_provider,
                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    char          *css_text;
    css_text = g_strdup_printf ("popover {\n"
                                "  padding: 0px;\n"
                                "  border: solid 2px;\n"
                                "}\n");

    gtk_css_provider_load_from_data (GTK_CSS_PROVIDER
                                   (style_provider),
                                   css_text, -1, NULL);
    g_free (css_text);

    gtk_container_add (GTK_CONTAINER (dicons->window), dicons->popover);
    gtk_container_set_border_width (GTK_CONTAINER(dicons->window),
                                     0);
    gtk_container_set_border_width (GTK_CONTAINER(dicons->popover),
                                     10);
    scrolled_window = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled_window),
                                    GTK_SHADOW_ETCHED_OUT);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);

    gtk_widget_set_size_request (scrolled_window, 400, 250);
    gtk_container_add (GTK_CONTAINER (scrolled_window), boxl);
    gtk_container_add (GTK_CONTAINER (dicons->popover), scrolled_window);

    gtk_box_pack_start (GTK_BOX(box_a), label_home, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_b), switch_home, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_a), label_trash, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_b), switch_trash, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_a), label_filesystem, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_b), switch_filesystem, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_a), label_removable, TRUE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX(box_b), switch_removable, TRUE, FALSE, 10);

    about_button = gtk_button_new_with_label("About");
    cancel_button = gtk_button_new_with_label("Cancel");

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

    gtk_box_pack_start (GTK_BOX(boxl), box_a, FALSE, FALSE, 5);
    gtk_box_pack_start (GTK_BOX(boxl), box_b, FALSE, FALSE, 5);
    
    gtk_box_pack_start (GTK_BOX(box), about_button, TRUE, TRUE, 10);
    gtk_box_pack_start (GTK_BOX (box), cancel_button, TRUE, TRUE, 10);
    gtk_box_pack_start (GTK_BOX(boxl), box, FALSE, FALSE, 10);
    
    gtk_widget_set_sensitive(scrolled_window, TRUE);

    g_signal_connect (G_OBJECT (GTK_WINDOW (dicons->window)),
                      "focus-out-event",
                      G_CALLBACK (on_popup_focus_out),
                      dicons);
    g_signal_connect (G_OBJECT (GTK_WINDOW (dicons->window)),
                      "key-press-event",
                      G_CALLBACK (on_key_pressed),
                      dicons->button);
    g_signal_connect (G_OBJECT (switch_home),
                     "state-set",
                      G_CALLBACK (on_switch),
                      (void *)icon.home);
    g_signal_connect (G_OBJECT (switch_trash),
                     "state-set",
                      G_CALLBACK (on_switch),
                      (void *)icon.trash);
    g_signal_connect (G_OBJECT (switch_filesystem),
                     "state-set",
                      G_CALLBACK (on_switch),
                      (void *)icon.filesystem);
    g_signal_connect (G_OBJECT (switch_removable),
                     "state-set",
                      G_CALLBACK (on_switch),
                      (void *)icon.removable);
    g_signal_connect (G_OBJECT (cancel_button),
                      "clicked",
                      G_CALLBACK (_quit_cb),
                      dicons->window);
    g_signal_connect (G_OBJECT (about_button),
                      "clicked",
                      G_CALLBACK (dicons_about),
                      dicons->plugin);
    g_signal_connect (G_OBJECT (dicons->popover),
                      "size-allocate",
                      G_CALLBACK (popover_size_changed),
                      dicons);
       xfce_panel_plugin_block_autohide(dicons->plugin, TRUE);
       
       gtk_widget_get_allocation(dicons->button, &rect);

       if (GTK_IS_TOGGLE_BUTTON (button)) {
           
           gtk_widget_show_all(GTK_WIDGET(dicons->window));

           xfce_panel_plugin_position_widget (dicons->plugin,
                                              dicons->window,
                                              NULL,
                                              &x,
                                              &y);
       } else {

           gdk_window_get_device_position(gdk_get_default_root_window(),
                                          device, &x, &y, NULL);
       }

    position = xfce_panel_plugin_get_screen_position(dicons->plugin);
    
    offset_x = 0;
    offset_y = 0;
    gint root_x, root_y, win_width, win_height;
    gtk_window_get_size (GTK_WINDOW (dicons->window), &win_width, &win_height);
    gtk_widget_realize (dicons->window);

    GdkRectangle workarea = {0};
    gdk_monitor_get_workarea(
    gdk_display_get_primary_monitor(gdk_display_get_default()), &workarea);

    gtk_window_get_position (GTK_WINDOW (dicons->window), &win_x, &win_y);
    GtkWidget *toplevel = gtk_widget_get_toplevel (dicons->button);
    gtk_widget_translate_coordinates (dicons->button, toplevel, 0, 0, &wx, &wy);

   if (gtk_widget_is_toplevel (toplevel))
     {
       gtk_window_get_size(GTK_WINDOW (toplevel), &width, &height);
       gtk_window_get_position (GTK_WINDOW (toplevel),
                                &root_x,
                                &root_y);
     }
    if (xfce_screen_position_is_horizontal(position)) {
        /* horizontal */
            if (win_width/2 > (root_x + wx)){
              offset_x = x + 10;
              rect.x = wx + 10;
            }
            else if ((win_width) > (workarea.width - (root_x + wx))) {
              offset_x = - 10;
              rect.x = (win_width - (workarea.width - (root_x + wx + offset_x)));
              if ((workarea.width - (root_x + wx)) > win_width/2) {
                   offset_x = workarea.width - (root_x + wx) - win_width/2 - rect.width/2;
                   rect.x = win_width/2 - rect.width/2;
              }
            }
            else {
              offset_x = win_width/2 - rect.width/2;
              rect.x = win_width/2 - rect.width/2;
            }
        if (win_y > (root_y + wy)) {
              /* top panel position */
              gtk_popover_set_position(GTK_POPOVER(dicons->popover), GTK_POS_BOTTOM);
              rect.y = 0;
            }
        if (win_y < (root_y + wy)) {
              /* bottom */
              gtk_popover_set_position(GTK_POPOVER(dicons->popover), GTK_POS_TOP);
              rect.y = win_height + rect.height;
            }
    } else {
            if (win_height/2 > (root_y + wy)){
              offset_y = y + 10;
              rect.y = wy + 10;
            }
            else if (win_height > (workarea.height - (root_y + wy))) {
              offset_y = - 10;
              rect.y = (win_height - (workarea.height - (root_y + wy + offset_y)));
              if ((workarea.height - (root_y + wy)) > win_height/2) {
                   offset_y = workarea.height - (root_y + wy) - win_height/2 - rect.height/2;
                   rect.y = win_height/2 - rect.height/2;
              }
            }
            else {
              offset_y = win_height/2 - rect.height/2;
              rect.y = win_height/2 - rect.height/2;
            }
        /* vertical */
        if (win_x < (root_x + wx)) {
            /* left */
            gtk_popover_set_position(GTK_POPOVER(dicons->popover), GTK_POS_RIGHT);
            rect.x = 0;
            }
        if (win_x < (root_x + wx)) {
            /* right */
            gtk_popover_set_position(GTK_POPOVER(dicons->popover), GTK_POS_LEFT);
            rect.x = win_width + rect.width;
            }
    }
       gtk_window_move (GTK_WINDOW (dicons->window), x - offset_x, y - offset_y);

       gtk_popover_set_pointing_to (GTK_POPOVER (dicons->popover), &rect);
       gtk_popover_popup (GTK_POPOVER (dicons->popover));
       gtk_widget_set_sensitive (cancel_button, TRUE);
       gtk_widget_grab_focus (cancel_button);
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dicons->button), TRUE);

  } else {
      
       _quit_cb(dicons->button, dicons->window, NULL);
       if (GTK_IS_TOGGLE_BUTTON (button))
           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(dicons->button), FALSE);
       
       xfce_panel_plugin_block_autohide(dicons->plugin, FALSE);
       gtk_popover_popdown (GTK_POPOVER (dicons->popover));
  }
}


static DiconsPlugin *dicons_init(XfcePanelPlugin *plugin)
{
    GtkOrientation  orientation;

    DiconsPlugin *dicons = g_slice_new0(DiconsPlugin);

    dicons->plugin = plugin;

    dicons->icon_name = g_strdup(DEFAULT_ICON_NAME);

    dicons->ebox = gtk_event_box_new ();
    gtk_event_box_set_visible_window (GTK_EVENT_BOX (dicons->ebox), FALSE);
    gtk_widget_show (dicons->ebox);

    orientation = xfce_panel_plugin_get_orientation (plugin);

    dicons->hvbox = gtk_box_new (orientation, 2);
    gtk_widget_show (dicons->hvbox);
    gtk_container_add (GTK_CONTAINER (dicons->ebox), dicons->hvbox);


    dicons->button = xfce_panel_create_toggle_button();
    gtk_widget_show (dicons->button);
    gtk_box_pack_start (GTK_BOX (dicons->hvbox), dicons->button, FALSE, FALSE, 0);

    dicons->icon = xfce_panel_image_new_from_source(dicons->icon_name);
    gtk_widget_show(dicons->icon);
    gtk_container_add(GTK_CONTAINER(dicons->button), dicons->icon);


    gtk_widget_set_tooltip_text (GTK_WIDGET(dicons->hvbox),
                                 DEFAULT_TOOLTIP_MESSAGE);

    g_signal_connect (G_OBJECT(dicons->button), "toggled",
                      G_CALLBACK(button_clicked_cb), dicons);

    return dicons;
}

static void dicons_free(XfcePanelPlugin *plugin, DiconsPlugin *dicons)
{
    gtk_widget_destroy(dicons->button);
    
    gtk_widget_destroy(dicons->icon);

    g_slice_free(DiconsPlugin, dicons);
}

static void set_button_active (GtkToggleButton *button)
{
     if (GTK_IS_TOGGLE_BUTTON(button)) {
     
         if (!gtk_toggle_button_get_active(button)) {
              gtk_toggle_button_set_active(button, TRUE);
             }
         else
             {
              gtk_toggle_button_set_active(button, FALSE);
             }
     }
}

static gboolean dicons_remote (XfcePanelPlugin *plugin,
                               gchar           *name,
                               GValue          *value,
                               DiconsPlugin    *dicons)
{
    g_return_val_if_fail (value == NULL || G_IS_VALUE (value), FALSE);
    
    if (strcmp (name, "popup") == 0
        && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dicons->button)) 
        &&  gtk_widget_get_visible (GTK_WIDGET (plugin)) )
        {
        if (value != NULL
            && G_VALUE_HOLDS_BOOLEAN (value)
            && g_value_get_boolean (value))
            {
              set_button_active (GTK_TOGGLE_BUTTON(dicons->button));
                /* popup here at mouse pointer , where X is an internal id
                 * xfce4-panel --plugin-event=desktop-icons-applet-X:popup:bool:true
                 */
              button_clicked_cb (NULL, dicons);
            }
        else
            {    
                set_button_active (GTK_TOGGLE_BUTTON(dicons->button));
                /* popup here, where X is an internal id
                 * xfce4-panel --plugin-event=desktop-icons-applet-X:popup:bool:false
                 */
              button_clicked_cb (dicons->button, dicons);
            }
       return TRUE;

        }
    return FALSE;
}

static void dicons_construct(XfcePanelPlugin *plugin)
{
    DiconsPlugin *dicons;
    
    dicons = dicons_init(plugin);

    gtk_container_add (GTK_CONTAINER(plugin), dicons->ebox);
    
    xfce_panel_plugin_add_action_widget(plugin, dicons->ebox);
    
    xfce_panel_plugin_menu_show_about(plugin);
    
    g_signal_connect (G_OBJECT(plugin),
                     "free-data",
                     G_CALLBACK(dicons_free), dicons);
    g_signal_connect (G_OBJECT(plugin),
                     "size-changed",
                     G_CALLBACK(dicons_size_changed), dicons);
    g_signal_connect (G_OBJECT (plugin),
                     "remote-event",
                     G_CALLBACK(dicons_remote), dicons);
    g_signal_connect (G_OBJECT (plugin),
                     "about",
                    G_CALLBACK (dicons_about), dicons);
}

Compile with:

gcc -Wall -s -shared -fPIC -g desktop-icons-plugin.c -o libdicons.so $(pkg-config --libs --cflags gtk+-3.0 libxfce4util-1.0 libxfce4panel-2.0 libxfconf-0)

Then move libdicons.so to libdir.

sudo mv libdicons.so $(pkg-config --variable=libdir libxfce4panel-2.0)/xfce4/panel/plugins/libdicons.so

Add "Desktop Icons" to the panel.

It will close if clicked outside (looses focus) or panel button is clicked, or escape key is pressed.
Can launch with this from terminal:

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

What I can't figure out is how to close the window if popover's arrow is clicked.
Also if on popover is clicked, that small area between the scrolled window inside the popover and popover's outer border.
Then a black popover is painted.

Edit:
And video: https://www.youtube.com/watch?v=nFLXxA0i1dg

Last edited by Misko_2083 (2022-05-25 13:45:29)


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

Offline

Board footer

Powered by FluxBB