~ubuntu-branches/debian/experimental/xfce4-panel/experimental

« back to all changes in this revision

Viewing changes to panel/popup.c

  • Committer: Bazaar Package Importer
  • Author(s): Yves-Alexis Perez
  • Date: 2008-05-19 08:08:22 UTC
  • mfrom: (1.1.16 upstream)
  • Revision ID: james.westby@ubuntu.com-20080519080822-c8ptdv1s8o9r4ou0
Tags: 4.4.2-6
* switch to triggers:
  - debian/postinst: remove xfce-mcs-manager refresh.
  - debian/prerm dropped.
  - debian/control: conflicts against non-triggers-enable xfce4-mcs-manager.
* debian/control: remove useless Conflicts/Replaces against Sarge stuff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  $Id: popup.c 4139 2004-09-19 09:29:16Z jasper $
2
 
 *  
3
 
 *  Copyright 2002-2004 Jasper Huijsmans (jasper@xfce.org)
4
 
 *
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.
9
 
 *
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.
14
 
 *
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.
18
 
*/
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include <config.h>
22
 
#endif
23
 
 
24
 
#ifdef GDK_MULTIHEAD_SAFE
25
 
#undef GDK_MULTIHEAD_SAFE
26
 
#endif
27
 
 
28
 
#include <gdk/gdkkeysyms.h>
29
 
 
30
 
#include <gmodule.h>
31
 
#include <libxfce4util/libxfce4util.h>
32
 
#include <libxfcegui4/xfce_togglebutton.h>
33
 
#include <libxfcegui4/xfce_menubutton.h>
34
 
 
35
 
#include "xfce.h"
36
 
#include "popup.h"
37
 
#include "item.h"
38
 
#include "settings.h"
39
 
 
40
 
#define NBITEMS 32
41
 
 
42
 
G_MODULE_EXPORT /* EXPORT:open_popup */
43
 
PanelPopup *open_popup = NULL;
44
 
 
45
 
/*  Panel popup callbacks
46
 
 *  ---------------------
47
 
*/
48
 
static void
49
 
hide_popup (PanelPopup * pp)
50
 
{
51
 
    if (open_popup == pp)
52
 
        open_popup = NULL;
53
 
 
54
 
    if (!pp)
55
 
        return;
56
 
 
57
 
    xfce_togglebutton_set_active (XFCE_TOGGLEBUTTON (pp->button), FALSE);
58
 
 
59
 
    gtk_widget_hide (pp->window);
60
 
 
61
 
    if (pp->detached)
62
 
    {
63
 
        pp->detached = FALSE;
64
 
        gtk_widget_show (pp->tearoff_button);
65
 
        gtk_window_set_decorated (GTK_WINDOW (pp->window), FALSE);
66
 
    }
67
 
}
68
 
 
69
 
static void
70
 
position_popup (PanelPopup * pp)
71
 
{
72
 
    GtkRequisition req;
73
 
    GdkWindow *p;
74
 
    int xbutton, ybutton, xparent, yparent, x, y;
75
 
    int w, h;
76
 
    gboolean vertical = settings.orientation == VERTICAL;
77
 
    GtkAllocation alloc1 = { 0 }, alloc2 =
78
 
    {
79
 
    0};
80
 
    GtkArrowType at;
81
 
 
82
 
    if (!pp)
83
 
        return;
84
 
 
85
 
    if (pp->detached)
86
 
        return;
87
 
 
88
 
    alloc1 = pp->button->allocation;
89
 
    xbutton = alloc1.x;
90
 
    ybutton = alloc1.y;
91
 
 
92
 
    p = gtk_widget_get_parent_window (pp->button);
93
 
    gdk_window_get_root_origin (p, &xparent, &yparent);
94
 
 
95
 
    w = gdk_screen_width ();
96
 
    h = gdk_screen_height ();
97
 
 
98
 
    at = xfce_togglebutton_get_arrow_type (XFCE_TOGGLEBUTTON (pp->button));
99
 
 
100
 
    if (!GTK_WIDGET_REALIZED (pp->window))
101
 
        gtk_widget_realize (pp->window);
102
 
 
103
 
    gtk_widget_size_request (pp->window, &req);
104
 
 
105
 
    alloc2.width = req.width;
106
 
    alloc2.height = req.height;
107
 
    gtk_widget_size_allocate (pp->window, &alloc2);
108
 
 
109
 
    /* this is necessary, because the icons are resized on allocation */
110
 
    gtk_widget_size_request (pp->window, &req);
111
 
 
112
 
    /*  positioning logic (well ...)
113
 
     *  ----------------------------
114
 
     *  1) vertical panel
115
 
     *  - to the left or the right
116
 
     *    - if buttons left the left  else right
117
 
     *  - fit the screen
118
 
     *  2) horizontal
119
 
     *  - up or down
120
 
     *    - if buttons down -> down else up
121
 
     *  - fit the screen
122
 
     */
123
 
 
124
 
    /* set x and y to topleft corner of the button */
125
 
    x = xbutton + xparent;
126
 
    y = ybutton + yparent;
127
 
 
128
 
    if (vertical)
129
 
    {
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)
134
 
        {
135
 
            x = x - req.width;
136
 
        }
137
 
        else                    /* right */
138
 
        {
139
 
            x = x + alloc1.width;
140
 
        }
141
 
        y = y + alloc1.height - req.height;
142
 
 
143
 
        /* check if it fits upwards */
144
 
        if (y < 0)
145
 
            y = 0;
146
 
    }
