4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, 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 */
43 #include "gui_support.h"
54 Panel
*current_panel
[PANEL_NUMBER_OF_SIDES
];
56 /* NULL => Not loading a panel */
57 static Panel
*loading_panel
= NULL
;
59 /* Static prototypes */
60 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
);
61 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
);
62 static char *pan_from_file(guchar
*line
);
63 static gint
icon_button_release(GtkWidget
*widget
,
64 GdkEventButton
*event
,
66 static gint
icon_button_press(GtkWidget
*widget
,
67 GdkEventButton
*event
,
69 static void reposition_panel(GtkWidget
*window
,
70 GtkAllocation
*alloc
, Panel
*panel
);
71 static gint
expose_icon(GtkWidget
*widget
,
72 GdkEventExpose
*event
,
74 static gint
draw_icon(GtkWidget
*widget
,
75 GdkRectangle
*badarea
,
77 static gint
panel_button_release(GtkWidget
*widget
,
78 GdkEventButton
*event
,
80 static gint
panel_button_press(GtkWidget
*widget
,
81 GdkEventButton
*event
,
83 static void panel_post_resize(GtkWidget
*box
,
84 GtkRequisition
*req
, Panel
*panel
);
85 static void drag_set_panel_dest(Icon
*icon
);
86 static void add_uri_list(GtkWidget
*widget
,
87 GdkDragContext
*context
,
90 GtkSelectionData
*selection_data
,
94 static void panel_add_item(Panel
*panel
,
98 static gboolean
drag_motion(GtkWidget
*widget
,
99 GdkDragContext
*context
,
104 static void drag_leave(GtkWidget
*widget
,
105 GdkDragContext
*context
,
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
);
130 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
);
133 static GtkWidget
*dnd_highlight
= NULL
; /* (stops flickering) */
135 /* When sliding the panel, records where the panel was before */
136 static gint slide_from_value
= 0;
139 #define SHOW_APPS_SMALL 1
141 static int panel_style
= SHOW_APPS_SMALL
;
143 static int closing_panel
= 0; /* Don't panel_save; destroying! */
145 /****************************************************************
146 * EXTERNAL INTERFACE *
147 ****************************************************************/
149 void panel_init(void)
151 option_add_int("panel_style", panel_style
, panel_set_style
);
154 /* 'name' may be NULL or "" to remove the panel */
155 Panel
*panel_new(guchar
*name
, PanelSide side
)
159 GtkWidget
*vp
, *box
, *frame
;
161 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, NULL
);
162 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
164 if (name
&& *name
== '\0')
167 if (current_panel
[side
])
172 gtk_widget_destroy(current_panel
[side
]->window
);
178 if (name
== NULL
|| *name
== '\0')
181 panel
= g_new(Panel
, 1);
182 panel
->name
= g_strdup(name
);
184 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
185 gtk_window_set_policy(GTK_WINDOW(panel
->window
), FALSE
, FALSE
, TRUE
);
186 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
187 gtk_widget_set_events(panel
->window
,
188 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
189 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
190 GDK_BUTTON2_MOTION_MASK
);
192 gtk_signal_connect(GTK_OBJECT(panel
->window
), "delete-event",
193 GTK_SIGNAL_FUNC(panel_delete
), panel
);
194 gtk_signal_connect(GTK_OBJECT(panel
->window
), "destroy",
195 GTK_SIGNAL_FUNC(panel_destroyed
), panel
);
196 gtk_signal_connect(GTK_OBJECT(panel
->window
), "button_press_event",
197 GTK_SIGNAL_FUNC(panel_button_press
), panel
);
198 gtk_signal_connect(GTK_OBJECT(panel
->window
), "button_release_event",
199 GTK_SIGNAL_FUNC(panel_button_release
), panel
);
200 gtk_signal_connect(GTK_OBJECT(panel
->window
), "motion-notify-event",
201 GTK_SIGNAL_FUNC(panel_motion_event
), panel
);
203 if (strchr(name
, '/'))
204 load_path
= g_strdup(name
);
209 leaf
= g_strconcat("pan_", name
, NULL
);
210 load_path
= choices_find_path_load(leaf
, PROJECT
);
214 vp
= gtk_viewport_new(NULL
, NULL
);
215 gtk_container_set_resize_mode(GTK_CONTAINER(vp
), GTK_RESIZE_PARENT
);
216 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_OUT
);
217 gtk_container_add(GTK_CONTAINER(panel
->window
), vp
);
219 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
221 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
222 box
= gtk_hbox_new(FALSE
, 0);
223 panel
->before
= gtk_hbox_new(FALSE
, 0);
224 panel
->after
= gtk_hbox_new(FALSE
, 0);
228 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
229 box
= gtk_vbox_new(FALSE
, 0);
230 panel
->before
= gtk_vbox_new(FALSE
, 0);
231 panel
->after
= gtk_vbox_new(FALSE
, 0);
234 gtk_container_add(GTK_CONTAINER(vp
), box
);
235 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
236 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
238 frame
= make_insert_frame(panel
);
239 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
241 /* This is used so that we can find the middle easily! */
242 panel
->gap
= gtk_event_box_new();
243 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
245 frame
= make_insert_frame(panel
);
246 gtk_object_set_data(GTK_OBJECT(frame
), "after", "yes");
247 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
249 gtk_widget_realize(panel
->window
);
250 make_panel_window(panel
->window
);
252 gtk_widget_show_all(vp
);
254 loading_panel
= panel
;
255 if (load_path
&& access(load_path
, F_OK
) == 0)
258 doc
= xmlParseFile(load_path
);
261 panel_load_from_xml(panel
, doc
);
266 parse_file(load_path
, pan_from_file
);
267 delayed_error(_("Your old panel file has been "
268 "converted to the new XML format."));
274 /* Don't scare users with an empty panel... */
277 panel_add_item(panel
, "~", "Home", FALSE
);
279 apps
= pathdup(make_path(app_dir
, "..")->str
);
282 panel_add_item(panel
, apps
, "Apps", FALSE
);
286 loading_panel
= NULL
;
289 current_panel
[side
] = panel
;
291 gtk_widget_queue_resize(box
);
292 gtk_signal_connect_after(GTK_OBJECT(panel
->window
), "size-request",
293 GTK_SIGNAL_FUNC(panel_post_resize
), (GtkObject
*) panel
);
294 gtk_signal_connect_after(GTK_OBJECT(panel
->window
), "size-allocate",
295 GTK_SIGNAL_FUNC(reposition_panel
), (GtkObject
*) panel
);
298 gtk_widget_show(panel
->window
);
303 gboolean
panel_want_show_text(Icon
*icon
)
305 if (panel_style
== SHOW_BOTH
)
307 if (panel_style
== SHOW_ICON
)
310 if (icon
->item
->flags
& ITEM_FLAG_APPDIR
)
316 void panel_icon_renamed(Icon
*icon
)
318 GtkLabel
*label
= GTK_LABEL(icon
->label
);
320 gtk_label_set_text(label
, icon
->item
->leafname
);
324 /****************************************************************
325 * INTERNAL FUNCTIONS *
326 ****************************************************************/
328 /* User has tried to close the panel via the window manager - confirm */
329 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
331 return get_choice(_("Close panel?"),
332 _("You have tried to close a panel via the window "
333 "manager - I usually find that this is accidental... "
335 2, _("Cancel"), _("Remove")) != 1;
338 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
340 if (current_panel
[panel
->side
] == panel
)
341 current_panel
[panel
->side
] = NULL
;
343 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
345 if (current_panel
[PANEL_RIGHT
])
346 gtk_widget_queue_resize(
347 current_panel
[PANEL_RIGHT
]->window
);
348 if (current_panel
[PANEL_LEFT
])
349 gtk_widget_queue_resize(
350 current_panel
[PANEL_LEFT
]->window
);
356 if (--number_of_windows
< 1)
360 static void panel_load_side(Panel
*panel
, xmlNodePtr side
, gboolean after
)
365 for (node
= side
->xmlChildrenNode
; node
; node
= node
->next
)
367 if (node
->type
!= XML_ELEMENT_NODE
)
369 if (strcmp(node
->name
, "icon") != 0)
372 label
= xmlGetProp(node
, "label");
374 label
= g_strdup("<missing label>");
375 path
= xmlNodeGetContent(node
);
377 path
= g_strdup("<missing path>");
380 panel_add_item(panel
, path
, label
, after
);
383 gchar
*loc_path
, *loc_label
;
385 loc_path
= from_utf8(path
);
386 loc_label
= from_utf8(leaf
);
387 panel_add_item(panel
, loc_path
, loc_label
, after
);
398 /* Create one panel icon for each icon in the doc */
399 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
)
403 root
= xmlDocGetRootElement(doc
);
404 panel_load_side(panel
, get_subnode(root
, NULL
, "start"), FALSE
);
405 panel_load_side(panel
, get_subnode(root
, NULL
, "end"), TRUE
);
408 /* Called for each line in the config file while loading a new panel */
409 static char *pan_from_file(guchar
*line
)
413 g_return_val_if_fail(line
!= NULL
, NULL
);
414 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
419 sep
= strpbrk(line
, "<>");
421 return _("Missing < or > in panel config file");
424 leaf
= g_strndup(line
, sep
- line
);
428 panel_add_item(loading_panel
, sep
+ 1, leaf
, sep
[0] == '>');
435 /* Add an icon with this path to the panel. If after is TRUE then the
436 * icon is added to the right/bottom end of the panel.
438 * If name is NULL a suitable name is taken from path.
440 * name and path are in UTF-8 for Gtk+-2.0 only.
442 static void panel_add_item(Panel
*panel
,
450 widget
= gtk_event_box_new();
451 gtk_widget_set_events(widget
,
452 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
453 GDK_BUTTON3_MOTION_MASK
|
454 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
455 GDK_BUTTON_RELEASE_MASK
);
457 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
458 widget
, FALSE
, TRUE
, 4);
460 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
462 gtk_widget_realize(widget
);
464 icon
= g_new(Icon
, 1);
466 icon
->src_path
= g_strdup(path
);
467 icon
->path
= icon_convert_path(path
);
474 gtk_object_set_data(GTK_OBJECT(widget
), "icon", icon
);
476 icon_hash_path(icon
);
478 icon
->widget
= widget
;
479 gtk_widget_set_name(icon
->widget
, "panel-icon");
480 icon
->selected
= FALSE
;
483 icon
->item
= diritem_new(name
);
488 slash
= strrchr(icon
->path
, '/');
489 icon
->item
= diritem_new(slash
&& slash
[1] ? slash
+ 1
492 diritem_restat(icon
->path
, icon
->item
);
494 gtk_signal_connect_object(GTK_OBJECT(widget
), "destroy",
495 GTK_SIGNAL_FUNC(icon_destroyed
), (gpointer
) icon
);
497 if (icon
->item
->base_type
== TYPE_DIRECTORY
)
500 gtk_signal_connect(GTK_OBJECT(widget
), "button_release_event",
501 GTK_SIGNAL_FUNC(icon_button_release
), icon
);
502 gtk_signal_connect(GTK_OBJECT(widget
), "button_press_event",
503 GTK_SIGNAL_FUNC(icon_button_press
), icon
);
504 gtk_signal_connect(GTK_OBJECT(icon
->widget
), "motion-notify-event",
505 GTK_SIGNAL_FUNC(icon_motion_event
), icon
);
509 gtk_signal_connect_after(GTK_OBJECT(widget
),
510 "enter-notify-event",
511 GTK_SIGNAL_FUNC(enter_icon
), icon
);
513 gtk_signal_connect_after(GTK_OBJECT(widget
), "draw",
514 GTK_SIGNAL_FUNC(draw_icon
), icon
);
516 gtk_signal_connect_after(GTK_OBJECT(widget
), "expose_event",
517 GTK_SIGNAL_FUNC(expose_icon
), icon
);
518 gtk_signal_connect(GTK_OBJECT(widget
), "drag_data_get",
519 GTK_SIGNAL_FUNC(drag_data_get
), NULL
);
521 gtk_signal_connect(GTK_OBJECT(widget
), "size_request",
522 GTK_SIGNAL_FUNC(size_request
), icon
);
524 drag_set_panel_dest(icon
);
526 icon
->label
= gtk_label_new(icon
->item
->leafname
);
527 gtk_container_add(GTK_CONTAINER(icon
->widget
), icon
->label
);
528 gtk_misc_set_alignment(GTK_MISC(icon
->label
), 0.5, 1);
529 gtk_misc_set_padding(GTK_MISC(icon
->label
), 1, 2);
536 gtk_widget_show(widget
);
539 /* Called when Gtk+ wants to know how much space an icon needs.
540 * 'req' is already big enough for the label, if shown.
542 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, Icon
*icon
)
544 int im_width
, im_height
;
546 im_width
= icon
->item
->image
->width
;
547 im_height
= MIN(icon
->item
->image
->height
, ICON_HEIGHT
);
549 req
->height
+= im_height
;
550 req
->width
= MAX(req
->width
, im_width
);
553 static gint
expose_icon(GtkWidget
*widget
,
554 GdkEventExpose
*event
,
557 return draw_icon(widget
, &event
->area
, icon
);
560 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, Icon
*icon
)
565 gdk_window_get_size(widget
->window
, &width
, &height
);
569 area
.height
= icon
->item
->image
->height
;
571 if (panel_want_show_text(icon
))
573 int text_height
= icon
->label
->requisition
.height
;
575 area
.y
= height
- text_height
- area
.height
;
577 draw_large_icon(widget
, &area
, icon
->item
,
578 icon
->item
->image
, icon
->selected
);
582 area
.y
= (height
- area
.height
) >> 1;
583 draw_large_icon(widget
, &area
, icon
->item
,
584 icon
->item
->image
, icon
->selected
);
590 /* icon may be NULL if the event is on the background */
591 static void perform_action(Panel
*panel
, Icon
*icon
, GdkEventButton
*event
)
595 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
597 if (icon
&& icon
->socket
)
598 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
605 wink_widget(icon
->widget
);
606 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, FALSE
);
610 wink_widget(icon
->widget
);
611 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, TRUE
);
615 icon_show_menu(event
, icon
, panel
);
618 dnd_motion_start(MOTION_REPOSITION
);
620 case ACT_PRIME_AND_SELECT
:
622 icon_select_only(icon
);
623 dnd_motion_start(MOTION_READY_FOR_DND
);
625 case ACT_PRIME_AND_TOGGLE
:
626 icon_set_selected(icon
, !icon
->selected
);
627 dnd_motion_start(MOTION_READY_FOR_DND
);
629 case ACT_PRIME_FOR_DND
:
630 dnd_motion_start(MOTION_READY_FOR_DND
);
632 case ACT_TOGGLE_SELECTED
:
633 icon_set_selected(icon
, !icon
->selected
);
635 case ACT_SELECT_EXCL
:
636 icon_set_selected(icon
, TRUE
);
638 case ACT_SLIDE_CLEAR_PANEL
:
639 icon_select_only(NULL
);
641 case ACT_SLIDE_PANEL
:
642 dnd_motion_grab_pointer();
643 slide_from_value
= panel
->adj
->value
;
644 dnd_motion_start(MOTION_REPOSITION
);
648 case ACT_CLEAR_SELECTION
:
649 icon_select_only(NULL
);
652 g_warning("Unsupported action : %d\n", action
);
657 static gint
panel_button_release(GtkWidget
*widget
,
658 GdkEventButton
*event
,
661 if (dnd_motion_release(event
))
664 perform_action(panel
, NULL
, event
);
669 static gint
panel_button_press(GtkWidget
*widget
,
670 GdkEventButton
*event
,
673 if (dnd_motion_press(panel
->window
, event
))
674 perform_action(panel
, NULL
, event
);
679 static gint
icon_button_release(GtkWidget
*widget
,
680 GdkEventButton
*event
,
683 if (icon
->socket
&& event
->button
== 1)
684 return FALSE
; /* Restart button */
686 if (dnd_motion_release(event
))
689 perform_action(icon
->panel
, icon
, event
);
694 static gint
icon_button_press(GtkWidget
*widget
,
695 GdkEventButton
*event
,
698 if (icon
->socket
&& event
->button
== 1)
699 return FALSE
; /* Restart button */
701 if (dnd_motion_press(widget
, event
))
702 perform_action(icon
->panel
, icon
, event
);
707 static void reposition_panel(GtkWidget
*window
,
708 GtkAllocation
*alloc
, Panel
*panel
)
711 PanelSide side
= panel
->side
;
713 if (side
== PANEL_LEFT
|| side
== PANEL_RIGHT
)
715 if (side
== PANEL_RIGHT
)
716 x
= screen_width
- alloc
->width
;
718 if (current_panel
[PANEL_TOP
])
720 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
721 y
+= win
->allocation
.height
;
725 if (side
== PANEL_BOTTOM
)
726 y
= screen_height
- alloc
->height
;
728 gtk_widget_set_uposition(panel
->window
, x
, y
);
729 gdk_window_move(panel
->window
->window
, x
, y
);
731 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
733 if (current_panel
[PANEL_RIGHT
])
734 gtk_widget_queue_resize(
735 current_panel
[PANEL_RIGHT
]->window
);
736 if (current_panel
[PANEL_LEFT
])
737 gtk_widget_queue_resize(
738 current_panel
[PANEL_LEFT
]->window
);
742 /* Same as drag_set_dest(), but for panel icons */
743 static void drag_set_panel_dest(Icon
*icon
)
745 GtkObject
*obj
= GTK_OBJECT(icon
->widget
);
747 make_drop_target(icon
->widget
, 0);
749 gtk_signal_connect(obj
, "drag_motion",
750 GTK_SIGNAL_FUNC(drag_motion
), icon
);
751 gtk_signal_connect(obj
, "drag_leave",
752 GTK_SIGNAL_FUNC(drag_leave
), icon
);
753 gtk_signal_connect(obj
, "drag_end",
754 GTK_SIGNAL_FUNC(drag_end
), icon
);
757 static gboolean
drag_motion(GtkWidget
*widget
,
758 GdkDragContext
*context
,
764 GdkDragAction action
= context
->suggested_action
;
766 DirItem
*item
= icon
->item
;
769 goto out
; /* Can't drag a selection to itself */
771 type
= dnd_motion_item(context
, &item
);
776 /* We actually must pretend to accept the drop, even if the
777 * directory isn't writeable, so that the spring-opening
781 /* Don't allow drops to non-writeable directories */
782 if (option_get_int("dnd_spring_open") == FALSE
&&
783 type
== drop_dest_dir
&&
784 access(icon
->path
, W_OK
) != 0)
789 g_dataset_set_data(context
, "drop_dest_type", type
);
792 gdk_drag_status(context
, action
, time
);
793 g_dataset_set_data_full(context
, "drop_dest_path",
794 g_strdup(icon
->path
), g_free
);
795 if (type
== drop_dest_dir
)
796 dnd_spring_load(context
, NULL
);
798 if (dnd_highlight
&& dnd_highlight
!= icon
->widget
)
800 gtk_drag_unhighlight(dnd_highlight
);
801 dnd_highlight
= NULL
;
804 if (dnd_highlight
== NULL
)
806 gtk_drag_highlight(icon
->widget
);
807 dnd_highlight
= icon
->widget
;
815 static void add_uri_list(GtkWidget
*widget
,
816 GdkDragContext
*context
,
819 GtkSelectionData
*selection_data
,
824 gboolean after
= FALSE
;
827 if (!selection_data
->data
)
830 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
832 if (gtk_object_get_data(GTK_OBJECT(widget
), "after"))
835 uris
= uri_list_to_glist(selection_data
->data
);
837 for (next
= uris
; next
; next
= next
->next
)
841 path
= get_local_path((guchar
*) next
->data
);
844 panel_add_item(panel
, path
, NULL
, after
);
850 static void drag_end(GtkWidget
*widget
,
851 GdkDragContext
*context
,
854 if (tmp_icon_selected
)
856 icon_select_only(NULL
);
857 tmp_icon_selected
= FALSE
;
861 static void drag_leave(GtkWidget
*widget
,
862 GdkDragContext
*context
,
866 if (dnd_highlight
&& dnd_highlight
== widget
)
868 gtk_drag_unhighlight(dnd_highlight
);
869 dnd_highlight
= NULL
;
875 /* Create XML icon nodes for these widgets.
876 * Always frees the widgets list.
878 static void make_widgets(xmlNodePtr side
, GList
*widgets
)
882 for (next
= widgets
; next
; next
= next
->next
)
887 icon
= gtk_object_get_data(GTK_OBJECT(next
->data
), "icon");
891 g_warning("Can't find Icon from widget\n");
896 tree
= xmlNewTextChild(side
, NULL
, "icon", icon
->src_path
);
900 u8
= to_utf8(icon
->src_path
);
901 tree
= xmlNewTextChild(side
, NULL
, "icon", u8
);
909 u8
= to_utf8(icon
->item
->leafname
);
910 xmlSetProp(tree
, "label", u8
);
914 xmlSetProp(tree
, "label", icon
->item
->leafname
);
919 g_list_free(widgets
);
922 void panel_save(Panel
*panel
)
927 guchar
*save_new
= NULL
;
929 g_return_if_fail(panel
!= NULL
);
931 if (strchr(panel
->name
, '/'))
932 save
= g_strdup(panel
->name
);
937 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
938 save
= choices_find_path_save(leaf
, PROJECT
, TRUE
);
945 doc
= xmlNewDoc("1.0");
946 xmlDocSetRootElement(doc
, xmlNewDocNode(doc
, NULL
, "pinboard", NULL
));
948 root
= xmlDocGetRootElement(doc
);
949 make_widgets(xmlNewChild(root
, NULL
, "start", NULL
),
950 gtk_container_children(GTK_CONTAINER(panel
->before
)));
952 make_widgets(xmlNewChild(root
, NULL
, "end", NULL
),
953 g_list_reverse(gtk_container_children(
954 GTK_CONTAINER(panel
->after
))));
956 save_new
= g_strconcat(save
, ".new", NULL
);
957 if (save_xml_file(doc
, save_new
) || rename(save_new
, save
))
958 delayed_error(_("Error saving panel %s: %s"),
959 save
, g_strerror(errno
));
967 /* Create a frame widget which can be used to add icons to the panel */
968 static GtkWidget
*make_insert_frame(Panel
*panel
)
971 GtkTargetEntry target_table
[] = {
972 {"text/uri-list", 0, TARGET_URI_LIST
},
975 frame
= gtk_frame_new(NULL
);
976 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
977 gtk_widget_set_usize(frame
, 16, 16);
979 gtk_signal_connect(GTK_OBJECT(frame
), "drag-data-received",
980 GTK_SIGNAL_FUNC(add_uri_list
), panel
);
981 gtk_drag_dest_set(frame
,
982 GTK_DEST_DEFAULT_ALL
,
984 sizeof(target_table
) / sizeof(*target_table
),
990 static gboolean
enter_icon(GtkWidget
*widget
,
991 GdkEventCrossing
*event
,
994 icon_may_update(icon
);
999 static gint
panel_motion_event(GtkWidget
*widget
,
1000 GdkEventMotion
*event
,
1004 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1006 if (motion_state
!= MOTION_REPOSITION
)
1010 delta
= event
->x_root
- drag_start_x
;
1012 delta
= event
->y_root
- drag_start_y
;
1014 new = slide_from_value
- delta
;
1015 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
1017 gtk_adjustment_set_value(panel
->adj
, new);
1022 static gint
icon_motion_event(GtkWidget
*widget
,
1023 GdkEventMotion
*event
,
1026 Panel
*panel
= icon
->panel
;
1028 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1032 if (motion_state
== MOTION_READY_FOR_DND
)
1034 if (dnd_motion_moved(event
))
1035 start_drag(icon
, event
);
1038 else if (motion_state
!= MOTION_REPOSITION
)
1041 list
= gtk_container_children(GTK_CONTAINER(panel
->before
));
1042 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1043 list
= g_list_concat(list
,
1044 gtk_container_children(GTK_CONTAINER(panel
->after
)));
1045 me
= g_list_find(list
, widget
);
1047 g_return_val_if_fail(me
!= NULL
, TRUE
);
1049 val
= horz
? event
->x_root
: event
->y_root
;
1057 prev
= GTK_WIDGET(me
->prev
->data
);
1061 gdk_window_get_deskrelative_origin(prev
->window
, &x
, &y
);
1063 if (val
<= (horz
? x
: y
))
1067 if (dir
== 0 && me
->next
)
1073 next
= GTK_WIDGET(me
->next
->data
);
1077 gdk_window_get_deskrelative_origin(next
->window
, &x
, &y
);
1079 gdk_window_get_size(next
->window
, &w
, &h
);
1084 if (val
>= (horz
? x
: y
))
1086 if (next
== panel
->gap
)
1094 reposition_icon(icon
, g_list_index(list
, widget
) + dir
);
1099 /* Move icon to this index in the complete widget list.
1100 * 0 makes the icon the left-most icon. The gap in the middle has
1101 * an index number, which allows you to specify that the icon should
1102 * go on the left or right side.
1104 static void reposition_icon(Icon
*icon
, int index
)
1106 Panel
*panel
= icon
->panel
;
1107 GtkWidget
*widget
= icon
->widget
;
1111 list
= gtk_container_children(GTK_CONTAINER(panel
->before
));
1112 before_len
= g_list_length(list
);
1114 if (index
<= before_len
)
1116 /* Want to move icon to the 'before' list. Is it there
1120 if (!g_list_find(list
, widget
))
1123 gtk_grab_remove(widget
);
1124 gtk_widget_reparent(widget
, panel
->before
);
1125 dnd_motion_grab_pointer();
1126 gtk_grab_add(widget
);
1129 gtk_box_reorder_child(GTK_BOX(panel
->before
), widget
, index
);
1133 /* Else, we need it in the 'after' list. */
1135 index
-= before_len
+ 1;
1139 list
= gtk_container_children(GTK_CONTAINER(panel
->after
));
1141 if (!g_list_find(list
, widget
))
1143 /* Not already there, reparent */
1144 gtk_grab_remove(widget
);
1145 gtk_widget_reparent(widget
, panel
->after
);
1146 dnd_motion_grab_pointer();
1147 gtk_grab_add(widget
);
1150 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, index
);
1158 static void start_drag(Icon
*icon
, GdkEventMotion
*event
)
1160 GtkWidget
*widget
= icon
->widget
;
1162 if (!icon
->selected
)
1164 if (event
->state
& GDK_BUTTON1_MASK
)
1166 /* Select just this one */
1167 icon_select_only(icon
);
1168 tmp_icon_selected
= TRUE
;
1171 icon_set_selected(icon
, TRUE
);
1174 g_return_if_fail(icon_selection
!= NULL
);
1176 if (icon_selection
->next
== NULL
)
1177 drag_one_item(widget
, event
, icon
->path
, icon
->item
, NULL
);
1182 uri_list
= create_uri_list(icon_selection
);
1183 drag_selection(widget
, event
, uri_list
);
1188 /* Return a text/uri-list of all the icons in the list */
1189 static guchar
*create_uri_list(GList
*list
)
1195 tmp
= g_string_new(NULL
);
1196 leader
= g_strdup_printf("file://%s", our_host_name_for_dnd());
1198 for (; list
; list
= list
->next
)
1200 Icon
*icon
= (Icon
*) list
->data
;
1202 g_string_append(tmp
, leader
);
1203 g_string_append(tmp
, icon
->path
);
1204 g_string_append(tmp
, "\r\n");
1209 g_string_free(tmp
, FALSE
);
1214 static void applet_died(GtkWidget
*socket
)
1216 gboolean never_plugged
;
1218 never_plugged
= (!gtk_object_get_data(GTK_OBJECT(socket
), "lost_plug"))
1219 && !GTK_SOCKET(socket
)->plug_window
;
1224 _("Applet quit without ever creating a widget!"));
1225 gtk_widget_destroy(socket
);
1228 gtk_widget_unref(socket
);
1231 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1233 gtk_object_set_data(GTK_OBJECT(socket
), "lost_plug", "yes");
1235 gtk_widget_unref(socket
);
1237 gtk_widget_destroy(widget
); /* Remove from panel */
1240 panel_save(gtk_object_get_data(GTK_OBJECT(socket
), "panel"));
1243 /* Try to run this applet.
1246 * - No executable AppletRun:
1247 * icon->socket == NULL (unchanged) on return.
1249 * Otherwise, create socket (setting icon->socket) and ref it twice.
1251 * - AppletRun quits without connecting a plug:
1252 * On child death lost_plug is unset and socket is empty.
1254 * Report error and destroy widget (to 'socket destroyed').
1256 * - AppletRun quits while plug is in socket:
1257 * Unref socket once. Socket will be destroyed later.
1259 * - Socket is destroyed.
1260 * Set lost_plug = "yes" and remove widget from panel.
1263 static void run_applet(Icon
*icon
)
1268 argv
[0] = make_path(icon
->path
, "AppletRun")->str
;
1270 if (access(argv
[0], X_OK
) != 0)
1273 icon
->socket
= gtk_socket_new();
1274 /* Two refs held: one for child death, one for socket destroyed */
1275 gtk_widget_ref(icon
->socket
);
1276 gtk_widget_ref(icon
->socket
);
1278 gtk_container_add(GTK_CONTAINER(icon
->widget
), icon
->socket
);
1279 gtk_widget_show_all(icon
->socket
);
1280 gtk_widget_realize(icon
->socket
);
1284 PanelSide side
= icon
->panel
->side
;
1286 /* Set a hint to let applets position their menus correctly */
1287 pos
= g_strdup_printf("%s,%d",
1288 side
== PANEL_TOP
? "Top" :
1289 side
== PANEL_BOTTOM
? "Bottom" :
1290 side
== PANEL_LEFT
? "Left" :
1291 "Right", MENU_MARGIN
);
1292 gdk_property_change(icon
->socket
->window
,
1293 gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE
),
1294 gdk_atom_intern("STRING", FALSE
),
1295 8, GDK_PROP_MODE_REPLACE
,
1300 gtk_object_set_data(GTK_OBJECT(icon
->widget
), "icon", icon
);
1301 gtk_object_set_data(GTK_OBJECT(icon
->socket
), "panel", icon
->panel
);
1303 gtk_signal_connect(GTK_OBJECT(icon
->socket
), "destroy",
1304 GTK_SIGNAL_FUNC(socket_destroyed
), icon
->widget
);
1306 argv
[1] = g_strdup_printf("%ld",
1307 GDK_WINDOW_XWINDOW(icon
->socket
->window
));
1310 pid
= spawn_full(argv
, NULL
, NULL
);
1312 on_child_death(pid
, (CallbackFn
) applet_died
, icon
->socket
);
1317 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
1319 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1320 req
->width
= screen_width
;
1323 int h
= screen_height
;
1325 if (current_panel
[PANEL_TOP
])
1327 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1328 h
-= win
->allocation
.height
;
1331 if (current_panel
[PANEL_BOTTOM
])
1333 GtkWidget
*win
= current_panel
[PANEL_BOTTOM
]->window
;
1334 h
-= win
->allocation
.height
;
1341 /* The style setting has been changed -- update all panels */
1342 static void panel_set_style(guchar
*new)
1344 int os
= panel_style
;
1346 panel_style
= option_get_int("panel_style");
1348 if (os
!= panel_style
)
1354 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1356 Panel
*panel
= current_panel
[i
];
1361 gtk_widget_queue_resize(panel
->window
);