1
/* $Id: popup.c 4139 2004-09-19 09:29:16Z jasper $
3
* Copyright 2002-2004 Jasper Huijsmans (jasper@xfce.org)
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
#ifdef GDK_MULTIHEAD_SAFE
25
#undef GDK_MULTIHEAD_SAFE
28
#include <gdk/gdkkeysyms.h>
31
#include <libxfce4util/libxfce4util.h>
32
#include <libxfcegui4/xfce_togglebutton.h>
33
#include <libxfcegui4/xfce_menubutton.h>
42
G_MODULE_EXPORT /* EXPORT:open_popup */
43
PanelPopup *open_popup = NULL;
45
/* Panel popup callbacks
46
* ---------------------
49
hide_popup (PanelPopup * pp)
57
xfce_togglebutton_set_active (XFCE_TOGGLEBUTTON (pp->button), FALSE);
59
gtk_widget_hide (pp->window);
64
gtk_widget_show (pp->tearoff_button);
65
gtk_window_set_decorated (GTK_WINDOW (pp->window), FALSE);
70
position_popup (PanelPopup * pp)
74
int xbutton, ybutton, xparent, yparent, x, y;
76
gboolean vertical = settings.orientation == VERTICAL;
77
GtkAllocation alloc1 = { 0 }, alloc2 =
88
alloc1 = pp->button->allocation;
92
p = gtk_widget_get_parent_window (pp->button);
93
gdk_window_get_root_origin (p, &xparent, &yparent);
95
w = gdk_screen_width ();
96
h = gdk_screen_height ();
98
at = xfce_togglebutton_get_arrow_type (XFCE_TOGGLEBUTTON (pp->button));
100
if (!GTK_WIDGET_REALIZED (pp->window))
101
gtk_widget_realize (pp->window);
103
gtk_widget_size_request (pp->window, &req);
105
alloc2.width = req.width;
106
alloc2.height = req.height;
107
gtk_widget_size_allocate (pp->window, &alloc2);
109
/* this is necessary, because the icons are resized on allocation */
110
gtk_widget_size_request (pp->window, &req);
112
/* positioning logic (well ...)
113
* ----------------------------
115
* - to the left or the right
116
* - if buttons left the left else right
120
* - if buttons down -> down else up
124
/* set x and y to topleft corner of the button */
125
x = xbutton + xparent;
126
y = ybutton + yparent;
130
/* left if buttons left or if menu doesn't fit right,
131
* but does fit left */
132
if ((at == GTK_ARROW_LEFT || x + req.width + alloc1.width > w)
133
&& x - req.width >= 0)
139
x = x + alloc1.width;
141
y = y + alloc1.height - req.height;
143
/* check if it fits upwards */
149
/* down if buttons on bottom or up doesn't fit and down does */
150
if ((at == GTK_ARROW_DOWN || y - req.height < 0)
151
&& y + alloc1.height + req.height <= h)
153
y = y + alloc1.height;
159
x = x + alloc1.width / 2 - req.width / 2;
161
/* check if it fits to the left and the right */
164
else if (x + req.width > w)
168
gtk_window_move (GTK_WINDOW (pp->window), x, y);
169
gtk_window_stick (GTK_WINDOW (pp->window));
170
gtk_widget_show (pp->window);
174
show_popup (PanelPopup * pp)
180
hide_popup (open_popup);
185
if (pp->items && !pp->detached)
186
gtk_widget_show (pp->tearoff_button);
188
gtk_widget_hide (pp->tearoff_button);
190
if (disable_user_config || g_list_length (pp->items) >= NBITEMS)
192
gtk_widget_hide (pp->addtomenu_item->button);
193
gtk_widget_hide (pp->separator);
197
gtk_widget_show (pp->addtomenu_item->button);
198
gtk_widget_show (pp->separator);
204
G_MODULE_EXPORT /* EXPORT:hide_current_popup_menu */
206
hide_current_popup_menu (void)
209
hide_popup (open_popup);
212
G_MODULE_EXPORT /* EXPORT:toggle_popup */
214
toggle_popup (GtkWidget * button, PanelPopup * pp)
216
hide_current_popup_menu ();
218
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
224
G_MODULE_EXPORT /* EXPORT:tearoff_popup */
226
tearoff_popup (GtkWidget * button, PanelPopup * pp)
230
gtk_widget_hide (pp->tearoff_button);
231
gtk_window_set_decorated (GTK_WINDOW (pp->window), TRUE);
234
G_MODULE_EXPORT /* EXPORT:delete_popup */
236
delete_popup (GtkWidget * window, GdkEvent * ev, PanelPopup * pp)
243
G_MODULE_EXPORT /* EXPORT:popup_key_pressed */
245
popup_key_pressed (GtkWidget * window, GdkEventKey * ev, PanelPopup * pp)
247
if (ev->keyval == GDK_Escape)
259
set_popup_window_properties (GtkWidget * win)
261
GtkWindow *window = GTK_WINDOW (win);
264
gtk_window_set_decorated (window, FALSE);
265
gtk_window_set_resizable (window, FALSE);
266
gtk_window_stick (window);
267
gtk_window_set_title (window, _("Menu"));
268
gtk_window_set_transient_for (window, GTK_WINDOW (panel.toplevel));
269
gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_MENU);
271
pb = get_panel_pixbuf ();
272
gtk_window_set_icon (window, pb);
275
set_window_layer (win, settings.layer);
277
/* don't care about decorations when calculating position */
278
gtk_window_set_gravity (window, GDK_GRAVITY_STATIC);
281
static GtkTargetEntry entry[] = {
282
{"text/uri-list", 0, 0},
287
drag_motion (GtkWidget * widget, GdkDragContext * context,
288
int x, int y, guint time, PanelPopup * pp)
290
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pp->button)))
292
DBG ("open popup\n");
293
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pp->button), TRUE);
296
DBG ("already open\n");
301
G_MODULE_EXPORT /* EXPORT:create_panel_popup */
303
create_panel_popup (void)
305
PanelPopup *pp = g_new (PanelPopup, 1);
308
gboolean vertical = settings.orientation == VERTICAL;
310
xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
315
if (settings.popup_position == LEFT)
318
at = GTK_ARROW_RIGHT;
322
if (settings.popup_position == BOTTOM)
328
pp->button = xfce_togglebutton_new (at);
329
gtk_widget_show (pp->button);
330
g_object_ref (pp->button);
331
gtk_widget_set_name (pp->button, "xfce_popup_button");
333
xfce_togglebutton_set_relief (XFCE_TOGGLEBUTTON (pp->button),
336
g_signal_connect (pp->button, "toggled", G_CALLBACK (toggle_popup), pp);
338
gtk_drag_dest_set (pp->button, GTK_DEST_DEFAULT_ALL, entry, 2,
340
g_signal_connect (pp->button, "drag-motion", G_CALLBACK (drag_motion),
344
pp->hgroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
346
pp->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
347
set_popup_window_properties (pp->window);
349
g_signal_connect_swapped (pp->window, "size-allocate",
350
G_CALLBACK (position_popup), pp);
352
pp->frame = gtk_frame_new (NULL);
353
gtk_frame_set_shadow_type (GTK_FRAME (pp->frame), GTK_SHADOW_OUT);
354
gtk_container_add (GTK_CONTAINER (pp->window), pp->frame);
356
pp->vbox = gtk_vbox_new (FALSE, 0);
357
gtk_container_add (GTK_CONTAINER (pp->frame), pp->vbox);
359
pp->addtomenu_item = menu_item_new (pp);
360
create_addtomenu_item (pp->addtomenu_item);
361
gtk_box_pack_start (GTK_BOX (pp->vbox), pp->addtomenu_item->button, FALSE,
364
pp->separator = gtk_hseparator_new ();
365
gtk_box_pack_start (GTK_BOX (pp->vbox), pp->separator, FALSE, FALSE, 0);
367
/* we don't know the items until we read the config file */
369
pp->item_vbox = gtk_vbox_new (FALSE, 0);
370
gtk_widget_show (pp->item_vbox);
371
gtk_box_pack_start (GTK_BOX (pp->vbox), pp->item_vbox, FALSE, FALSE, 0);
373
pp->tearoff_button = gtk_button_new ();
374
gtk_button_set_relief (GTK_BUTTON (pp->tearoff_button), GTK_RELIEF_NONE);
375
gtk_box_pack_start (GTK_BOX (pp->vbox), pp->tearoff_button, FALSE, FALSE,
377
sep = gtk_hseparator_new ();
378
gtk_container_add (GTK_CONTAINER (pp->tearoff_button), sep);
381
g_signal_connect (pp->tearoff_button, "clicked",
382
G_CALLBACK (tearoff_popup), pp);
384
g_signal_connect (pp->window, "delete-event", G_CALLBACK (delete_popup),
387
g_signal_connect (pp->window, "key-press-event",
388
G_CALLBACK (popup_key_pressed), pp);
390
/* apparently this is necessary to make the popup show correctly */
391
pp->detached = FALSE;
393
gtk_widget_show_all (pp->frame);
395
panel_popup_set_size (pp, settings.size);
400
G_MODULE_EXPORT /* EXPORT:panel_popup_pack */
402
panel_popup_pack (PanelPopup * pp, GtkBox * box)
407
gtk_box_pack_start (box, pp->button, FALSE, FALSE, 0);
410
G_MODULE_EXPORT /* EXPORT:panel_popup_unpack */
412
panel_popup_unpack (PanelPopup * pp)
414
GtkWidget *container;
419
container = pp->button->parent;
421
gtk_container_remove (GTK_CONTAINER (container), pp->button);
424
G_MODULE_EXPORT /* EXPORT:panel_popup_add_item */
426
panel_popup_add_item (PanelPopup * pp, Item * mi)
431
gtk_box_pack_start (GTK_BOX (pp->item_vbox), mi->button, FALSE, FALSE, 0);
432
gtk_box_reorder_child (GTK_BOX (pp->item_vbox), mi->button, mi->pos);
434
pp->items = g_list_insert (pp->items, mi, mi->pos);
436
for (i = 0, li = pp->items; li && li->data; i++, li = li->next)
438
Item *item = li->data;
444
G_MODULE_EXPORT /* EXPORT:panel_popup_remove_item */
446
panel_popup_remove_item (PanelPopup * pp, Item * mi)
451
gtk_container_remove (GTK_CONTAINER (pp->vbox), mi->button);
453
pp->items = g_list_remove (pp->items, mi);
457
for (i = 0, li = pp->items; li && li->data; i++, li = li->next)
459
Item *item = li->data;
465
G_MODULE_EXPORT /* EXPORT:panel_popup_set_from_xml */
467
panel_popup_set_from_xml (PanelPopup * pp, xmlNodePtr node)
475
for (i = 0, child = node->children; child; i++, child = child->next)
479
if (!xmlStrEqual (child->name, (const xmlChar *) "Item"))
482
mi = menu_item_new (pp);
483
item_read_config (mi, child);
484
create_menu_item (mi);
488
panel_popup_add_item (pp, mi);
492
G_MODULE_EXPORT /* EXPORT:panel_popup_write_xml */
494
panel_popup_write_xml (PanelPopup * pp, xmlNodePtr root)
496
xmlNodePtr node, child;
499
if (!pp || !pp->items)
502
node = xmlNewTextChild (root, NULL, "Popup", NULL);
504
for (li = pp->items; li; li = li->next)
508
child = xmlNewTextChild (node, NULL, "Item", NULL);
510
item_write_config (mi, child);
514
G_MODULE_EXPORT /* EXPORT:panel_popup_free */
516
panel_popup_free (PanelPopup * pp)
518
/* only items contain non-gtk elements to be freed */
524
gtk_widget_destroy (pp->window);
526
for (li = pp->items; li && li->data; li = li->next)
536
G_MODULE_EXPORT /* EXPORT:panel_popup_set_size */
538
panel_popup_set_size (PanelPopup * pp, int size)
540
int pos = settings.popup_position;
547
w = icon_size[size] + border_width;
548
h = top_height[size];
550
if (pos == LEFT || pos == RIGHT)
551
gtk_widget_set_size_request (pp->button, h, w);
553
gtk_widget_set_size_request (pp->button, w, h);
555
/* decide on popup size based on panel size */
556
menu_item_set_popup_size (pp->addtomenu_item, size);
558
for (li = pp->items; li && li->data; li = li->next)
562
menu_item_set_popup_size (mi, size);
566
G_MODULE_EXPORT /* EXPORT:panel_popup_set_popup_position */
568
panel_popup_set_popup_position (PanelPopup * pp, int position)
570
settings.popup_position = position;
575
panel_popup_set_size (pp, settings.size);
578
G_MODULE_EXPORT /* EXPORT:panel_popup_set_layer */
580
panel_popup_set_layer (PanelPopup * pp, int layer)
585
set_window_layer (pp->window, layer);
588
G_MODULE_EXPORT /* EXPORT:panel_popup_set_theme */
590
panel_popup_set_theme (PanelPopup * pp, const char *theme)
597
for (li = pp->items; li && li->data; li = li->next)
601
item_set_theme (mi, theme);
605
G_MODULE_EXPORT /* EXPORT:panel_popup_set_arrow_type */
607
panel_popup_set_arrow_type (PanelPopup * pp, GtkArrowType type)
609
if (!pp || !pp->button)
612
xfce_togglebutton_set_arrow_type (XFCE_TOGGLEBUTTON (pp->button), type);