I am trying to write a plugin for xfce4 panel. It should show a popup with complex container like GtkBox.
My code in vala is:
using Xfce;
public class ButtonPlugin : Xfce.PanelPlugin {
private Gtk.MenuButton button;
private Gtk.Popover popover;
public override void #construct () {
button = new Gtk.MenuButton();
popover = new Gtk.Popover(button);
button.set_image(
new Gtk.Image.from_icon_name (
"open-menu-symbolic",
Gtk.IconSize.LARGE_TOOLBAR
)
);
var menu_container = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
menu_container.pack_start(new Gtk.Label("Hello World 1"));
menu_container.pack_start(new Gtk.Label("Hello World 2"));
menu_container.pack_start(new Gtk.Label("Hello World 3"));
popover.add(menu_container);
popover.show_all ();
popover.hide();
button.popover = popover;
add (button);
//button.show ();
add_action_widget (button);
save.connect (() => { message ("save yourself"); });
free_data.connect (() => { message ("free yourself"); });
size_changed.connect (() => { message ("panel size changed"); return false; });
menu_show_about ();
about.connect (() => {
Gtk.show_about_dialog (null,
"program-name", "Button",
"comments", "Test plugin for the Xfce 4.14 Panel",
null);
});
destroy.connect (() => { Gtk.main_quit (); });
show_all();
}
}
[ModuleInit]
public Type xfce_panel_module_init (TypeModule module) {
return typeof (ButtonPlugin);
}
The plugin starts, but doesn't show the popover when clicked.
Is it possible using Popover or should I switch to another widget ?
From what I understand, no, popovers won't work in Xfce panel plugins.
Take a look at this gist: https://gist.github.com/andreldm/83c9b99e7aa133c924fb4165acc8427a
The standalone app shows the popover correctly, but try making the window as small as the button, there is no room left for the popover, that's the same problem in a panel plugin. If I'm not mistaken context menus work because they are completely new windows while popover aren't.
In the same gist you can find a diff against xfce4-sample-plugin with code similar to what you are trying.
Popover is not designed to work as a standalone menu.
It does not have it's own window.
There has to be a window and popover has to be attached to the widget.
Let's say dummy widget as a 1x1 pixel transparent image.
This is a standalone (sort of) popover in C:
#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;
}
What adds more complications are the arrows.
You have to calculate where to position the window next to the panel plugin button.
Above that you have to position the arrow correctly which does not look so easy.
https://www.youtube.com/watch?v=eXZzwDDQlZ8
Perhaps putting 8 or more dummy images around the popover and point to them depending on the panel's orientation and plugin's position on the screen.
The code in the video:
/*
* Copyright © 2020 misko_2083
*
* Distributed under terms of the GPL2 license.
*
* Compile:
* gcc -Wall -s -shared -fPIC -g desktop-icons-applet.c -o desktop-icons-applet $(pkg-config --libs --cflags gtk+-3.0 libxfce4panel-2.0 libxfconf-0)
* move to lib dir (Debian 64bit here):
* mv libdicons.so /usr/lib/x86_64-linux-gnu/xfce4/panel/plugins/libdicons.so
*/
#include <libxfce4util/libxfce4util.h>
#include <libxfce4panel/xfce-panel-plugin.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.1"
/* change the path here to a 1 pixel transparent png */
#define DUMMY_PNG "/home/misko/Desktop/null.png"
typedef struct _DiconsPlugin {
XfcePanelPlugin *plugin;
GtkWidget *button;
GtkWidget *icon;
GtkWidget *window;
GtkWidget *popover;
GtkWidget *dummy_png_top_left;
GtkWidget *dummy_png_top_center;
GtkWidget *dummy_png_top_right;
GtkWidget *dummy_png_bottom_left;
GtkWidget *dummy_png_bottom_center;
GtkWidget *dummy_png_bottom_right;
gchar *icon_name;
} DiconsPlugin;
static void
button_clicked (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 *icon;
icon = xfce_panel_pixbuf_from_source("emblem-desktop", NULL, 32);
gtk_show_about_dialog(NULL,
"logo", icon,
"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 (icon)
g_object_unref(G_OBJECT(icon));
}
static void
_quit_cb (GtkWidget *button, GtkWidget *window, gpointer data)
{
(void)data; /* Avoid compiler warnings */
gtk_widget_hide (window);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
return;
}
static gboolean
on_popup_focus_out (GtkWidget *widget,
GdkEventFocus *event,
gpointer data)
{
gtk_widget_hide (widget);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), FALSE);
return TRUE;
}
static gboolean
on_key_pressed (GtkWidget *widget,
GdkEventKey *event,
gpointer data)
{
if (event->keyval == GDK_KEY_Escape){
gtk_widget_hide (widget);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), FALSE);
return TRUE;
}
return FALSE;
}
static gboolean
on_switch_home (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, "/desktop-icons/file-icons/show-home", TRUE);
else
xfconf_channel_set_bool(channel, "/desktop-icons/file-icons/show-home", FALSE);
xfconf_shutdown();
return FALSE;
}
static gboolean
on_switch_trash (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, "/desktop-icons/file-icons/show-trash", TRUE);
else
xfconf_channel_set_bool(channel, "/desktop-icons/file-icons/show-trash", FALSE);
xfconf_shutdown();
return FALSE;
}
static gboolean
on_switch_filesystem (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, "/desktop-icons/file-icons/show-filesystem", TRUE);
else
xfconf_channel_set_bool(channel, "/desktop-icons/file-icons/show-filesystem", FALSE);
xfconf_shutdown();
return FALSE;
}
static gboolean
on_switch_removable (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, "/desktop-icons/file-icons/show-removable", TRUE);
else
xfconf_channel_set_bool(channel, "/desktop-icons/file-icons/show-removable", FALSE);
xfconf_shutdown();
return FALSE;
}
static gboolean dicons_size_changed (XfcePanelPlugin *plugin,
gint size,
DiconsPlugin *dicons)
{
XfceScreenPosition position;
position = xfce_panel_plugin_get_screen_position(plugin);
if (xfce_screen_position_is_horizontal(position)) {
/* horizontal */
if (xfce_screen_position_is_top(position)) {
/* top panel position */
gtk_popover_set_relative_to(GTK_POPOVER(dicons->popover), dicons->dummy_png_top_left);
}
if (xfce_screen_position_is_bottom(position)) {
/* bottom */
gtk_popover_set_relative_to(GTK_POPOVER(dicons->popover), dicons->dummy_png_bottom_left);
}
if (xfce_screen_position_is_floating(position)) {
/* floating */
gtk_popover_set_relative_to(GTK_POPOVER(dicons->popover), dicons->dummy_png_top_left);
/* TO DO: check if the button is in the top or bottom side
* of the screen and set the correct dummy widget
*/
}
} else {
/* vertical */
if (xfce_screen_position_is_left(position)) {
/* left */
gtk_popover_set_relative_to(GTK_POPOVER(dicons->popover), dicons->dummy_png_top_left);
}
if (xfce_screen_position_is_right(position)) {
/* right */
gtk_popover_set_relative_to(GTK_POPOVER(dicons->popover), dicons->dummy_png_top_left);
}
if (xfce_screen_position_is_floating(position)) {
/* floating */
gtk_popover_set_relative_to(GTK_POPOVER(dicons->popover), dicons->dummy_png_bottom_left);
/* TO DO: check if the button is in the left or right side
* of the screen and set the correct dummy widget
*/
}
}
size = size / xfce_panel_plugin_get_nrows(plugin);
gtk_widget_set_size_request (GTK_WIDGET (plugin), size, size);
return TRUE;
}
static void button_clicked(GtkWidget *button,
DiconsPlugin *dicons)
{
gint x, y;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dicons->button)))
{
dicons_size_changed(dicons->plugin, xfce_panel_plugin_get_size (dicons->plugin), dicons);
xfce_panel_plugin_block_autohide(dicons->plugin, TRUE);
if (GTK_IS_TOGGLE_BUTTON (button)) {
xfce_panel_plugin_position_widget(XFCE_PANEL_PLUGIN (dicons->plugin),
GTK_WIDGET(dicons->window),
button, &x, &y);
} else {
GdkDisplay *display = gdk_display_get_default();
GdkSeat *seat = gdk_display_get_default_seat(display);
GdkDevice *device = gdk_seat_get_pointer(seat);
gdk_window_get_device_position(gdk_get_default_root_window(),
device, &x, &y, NULL);
}
gtk_popover_popup(GTK_POPOVER(dicons->popover));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dicons->button), TRUE);
if (!gtk_widget_get_mapped(dicons->window))
gtk_widget_show_all(GTK_WIDGET(dicons->window));
gtk_window_move (GTK_WINDOW(dicons->window), x, y);
/* fix me: this function is called twice */
} else {
_quit_cb(dicons->button, dicons->window, NULL);
if (GTK_IS_TOGGLE_BUTTON (button))
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
xfce_panel_plugin_block_autohide(dicons->plugin, FALSE);
gtk_popover_popdown(GTK_POPOVER(dicons->popover));
}
}
static DiconsPlugin *dicons_init(XfcePanelPlugin *plugin)
{
GtkWidget *box;
GtkWidget *box_a;
GtkWidget *box_b;
GtkWidget *boxl;
GtkWidget *about_button;
GtkWidget *cancel_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;
GdkWindow *pwindow;
GtkWidget *dummy_box_top;
GtkWidget *dummy_box_bottom;
XfconfChannel *channel;
DiconsPlugin *dicons = g_slice_new0(DiconsPlugin);
dicons->plugin = plugin;
dicons->icon_name = g_strdup(DEFAULT_ICON_NAME);
dicons->button = xfce_panel_create_toggle_button();
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (dicons->plugin),
dicons->button);
gtk_init(NULL, NULL);
dicons->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_type_hint (GTK_WINDOW(dicons->window),
GDK_WINDOW_TYPE_HINT_POPUP_MENU);
gtk_widget_set_size_request(dicons->window, 250, 220);
gtk_window_set_resizable (GTK_WINDOW(dicons->window), TRUE);
gtk_window_set_keep_above (GTK_WINDOW (dicons->window), TRUE);
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), "Desktop Icons");
gtk_widget_set_events (dicons->window, GDK_FOCUS_CHANGE_MASK);
g_signal_connect (G_OBJECT (GTK_WINDOW (dicons->window)),
"focus-out-event",
G_CALLBACK (on_popup_focus_out),
dicons->button);
gtk_widget_set_events (GTK_WIDGET(dicons->window), GDK_KEY_PRESS_MASK);
g_signal_connect (G_OBJECT (GTK_WINDOW (dicons->window)),
"key-press-event",
G_CALLBACK (on_key_pressed),
dicons->button);
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_DND);
question = gtk_label_new ("\nDesktop 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 ();
g_signal_connect (G_OBJECT (switch_home),
"state-set",
G_CALLBACK (on_switch_home),
NULL);
g_signal_connect (G_OBJECT (switch_trash),
"state-set",
G_CALLBACK (on_switch_trash),
NULL);
g_signal_connect (G_OBJECT (switch_filesystem),
"state-set",
G_CALLBACK (on_switch_filesystem),
NULL);
g_signal_connect (G_OBJECT (switch_removable),
"state-set",
G_CALLBACK (on_switch_removable),
NULL);
xfconf_init(NULL);
channel = xfconf_channel_get("xfce4-desktop");
/* set initial switches */
if (xfconf_channel_get_bool(channel, "/desktop-icons/file-icons/show-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, "/desktop-icons/file-icons/show-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, "/desktop-icons/file-icons/show-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, "/desktop-icons/file-icons/show-removable", TRUE))
gtk_switch_set_state (GTK_SWITCH(switch_removable), TRUE);
else
gtk_switch_set_state (GTK_SWITCH(switch_removable), FALSE);
xfconf_shutdown();
dicons->dummy_png_top_left = gtk_image_new_from_file (DUMMY_PNG);
dicons->dummy_png_top_center = gtk_image_new_from_file (DUMMY_PNG);
dicons->dummy_png_top_right = gtk_image_new_from_file (DUMMY_PNG);
dummy_box_top = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX(dummy_box_top), dicons->dummy_png_top_left, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX(dummy_box_top), dicons->dummy_png_top_center, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX(dummy_box_top), dicons->dummy_png_top_right, TRUE, FALSE, 0);
dicons->dummy_png_bottom_left = gtk_image_new_from_file (DUMMY_PNG);
dicons->dummy_png_bottom_center = gtk_image_new_from_file (DUMMY_PNG);
dicons->dummy_png_bottom_right = gtk_image_new_from_file (DUMMY_PNG);
dummy_box_bottom = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX(dummy_box_bottom), dicons->dummy_png_bottom_left, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX(dummy_box_bottom), dicons->dummy_png_bottom_center, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX(dummy_box_bottom), dicons->dummy_png_bottom_right, TRUE, FALSE, 0);
gtk_widget_show(dicons->dummy_png_top_left);
gtk_widget_show(dicons->dummy_png_top_center);
gtk_widget_show(dicons->dummy_png_top_right);
gtk_widget_show(dicons->dummy_png_bottom_left);
gtk_widget_show(dicons->dummy_png_bottom_center);
gtk_widget_show(dicons->dummy_png_bottom_right);
dicons->popover = gtk_popover_new(dicons->dummy_png_top_left);
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);
gtk_container_add(GTK_CONTAINER(dicons->window), dicons->popover);
gtk_container_add(GTK_CONTAINER(dicons->popover), boxl);
gtk_box_pack_start (GTK_BOX(box_a), label_home, TRUE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_a), switch_home, FALSE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_a), label_trash, TRUE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_a), switch_trash, FALSE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_b), label_filesystem, TRUE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_b), switch_filesystem, FALSE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_b), label_removable, TRUE, TRUE, 10);
gtk_box_pack_start (GTK_BOX(box_b), switch_removable, FALSE, TRUE, 10);
about_button = gtk_button_new_with_label("About");
cancel_button = gtk_button_new_with_label("Cancel");
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),
plugin);
gtk_box_pack_start (GTK_BOX(boxl), dummy_box_top, TRUE, TRUE, 0);
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, TRUE, 5);
gtk_box_pack_start (GTK_BOX(boxl), box_b, FALSE, TRUE, 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, TRUE, TRUE, 10);
gtk_box_pack_end (GTK_BOX(boxl), dummy_box_bottom, TRUE, TRUE, 0);
gtk_window_set_decorated (GTK_WINDOW(dicons->window), FALSE);
gtk_widget_show(dicons->button);
/*gtk_window_set_attached_to(GTK_WINDOW(dicons->window),
dicons->button);*/
pwindow = gtk_widget_get_parent_window(dicons->button);
gtk_window_set_transient_for(GTK_WINDOW(dicons->window),
GTK_WINDOW(pwindow));
g_signal_connect(G_OBJECT(dicons->button), "toggled",
G_CALLBACK(button_clicked), dicons);
gtk_widget_set_tooltip_text (GTK_WIDGET(dicons->button),
DEFAULT_TOOLTIP_MESSAGE);
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);
return dicons;
}
static void dicons_free(XfcePanelPlugin *plugin, DiconsPlugin *dicons)
{
gtk_widget_destroy(dicons->button);
gtk_widget_destroy(dicons->icon);
if (GTK_IS_WIDGET (dicons->window))
gtk_widget_destroy(dicons->window);
if (GTK_IS_WIDGET (dicons->popover))
gtk_widget_destroy(dicons->popover);
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(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(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->button);
xfce_panel_plugin_add_action_widget(plugin, dicons->button);
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);
}
XFCE_PANEL_PLUGIN_REGISTER(dicons_construct);
And the desktop file
/usr/share/xfce4/panel/plugins/desktop-icons-applet.desktop
[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
This code takes a file from dialogo_chosser and adds in a gtk_tree_view...
I would take more files from one gtkfilechosser and add them in a gtk_tree_view...
I saw that you must enter this function:
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE)
but I do not know how to take the selected files :(
I ask "politely" a small example for this solution
my code is:
#include "header.h"
#include <string.h>
#include <gtk/gtk.h>
GtkWidget *list;
GtkWidget *win;
char *filename;
void Add_Items_List(GtkWidget *widget, gpointer data)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, filename, -1);
}
void Dialog_Chooser(GtkWidget *widget, gpointer gst)
{
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
GtkFileChooser *chooser;
gint res;
dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(win), action,
"Cancel", GTK_RESPONSE_CANCEL,
"Open", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if(res == GTK_RESPONSE_ACCEPT){
chooser = GTK_FILE_CHOOSER(dialog);
filename = gtk_file_chooser_get_filename(chooser);
Add_Items_List(NULL, NULL);
g_free(filename);
}
gtk_widget_destroy(dialog);
}
void Delete_Item_List(GtkWidget *widget, gpointer selection)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
if(gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)){
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
}
}
void Delete_All_Items_List(GtkWidget *widget, gpointer selection)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_clear(store);
}
void Inizializes_The_List(GtkWidget *list)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkListStore *store;
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Lenguages", renderer, "text", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
store = gtk_list_store_new(1, G_TYPE_STRING);
gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
g_object_unref(store);
}
void Add_Lista(GtkWidget *list, const gchar *str)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, str, -1);
}
int main(int argc, char **argv)
{
GtkWidget *Button_remove;
GtkWidget *button_remove_all;
GtkWidget *button_chosser;
GtkWidget *sw;
GtkWidget *hbox;
GtkWidget *vbox;
GtkTreeSelection *selection;
gtk_init(&argc, &argv);
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Simple chosser list");
gtk_window_set_default_size(GTK_WINDOW(win), 200, 200);
gtk_container_set_border_width(GTK_CONTAINER(win), 10);
sw = gtk_scrolled_window_new(NULL, NULL);
list = gtk_tree_view_new();
gtk_container_add(GTK_CONTAINER(sw), list);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 5);
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
Button_remove = gtk_button_new_with_label("Delete");
button_remove_all = gtk_button_new_with_label("Delte All");
button_chosser = gtk_button_new_with_label("List");
gtk_box_pack_start(GTK_BOX(hbox), Button_remove, FALSE, TRUE, 3);
gtk_box_pack_start(GTK_BOX(hbox), button_remove_all, FALSE, TRUE, 3);
gtk_box_pack_start(GTK_BOX(hbox), button_chosser, FALSE, TRUE, 3);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3);
gtk_container_add(GTK_CONTAINER(win), vbox);
Inizializes_The_List(list);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
g_signal_connect(G_OBJECT(button_chosser), "clicked", G_CALLBACK(Dialog_Chooser), NULL);
g_signal_connect(Button_remove, "clicked", G_CALLBACK(Delete_Item_List), selection);
g_signal_connect(button_remove_all, "clicked", G_CALLBACK(Delete_All_Items_List), selection);
g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy), NULL);
gtk_widget_show_all(win);
gtk_main();
return 0;
}
ps: use gtk+3 on ubuntu 16.04
For now, I have found this solution:
void Dialog_Chooser(GtkWidget *widget, gpointer gst)
{
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
GtkFileChooser *chooser;
gint res;
dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(win), action, "Cancel",
GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if(res == GTK_RESPONSE_ACCEPT){
GSList *filenamepus;
chooser = GTK_FILE_CHOOSER(dialog);
//filename = gtk_file_chooser_get_filename(chooser);
filenamepus = gtk_file_chooser_get_filenames(chooser);
int nIndex;
GSList *node;
for(nIndex = 0; node = g_slist_nth(filenamepus, nIndex); nIndex++){
filename = (char *) node->data; //g_slist_nth(filenamepus, nIndex);
Add_Items_List(NULL, NULL);
//g_print ("%s\n", filename); //(char *) node->data);
}
//Add_Items_List(NULL, NULL);
g_free(filename);
}
gtk_widget_destroy(dialog);
}
If anyone knows a better solution, I would still love to hear it.
I am trying to show a animated gif which has transparent background. but the result is that the background is not transparent, below is my code, what is wrong with it?
package amarsoft.rcp.base.widgets;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
/**
* 负责显示各种格式的图片
*
* #author ggfan#amarsoft
*/
public class ImageViewer extends Canvas {
protected Point origin = new Point(0, 0);
protected Image image;
protected ImageData[] imageDatas;
protected Image[] images;
protected int current;
private int repeatCount;
private Runnable animationTimer;
private Color bg;
private Display display;
public ImageViewer(Composite parent) {
super(parent,SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND);
bg = getBackground();
display = getDisplay();
addListeners();
}
public void setImage(ImageData imageData) {
checkWidget();
stopAnimationTimer();
if(imageData != null){
this.image = new Image(display, imageData);
}
this.imageDatas = null;
this.images = null;
redraw();
}
/**
* #param repeatCount
* 0 forever
*/
public void setImages(ImageData[] imageDatas, int repeatCount) {
checkWidget();
this.image = null;
this.imageDatas = imageDatas;
this.repeatCount = repeatCount;
convertImageDatasToImages();
startAnimationTimer();
redraw();
}
#Override
public Point computeSize(int wHint, int hHint, boolean changed) {
checkWidget();
Image image = getCurrentImage();
if (image != null) {
Rectangle rect = image.getBounds();
Rectangle trim = computeTrim(0, 0, rect.width, rect.height);
return new Point(trim.width, trim.height);
}
return new Point(wHint, hHint);
}
#Override
public void dispose() {
if (image != null)
image.dispose();
if (images != null)
for (int i = 0; i < images.length; i++)
images[i].dispose();
super.dispose();
}
protected void paint(Event e) {
Image image = getCurrentImage();
if (image == null)
return;
GC gc = e.gc;
gc.drawImage(image, origin.x, origin.y);
gc.setAntialias(SWT.ON);
//gc.setBackground(bg);
Rectangle rect = image.getBounds();
Rectangle client = getClientArea();
int marginWidth = client.width - rect.width;
if (marginWidth > 0) {
//gc.fillRectangle(rect.width, 0, marginWidth, client.height);
}
int marginHeight = client.height - rect.height;
if (marginHeight > 0) {
//gc.fillRectangle(0, rect.height, client.width, marginHeight);
}
}
void addListeners() {
addListener(SWT.Paint, new Listener() {
public void handleEvent(Event e) {
paint(e);
}
});
}
void convertImageDatasToImages() {
images = new Image[imageDatas.length];
// Step 1: Determine the size of the resulting images.
int width = imageDatas[0].width;
int height = imageDatas[0].height;
// Step 2: Construct each image.
int transition = SWT.DM_FILL_BACKGROUND;
for (int i = 0; i < imageDatas.length; i++) {
ImageData id = imageDatas[i];
images[i] = new Image(display, width, height);
GC gc = new GC(images[i]);
gc.setAntialias(SWT.ON);
// Do the transition from the previous image.
switch (transition) {
case SWT.DM_FILL_NONE:
case SWT.DM_UNSPECIFIED:
// Start from last image.
gc.drawImage(images[i - 1], 0, 0);
break;
case SWT.DM_FILL_PREVIOUS:
// Start from second last image.
gc.drawImage(images[i - 2], 0, 0);
break;
default:
// DM_FILL_BACKGROUND or anything else,
// just fill with default background.
//gc.setBackground(bg);
//gc.fillRectangle(0, 0, width, height);
break;
}
// Draw the current image and clean up.
Image img = new Image(display, id);
gc.drawImage(img, 0, 0, id.width, id.height, id.x, id.y, id.width,
id.height);
img.dispose();
gc.dispose();
// Compute the next transition.
// Special case: Can't do DM_FILL_PREVIOUS on the
// second image since there is no "second last"
// image to use.
transition = id.disposalMethod;
if (i == 0 && transition == SWT.DM_FILL_PREVIOUS)
transition = SWT.DM_FILL_NONE;
}
}
Image getCurrentImage() {
if (image != null)
return image;
if (images == null)
return null;
return images[current];
}
void startAnimationTimer() {
if (images == null || images.length < 2)
return;
final int delay = imageDatas[current].delayTime * 10;
display.timerExec(delay, animationTimer = new Runnable() {
public void run() {
if (isDisposed())
return;
current = (current + 1) % images.length;
redraw();
if (current + 1 == images.length && repeatCount != 0
&& --repeatCount <= 0)
return;
display.timerExec(delay, this);
}
});
}
void stopAnimationTimer() {
if (animationTimer != null)
display.timerExec(-1, animationTimer);
}
}
Wow, so much work for gif animation..
Anyway, check Transparency part of article about SWT Images, it might help you.