2
* GNOME panel drawer module.
3
* (C) 1997 The Free Software Foundation
5
* Authors: Miguel de Icaza
12
#include <sys/types.h>
18
#include <glib/gi18n.h>
19
#include <gdk/gdkkeysyms.h>
24
#include "button-widget.h"
25
#include "panel-config-global.h"
26
#include "panel-gconf.h"
27
#include "panel-profile.h"
28
#include "panel-util.h"
30
#include "panel-globals.h"
31
#include "panel-lockdown.h"
32
#include "panel-icon-names.h"
35
drawer_click (GtkWidget *w, Drawer *drawer)
37
if (!panel_toplevel_get_is_hidden (drawer->toplevel))
38
panel_toplevel_hide (drawer->toplevel, FALSE, -1);
40
panel_toplevel_unhide (drawer->toplevel);
44
toplevel_destroyed (GtkWidget *widget,
47
drawer->toplevel = NULL;
48
gtk_widget_destroy (drawer->button);
52
destroy_drawer (GtkWidget *widget,
58
client = panel_gconf_get_client ();
60
for (i = 0; i < PANEL_DRAWER_N_LISTENERS; i++) {
61
if (drawer->listeners [i])
62
gconf_client_notify_remove (client, drawer->listeners [i]);
63
drawer->listeners [i] = 0;
67
gtk_widget_destroy (GTK_WIDGET (drawer->toplevel));
68
drawer->toplevel = NULL;
70
if (drawer->close_timeout_id)
71
g_source_remove (drawer->close_timeout_id);
72
drawer->close_timeout_id = 0;
76
drawer_focus_panel_widget (Drawer *drawer,
77
GtkDirectionType direction)
79
PanelWidget *panel_widget;
81
panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel);
83
gtk_window_present (GTK_WINDOW (drawer->toplevel));
84
gtk_container_set_focus_child (GTK_CONTAINER (panel_widget), NULL);
85
gtk_widget_child_focus (GTK_WIDGET (panel_widget), direction);
89
key_press_drawer (GtkWidget *widget,
93
gboolean retval = TRUE;
94
GtkOrientation orient;
96
if (event->state & gtk_accelerator_get_default_mod_mask ())
99
orient = PANEL_WIDGET (gtk_widget_get_parent (drawer->button))->orient;
101
switch (event->keyval) {
104
if (orient == GTK_ORIENTATION_HORIZONTAL) {
105
if (!panel_toplevel_get_is_hidden (drawer->toplevel))
106
drawer_focus_panel_widget (drawer, GTK_DIR_TAB_BACKWARD);
108
/* let default focus movement happen */
114
if (orient == GTK_ORIENTATION_VERTICAL) {
115
if (!panel_toplevel_get_is_hidden (drawer->toplevel))
116
drawer_focus_panel_widget (drawer, GTK_DIR_TAB_BACKWARD);
118
/* let default focus movement happen */
124
if (orient == GTK_ORIENTATION_HORIZONTAL) {
125
if (!panel_toplevel_get_is_hidden (drawer->toplevel))
126
drawer_focus_panel_widget (drawer, GTK_DIR_TAB_FORWARD);
128
/* let default focus movement happen */
134
if (orient == GTK_ORIENTATION_VERTICAL) {
135
if (!panel_toplevel_get_is_hidden (drawer->toplevel))
136
drawer_focus_panel_widget (drawer, GTK_DIR_TAB_FORWARD);
138
/* let default focus movement happen */
143
panel_toplevel_hide (drawer->toplevel, FALSE, -1);
154
* This function implements Esc moving focus from the drawer to the drawer
155
* icon and closing the drawer and Shift+Esc moving focus from the drawer
156
* to the drawer icon without closing the drawer when focus is in the drawer.
159
key_press_drawer_widget (GtkWidget *widget,
163
PanelWidget *panel_widget;
165
if (event->keyval != GDK_Escape)
168
panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel);
170
gtk_window_present (GTK_WINDOW (panel_widget->toplevel));
172
if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_SHIFT_MASK ||
173
panel_toplevel_get_is_hidden (drawer->toplevel))
176
panel_toplevel_hide (drawer->toplevel, FALSE, -1);
182
drag_data_received_cb (GtkWidget *widget,
183
GdkDragContext *context,
186
GtkSelectionData *selection_data,
191
PanelWidget *panel_widget;
193
if (!panel_check_dnd_target_data (widget, context, &info, NULL)) {
194
gtk_drag_finish (context, FALSE, FALSE, time_);
198
panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel);
200
panel_receive_dnd_data (
201
panel_widget, info, -1, selection_data, context, time_);
205
drag_motion_cb (GtkWidget *widget,
206
GdkDragContext *context,
212
PanelWidget *panel_widget;
215
if (!panel_check_dnd_target_data (widget, context, &info, NULL))
218
panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel);
220
if (!panel_check_drop_forbidden (panel_widget, context, info, time_))
223
if (drawer->close_timeout_id)
224
g_source_remove (drawer->close_timeout_id);
225
drawer->close_timeout_id = 0;
227
button_widget_set_dnd_highlight (BUTTON_WIDGET (widget), TRUE);
229
if (panel_toplevel_get_is_hidden (drawer->toplevel)) {
230
panel_toplevel_unhide (drawer->toplevel);
231
drawer->opened_for_drag = TRUE;
238
close_drawer_in_idle (gpointer data)
240
Drawer *drawer = (Drawer *) data;
242
drawer->close_timeout_id = 0;
244
if (drawer->opened_for_drag) {
245
panel_toplevel_hide (drawer->toplevel, FALSE, -1);
246
drawer->opened_for_drag = FALSE;
253
queue_drawer_close_for_drag (Drawer *drawer)
255
if (!drawer->close_timeout_id)
256
drawer->close_timeout_id =
257
g_timeout_add_seconds (1, close_drawer_in_idle, drawer);
261
drag_leave_cb (GtkWidget *widget,
262
GdkDragContext *context,
266
queue_drawer_close_for_drag (drawer);
268
button_widget_set_dnd_highlight (BUTTON_WIDGET (widget), FALSE);
272
drag_drop_cb (GtkWidget *widget,
273
GdkDragContext *context,
281
if (!panel_check_dnd_target_data (widget, context, NULL, &atom))
284
gtk_drag_get_data (widget, context, atom, time_);
290
drag_data_get_cb (GtkWidget *widget,
291
GdkDragContext *context,
292
GtkSelectionData *selection_data,
299
foo = g_strdup_printf ("DRAWER:%d", panel_find_applet_index (widget));
301
gtk_selection_data_set (selection_data,
302
gtk_selection_data_get_target (selection_data), 8, (guchar *)foo,
309
set_tooltip_and_name (Drawer *drawer,
312
g_return_if_fail (drawer != NULL);
313
g_return_if_fail (tooltip != NULL);
315
if (tooltip && !tooltip [0])
318
panel_toplevel_set_name (drawer->toplevel, tooltip);
319
panel_util_set_tooltip_text (drawer->button, tooltip);
323
create_drawer_applet (PanelToplevel *toplevel,
324
PanelToplevel *parent_toplevel,
326
const char *custom_icon,
327
gboolean use_custom_icon,
328
PanelOrientation orientation)
333
drawer = g_new0 (Drawer, 1);
335
drawer->toplevel = toplevel;
337
if (!use_custom_icon || !custom_icon || !custom_icon [0]) {
338
drawer->button = button_widget_new (PANEL_ICON_DRAWER, TRUE,
341
drawer->button = button_widget_new (custom_icon, TRUE,
345
if (!drawer->button) {
349
atk_obj = gtk_widget_get_accessible (drawer->button);
350
atk_object_set_name (atk_obj, _("Drawer"));
352
set_tooltip_and_name (drawer, tooltip);
354
gtk_drag_dest_set (drawer->button, 0, NULL, 0, 0);
356
g_signal_connect (drawer->button, "drag_data_get",
357
G_CALLBACK (drag_data_get_cb), drawer);
358
g_signal_connect (drawer->button, "drag_data_received",
359
G_CALLBACK (drag_data_received_cb), drawer);
360
g_signal_connect (drawer->button, "drag_motion",
361
G_CALLBACK (drag_motion_cb), drawer);
362
g_signal_connect (drawer->button, "drag_leave",
363
G_CALLBACK (drag_leave_cb), drawer);
364
g_signal_connect (drawer->button, "drag_drop",
365
G_CALLBACK (drag_drop_cb), drawer);
367
g_signal_connect (drawer->button, "clicked",
368
G_CALLBACK (drawer_click), drawer);
369
g_signal_connect (drawer->button, "destroy",
370
G_CALLBACK (destroy_drawer), drawer);
371
g_signal_connect (drawer->button, "key_press_event",
372
G_CALLBACK (key_press_drawer), drawer);
373
g_signal_connect (toplevel, "destroy",
374
G_CALLBACK (toplevel_destroyed), drawer);
376
gtk_widget_show (drawer->button);
378
g_signal_connect (drawer->toplevel, "key_press_event",
379
G_CALLBACK (key_press_drawer_widget), drawer);
381
panel_toplevel_attach_to_widget (
382
toplevel, parent_toplevel, GTK_WIDGET (drawer->button));
387
static PanelToplevel *
388
create_drawer_toplevel (const char *drawer_id)
390
PanelToplevel *toplevel;
395
client = panel_gconf_get_client ();
397
toplevel_id = panel_profile_find_new_id (PANEL_GCONF_TOPLEVELS);
399
toplevel = panel_profile_load_toplevel (client, PANEL_CONFIG_DIR,
400
PANEL_GCONF_TOPLEVELS, toplevel_id);
403
g_free (toplevel_id);
407
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer_id, "attached_toplevel_id");
408
gconf_client_set_string (client, key, toplevel_id, NULL);
409
g_free (toplevel_id);
411
panel_profile_set_toplevel_enable_buttons (toplevel, TRUE);
412
panel_profile_set_toplevel_enable_arrows (toplevel, TRUE);
418
drawer_button_size_allocated (GtkWidget *widget,
419
GtkAllocation *alloc,
422
if (!gtk_widget_get_realized (widget))
425
gtk_widget_queue_resize (GTK_WIDGET (drawer->toplevel));
427
g_object_set_data (G_OBJECT (widget), "allocated", GINT_TO_POINTER (TRUE));
431
panel_drawer_use_custom_icon_changed (GConfClient *client,
436
gboolean use_custom_icon;
437
char *custom_icon = NULL;
439
if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
442
use_custom_icon = gconf_value_get_bool (entry->value);
444
if (use_custom_icon) {
447
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer->info->id, "custom_icon");
448
custom_icon = gconf_client_get_string (client, key, NULL);
451
button_widget_set_icon_name (BUTTON_WIDGET (drawer->button), custom_icon);
453
g_free (custom_icon);
457
panel_drawer_custom_icon_changed (GConfClient *client,
462
const char *custom_icon;
464
if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
467
custom_icon = gconf_value_get_string (entry->value);
469
if (custom_icon && custom_icon [0]) {
471
gboolean use_custom_icon;
473
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer->info->id, "use_custom_icon");
474
use_custom_icon = gconf_client_get_bool (client, key, NULL);
476
button_widget_set_icon_name (BUTTON_WIDGET (drawer->button), custom_icon);
481
panel_drawer_tooltip_changed (GConfClient *client,
486
if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
489
set_tooltip_and_name (drawer,
490
gconf_value_get_string (entry->value));
494
panel_drawer_connect_to_gconf (Drawer *drawer)
500
client = panel_gconf_get_client ();
502
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer->info->id, "use_custom_icon");
503
drawer->listeners [i++] =
504
gconf_client_notify_add (client, key,
505
(GConfClientNotifyFunc) panel_drawer_use_custom_icon_changed,
508
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer->info->id, "custom_icon");
509
drawer->listeners [i++] =
510
gconf_client_notify_add (client, key,
511
(GConfClientNotifyFunc) panel_drawer_custom_icon_changed,
514
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer->info->id, "tooltip");
515
drawer->listeners [i++] =
516
gconf_client_notify_add (client, key,
517
(GConfClientNotifyFunc) panel_drawer_tooltip_changed,
520
g_assert (i == PANEL_DRAWER_N_LISTENERS);
524
drawer_changes_enabled (void)
526
return !panel_lockdown_get_locked_down ();
530
load_drawer_applet (char *toplevel_id,
531
const char *custom_icon,
532
gboolean use_custom_icon,
534
PanelToplevel *parent_toplevel,
540
PanelOrientation orientation;
541
PanelToplevel *toplevel = NULL;
542
Drawer *drawer = NULL;
543
PanelWidget *panel_widget;
545
orientation = panel_toplevel_get_orientation (parent_toplevel);
548
toplevel = panel_profile_get_toplevel_by_id (toplevel_id);
551
toplevel = create_drawer_toplevel (id);
554
panel_toplevel_hide (toplevel, FALSE, -1);
555
drawer = create_drawer_applet (toplevel,
566
panel_widget = panel_toplevel_get_panel_widget (parent_toplevel);
568
drawer->info = panel_applet_register (drawer->button, drawer,
569
(GDestroyNotify) g_free,
571
locked, pos, exactpos,
572
PANEL_OBJECT_DRAWER, id);
575
gtk_widget_destroy (GTK_WIDGET (toplevel));
579
g_signal_connect_after (drawer->button, "size_allocate",
580
G_CALLBACK (drawer_button_size_allocated), drawer);
582
panel_widget_add_forbidden (panel_toplevel_get_panel_widget (drawer->toplevel));
583
panel_widget_set_applet_expandable (panel_widget, GTK_WIDGET (drawer->button), FALSE, TRUE);
584
panel_widget_set_applet_size_constrained (panel_widget, GTK_WIDGET (drawer->button), TRUE);
586
panel_applet_add_callback (drawer->info,
589
_("_Add to Drawer..."),
590
drawer_changes_enabled);
592
panel_applet_add_callback (drawer->info,
594
GTK_STOCK_PROPERTIES,
596
drawer_changes_enabled);
598
panel_applet_add_callback (drawer->info,
604
panel_drawer_connect_to_gconf (drawer);
608
panel_drawer_prepare (const char *drawer_id,
609
const char *custom_icon,
610
gboolean use_custom_icon,
612
char **attached_toplevel_id)
617
client = panel_gconf_get_client ();
620
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer_id, "tooltip");
621
gconf_client_set_string (client, key, tooltip, NULL);
624
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer_id, "use_custom_icon");
625
gconf_client_set_bool (client, key, use_custom_icon, NULL);
628
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer_id, "custom_icon");
629
gconf_client_set_string (client, key, custom_icon, NULL);
632
if (attached_toplevel_id) {
636
toplevel_id = panel_profile_find_new_id (PANEL_GCONF_TOPLEVELS);
638
toplevel_dir = g_strdup_printf (PANEL_CONFIG_DIR "/toplevels/%s",
640
panel_gconf_associate_schemas_in_dir (client, toplevel_dir, PANEL_SCHEMAS_DIR "/toplevels");
642
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, drawer_id, "attached_toplevel_id");
643
gconf_client_set_string (client, key, toplevel_id, NULL);
645
key = panel_gconf_full_key (PANEL_GCONF_TOPLEVELS, toplevel_id, "enable_buttons");
646
gconf_client_set_bool (client, key, TRUE, NULL);
648
key = panel_gconf_full_key (PANEL_GCONF_TOPLEVELS, toplevel_id, "enable_arrows");
649
gconf_client_set_bool (client, key, TRUE, NULL);
651
*attached_toplevel_id = toplevel_id;
656
panel_drawer_create (PanelToplevel *toplevel,
658
const char *custom_icon,
659
gboolean use_custom_icon,
664
id = panel_profile_prepare_object (PANEL_OBJECT_DRAWER, toplevel, position, FALSE);
666
panel_drawer_prepare (id, custom_icon, use_custom_icon, tooltip, NULL);
668
panel_profile_add_to_list (PANEL_GCONF_OBJECTS, id);
674
panel_drawer_create_with_id (const char *toplevel_id,
676
const char *custom_icon,
677
gboolean use_custom_icon,
681
char *attached_toplevel_id = NULL;
683
id = panel_profile_prepare_object_with_id (PANEL_OBJECT_DRAWER, toplevel_id, position, FALSE);
685
panel_drawer_prepare (id, custom_icon, use_custom_icon, tooltip, &attached_toplevel_id);
687
panel_profile_add_to_list (PANEL_GCONF_OBJECTS, id);
691
return attached_toplevel_id;
695
drawer_load_from_gconf (PanelWidget *panel_widget,
702
gboolean use_custom_icon;
707
g_return_if_fail (panel_widget != NULL);
708
g_return_if_fail (id != NULL);
710
client = panel_gconf_get_client ();
712
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, id, "attached_toplevel_id");
713
toplevel_id = gconf_client_get_string (client, key, NULL);
715
panel_profile_load_toplevel (client, PANEL_CONFIG_DIR, PANEL_GCONF_TOPLEVELS, toplevel_id);
717
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, id, "use_custom_icon");
718
use_custom_icon = gconf_client_get_bool (client, key, NULL);
720
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, id, "custom_icon");
721
custom_icon = gconf_client_get_string (client, key, NULL);
723
key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, id, "tooltip");
724
tooltip = gconf_client_get_string (client, key, NULL);
726
load_drawer_applet (toplevel_id,
730
panel_widget->toplevel,
736
g_free (toplevel_id);
737
g_free (custom_icon);
742
panel_drawer_set_dnd_enabled (Drawer *drawer,
743
gboolean dnd_enabled)
746
static GtkTargetEntry dnd_targets[] = {
747
{ "application/x-panel-applet-internal", 0, 0 }
750
gtk_widget_set_has_window (drawer->button, TRUE);
751
gtk_drag_source_set (drawer->button,
755
//FIXME: we're forgetting the use_custom_icon case, here
756
gtk_drag_source_set_icon_name (drawer->button,
757
button_widget_get_icon_name (BUTTON_WIDGET (drawer->button)));
759
gtk_widget_set_has_window (drawer->button, FALSE);
762
gtk_drag_source_unset (drawer->button);
766
drawer_deletion_response (GtkWidget *dialog,
770
if (response == GTK_RESPONSE_OK)
771
panel_profile_delete_object (drawer->info);
773
gtk_widget_destroy (dialog);
777
drawer_query_deletion (Drawer *drawer)
781
if (drawer->toplevel) {
782
PanelWidget *panel_widget;
784
panel_widget = panel_toplevel_get_panel_widget (
787
if (!panel_global_config_get_confirm_panel_remove () ||
788
!g_list_length (panel_widget->applet_list)) {
789
panel_profile_delete_object (drawer->info);
793
dialog = panel_deletion_dialog (drawer->toplevel);
795
g_signal_connect (dialog, "response",
796
G_CALLBACK (drawer_deletion_response),
799
g_signal_connect_object (drawer->toplevel, "destroy",
800
G_CALLBACK (gtk_widget_destroy),
804
gtk_widget_show_all (dialog);