4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2001, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* panel.c - code for dealing with panel windows */
42 #include "gui_support.h"
53 Panel
*current_panel
[PANEL_NUMBER_OF_SIDES
];
55 /* NULL => Not loading a panel */
56 static Panel
*loading_panel
= NULL
;
58 /* Static prototypes */
59 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
);
60 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
);
61 static char *pan_from_file(guchar
*line
);
62 static gint
icon_button_release(GtkWidget
*widget
,
63 GdkEventButton
*event
,
65 static gint
icon_button_press(GtkWidget
*widget
,
66 GdkEventButton
*event
,
68 static void reposition_panel(Panel
*panel
, gboolean force_resize
);
69 static gint
expose_icon(GtkWidget
*widget
,
70 GdkEventExpose
*event
,
72 static gint
draw_icon(GtkWidget
*widget
,
73 GdkRectangle
*badarea
,
75 static gint
panel_button_release(GtkWidget
*widget
,
76 GdkEventButton
*event
,
78 static gint
panel_button_press(GtkWidget
*widget
,
79 GdkEventButton
*event
,
81 static void panel_post_resize(GtkWidget
*box
,
82 GtkRequisition
*req
, Panel
*panel
);
83 static void box_resized(GtkWidget
*box
, GtkAllocation
*alloc
, Panel
*panel
);
84 static void drag_set_panel_dest(Icon
*icon
);
85 static void add_uri_list(GtkWidget
*widget
,
86 GdkDragContext
*context
,
89 GtkSelectionData
*selection_data
,
93 static void panel_add_item(Panel
*panel
,
97 static gboolean
drag_motion(GtkWidget
*widget
,
98 GdkDragContext
*context
,
103 static void drag_leave(GtkWidget
*widget
,
104 GdkDragContext
*context
,
107 static GList
*get_widget_list(Panel
*panel
);
108 static GtkWidget
*make_insert_frame(Panel
*panel
);
109 static gboolean
enter_icon(GtkWidget
*widget
,
110 GdkEventCrossing
*event
,
112 static gint
icon_motion_event(GtkWidget
*widget
,
113 GdkEventMotion
*event
,
115 static gint
panel_motion_event(GtkWidget
*widget
,
116 GdkEventMotion
*event
,
118 static void reposition_icon(Icon
*icon
, int index
);
119 static void start_drag(Icon
*icon
, GdkEventMotion
*event
);
120 static guchar
*create_uri_list(GList
*list
);
121 static void drag_end(GtkWidget
*widget
,
122 GdkDragContext
*context
,
124 static void perform_action(Panel
*panel
,
126 GdkEventButton
*event
);
127 static void run_applet(Icon
*icon
);
128 static void panel_set_style(guchar
*new);
129 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, Icon
*icon
);
132 static GtkWidget
*dnd_highlight
= NULL
; /* (stops flickering) */
134 /* When sliding the panel, records where the panel was before */
135 static gint slide_from_value
= 0;
138 #define SHOW_APPS_SMALL 1
140 static int panel_style
= SHOW_APPS_SMALL
;
142 /****************************************************************
143 * EXTERNAL INTERFACE *
144 ****************************************************************/
146 void panel_init(void)
148 option_add_int("panel_style", panel_style
, panel_set_style
);
151 /* 'name' may be NULL or "" to remove the panel */
152 Panel
*panel_new(guchar
*name
, PanelSide side
)
156 GtkWidget
*vp
, *box
, *frame
;
158 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, NULL
);
159 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
161 if (name
&& *name
== '\0')
164 if (current_panel
[side
])
168 gtk_widget_destroy(current_panel
[side
]->window
);
173 if (name
== NULL
|| *name
== '\0')
176 panel
= g_new(Panel
, 1);
177 panel
->name
= g_strdup(name
);
180 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
181 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
182 gtk_widget_set_events(panel
->window
,
183 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
184 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
185 GDK_BUTTON2_MOTION_MASK
);
187 gtk_signal_connect(GTK_OBJECT(panel
->window
), "delete-event",
188 GTK_SIGNAL_FUNC(panel_delete
), panel
);
189 gtk_signal_connect(GTK_OBJECT(panel
->window
), "destroy",
190 GTK_SIGNAL_FUNC(panel_destroyed
), panel
);
191 gtk_signal_connect(GTK_OBJECT(panel
->window
), "button_press_event",
192 GTK_SIGNAL_FUNC(panel_button_press
), panel
);
193 gtk_signal_connect(GTK_OBJECT(panel
->window
), "button_release_event",
194 GTK_SIGNAL_FUNC(panel_button_release
), panel
);
195 gtk_signal_connect(GTK_OBJECT(panel
->window
), "motion-notify-event",
196 GTK_SIGNAL_FUNC(panel_motion_event
), panel
);
198 if (strchr(name
, '/'))
199 load_path
= g_strdup(name
);
204 leaf
= g_strconcat("pan_", name
, NULL
);
205 load_path
= choices_find_path_load(leaf
, PROJECT
);
209 vp
= gtk_viewport_new(NULL
, NULL
);
210 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_OUT
);
211 gtk_container_add(GTK_CONTAINER(panel
->window
), vp
);
213 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
215 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
216 box
= gtk_hbox_new(FALSE
, 0);
217 panel
->before
= gtk_hbox_new(FALSE
, 0);
218 panel
->after
= gtk_hbox_new(FALSE
, 0);
222 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
223 box
= gtk_vbox_new(FALSE
, 0);
224 panel
->before
= gtk_vbox_new(FALSE
, 0);
225 panel
->after
= gtk_vbox_new(FALSE
, 0);
228 gtk_container_add(GTK_CONTAINER(vp
), box
);
229 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
230 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
232 frame
= make_insert_frame(panel
);
233 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
235 /* This is used so that we can find the middle easily! */
236 panel
->gap
= gtk_event_box_new();
237 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
239 frame
= make_insert_frame(panel
);
240 gtk_object_set_data(GTK_OBJECT(frame
), "after", "yes");
241 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
243 gtk_widget_realize(panel
->window
);
244 make_panel_window(panel
->window
->window
);
246 gtk_widget_show_all(vp
);
248 loading_panel
= panel
;
249 if (load_path
&& access(load_path
, F_OK
) == 0)
250 parse_file(load_path
, pan_from_file
);
253 /* Don't scare users with an empty panel... */
256 panel_add_item(panel
, "~", "Home", FALSE
);
258 apps
= pathdup(make_path(app_dir
, "..")->str
);
261 panel_add_item(panel
, apps
, "Apps", FALSE
);
265 loading_panel
= NULL
;
268 current_panel
[side
] = panel
;
270 gtk_widget_queue_resize(box
);
271 gtk_signal_connect_after(GTK_OBJECT(panel
->window
), "size-request",
272 GTK_SIGNAL_FUNC(panel_post_resize
), (GtkObject
*) panel
);
273 gtk_signal_connect_after(GTK_OBJECT(box
), "size-allocate",
274 GTK_SIGNAL_FUNC(box_resized
), (GtkObject
*) panel
);
277 gtk_widget_show(panel
->window
);
282 gboolean
panel_want_show_text(Icon
*icon
)
284 if (panel_style
== SHOW_BOTH
)
286 if (panel_style
== SHOW_ICON
)
289 if (icon
->item
.flags
& ITEM_FLAG_APPDIR
)
295 void panel_icon_renamed(Icon
*icon
)
297 GtkLabel
*label
= GTK_LABEL(icon
->label
);
299 gtk_label_set_text(label
, icon
->item
.leafname
);
303 /****************************************************************
304 * INTERNAL FUNCTIONS *
305 ****************************************************************/
307 /* User has tried to close the panel via the window manager - confirm */
308 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
310 return get_choice(_("Close panel?"),
311 _("You have tried to close a panel via the window "
312 "manager - I usually find that this is accidental... "
314 2, _("Remove"), _("Cancel")) != 0;
317 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
319 if (current_panel
[panel
->side
] == panel
)
320 current_panel
[panel
->side
] = NULL
;
322 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
324 if (current_panel
[PANEL_RIGHT
])
325 reposition_panel(current_panel
[PANEL_RIGHT
], FALSE
);
326 if (current_panel
[PANEL_LEFT
])
327 reposition_panel(current_panel
[PANEL_LEFT
], FALSE
);
333 if (--number_of_windows
< 1)
337 /* Called for each line in the config file while loading a new panel */
338 static char *pan_from_file(guchar
*line
)
342 g_return_val_if_fail(line
!= NULL
, NULL
);
343 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
348 sep
= strpbrk(line
, "<>");
350 return _("Missing < or > in panel config file");
353 leaf
= g_strndup(line
, sep
- line
);
357 panel_add_item(loading_panel
,
367 /* Add an icon with this path to the panel. If after is TRUE then the
368 * icon is added to the right/bottom end of the panel.
370 * If name is NULL a suitable name is taken from path.
372 static void panel_add_item(Panel
*panel
,
380 widget
= gtk_event_box_new();
381 gtk_widget_set_events(widget
,
382 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
383 GDK_BUTTON3_MOTION_MASK
|
384 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
385 GDK_BUTTON_RELEASE_MASK
);
387 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
388 widget
, FALSE
, TRUE
, 4);
390 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
392 gtk_widget_realize(widget
);
394 icon
= g_new(Icon
, 1);
396 icon
->src_path
= g_strdup(path
);
397 icon
->path
= icon_convert_path(path
);
404 gtk_object_set_data(GTK_OBJECT(widget
), "icon", icon
);
406 icon_hash_path(icon
);
408 icon
->widget
= widget
;
409 gtk_widget_set_name(icon
->widget
, "panel-icon");
410 icon
->selected
= FALSE
;
411 diritem_stat(icon
->path
, &icon
->item
, FALSE
);
414 icon
->item
.leafname
= g_strdup(name
);
419 slash
= strrchr(icon
->path
, '/');
420 icon
->item
.leafname
= g_strdup(slash
&& slash
[1] ? slash
+ 1
424 gtk_signal_connect_object(GTK_OBJECT(widget
), "destroy",
425 GTK_SIGNAL_FUNC(icon_destroyed
), (gpointer
) icon
);
427 if (icon
->item
.base_type
== TYPE_DIRECTORY
)
430 gtk_signal_connect(GTK_OBJECT(widget
), "button_release_event",
431 GTK_SIGNAL_FUNC(icon_button_release
), icon
);
432 gtk_signal_connect(GTK_OBJECT(widget
), "button_press_event",
433 GTK_SIGNAL_FUNC(icon_button_press
), icon
);
434 gtk_signal_connect(GTK_OBJECT(icon
->widget
), "motion-notify-event",
435 GTK_SIGNAL_FUNC(icon_motion_event
), icon
);
439 gtk_signal_connect_after(GTK_OBJECT(widget
),
440 "enter-notify-event",
441 GTK_SIGNAL_FUNC(enter_icon
), icon
);
443 gtk_signal_connect_after(GTK_OBJECT(widget
), "draw",
444 GTK_SIGNAL_FUNC(draw_icon
), icon
);
446 gtk_signal_connect_after(GTK_OBJECT(widget
), "expose_event",
447 GTK_SIGNAL_FUNC(expose_icon
), icon
);
448 gtk_signal_connect(GTK_OBJECT(widget
), "drag_data_get",
449 GTK_SIGNAL_FUNC(drag_data_get
), NULL
);
451 gtk_signal_connect(GTK_OBJECT(widget
), "size_request",
452 GTK_SIGNAL_FUNC(size_request
), icon
);
454 drag_set_panel_dest(icon
);
456 icon
->label
= gtk_label_new(icon
->item
.leafname
);
457 gtk_container_add(GTK_CONTAINER(icon
->widget
), icon
->label
);
458 gtk_misc_set_alignment(GTK_MISC(icon
->label
), 0.5, 1);
459 gtk_misc_set_padding(GTK_MISC(icon
->label
), 1, 2);
466 gtk_widget_show(widget
);
469 /* Called when Gtk+ wants to know how much space an icon needs.
470 * 'req' is already big enough for the label, if shown.
472 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, Icon
*icon
)
474 int im_width
, im_height
;
476 im_width
= icon
->item
.image
->width
;
477 im_height
= MIN(icon
->item
.image
->height
, ICON_HEIGHT
);
479 req
->height
+= im_height
;
480 req
->width
= MAX(req
->width
, im_width
);
483 static gint
expose_icon(GtkWidget
*widget
,
484 GdkEventExpose
*event
,
487 return draw_icon(widget
, &event
->area
, icon
);
490 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, Icon
*icon
)
495 gdk_window_get_size(widget
->window
, &width
, &height
);
499 area
.height
= icon
->item
.image
->height
;
501 if (panel_want_show_text(icon
))
503 int text_height
= icon
->label
->requisition
.height
;
505 area
.y
= height
- text_height
- area
.height
;
507 draw_large_icon(widget
, &area
, &icon
->item
, icon
->selected
);
511 area
.y
= (height
- area
.height
) >> 1;
512 draw_large_icon(widget
, &area
, &icon
->item
, icon
->selected
);
518 /* icon may be NULL if the event is on the background */
519 static void perform_action(Panel
*panel
, Icon
*icon
, GdkEventButton
*event
)
523 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
525 if (icon
&& icon
->socket
)
526 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
533 wink_widget(icon
->widget
);
534 run_diritem(icon
->path
, &icon
->item
, NULL
, NULL
, FALSE
);
538 wink_widget(icon
->widget
);
539 run_diritem(icon
->path
, &icon
->item
, NULL
, NULL
, TRUE
);
543 icon_show_menu(event
, icon
, panel
);
546 dnd_motion_start(MOTION_REPOSITION
);
548 case ACT_PRIME_AND_SELECT
:
550 icon_select_only(icon
);
551 dnd_motion_start(MOTION_READY_FOR_DND
);
553 case ACT_PRIME_AND_TOGGLE
:
554 icon_set_selected(icon
, !icon
->selected
);
555 dnd_motion_start(MOTION_READY_FOR_DND
);
557 case ACT_PRIME_FOR_DND
:
558 dnd_motion_start(MOTION_READY_FOR_DND
);
560 case ACT_TOGGLE_SELECTED
:
561 icon_set_selected(icon
, !icon
->selected
);
563 case ACT_SELECT_EXCL
:
564 icon_set_selected(icon
, TRUE
);
566 case ACT_SLIDE_CLEAR_PANEL
:
567 icon_select_only(NULL
);
569 case ACT_SLIDE_PANEL
:
570 dnd_motion_grab_pointer();
571 slide_from_value
= panel
->adj
->value
;
572 dnd_motion_start(MOTION_REPOSITION
);
576 case ACT_CLEAR_SELECTION
:
577 icon_select_only(NULL
);
580 g_warning("Unsupported action : %d\n", action
);
585 static gint
panel_button_release(GtkWidget
*widget
,
586 GdkEventButton
*event
,
589 if (dnd_motion_release(event
))
592 perform_action(panel
, NULL
, event
);
597 static gint
panel_button_press(GtkWidget
*widget
,
598 GdkEventButton
*event
,
601 if (dnd_motion_press(panel
->window
, event
))
602 perform_action(panel
, NULL
, event
);
607 static gint
icon_button_release(GtkWidget
*widget
,
608 GdkEventButton
*event
,
611 if (icon
->socket
&& event
->button
== 1)
612 return FALSE
; /* Restart button */
614 if (dnd_motion_release(event
))
617 perform_action(icon
->panel
, icon
, event
);
622 static gint
icon_button_press(GtkWidget
*widget
,
623 GdkEventButton
*event
,
626 if (icon
->socket
&& event
->button
== 1)
627 return FALSE
; /* Restart button */
629 if (dnd_motion_press(widget
, event
))
630 perform_action(icon
->panel
, icon
, event
);
635 /* Difference between height of an icon and height of panel (or width) */
638 static void reposition_panel(Panel
*panel
, gboolean force_resize
)
642 GList
*next
, *children
;
643 PanelSide side
= panel
->side
;
645 children
= get_widget_list(panel
);
647 for (next
= children
; next
; next
= next
->next
)
649 GtkWidget
*widget
= (GtkWidget
*) next
->data
;
652 gtk_widget_get_child_requisition(widget
, &req
);
660 g_list_free(children
);
662 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
670 if (side
== PANEL_RIGHT
)
671 x
= screen_width
- w
;
675 if (current_panel
[PANEL_TOP
])
679 ph
= current_panel
[PANEL_TOP
]->height
;
684 if (current_panel
[PANEL_BOTTOM
])
685 h
-= current_panel
[PANEL_BOTTOM
]->height
;
688 if (side
== PANEL_BOTTOM
)
689 y
= screen_height
- h
;
691 gtk_widget_set_uposition(panel
->window
, x
, y
);
693 gdk_window_move_resize(panel
->window
->window
, x
, y
, w
, h
);
695 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
697 if (current_panel
[PANEL_RIGHT
])
698 reposition_panel(current_panel
[PANEL_RIGHT
], FALSE
);
699 if (current_panel
[PANEL_LEFT
])
700 reposition_panel(current_panel
[PANEL_LEFT
], FALSE
);
704 /* Same as drag_set_dest(), but for panel icons */
705 static void drag_set_panel_dest(Icon
*icon
)
707 GtkObject
*obj
= GTK_OBJECT(icon
->widget
);
709 make_drop_target(icon
->widget
, 0);
711 gtk_signal_connect(obj
, "drag_motion",
712 GTK_SIGNAL_FUNC(drag_motion
), icon
);
713 gtk_signal_connect(obj
, "drag_leave",
714 GTK_SIGNAL_FUNC(drag_leave
), icon
);
715 gtk_signal_connect(obj
, "drag_end",
716 GTK_SIGNAL_FUNC(drag_end
), icon
);
719 static gboolean
drag_motion(GtkWidget
*widget
,
720 GdkDragContext
*context
,
726 GdkDragAction action
= context
->suggested_action
;
728 DirItem
*item
= &icon
->item
;
731 goto out
; /* Can't drag a selection to itself */
733 type
= dnd_motion_item(context
, &item
);
738 /* We actually must pretend to accept the drop, even if the
739 * directory isn't writeable, so that the spring-opening
743 /* Don't allow drops to non-writeable directories */
744 if (option_get_int("dnd_spring_open") == FALSE
&&
745 type
== drop_dest_dir
&&
746 access(icon
->path
, W_OK
) != 0)
751 g_dataset_set_data(context
, "drop_dest_type", type
);
754 gdk_drag_status(context
, action
, time
);
755 g_dataset_set_data_full(context
, "drop_dest_path",
756 g_strdup(icon
->path
), g_free
);
757 if (type
== drop_dest_dir
)
758 dnd_spring_load(context
, NULL
);
760 if (dnd_highlight
&& dnd_highlight
!= icon
->widget
)
762 gtk_drag_unhighlight(dnd_highlight
);
763 dnd_highlight
= NULL
;
766 if (dnd_highlight
== NULL
)
768 gtk_drag_highlight(icon
->widget
);
769 dnd_highlight
= icon
->widget
;
777 static void add_uri_list(GtkWidget
*widget
,
778 GdkDragContext
*context
,
781 GtkSelectionData
*selection_data
,
786 gboolean after
= FALSE
;
789 if (!selection_data
->data
)
792 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
794 if (gtk_object_get_data(GTK_OBJECT(widget
), "after"))
797 uris
= uri_list_to_glist(selection_data
->data
);
799 for (next
= uris
; next
; next
= next
->next
)
803 path
= get_local_path((guchar
*) next
->data
);
806 panel_add_item(panel
, path
, NULL
, after
);
812 static void drag_end(GtkWidget
*widget
,
813 GdkDragContext
*context
,
816 if (tmp_icon_selected
)
818 icon_select_only(NULL
);
819 tmp_icon_selected
= FALSE
;
823 static void drag_leave(GtkWidget
*widget
,
824 GdkDragContext
*context
,
828 if (dnd_highlight
&& dnd_highlight
== widget
)
830 gtk_drag_unhighlight(dnd_highlight
);
831 dnd_highlight
= NULL
;
837 /* Writes lines to the file, one for each widget, prefixed by 'side'.
838 * Returns TRUE on success, or FALSE on error (and sets errno).
839 * Always frees the widgets list.
841 static gboolean
write_widgets(FILE *file
, GList
*widgets
, guchar side
)
846 tmp
= g_string_new(NULL
);
848 for (next
= widgets
; next
; next
= next
->next
)
852 icon
= gtk_object_get_data(GTK_OBJECT(next
->data
), "icon");
856 g_warning("Can't find Icon from widget\n");
860 g_string_sprintf(tmp
, "%s%c%s\n",
862 side
, icon
->src_path
);
863 if (fwrite(tmp
->str
, 1, tmp
->len
, file
) < tmp
->len
)
865 g_list_free(widgets
);
870 g_string_free(tmp
, TRUE
);
873 g_list_free(widgets
);
878 void panel_save(Panel
*panel
)
882 guchar
*save_new
= NULL
;
884 g_return_if_fail(panel
!= NULL
);
886 if (strchr(panel
->name
, '/'))
887 save
= g_strdup(panel
->name
);
892 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
893 save
= choices_find_path_save(leaf
, PROJECT
, TRUE
);
900 save_new
= g_strconcat(save
, ".new", NULL
);
901 file
= fopen(save_new
, "wb");
905 if (!write_widgets(file
,
906 gtk_container_children(GTK_CONTAINER(panel
->before
)),
910 if (!write_widgets(file
,
911 g_list_reverse(gtk_container_children(
912 GTK_CONTAINER(panel
->after
))),
924 if (rename(save_new
, save
))
929 delayed_rox_error(_("Could not save panel: %s"), g_strerror(errno
));
937 static GList
*get_widget_list(Panel
*panel
)
941 list
= gtk_container_children(GTK_CONTAINER(panel
->before
));
942 list
= g_list_concat(list
,
943 gtk_container_children(GTK_CONTAINER(panel
->after
)));
948 /* Create a frame widget which can be used to add icons to the panel */
949 static GtkWidget
*make_insert_frame(Panel
*panel
)
952 GtkTargetEntry target_table
[] = {
953 {"text/uri-list", 0, TARGET_URI_LIST
},
956 frame
= gtk_frame_new(NULL
);
957 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
958 gtk_widget_set_usize(frame
, 16, 16);
960 gtk_signal_connect(GTK_OBJECT(frame
), "drag-data-received",
961 GTK_SIGNAL_FUNC(add_uri_list
), panel
);
962 gtk_drag_dest_set(frame
,
963 GTK_DEST_DEFAULT_ALL
,
965 sizeof(target_table
) / sizeof(*target_table
),
971 static gboolean
enter_icon(GtkWidget
*widget
,
972 GdkEventCrossing
*event
,
975 icon_may_update(icon
);
980 static gint
panel_motion_event(GtkWidget
*widget
,
981 GdkEventMotion
*event
,
985 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
987 if (motion_state
!= MOTION_REPOSITION
)
991 delta
= event
->x_root
- drag_start_x
;
993 delta
= event
->y_root
- drag_start_y
;
995 new = slide_from_value
- delta
;
996 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
998 gtk_adjustment_set_value(panel
->adj
, new);
1003 static gint
icon_motion_event(GtkWidget
*widget
,
1004 GdkEventMotion
*event
,
1007 Panel
*panel
= icon
->panel
;
1009 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1013 if (motion_state
== MOTION_READY_FOR_DND
)
1015 if (dnd_motion_moved(event
))
1016 start_drag(icon
, event
);
1019 else if (motion_state
!= MOTION_REPOSITION
)
1022 list
= gtk_container_children(GTK_CONTAINER(panel
->before
));
1023 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1024 list
= g_list_concat(list
,
1025 gtk_container_children(GTK_CONTAINER(panel
->after
)));
1026 me
= g_list_find(list
, widget
);
1028 g_return_val_if_fail(me
!= NULL
, TRUE
);
1030 val
= horz
? event
->x_root
: event
->y_root
;
1038 prev
= GTK_WIDGET(me
->prev
->data
);
1042 gdk_window_get_deskrelative_origin(prev
->window
, &x
, &y
);
1044 if (val
<= (horz
? x
: y
))
1048 if (dir
== 0 && me
->next
)
1054 next
= GTK_WIDGET(me
->next
->data
);
1058 gdk_window_get_deskrelative_origin(next
->window
, &x
, &y
);
1060 gdk_window_get_size(next
->window
, &w
, &h
);
1065 if (val
>= (horz
? x
: y
))
1067 if (next
== panel
->gap
)
1075 reposition_icon(icon
, g_list_index(list
, widget
) + dir
);
1080 /* Move icon to this index in the complete widget list.
1081 * 0 makes the icon the left-most icon. The gap in the middle has
1082 * an index number, which allows you to specify that the icon should
1083 * go on the left or right side.
1085 static void reposition_icon(Icon
*icon
, int index
)
1087 Panel
*panel
= icon
->panel
;
1088 GtkWidget
*widget
= icon
->widget
;
1092 list
= gtk_container_children(GTK_CONTAINER(panel
->before
));
1093 before_len
= g_list_length(list
);
1095 if (index
<= before_len
)
1097 /* Want to move icon to the 'before' list. Is it there
1101 if (!g_list_find(list
, widget
))
1104 gtk_grab_remove(widget
);
1105 gtk_widget_reparent(widget
, panel
->before
);
1106 dnd_motion_grab_pointer();
1107 gtk_grab_add(widget
);
1110 gtk_box_reorder_child(GTK_BOX(panel
->before
), widget
, index
);
1114 /* Else, we need it in the 'after' list. */
1116 index
-= before_len
+ 1;
1120 list
= gtk_container_children(GTK_CONTAINER(panel
->after
));
1122 if (!g_list_find(list
, widget
))
1124 /* Not already there, reparent */
1125 gtk_grab_remove(widget
);
1126 gtk_widget_reparent(widget
, panel
->after
);
1127 dnd_motion_grab_pointer();
1128 gtk_grab_add(widget
);
1131 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, index
);
1139 static void start_drag(Icon
*icon
, GdkEventMotion
*event
)
1141 GtkWidget
*widget
= icon
->widget
;
1143 if (!icon
->selected
)
1145 if (event
->state
& GDK_BUTTON1_MASK
)
1147 /* Select just this one */
1148 icon_select_only(icon
);
1149 tmp_icon_selected
= TRUE
;
1152 icon_set_selected(icon
, TRUE
);
1155 g_return_if_fail(icon_selection
!= NULL
);
1157 if (icon_selection
->next
== NULL
)
1158 drag_one_item(widget
, event
, icon
->path
, &icon
->item
);
1163 uri_list
= create_uri_list(icon_selection
);
1164 drag_selection(widget
, event
, uri_list
);
1169 /* Return a text/uri-list of all the icons in the list */
1170 static guchar
*create_uri_list(GList
*list
)
1176 tmp
= g_string_new(NULL
);
1177 leader
= g_strdup_printf("file://%s", our_host_name_for_dnd());
1179 for (; list
; list
= list
->next
)
1181 Icon
*icon
= (Icon
*) list
->data
;
1183 g_string_append(tmp
, leader
);
1184 g_string_append(tmp
, icon
->path
);
1185 g_string_append(tmp
, "\r\n");
1190 g_string_free(tmp
, FALSE
);
1195 static void applet_died(GtkWidget
*socket
)
1197 if (!GTK_OBJECT_DESTROYED(socket
))
1198 gtk_widget_destroy(socket
);
1200 gtk_widget_unref(socket
);
1203 static void restart_applet(GtkWidget
*button
, Icon
*icon
)
1205 gtk_widget_destroy(button
);
1209 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1212 gboolean lost_widget
;
1214 lost_widget
= GTK_OBJECT_DESTROYED(widget
);
1215 gtk_widget_unref(widget
);
1218 return; /* We're removing the icon... */
1220 icon
= gtk_object_get_data(GTK_OBJECT(widget
), "icon");
1221 icon
->socket
= gtk_button_new_with_label(_("Restart\nApplet"));
1223 gtk_signal_connect(GTK_OBJECT(icon
->socket
), "button_release_event",
1224 GTK_SIGNAL_FUNC(icon_button_release
), icon
);
1225 gtk_signal_connect(GTK_OBJECT(icon
->socket
), "button_press_event",
1226 GTK_SIGNAL_FUNC(icon_button_press
), icon
);
1228 gtk_container_add(GTK_CONTAINER(icon
->widget
), icon
->socket
);
1229 gtk_container_set_border_width(GTK_CONTAINER(icon
->socket
), 4);
1230 gtk_misc_set_padding(GTK_MISC(GTK_BIN(icon
->socket
)->child
), 4, 4);
1231 gtk_widget_show(icon
->socket
);
1233 gtk_signal_connect(GTK_OBJECT(icon
->socket
), "clicked",
1234 GTK_SIGNAL_FUNC(restart_applet
), icon
);
1237 /* Try to run this applet. Fills in icon->socket on success. */
1238 static void run_applet(Icon
*icon
)
1243 argv
[0] = make_path(icon
->path
, "AppletRun")->str
;
1245 if (access(argv
[0], X_OK
) != 0)
1248 icon
->socket
= gtk_socket_new();
1249 gtk_container_add(GTK_CONTAINER(icon
->widget
), icon
->socket
);
1250 gtk_widget_show_all(icon
->socket
);
1251 gtk_widget_realize(icon
->socket
);
1253 gtk_widget_ref(icon
->widget
);
1254 gtk_object_set_data(GTK_OBJECT(icon
->widget
), "icon", icon
);
1255 gtk_signal_connect(GTK_OBJECT(icon
->socket
), "destroy",
1256 GTK_SIGNAL_FUNC(socket_destroyed
), icon
->widget
);
1258 argv
[1] = g_strdup_printf("%ld",
1259 GDK_WINDOW_XWINDOW(icon
->socket
->window
));
1263 gtk_widget_ref(icon
->socket
);
1264 on_child_death(pid
, (CallbackFn
) applet_died
, icon
->socket
);
1269 /* When one of the panel icons resizes it will cause it's container box
1270 * to resize. This will cause the packing box inside the viewport to resize -
1271 * we get here right after that.
1273 static void box_resized(GtkWidget
*box
, GtkAllocation
*alloc
, Panel
*panel
)
1275 reposition_panel(panel
, FALSE
);
1278 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
1280 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1282 if (req
->width
< screen_width
)
1283 req
->width
= screen_width
;
1287 int h
= screen_height
;
1289 if (current_panel
[PANEL_TOP
])
1290 h
-= current_panel
[PANEL_TOP
]->height
;
1292 if (current_panel
[PANEL_BOTTOM
])
1293 h
-= current_panel
[PANEL_BOTTOM
]->height
;
1295 if (req
->height
< h
)
1300 /* The style setting has been changed -- update all panels */
1301 static void panel_set_style(guchar
*new)
1303 int os
= panel_style
;
1305 panel_style
= option_get_int("panel_style");
1307 if (os
!= panel_style
)
1313 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1315 Panel
*panel
= current_panel
[i
];
1320 gtk_widget_queue_resize(panel
->window
);