3
* Copyright (c) 2005 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
7
* by 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 Library 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.
28
#include <libxfcegui4/libxfcegui4.h>
29
#include <libxfce4panel/xfce-panel-window.h>
30
#include <libxfce4panel/xfce-itembar.h>
31
#include <libxfce4panel/xfce-panel-item-iface.h>
33
#include <libxfce4panel/libxfce4panel-enum-types.h>
34
#include <libxfce4panel/xfce-panel-convenience.h>
35
#include <libxfce4panel/xfce-panel-macros.h>
38
#include "panel-app.h"
39
#include "panel-properties.h"
40
#include "panel-item-manager.h"
41
#include "panel-dnd.h"
43
/* PanelPrivate struct */
44
#include "panel-private.h"
66
static void panel_finalize (GObject * object);
68
static void panel_get_property (GObject *object,
73
static void panel_set_property (GObject *object,
79
static void panel_size_request (GtkWidget *widget,
80
GtkRequisition *requisition);
82
static gboolean panel_button_pressed (GtkWidget *widget,
86
static void panel_menu_deactivated (GtkWidget *item);
88
static void panel_menu_opened (GtkWidget *item);
89
static void _item_start_move (GtkWidget *item, Panel *panel);
92
static void _panel_drag_data_received (GtkWidget *widget,
93
GdkDragContext *context,
96
GtkSelectionData *data,
101
static gboolean _panel_drag_drop (GtkWidget *widget,
102
GdkDragContext *context,
109
static void _panel_drag_begin (GtkWidget *widget,
110
GdkDragContext *drag_context,
113
/* pass through button press events */
114
static gboolean _panel_itembar_button_pressed (GtkWidget *widget,
119
static GtkWidget *_panel_create_menu (Panel *panel);
122
/* this sets up a lot of stuff, see GObject API reference */
123
G_DEFINE_TYPE (Panel, panel, XFCE_TYPE_PANEL_WINDOW);
126
panel_class_init (PanelClass * klass)
128
GObjectClass *object_class;
129
GtkWidgetClass *widget_class;
132
g_type_class_add_private (klass, sizeof (PanelPrivate));
134
object_class = (GObjectClass *) klass;
135
widget_class = (GtkWidgetClass *) klass;
137
object_class->finalize = panel_finalize;
138
object_class->get_property = panel_get_property;
139
object_class->set_property = panel_set_property;
141
widget_class->button_press_event = panel_button_pressed;
142
widget_class->size_request = panel_size_request;
146
pspec = g_param_spec_int ("size",
148
"The size of the panel",
150
DEFAULT_SIZE, G_PARAM_READWRITE);
152
g_object_class_install_property (object_class, PROP_SIZE, pspec);
154
pspec = g_param_spec_int ("monitor",
156
"The monitor number of the panel",
158
DEFAULT_MONITOR, G_PARAM_READWRITE);
160
g_object_class_install_property (object_class, PROP_MONITOR, pspec);
162
pspec = g_param_spec_enum ("screen-position",
164
"The screen position of the panel",
165
XFCE_TYPE_SCREEN_POSITION,
166
DEFAULT_SCREEN_POSITION, G_PARAM_READWRITE);
168
g_object_class_install_property (object_class, PROP_SCREEN_POSITION,
171
pspec = g_param_spec_int ("xoffset",
172
"Offset in x direction",
173
"Offset in x direction",
175
DEFAULT_XOFFSET, G_PARAM_READWRITE);
177
g_object_class_install_property (object_class, PROP_XOFFSET, pspec);
179
pspec = g_param_spec_int ("yoffset",
180
"Offset in y direction",
181
"Offset in y direction",
183
DEFAULT_YOFFSET, G_PARAM_READWRITE);
185
g_object_class_install_property (object_class, PROP_YOFFSET, pspec);
187
pspec = g_param_spec_boolean ("autohide",
189
"Automatically hide the panel",
190
DEFAULT_AUTOHIDE, G_PARAM_READWRITE);
192
g_object_class_install_property (object_class, PROP_AUTOHIDE, pspec);
194
pspec = g_param_spec_int ("fullwidth",
196
"Use the full screen width",
197
XFCE_PANEL_NORMAL_WIDTH,
198
XFCE_PANEL_SPAN_MONITORS,
199
DEFAULT_FULL_WIDTH, G_PARAM_READWRITE);
201
g_object_class_install_property (object_class, PROP_FULL_WIDTH, pspec);
203
pspec = g_param_spec_int ("transparency",
204
"panel_transparency",
205
"Transparency of the panel",
207
DEFAULT_TRANSPARENCY, G_PARAM_READWRITE);
209
g_object_class_install_property (object_class, PROP_TRANSPARENCY, pspec);
211
pspec = g_param_spec_boolean ("activetrans",
213
"Keep the active panel transparent",
214
DEFAULT_ACTIVE_TRANS, G_PARAM_READWRITE);
216
g_object_class_install_property (object_class, PROP_ACTIVE_TRANS, pspec);
220
panel_init (Panel * panel)
224
priv = panel->priv = G_TYPE_INSTANCE_GET_PRIVATE (panel,
228
priv->size = DEFAULT_SIZE;
229
priv->monitor = DEFAULT_MONITOR;
230
priv->screen_position = DEFAULT_SCREEN_POSITION;
231
priv->xoffset = DEFAULT_XOFFSET;
232
priv->yoffset = DEFAULT_YOFFSET;
233
priv->autohide = DEFAULT_AUTOHIDE;
234
priv->full_width = DEFAULT_FULL_WIDTH;
235
priv->transparency = DEFAULT_TRANSPARENCY;
236
priv->activetrans = DEFAULT_ACTIVE_TRANS;
238
priv->itembar = xfce_itembar_new (GTK_ORIENTATION_HORIZONTAL);
239
gtk_widget_show (priv->itembar);
240
gtk_container_add (GTK_CONTAINER (panel), priv->itembar);
242
panel_dnd_set_dest_name_and_widget (priv->itembar);
243
panel_dnd_set_source_widget (priv->itembar);
245
/* don't allow the wm to close the panel window */
246
g_signal_connect (panel, "delete-event", G_CALLBACK (gtk_true), NULL);
249
g_signal_connect (priv->itembar, "drag-data-received",
250
G_CALLBACK (_panel_drag_data_received), panel);
252
g_signal_connect (priv->itembar, "drag-drop",
253
G_CALLBACK (_panel_drag_drop), panel);
255
g_signal_connect (priv->itembar, "drag-begin",
256
G_CALLBACK (_panel_drag_begin), panel);
259
g_signal_connect (priv->itembar, "button-press-event",
260
G_CALLBACK (_panel_itembar_button_pressed), panel);
263
priv->menu = _panel_create_menu (PANEL (panel));
265
priv->opacity = priv->saved_opacity = 0;
269
panel_finalize (GObject * object)
271
/* TODO: properly ref and unref private widgets */
273
G_OBJECT_CLASS (panel_parent_class)->finalize (object);
277
panel_get_property (GObject *object,
282
PanelPrivate *priv = PANEL(object)->priv;
287
g_value_set_int (value, priv->size);
290
g_value_set_int (value, priv->monitor);
292
case PROP_SCREEN_POSITION:
293
g_value_set_enum (value, priv->screen_position);
296
g_value_set_int (value, priv->xoffset);
299
g_value_set_int (value, priv->yoffset);
302
g_value_set_boolean (value, priv->autohide);
304
case PROP_FULL_WIDTH:
305
g_value_set_int (value, priv->full_width);
307
case PROP_TRANSPARENCY:
308
g_value_set_int (value, priv->transparency);
310
case PROP_ACTIVE_TRANS:
311
g_value_set_boolean (value, priv->activetrans);
314
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320
panel_set_property (GObject *object,
325
Panel *panel = PANEL (object);
330
panel_set_size (panel, g_value_get_int (value));
333
panel_set_monitor (panel, g_value_get_int (value));
335
case PROP_SCREEN_POSITION:
336
panel_set_screen_position (panel, g_value_get_enum (value));
339
panel_set_xoffset (panel, g_value_get_int (value));
342
panel_set_yoffset (panel, g_value_get_int (value));
345
panel_set_autohide (panel, g_value_get_boolean (value));
347
case PROP_FULL_WIDTH:
348
panel_set_full_width (panel, g_value_get_int (value));
350
case PROP_TRANSPARENCY:
351
panel_set_transparency (panel, g_value_get_int (value));
353
case PROP_ACTIVE_TRANS:
354
panel_set_activetrans (panel, g_value_get_boolean (value));
357
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363
panel_size_request (GtkWidget *widget,
364
GtkRequisition *requisition)
366
PanelPrivate *priv = PANEL(widget)->priv;
368
GTK_WIDGET_CLASS (panel_parent_class)->size_request (widget, requisition);
370
if (panel_is_horizontal (PANEL (widget)))
372
requisition->width = MAX (MIN_SIZE, requisition->width);
373
requisition->height = MAX (priv->size, requisition->height);
377
requisition->width = MAX (priv->size, requisition->width);
378
requisition->height = MAX (MIN_SIZE, requisition->height);
383
panel_button_pressed (GtkWidget *widget,
388
modifiers = gtk_accelerator_get_default_mod_mask ();
390
if (ev->button == 3 || (ev->button == 1 &&
391
(ev->state & modifiers) == GDK_CONTROL_MASK))
395
priv = PANEL (widget)->priv;
397
gtk_menu_set_screen (GTK_MENU (priv->menu),
398
gtk_widget_get_screen (widget));
400
gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, NULL, NULL,
401
ev->button, ev->time);
407
GTK_WIDGET_CLASS (panel_parent_class)->button_press_event (widget, ev);
412
_panel_drag_data_received (GtkWidget *widget,
413
GdkDragContext *context,
416
GtkSelectionData *data,
421
XfceItembar *itembar = XFCE_ITEMBAR (widget);
422
PanelPrivate *priv = panel->priv;
428
gboolean succeed = FALSE;
430
DBG (" + drag data received: %d", info);
432
/* get the drop index */
433
index_ = xfce_itembar_get_drop_index (itembar, x, y);
437
case TARGET_PLUGIN_NAME:
438
if (data->length > 0)
440
/* insert the new plugin */
441
panel_insert_item (panel, (const gchar *) data->data, index_);
448
case TARGET_PLUGIN_WIDGET:
449
/* get the plugin from the drag context */
450
plugin = gtk_drag_get_source_widget (context);
452
/* try the drag_widget or leave */
453
if (!plugin || !XFCE_IS_PANEL_ITEM (plugin))
456
if (gtk_widget_get_parent (plugin) != widget)
458
/* get the plugin and information */
459
item = XFCE_PANEL_ITEM (plugin);
460
expand = xfce_panel_item_get_expand (item);
462
/* freeze plugin notifications */
463
g_object_freeze_notify (G_OBJECT (widget));
465
/* move the plugin from the old panel to the new one */
466
gtk_widget_reparent (GTK_WIDGET (plugin), widget);
468
/* update the plugin */
469
xfce_panel_item_set_size (item, priv->size);
470
xfce_panel_item_set_screen_position (item, priv->screen_position);
472
/* update the itembar */
473
xfce_itembar_reorder_child (itembar, plugin, index_);
474
xfce_itembar_set_child_expand (itembar, plugin, expand);
476
/* thaw update notifications */
477
g_object_thaw_notify (G_OBJECT (widget));
479
else /* move on same panel */
481
/* get the old index */
482
oldindex = xfce_itembar_get_item_index (itembar, plugin);
484
if (index_ > oldindex)
487
if (index_ != oldindex)
488
xfce_itembar_reorder_child (itembar, plugin, index_);
491
/* properly handled */
500
/* finish the drag */
501
gtk_drag_finish (context, succeed, FALSE, time_);
505
_panel_drag_drop (GtkWidget *widget,
506
GdkDragContext *context,
512
GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
514
/* we cannot handle the drag data */
515
if (G_UNLIKELY (target == GDK_NONE))
518
/* request the drag data */
519
gtk_drag_get_data (widget, context, target, time_);
521
/* we call gtk_drag_finish later */
527
_panel_drag_begin (GtkWidget *widget,
528
GdkDragContext *drag_context,
531
gint x, y, rootx, rooty;
534
DBG (" + drag begin");
536
/* get the pointer position */
537
gdk_display_get_pointer (gtk_widget_get_display (widget), NULL, &x, &y, NULL);
539
/* get the window root coordinates */
540
gdk_window_get_root_origin (widget->window, &rootx, &rooty);
542
/* calc the position inside the panel */
546
/* get the plugin on the itembar at this position */
547
plugin = xfce_itembar_get_item_at_point (XFCE_ITEMBAR (widget), x, y);
549
/* start an item move */
550
if (G_LIKELY (plugin))
551
_item_start_move (plugin, panel);
554
/* pass through right-click events when the event window of itembar is raised
557
_panel_itembar_button_pressed (GtkWidget *widget,
564
if (xfce_itembar_event_window_is_raised (XFCE_ITEMBAR (widget)))
566
modifiers = gtk_accelerator_get_default_mod_mask ();
568
if (ev->button == 3 || (ev->button == 1 &&
569
(ev->state & modifiers) == GDK_CONTROL_MASK))
571
plugin = xfce_itembar_get_item_at_point (XFCE_ITEMBAR (widget),
575
gtk_widget_event (plugin, (GdkEvent *)ev);
587
_panel_create_menu (Panel *panel)
589
GtkWidget *menu, *mi, *img;
591
menu = gtk_menu_new ();
593
if (xfce_allow_panel_customization ())
595
mi = gtk_image_menu_item_new_with_label (_("Customize Panel..."));
596
gtk_widget_show (mi);
597
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
599
img = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
600
gtk_widget_show (img);
601
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img);
603
g_signal_connect (mi, "activate", G_CALLBACK (panel_app_customize),
606
mi = gtk_image_menu_item_new_with_label (_("Add New Items..."));
607
gtk_widget_show (mi);
608
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
610
img = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
611
gtk_widget_show (img);
612
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img);
614
g_signal_connect_swapped (mi, "activate",
615
G_CALLBACK (panel_app_customize_items), NULL);
617
mi = gtk_separator_menu_item_new ();
618
gtk_widget_show (mi);
619
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
621
mi = gtk_image_menu_item_new_with_label (_("Quit"));
622
gtk_widget_show (mi);
623
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
625
img = gtk_image_new_from_stock (GTK_STOCK_QUIT, GTK_ICON_SIZE_MENU);
626
gtk_widget_show (img);
627
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img);
629
g_signal_connect (mi, "activate", G_CALLBACK (panel_app_quit), NULL);
631
mi = gtk_image_menu_item_new_with_label (_("Restart"));
632
gtk_widget_show (mi);
633
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
635
img = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU);
636
gtk_widget_show (img);
637
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img);
639
g_signal_connect (mi, "activate", G_CALLBACK (panel_app_restart), NULL);
641
mi = gtk_separator_menu_item_new ();
642
gtk_widget_show (mi);
643
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
646
mi = gtk_image_menu_item_new_with_label (_("About the Xfce Panel"));
647
gtk_widget_show (mi);
648
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
650
img = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU);
651
gtk_widget_show (img);
652
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img);
654
g_signal_connect_swapped (mi, "activate", G_CALLBACK (panel_app_about),
665
return PANEL (g_object_new (PANEL_TYPE_PANEL, NULL));
669
panel_free_data (Panel *panel)
675
_panel_return_if_fail (PANEL_IS_PANEL (panel));
679
/* try and prevent some race conditions */
680
priv->block_autohide++;
681
xfce_panel_window_set_move_function (XFCE_PANEL_WINDOW (panel),
683
xfce_panel_window_set_resize_function (XFCE_PANEL_WINDOW (panel),
686
for (l = gtk_container_get_children (GTK_CONTAINER (priv->itembar));
690
XfcePanelItem *item = l->data;
692
xfce_panel_item_free_data (item);
697
/* give plugins the chance to quit */
698
for (i = 0; i < 10 &&
699
xfce_itembar_get_n_items (XFCE_ITEMBAR (priv->itembar)) != 0; ++i)
701
DBG (" + %d item(s) on the panel",
702
xfce_itembar_get_n_items (XFCE_ITEMBAR (priv->itembar)));
703
g_usleep (200000); /* 0.2 sec */
705
while (gtk_events_pending ())
706
gtk_main_iteration ();
714
panel_menu_deactivated (GtkWidget *item)
716
int x, y, w, h, px, py;
717
Panel *panel = PANEL (item->parent->parent);
719
_panel_return_if_fail (PANEL_IS_PANEL (panel));
721
panel_unblock_autohide (panel);
723
gdk_display_get_pointer (gdk_display_get_default (), NULL, &px, &py, NULL);
725
gtk_window_get_position (GTK_WINDOW (panel), &x, &y);
726
gtk_window_get_size (GTK_WINDOW (panel), &w, &h);
728
if (px < x || px > x + w || py < y || py > y + h)
730
GdkEvent *ev = gdk_event_new (GDK_LEAVE_NOTIFY);
732
((GdkEventCrossing *) ev)->time = GDK_CURRENT_TIME;
733
((GdkEventCrossing *) ev)->detail = GDK_NOTIFY_NONLINEAR;
735
gtk_widget_event (GTK_WIDGET (panel), ev);
742
panel_menu_opened (GtkWidget *item)
744
_panel_return_if_fail (PANEL_IS_PANEL (item->parent->parent));
746
panel_block_autohide (PANEL (item->parent->parent));
750
_item_expand_changed (GtkWidget *item,
756
_panel_return_if_fail (PANEL_IS_PANEL (panel));
760
xfce_itembar_set_child_expand (XFCE_ITEMBAR (priv->itembar), item, expand);
766
_item_start_move_end (GtkWidget *item,
767
GdkDragContext *context,
770
PanelPrivate *priv = panel->priv;
773
DBG ("+ finish item drag");
775
/* disconnect drag end signal */
776
g_signal_handlers_disconnect_by_func (G_OBJECT (item), G_CALLBACK (_item_start_move_end), panel);
778
if (!priv->edit_mode)
780
const GPtrArray *panels = panel_app_get_panel_list ();
783
for (i = 0; i < panels->len; ++i)
785
p = g_ptr_array_index (panels, i);
788
xfce_itembar_lower_event_window (XFCE_ITEMBAR (priv->itembar));
789
panel_set_items_sensitive (p, TRUE);
791
panel_unblock_autohide (p);
799
_item_start_move (GtkWidget *item,
802
const GPtrArray *panels = panel_app_get_panel_list ();
807
for (i = 0; i < panels->len; ++i)
809
p = g_ptr_array_index (panels, i);
812
if (!priv->edit_mode)
814
panel_set_items_sensitive (p, FALSE);
815
xfce_itembar_raise_event_window (XFCE_ITEMBAR (priv->itembar));
816
panel_block_autohide (p);
821
panel_dnd_begin_drag (item);
823
/* signal to make panels sensitive after a drop */
824
g_signal_connect (G_OBJECT (item), "drag-end", G_CALLBACK (_item_start_move_end), panel);
830
_item_set_panel_hidden (GtkWidget *item,
836
_panel_return_if_fail (PANEL_IS_PANEL (panel));
841
panel_set_hidden (panel, hidden);
845
panel_insert_widget (Panel *panel,
849
PanelPrivate *priv = panel->priv;
851
gtk_widget_show (item);
854
xfce_itembar_append (XFCE_ITEMBAR (priv->itembar), item);
856
xfce_itembar_insert (XFCE_ITEMBAR (priv->itembar), item, position);
858
xfce_itembar_set_child_expand (XFCE_ITEMBAR (priv->itembar), item,
859
xfce_panel_item_get_expand (XFCE_PANEL_ITEM (item)));
861
if (xfce_itembar_event_window_is_raised (XFCE_ITEMBAR (priv->itembar)))
862
xfce_panel_item_set_sensitive (XFCE_PANEL_ITEM (item), FALSE);
864
g_signal_connect (item, "destroy", G_CALLBACK (panel_app_queue_save),
869
panel_create_item (Panel *panel,
874
GtkWidget *item = NULL;
878
xmon = panel_app_get_monitor (priv->monitor);
880
item = xfce_panel_item_manager_create_item (xmon->screen,
884
priv->screen_position);
888
g_signal_connect (item, "menu-deactivated",
889
G_CALLBACK (panel_menu_deactivated), panel);
891
g_signal_connect (item, "menu-opened",
892
G_CALLBACK (panel_menu_opened), panel);
894
g_signal_connect (item, "expand-changed",
895
G_CALLBACK (_item_expand_changed), panel);
897
g_signal_connect (item, "customize-panel",
898
G_CALLBACK (panel_app_customize), NULL);
900
g_signal_connect (item, "customize-items",
901
G_CALLBACK (panel_app_customize_items), NULL);
903
g_signal_connect (item, "move",
904
G_CALLBACK (_item_start_move), panel);
906
g_signal_connect (item, "set-hidden",
907
G_CALLBACK (_item_set_panel_hidden), panel);
914
_panel_get_new_id (void)
916
static int counter = 0;
919
/* unique number: pseudo-random time() + counter */
920
g_snprintf (id, sizeof(id), "%ld%d", (glong) time (NULL), counter++);
926
panel_add_item_with_id (Panel *panel,
932
item = panel_create_item (panel, name, id);
936
panel_insert_widget (panel, item, -1);
943
panel_add_item (Panel *panel,
946
return panel_add_item_with_id (panel, name, _panel_get_new_id ());
950
panel_insert_item (Panel *panel,
956
item = panel_create_item (panel, name, _panel_get_new_id ());
960
panel_insert_widget (panel, item, position);
969
panel_get_item_list (Panel * panel)
975
return gtk_container_get_children (GTK_CONTAINER (priv->itembar));
979
panel_save_items (Panel *panel)
983
_panel_return_if_fail (PANEL_IS_PANEL (panel));
987
gtk_container_foreach (GTK_CONTAINER (priv->itembar),
988
(GtkCallback)xfce_panel_item_save, NULL);
994
panel_is_horizontal (Panel *panel)
996
return (GTK_ORIENTATION_HORIZONTAL ==
997
xfce_panel_window_get_orientation (XFCE_PANEL_WINDOW (panel)));
1001
panel_set_items_sensitive (Panel *panel,
1004
PanelPrivate *priv = panel->priv;
1005
GList *l, *children;
1007
children = gtk_container_get_children (GTK_CONTAINER (priv->itembar));
1009
for (l = children; l != NULL; l = l->next)
1011
xfce_panel_item_set_sensitive (XFCE_PANEL_ITEM (l->data), sensitive);
1014
g_list_free (children);