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'm using an arduino to make a Cloud Light with an IR remote. I am trying to make one of the buttons simulate a thunder storm where the white LED's will randomly flash WITHIN the boolean statement under the specific code... Trouble is, I can only make it go through the flash period once... Here's the portion of code for the storm:
#include <IRremote.h>
// My modified code
int RECV_PIN = 11;
int red = 2;
int yellow = 3;
int green = 4;
int blue = 5;
int purple = 6;
int white = 7;
long randOn = random(10,200);
long guess = random(1000,20000);
#define powercode 16726725
#define stormcode 4294967295
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
pinMode(red, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(green, OUTPUT);
pinMode(blue, OUTPUT);
pinMode(purple, OUTPUT);
pinMode(white, OUTPUT);
irrecv.enableIRIn(); // Start the receiver
}
int redbool = 0;
int orangebool = 0;
int yellowbool = 0;
int greenbool = 0;
int bluebool = 0;
int purplebool = 0;
int whitebool = 0;
int rgbbool = 0;
int rainbowbool = 0;
int sunbool = 0;
int rainbool = 0;
int stormbool = 0;
int quickbool = 0;
unsigned long last = millis();
void loop() {
if (irrecv.decode(&results)) {
//Sun
if (results.value == 16726725) {
if (millis() - last > 250) {
sunbool = !sunbool;
if (sunbool == 0) {
digitalWrite (red, LOW);
digitalWrite (yellow, LOW);
digitalWrite (green, LOW);
digitalWrite (blue, LOW);
digitalWrite (purple, LOW);
digitalWrite (white, LOW);
}
else {
digitalWrite (red, LOW);
digitalWrite (green, LOW);
digitalWrite (blue, LOW);
digitalWrite (purple, LOW);
digitalWrite (white, HIGH);
digitalWrite (yellow, HIGH);
}
}
last = millis();
}
//rain
if (results.value == 16745085) {
if (millis() - last > 250) {
rainbool = !rainbool;
if (rainbool == 0) {
digitalWrite (red, LOW);
digitalWrite (yellow, LOW);
digitalWrite (green, LOW);
digitalWrite (blue, LOW);
digitalWrite (purple, LOW);
digitalWrite (white, LOW);
}
else {
digitalWrite (red, LOW);
digitalWrite (green, LOW);
digitalWrite (yellow, LOW);
digitalWrite (purple, LOW);
digitalWrite (white, HIGH);
digitalWrite (blue, HIGH);
}
}
last = millis();
}
//storm
if (results.value == 16759365) {
if (millis() - last > 250) {
stormbool = !stormbool;
if (stormbool == 0) {
digitalWrite (red, LOW);
digitalWrite (yellow, LOW);
digitalWrite (green, LOW);
digitalWrite (blue, HIGH);
digitalWrite (purple, HIGH);
digitalWrite (white, LOW);
}
else {
digitalWrite (red, LOW);
digitalWrite (green, LOW);
digitalWrite (yellow, LOW);
digitalWrite (white, LOW);
digitalWrite (blue, HIGH);
digitalWrite (purple, HIGH);
digitalWrite(white, HIGH);
delay(randOn);
digitalWrite(white, LOW);
delay(randOn + randOn);
digitalWrite(white, HIGH);
delay(randOn);
digitalWrite(white, LOW);
}
}
last = millis();
}
//rainbow
if (results.value == 16712445) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
rainbowbool = !rainbowbool;
digitalWrite(white, LOW);
digitalWrite(red, rainbowbool ? HIGH : LOW);
digitalWrite(yellow, rainbowbool ? HIGH : LOW);
digitalWrite(green, rainbowbool ? HIGH : LOW);
digitalWrite(blue, rainbowbool ? HIGH : LOW);
digitalWrite(purple, rainbowbool ? HIGH : LOW);
}
last = millis();
}
//red
if (results.value == 16718565) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
redbool = !redbool;
digitalWrite(red, redbool ? HIGH : LOW);
}
last = millis();
}
//orange
if (results.value == 16726215) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
orangebool = !orangebool;
digitalWrite(red, orangebool ? HIGH : LOW);
digitalWrite(yellow, orangebool ? HIGH : LOW);
}
last = millis();
}
//yellow
if (results.value == 16718055) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
yellowbool = !yellowbool;
digitalWrite(yellow, yellowbool ? HIGH : LOW);
}
last = millis();
}
//green
if (results.value == 16751205) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
greenbool = !greenbool;
digitalWrite(green, greenbool ? HIGH : LOW);
}
last = millis();
}
//blue
if (results.value == 16753245) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
bluebool = !bluebool;
digitalWrite(blue, bluebool ? HIGH : LOW);
}
last = millis();
}
//purple
if (results.value == 16757325) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
purplebool = !purplebool;
digitalWrite(purple, purplebool ? HIGH : LOW);
}
last = millis();
}
//white
if (results.value == 16720605) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
whitebool = !whitebool;
digitalWrite(white, whitebool ? HIGH : LOW);
}
last = millis();
}
//Quick section
if (results.value == 16771095) { // TIVO button
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
quickbool =! quickbool;
digitalWrite(white, HIGH);
delay(guess);
digitalWrite(white, LOW);
delay(guess);
digitalWrite(white, HIGH);
delay(guess + guess);
digitalWrite(white, LOW);
}
last = millis();
}
irrecv.resume(); // Receive the next value
}
}
If I keep adding these delays and digitalWrites, I can't change "channels" or LED's to different colors, I'm stuck until the thing finishes! Thanks for helping me ahead of time!
you are correct that when using the delay function no other action can happen. You should try and make your code like the blinkWithoutDelay example.
so you could do something like this
// struct that represents the values for each led
struct LED{
int pin; // pin # the led is connected to
int state; // state of the led , on or off
long interval; // how long we should wait before toggling
long timeToggled; // last time we toggled
};
if(results.value == 16759365){
digitalWrite(0,HIGH);
digitalWrite(1,HIGH);
digitalWrite(2,HIGH);
LED white = {0,HIGH,100,millis()};
LED yellow = {1,HIGH,10,millis()};
LED blue = {2,HIGH,420,millis()};
results = readIr(); // check the ir value again and keep looping until it changes
while(results.value == 16759365){
toggleLed(white);
toggleLed(yellow);
toggleLed(blue);
results = readIr(); // if ir value hasnt changed keep looping until it does
}
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
}
void toggleLed(struct LED currentLed){
unsigned long currentMillis = millis();
if(currentMillis - currentLed.timeToggled > currentLed.interval) {
// save the last time you blinked the LED
currentLed.timeToggled = currentMillis;
// if the LED is off turn it on and vice-versa:
if (currentLed.state == LOW)
currentLed.state = HIGH;
else
currentLed.state = LOW;
// set the LED with the ledState of the variable:
digitalWrite(currentLed.pin, currentLed.state);
}
}