147
 
    else
148
 
    {
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)
152
 
        {
153
 
            y = y + alloc1.height;
154
 
        }
155
 
        else
156
 
        {
157
 
            y = y - req.height;
158
 
        }
159
 
        x = x + alloc1.width / 2 - req.width / 2;
160
 
 
161
 
        /* check if it fits to the left and the right */
162
 
        if (x < 0)
163
 
            x = 0;
164
 
        else if (x + req.width > w)
165
 
            x = w - req.width;
166
 
    }
167
 
 
168
 
    gtk_window_move (GTK_WINDOW (pp->window), x, y);
169
 
    gtk_window_stick (GTK_WINDOW (pp->window));
170
 
    gtk_widget_show (pp->window);
171
 
}
172
 
 
173
 
static void
174
 
show_popup (PanelPopup * pp)
175
 
{
176
 
    if (!pp)
177
 
        return;
178
 
 
179
 
    if (open_popup)
180
 
        hide_popup (open_popup);
181
 
 
182
 
    if (!pp->detached)
183
 
        open_popup = pp;
184
 
 
185
 
    if (pp->items && !pp->detached)
186
 
        gtk_widget_show (pp->tearoff_button);
187
 
    else
188
 
        gtk_widget_hide (pp->tearoff_button);
189
 
 
190
 
    if (disable_user_config || g_list_length (pp->items) >= NBITEMS)
191
 
    {
192
 
        gtk_widget_hide (pp->addtomenu_item->button);
193
 
        gtk_widget_hide (pp->separator);
194
 
    }
195
 
    else
196
 
    {
197
 
        gtk_widget_show (pp->addtomenu_item->button);
198
 
        gtk_widget_show (pp->separator);
199
 
    }
200
 
 
201
 
    position_popup (pp);
202
 
}
203
 
 
204
 
G_MODULE_EXPORT /* EXPORT:hide_current_popup_menu */
205
 
void
206
 
hide_current_popup_menu (void)
207
 
{
208
 
    if (open_popup)
209
 
        hide_popup (open_popup);
210
 
}
211
 
 
212
 
G_MODULE_EXPORT /* EXPORT:toggle_popup */
213
 
void
214
 
toggle_popup (GtkWidget * button, PanelPopup * pp)
215
 
{
216
 
    hide_current_popup_menu ();
217
 
 
218
 
    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
219
 
        show_popup (pp);
220
 
    else
221
 
        hide_popup (pp);
222
 
}
223
 
 
224
 
G_MODULE_EXPORT /* EXPORT:tearoff_popup */
225
 
void
226
 
tearoff_popup (GtkWidget * button, PanelPopup * pp)
227
 
{
228
 
    open_popup = NULL;
229
 
    pp->detached = TRUE;
230
 
    gtk_widget_hide (pp->tearoff_button);
231
 
    gtk_window_set_decorated (GTK_WINDOW (pp->window), TRUE);
232
 
}
233
 
 
234
 
G_MODULE_EXPORT /* EXPORT:delete_popup */
235
 
gboolean
236
 
delete_popup (GtkWidget * window, GdkEvent * ev, PanelPopup * pp)
237
 
{
238
 
    hide_popup (pp);
239
 
 
240
 
    return TRUE;
241
 
}
242
 
 
243
 
G_MODULE_EXPORT /* EXPORT:popup_key_pressed */
244
 
gboolean
245
 
popup_key_pressed (GtkWidget * window, GdkEventKey * ev, PanelPopup * pp)
246
 
{
247
 
    if (ev->keyval == GDK_Escape)
248
 
    {
249
 
        hide_popup (pp);
250
 
        return TRUE;
251
 
    }
252
 
    return FALSE;
253
 
}
254
 
 
255
 
/*  Popup menus 
256
 
 *  -----------
257
 
*/
258
 
static void
259
 
set_popup_window_properties (GtkWidget * win)
260
 
{
261
 
    GtkWindow *window = GTK_WINDOW (win);
262
 
    GdkPixbuf *pb;
263
 
 
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);
270
 
 
271
 
    pb = get_panel_pixbuf ();
272
 
    gtk_window_set_icon (window, pb);
273
 
    g_object_unref (pb);
274
 
 
275
 
    set_window_layer (win, settings.layer);
276
 
 
277
 
    /* don't care about decorations when calculating position */
278
 
    gtk_window_set_gravity (window, GDK_GRAVITY_STATIC);
279
 
}
280
 
 
281
 
static GtkTargetEntry entry[] = {
282
 
    {"text/uri-list", 0, 0},
283
 
    {"STRING", 0, 1}
284
 
};
285
 
 
286
 
static gboolean
287
 
drag_motion (GtkWidget * widget, GdkDragContext * context,
288
 
             int x, int y, guint time, PanelPopup * pp)
289
 
{
290
 
    if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pp->button)))
291
 
    {
292
 
        DBG ("open popup\n");
293
 
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pp->button), TRUE);
294
 
    }
295
 
    else
296
 
        DBG ("already open\n");
297
 
 
298
 
    return TRUE;
299
 
}
300
 
 
301
 
G_MODULE_EXPORT /* EXPORT:create_panel_popup */
302
 
PanelPopup *
303
 
create_panel_popup (void)
304
 
{
305
 
    PanelPopup *pp = g_new (PanelPopup, 1);
306
 
    GtkWidget *sep;
307
 
    GtkArrowType at;
308
 
    gboolean vertical = settings.orientation == VERTICAL;
309
 
 
310
 
    xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
311
 
 
312
 
    /* the button */
313
 
    if (vertical)
314
 
    {
315
 
        if (settings.popup_position == LEFT)
316
 
            at = GTK_ARROW_LEFT;
317
 
        else
318
 
            at = GTK_ARROW_RIGHT;
319
 
    }
320
 
    else
321
 
    {
322
 
        if (settings.popup_position == BOTTOM)
323
 
            at = GTK_ARROW_DOWN;
324
 
        else
325
 
            at = GTK_ARROW_UP;
326
 
    }
327
 
 
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");
332
 
 
333
 
    xfce_togglebutton_set_relief (XFCE_TOGGLEBUTTON (pp->button),
334
 
                                  GTK_RELIEF_NONE);
335
 
 
336
 
    g_signal_connect (pp->button, "toggled", G_CALLBACK (toggle_popup), pp);
337
 
 
338
 
    gtk_drag_dest_set (pp->button, GTK_DEST_DEFAULT_ALL, entry, 2,
339
 
                       GDK_ACTION_COPY);
340
 
    g_signal_connect (pp->button, "drag-motion", G_CALLBACK (drag_motion),
341
 
                      pp);
342
 
 
343
 
    /* the menu */
344
 
    pp->hgroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
345
 
 
346
 
    pp->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
347
 
    set_popup_window_properties (pp->window);
348
 
 
349
 
    g_signal_connect_swapped (pp->window, "size-allocate",
350
 
                              G_CALLBACK (position_popup), pp);
351
 
 
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);
355
 
 
356
 
    pp->vbox = gtk_vbox_new (FALSE, 0);
357
 
    gtk_container_add (GTK_CONTAINER (pp->frame), pp->vbox);
358
 
 
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,
362
 
                        FALSE, 0);
363
 
 
364
 
    pp->separator = gtk_hseparator_new ();
365
 
    gtk_box_pack_start (GTK_BOX (pp->vbox), pp->separator, FALSE, FALSE, 0);
366
 
 
367
 
    /* we don't know the items until we read the config file */
368
 
    pp->items = NULL;
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);
372
 
 
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,
376
 
                        0);
377
 
    sep = gtk_hseparator_new ();
378
 
    gtk_container_add (GTK_CONTAINER (pp->tearoff_button), sep);
379
 
 
380
 
    /* signals */
381
 
    g_signal_connect (pp->tearoff_button, "clicked",
382
 
                      G_CALLBACK (tearoff_popup), pp);
383
 
 
384
 
    g_signal_connect (pp->window, "delete-event", G_CALLBACK (delete_popup),
385
 
                      pp);
386
 
 
387
 
    g_signal_connect (pp->window, "key-press-event",
388
 
                      G_CALLBACK (popup_key_pressed), pp);
389
 
 
390
 
    /* apparently this is necessary to make the popup show correctly */
391
 
    pp->detached = FALSE;
392
 
 
393
 
    gtk_widget_show_all (pp->frame);
394
 
 
395
 
    panel_popup_set_size (pp, settings.size);
396
 
 
397
 
    return pp;
398
 
}
399
 
 
400
 
G_MODULE_EXPORT /* EXPORT:panel_popup_pack */
401
 
void
402
 
panel_popup_pack (PanelPopup * pp, GtkBox * box)
403
 
{
404
 
    if (!pp)
405
 
        return;
406
 
 
407
 
    gtk_box_pack_start (box, pp->button, FALSE, FALSE, 0);
408
 
}
409
 
 
410
 
G_MODULE_EXPORT /* EXPORT:panel_popup_unpack */
411
 
void
412
 
panel_popup_unpack (PanelPopup * pp)
413
 
{
414
 
    GtkWidget *container;
415
 
 
416
 
    if (!pp)
417
 
        return;
418
 
 
419
 
    container = pp->button->parent;
420
 
 
421
 
    gtk_container_remove (GTK_CONTAINER (container), pp->button);
422
 
}
423
 
 
424
 
G_MODULE_EXPORT /* EXPORT:panel_popup_add_item */
425
 
void
426
 
panel_popup_add_item (PanelPopup * pp, Item * mi)
427
 
{
428
 
    GList *li;
429
 
    int i;
430
 
 
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);
433
 
 
434
 
    pp->items = g_list_insert (pp->items, mi, mi->pos);
435
 
 
436
 
    for (i = 0, li = pp->items; li && li->data; i++, li = li->next)
437
 
    {
438
 
        Item *item = li->data;
439
 
 
440
 
        item->pos = i;
441
 
    }
442
 
}
443
 
 
444
 
G_MODULE_EXPORT /* EXPORT:panel_popup_remove_item */
445
 
void
446
 
panel_popup_remove_item (PanelPopup * pp, Item * mi)
447
 
{
448
 
    GList *li;
449
 
    int i;
450
 
 
451
 
    gtk_container_remove (GTK_CONTAINER (pp->vbox), mi->button);
452
 
 
453
 
    pp->items = g_list_remove (pp->items, mi);
454
 
 
455
 
    item_free (mi);
456
 
 
457
 
    for (i = 0, li = pp->items; li && li->data; i++, li = li->next)
458
 
    {
459
 
        Item *item = li->data;
460
 
 
461
 
        item->pos = i;
462
 
    }
463
 
}
464
 
 
465
 
G_MODULE_EXPORT /* EXPORT:panel_popup_set_from_xml */
466
 
void
467
 
panel_popup_set_from_xml (PanelPopup * pp, xmlNodePtr node)
468
 
{
469
 
    xmlNodePtr child;
470
 
    int i;
471
 
 
472
 
    if (!pp)
473
 
        return;
474
 
 
475
 
    for (i = 0, child = node->children; child; i++, child = child->next)
476
 
    {
477
 
        Item *mi;
478
 
 
479
 
        if (!xmlStrEqual (child->name, (const xmlChar *) "Item"))
480
 
            continue;
481
 
 
482
 
        mi = menu_item_new (pp);
483
 
        item_read_config (mi, child);
484
 
        create_menu_item (mi);
485
 
 
486
 
        mi->pos = i;
487
 
 
488
 
        panel_popup_add_item (pp, mi);
489
 
    }
490
 
}
491
 
 
492
 
G_MODULE_EXPORT /* EXPORT:panel_popup_write_xml */
493
 
void
494
 
panel_popup_write_xml (PanelPopup * pp, xmlNodePtr root)
495
 
{
496
 
    xmlNodePtr node, child;
497
 
    GList *li;
498
 
 
499
 
    if (!pp || !pp->items)
500
 
        return;
501
 
 
502
 
    node = xmlNewTextChild (root, NULL, "Popup", NULL);
503
 
 
504
 
    for (li = pp->items; li; li = li->next)
505
 
    {
506
 
        Item *mi = li->data;
507
 
 
508
 
        child = xmlNewTextChild (node, NULL, "Item", NULL);
509
 
 
510
 
        item_write_config (mi, child);
511
 
    }
512
 
}
513
 
 
514
 
G_MODULE_EXPORT /* EXPORT:panel_popup_free */
515
 
void
516
 
panel_popup_free (PanelPopup * pp)
517
 
{
518
 
    /* only items contain non-gtk elements to be freed */
519
 
    GList *li;
520
 
 
521
 
    if (!pp)
522
 
        return;
523
 
 
524
 
    gtk_widget_destroy (pp->window);
525
 
 
526
 
    for (li = pp->items; li && li->data; li = li->next)
527
 
    {
528
 
        Item *mi = li->data;
529
 
 
530
 
        item_free (mi);
531
 
    }
532
 
 
533
 
    g_free (pp);
534
 
}
535
 
 
536
 
G_MODULE_EXPORT /* EXPORT:panel_popup_set_size */
537
 
void
538
 
panel_popup_set_size (PanelPopup * pp, int size)
539
 
{
540
 
    int pos = settings.popup_position;
541
 
    int w, h;
542
 
    GList *li;
543
 
 
544
 
    if (!pp)
545
 
        return;
546
 
 
547
 
    w = icon_size[size] + border_width;
548
 
    h = top_height[size];
549
 
 
550
 
    if (pos == LEFT || pos == RIGHT)
551
 
        gtk_widget_set_size_request (pp->button, h, w);
552
 
    else
553
 
        gtk_widget_set_size_request (pp->button, w, h);
554
 
 
555
 
    /* decide on popup size based on panel size */
556
 
    menu_item_set_popup_size (pp->addtomenu_item, size);
557
 
 
558
 
    for (li = pp->items; li && li->data; li = li->next)
559
 
    {
560
 
        Item *mi = li->data;
561
 
 
562
 
        menu_item_set_popup_size (mi, size);
563
 
    }
564
 
}
565
 
 
566
 
G_MODULE_EXPORT /* EXPORT:panel_popup_set_popup_position */
567
 
void
568
 
panel_popup_set_popup_position (PanelPopup * pp, int position)
569
 
{
570
 
    settings.popup_position = position;
571
 
 
572
 
    if (!pp)
573
 
        return;
574
 
 
575
 
    panel_popup_set_size (pp, settings.size);
576
 
}
577
 
 
578
 
G_MODULE_EXPORT /* EXPORT:panel_popup_set_layer */
579
 
void
580
 
panel_popup_set_layer (PanelPopup * pp, int layer)
581
 
{
582
 
    if (!pp)
583
 
        return;
584
 
 
585
 
    set_window_layer (pp->window, layer);
586
 
}
587
 
 
588
 
G_MODULE_EXPORT /* EXPORT:panel_popup_set_theme */
589
 
void
590
 
panel_popup_set_theme (PanelPopup * pp, const char *theme)
591
 
{
592
 
    GList *li;
593
 
 
594
 
    if (!pp)
595
 
        return;
596
 
 
597
 
    for (li = pp->items; li && li->data; li = li->next)
598
 
    {
599
 
        Item *mi = li->data;
600
 
 
601
 
        item_set_theme (mi, theme);
602
 
    }
603
 
}
604
 
 
605
 
G_MODULE_EXPORT /* EXPORT:panel_popup_set_arrow_type */
606
 
void
607
 
panel_popup_set_arrow_type (PanelPopup * pp, GtkArrowType type)
608
 
{
609
 
    if (!pp || !pp->button)
610
 
        return;
611
 
 
612
 
    xfce_togglebutton_set_arrow_type (XFCE_TOGGLEBUTTON (pp->button), type);
613
 
}