4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, 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 */
31 #include <libxml/parser.h>
43 #include "gui_support.h"
55 #include "pinboard.h" /* For pinboard_get_window() */
57 /* The width of the separator at the inner edge of the panel */
60 /* The gap between panel icons */
61 #define PANEL_ICON_SPACING 8
63 static gboolean tmp_icon_selected
= FALSE
; /* When dragging */
65 typedef struct _PanelIconClass PanelIconClass
;
66 typedef struct _PanelIcon PanelIcon
;
68 struct _PanelIconClass
{
76 GtkWidget
*widget
; /* The drawing area for the icon */
78 GtkWidget
*socket
; /* For applets */
81 #define PANEL_ICON(obj) GTK_CHECK_CAST((obj), panel_icon_get_type(), PanelIcon)
82 #define IS_PANEL_ICON(obj) \
83 G_TYPE_CHECK_INSTANCE_TYPE((obj), panel_icon_get_type())
85 Panel
*current_panel
[PANEL_NUMBER_OF_SIDES
];
87 /* NULL => Not loading a panel */
88 static Panel
*loading_panel
= NULL
;
90 /* Static prototypes */
91 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
);
92 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
);
93 static const char *pan_from_file(gchar
*line
);
94 static gint
icon_button_release(GtkWidget
*widget
,
95 GdkEventButton
*event
,
97 static gint
icon_button_press(GtkWidget
*widget
,
98 GdkEventButton
*event
,
100 static void reposition_panel(GtkWidget
*window
,
101 GtkAllocation
*alloc
, Panel
*panel
);
102 static gint
expose_icon(GtkWidget
*widget
,
103 GdkEventExpose
*event
,
105 static gint
draw_icon(GtkWidget
*widget
,
106 GdkRectangle
*badarea
,
108 static gint
panel_button_release(GtkWidget
*widget
,
109 GdkEventButton
*event
,
111 static gint
panel_button_press(GtkWidget
*widget
,
112 GdkEventButton
*event
,
114 static void panel_post_resize(GtkWidget
*box
,
115 GtkRequisition
*req
, Panel
*panel
);
116 static void drag_set_panel_dest(PanelIcon
*pi
);
117 static void add_uri_list(GtkWidget
*widget
,
118 GdkDragContext
*context
,
121 GtkSelectionData
*selection_data
,
125 static void panel_add_item(Panel
*panel
,
129 const gchar
*shortcut
);
130 static gboolean
panel_drag_motion(GtkWidget
*widget
,
131 GdkDragContext
*context
,
136 static gboolean
drag_motion(GtkWidget
*widget
,
137 GdkDragContext
*context
,
142 static void panel_drag_leave(GtkWidget
*widget
,
143 GdkDragContext
*context
,
146 static void drag_leave(GtkWidget
*widget
,
147 GdkDragContext
*context
,
150 static GtkWidget
*make_insert_frame(Panel
*panel
);
151 static gboolean
enter_icon(GtkWidget
*widget
,
152 GdkEventCrossing
*event
,
154 static gint
icon_motion_event(GtkWidget
*widget
,
155 GdkEventMotion
*event
,
157 static gint
panel_leave_event(GtkWidget
*widget
,
158 GdkEventCrossing
*event
,
160 static gint
panel_motion_event(GtkWidget
*widget
,
161 GdkEventMotion
*event
,
163 static void reposition_icon(PanelIcon
*pi
, int index
);
164 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
);
165 static void drag_end(GtkWidget
*widget
,
166 GdkDragContext
*context
,
168 static void perform_action(Panel
*panel
,
170 GdkEventButton
*event
);
171 static void run_applet(PanelIcon
*pi
);
172 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
);
173 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
);
174 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
176 static PanelIcon
*panel_icon_new(Panel
*panel
,
177 const char *pathname
,
179 static GType
panel_icon_get_type(void);
180 static gboolean
panel_want_show_text(PanelIcon
*pi
);
181 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
);
182 static void panel_style_changed(void);
185 static GtkWidget
*dnd_highlight
= NULL
; /* (stops flickering) */
187 /* When sliding the panel, records where the panel was before */
188 static gint slide_from_value
= 0;
191 #define SHOW_APPS_SMALL 1
193 static Option o_panel_style
;
195 static int closing_panel
= 0; /* Don't panel_save; destroying! */
197 /****************************************************************
198 * EXTERNAL INTERFACE *
199 ****************************************************************/
201 void panel_init(void)
203 option_add_int(&o_panel_style
, "panel_style", SHOW_APPS_SMALL
);
205 option_add_notify(panel_style_changed
);
208 /* 'name' may be NULL or "" to remove the panel */
209 Panel
*panel_new(const gchar
*name
, PanelSide side
)
213 GtkWidget
*vp
, *box
, *frame
, *align
;
215 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, NULL
);
216 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
218 if (name
&& *name
== '\0')
221 if (current_panel
[side
])
226 gtk_widget_destroy(current_panel
[side
]->window
);
232 if (name
== NULL
|| *name
== '\0')
235 panel
= g_new(Panel
, 1);
236 panel
->name
= g_strdup(name
);
238 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
239 gtk_window_set_resizable(GTK_WINDOW(panel
->window
), FALSE
);
240 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
241 gtk_widget_set_name(panel
->window
, "rox-panel");
242 gtk_widget_set_events(panel
->window
,
243 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
244 GDK_POINTER_MOTION_MASK
| GDK_LEAVE_NOTIFY_MASK
);
246 /* We make the panel a drop target only so that we can auto-raise! */
247 gtk_drag_dest_set(panel
->window
, 0, NULL
, 0, GDK_ACTION_PRIVATE
);
248 g_signal_connect(panel
->window
, "drag_leave",
249 G_CALLBACK(panel_drag_leave
), panel
);
250 g_signal_connect(panel
->window
, "drag_motion",
251 G_CALLBACK(panel_drag_motion
), panel
);
253 g_signal_connect(panel
->window
, "delete-event",
254 G_CALLBACK(panel_delete
), panel
);
255 g_signal_connect(panel
->window
, "destroy",
256 G_CALLBACK(panel_destroyed
), panel
);
257 g_signal_connect(panel
->window
, "button_press_event",
258 G_CALLBACK(panel_button_press
), panel
);
259 g_signal_connect(panel
->window
, "button_release_event",
260 G_CALLBACK(panel_button_release
), panel
);
261 g_signal_connect(panel
->window
, "motion-notify-event",
262 G_CALLBACK(panel_motion_event
), panel
);
263 g_signal_connect(panel
->window
, "leave-notify-event",
264 G_CALLBACK(panel_leave_event
), panel
);
266 if (strchr(name
, '/'))
267 load_path
= g_strdup(name
);
272 leaf
= g_strconcat("pan_", name
, NULL
);
273 load_path
= choices_find_path_load(leaf
, PROJECT
);
277 if (panel
->side
== PANEL_RIGHT
)
278 align
= gtk_alignment_new(1.0, 0.0, 0.0, 1.0);
279 else if (panel
->side
== PANEL_BOTTOM
)
280 align
= gtk_alignment_new(0.0, 1.0, 1.0, 0.0);
281 else if (panel
->side
== PANEL_TOP
)
282 align
= gtk_alignment_new(0.0, 0.0, 1.0, 0.0);
284 align
= gtk_alignment_new(0.0, 0.0, 0.0, 1.0);
286 gtk_container_add(GTK_CONTAINER(panel
->window
), align
);
288 vp
= gtk_viewport_new(NULL
, NULL
);
289 gtk_container_set_resize_mode(GTK_CONTAINER(vp
), GTK_RESIZE_PARENT
);
290 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_NONE
);
291 gtk_container_add(GTK_CONTAINER(align
), vp
);
293 g_signal_connect(align
, "expose-event",
294 G_CALLBACK(draw_panel_edge
), panel
);
296 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
298 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
299 box
= gtk_hbox_new(FALSE
, 0);
300 panel
->before
= gtk_hbox_new(FALSE
, 0);
301 panel
->after
= gtk_hbox_new(FALSE
, 0);
305 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
306 box
= gtk_vbox_new(FALSE
, 0);
307 panel
->before
= gtk_vbox_new(FALSE
, 0);
308 panel
->after
= gtk_vbox_new(FALSE
, 0);
311 gtk_container_add(GTK_CONTAINER(vp
), box
);
312 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
313 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
315 frame
= make_insert_frame(panel
);
316 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
318 /* This is used so that we can find the middle easily! */
319 panel
->gap
= gtk_event_box_new();
320 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
322 frame
= make_insert_frame(panel
);
323 g_object_set_data(G_OBJECT(frame
), "after", "yes");
324 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
326 gtk_widget_realize(panel
->window
);
327 make_panel_window(panel
->window
);
328 if (!(gtk_major_version
== 2 && gtk_minor_version
== 0))
329 gtk_window_stick(GTK_WINDOW(panel
->window
));
331 gtk_widget_show_all(align
);
333 loading_panel
= panel
;
334 if (load_path
&& access(load_path
, F_OK
) == 0)
337 doc
= xmlParseFile(load_path
);
340 panel_load_from_xml(panel
, doc
);
345 parse_file(load_path
, pan_from_file
);
346 info_message(_("Your old panel file has been "
347 "converted to the new XML format."));
353 /* Don't scare users with an empty panel... */
356 panel_add_item(panel
, "~", "Home", FALSE
, NULL
);
358 apps
= pathdup(make_path(app_dir
, ".."));
361 panel_add_item(panel
, apps
, "Apps", FALSE
, NULL
);
365 loading_panel
= NULL
;
368 current_panel
[side
] = panel
;
370 gtk_widget_queue_resize(box
);
371 g_signal_connect(panel
->window
, "size-request",
372 G_CALLBACK(panel_post_resize
), panel
);
373 g_signal_connect(panel
->window
, "size-allocate",
374 G_CALLBACK(reposition_panel
), panel
);
376 /* Stop windows from maximising over us completely, so that the
377 * auto-raise stuff works...
380 guint32 wm_strut
[] = {0, 0, 0, 0};
382 if (panel
->side
== PANEL_LEFT
)
384 else if (panel
->side
== PANEL_RIGHT
)
386 else if (panel
->side
== PANEL_TOP
)
391 gdk_property_change(panel
->window
->window
,
392 gdk_atom_intern("_NET_WM_STRUT", FALSE
),
393 gdk_atom_intern("CARDINAL", FALSE
),
394 32, GDK_PROP_MODE_REPLACE
,
395 (gchar
*) &wm_strut
, 4);
399 gdk_window_lower(panel
->window
->window
);
400 gtk_widget_show(panel
->window
);
405 pinboard
= pinboard_get_window();
406 /* (if pinboard is NULL, will go right to the back) */
407 window_put_just_above(panel
->window
->window
, pinboard
);
413 /* Externally visible function to add an item to a panel */
414 gboolean
panel_add(PanelSide side
,
415 const gchar
*path
, const gchar
*label
, gboolean after
)
417 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
419 g_return_val_if_fail(current_panel
[side
] != NULL
, FALSE
);
421 panel_add_item(current_panel
[side
], path
, label
, after
, NULL
);
426 /* Add the area covered by the panels to the region */
427 void panel_mark_used(GdkRegion
*used
)
431 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
433 Panel
*panel
= current_panel
[i
];
439 gdk_window_get_root_origin(panel
->window
->window
,
441 rect
.width
= panel
->window
->allocation
.width
;
442 rect
.height
= panel
->window
->allocation
.height
;
444 gdk_region_union_with_rect(used
, &rect
);
448 /****************************************************************
449 * INTERNAL FUNCTIONS *
450 ****************************************************************/
452 /* User has tried to close the panel via the window manager - confirm */
453 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
455 return !confirm(_("You have tried to close a panel via the window "
456 "manager - I usually find that this is accidental... "
458 GTK_STOCK_CLOSE
, NULL
);
461 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
463 if (current_panel
[panel
->side
] == panel
)
464 current_panel
[panel
->side
] = NULL
;
466 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
468 if (current_panel
[PANEL_RIGHT
])
469 gtk_widget_queue_resize(
470 current_panel
[PANEL_RIGHT
]->window
);
471 if (current_panel
[PANEL_LEFT
])
472 gtk_widget_queue_resize(
473 current_panel
[PANEL_LEFT
]->window
);
482 static void panel_load_side(Panel
*panel
, xmlNodePtr side
, gboolean after
)
485 char *label
, *path
, *shortcut
;
487 for (node
= side
->xmlChildrenNode
; node
; node
= node
->next
)
489 if (node
->type
!= XML_ELEMENT_NODE
)
491 if (strcmp(node
->name
, "icon") != 0)
494 label
= xmlGetProp(node
, "label");
496 label
= g_strdup("<missing label>");
497 path
= xmlNodeGetContent(node
);
499 path
= g_strdup("<missing path>");
500 shortcut
= xmlGetProp(node
, "shortcut");
502 panel_add_item(panel
, path
, label
, after
, shortcut
);
510 /* Create one panel icon for each icon in the doc */
511 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
)
515 root
= xmlDocGetRootElement(doc
);
516 panel_load_side(panel
, get_subnode(root
, NULL
, "start"), FALSE
);
517 panel_load_side(panel
, get_subnode(root
, NULL
, "end"), TRUE
);
520 /* Called for each line in the config file while loading a new panel */
521 static const char *pan_from_file(gchar
*line
)
525 g_return_val_if_fail(line
!= NULL
, NULL
);
526 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
531 sep
= strpbrk(line
, "<>");
533 return _("Missing < or > in panel config file");
536 leaf
= g_strndup(line
, sep
- line
);
540 panel_add_item(loading_panel
, sep
+ 1, leaf
, sep
[0] == '>', NULL
);
547 static gboolean
icon_pointer_in(GtkWidget
*widget
,
548 GdkEventCrossing
*event
,
551 gtk_widget_set_state(widget
, GTK_STATE_PRELIGHT
);
556 static gboolean
icon_pointer_out(GtkWidget
*widget
,
557 GdkEventCrossing
*event
,
560 gtk_widget_set_state(widget
, GTK_STATE_NORMAL
);
565 static void panel_icon_destroyed(PanelIcon
*pi
)
567 g_return_if_fail(pi
->widget
!= NULL
);
574 /* Set the tooltip AND hide/show the label */
575 static void panel_icon_set_tip(PanelIcon
*pi
)
579 Icon
*icon
= (Icon
*) pi
;
581 g_return_if_fail(pi
!= NULL
);
585 if (panel_want_show_text(pi
))
586 gtk_widget_show(pi
->label
);
588 gtk_widget_hide(pi
->label
);
594 ai
= appinfo_get(icon
->path
, icon
->item
);
596 if (ai
&& ((node
= xml_get_section(ai
, NULL
, "Summary"))))
599 str
= xmlNodeListGetString(node
->doc
,
600 node
->xmlChildrenNode
, 1);
603 gtk_tooltips_set_tip(tooltips
, pi
->widget
, str
, NULL
);
607 else if ((!panel_want_show_text(pi
)) && !pi
->socket
)
609 gtk_tooltips_set_tip(tooltips
, pi
->widget
,
610 icon
->item
->leafname
, NULL
);
613 gtk_tooltips_set_tip(tooltips
, pi
->widget
, NULL
, NULL
);
619 /* Add an icon with this path to the panel. If after is TRUE then the
620 * icon is added to the right/bottom end of the panel.
622 * If name is NULL a suitable name is taken from path.
624 static void panel_add_item(Panel
*panel
,
628 const gchar
*shortcut
)
634 g_return_if_fail(panel
!= NULL
);
635 g_return_if_fail(path
!= NULL
);
637 widget
= gtk_event_box_new();
638 gtk_widget_set_events(widget
,
639 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
640 GDK_BUTTON3_MOTION_MASK
|
641 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
642 GDK_BUTTON_RELEASE_MASK
);
644 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
645 widget
, FALSE
, TRUE
, 0);
647 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
649 gtk_widget_realize(widget
);
651 pi
= panel_icon_new(panel
, path
, name
);
654 /* Widget takes the initial ref of Icon */
655 g_object_set_data(G_OBJECT(widget
), "icon", pi
);
658 g_object_ref(widget
);
660 gtk_widget_set_name(pi
->widget
, "panel-icon");
662 g_signal_connect_swapped(widget
, "destroy",
663 G_CALLBACK(panel_icon_destroyed
), pi
);
665 if (icon
->item
->base_type
== TYPE_DIRECTORY
)
668 g_signal_connect(widget
, "button_release_event",
669 G_CALLBACK(icon_button_release
), pi
);
670 g_signal_connect(widget
, "button_press_event",
671 G_CALLBACK(icon_button_press
), pi
);
672 g_signal_connect(widget
, "motion-notify-event",
673 G_CALLBACK(icon_motion_event
), pi
);
674 g_signal_connect(widget
, "enter-notify-event",
675 G_CALLBACK(icon_pointer_in
), pi
);
676 g_signal_connect(widget
, "leave-notify-event",
677 G_CALLBACK(icon_pointer_out
), pi
);
681 g_signal_connect(widget
, "enter-notify-event",
682 G_CALLBACK(enter_icon
), pi
);
683 g_signal_connect_after(widget
, "expose_event",
684 G_CALLBACK(expose_icon
), pi
);
685 g_signal_connect(widget
, "drag_data_get",
686 G_CALLBACK(drag_data_get
), NULL
);
688 g_signal_connect(widget
, "size_request",
689 G_CALLBACK(size_request
), pi
);
691 drag_set_panel_dest(pi
);
693 pi
->label
= gtk_label_new(icon
->item
->leafname
);
694 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->label
);
695 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
696 gtk_misc_set_padding(GTK_MISC(pi
->label
), 1, 2);
699 icon_set_shortcut(icon
, shortcut
);
704 panel_icon_set_tip(pi
);
705 gtk_widget_show(widget
);
708 /* Called when Gtk+ wants to know how much space an icon needs.
709 * 'req' is already big enough for the label, if shown.
711 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
)
713 int im_width
, im_height
;
714 Icon
*icon
= (Icon
*) pi
;
716 im_width
= icon
->item
->image
->width
;
717 im_height
= MIN(icon
->item
->image
->height
, ICON_HEIGHT
);
719 req
->height
+= im_height
;
720 req
->width
= MAX(req
->width
, im_width
);
722 if (pi
->panel
->side
== PANEL_LEFT
|| pi
->panel
->side
== PANEL_RIGHT
)
723 req
->height
+= PANEL_ICON_SPACING
;
725 req
->width
+= PANEL_ICON_SPACING
;
728 static gint
expose_icon(GtkWidget
*widget
,
729 GdkEventExpose
*event
,
732 return draw_icon(widget
, &event
->area
, pi
);
735 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, PanelIcon
*pi
)
739 Icon
*icon
= (Icon
*) pi
;
741 gdk_drawable_get_size(widget
->window
, &width
, &height
);
745 area
.height
= icon
->item
->image
->height
;
747 if (panel_want_show_text(pi
))
749 int text_height
= pi
->label
->requisition
.height
;
751 area
.y
= height
- text_height
- area
.height
;
753 draw_large_icon(widget
->window
, &area
, icon
->item
,
754 icon
->item
->image
, icon
->selected
);
758 area
.y
= (height
- area
.height
) >> 1;
759 draw_large_icon(widget
->window
, &area
, icon
->item
,
760 icon
->item
->image
, icon
->selected
);
766 static void panel_icon_wink(Icon
*icon
)
768 PanelIcon
*pi
= (PanelIcon
*) icon
;
770 wink_widget(pi
->widget
);
773 /* icon may be NULL if the event is on the background */
774 static void perform_action(Panel
*panel
, PanelIcon
*pi
, GdkEventButton
*event
)
777 Icon
*icon
= (Icon
*) pi
;
779 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
781 if (pi
&& pi
->socket
)
782 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
789 wink_widget(pi
->widget
);
790 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, FALSE
);
794 wink_widget(pi
->widget
);
795 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, TRUE
);
799 panel_show_menu(event
, pi
, panel
);
802 dnd_motion_start(MOTION_REPOSITION
);
804 case ACT_PRIME_AND_SELECT
:
806 icon_select_only(icon
);
807 dnd_motion_start(MOTION_READY_FOR_DND
);
809 case ACT_PRIME_AND_TOGGLE
:
810 icon_set_selected(icon
, !icon
->selected
);
811 dnd_motion_start(MOTION_READY_FOR_DND
);
813 case ACT_PRIME_FOR_DND
:
814 dnd_motion_start(MOTION_READY_FOR_DND
);
816 case ACT_TOGGLE_SELECTED
:
817 icon_set_selected(icon
, !icon
->selected
);
819 case ACT_SELECT_EXCL
:
820 icon_set_selected(icon
, TRUE
);
822 case ACT_SLIDE_CLEAR_PANEL
:
823 icon_select_only(NULL
);
825 case ACT_SLIDE_PANEL
:
826 dnd_motion_grab_pointer();
827 slide_from_value
= panel
->adj
->value
;
828 dnd_motion_start(MOTION_REPOSITION
);
832 case ACT_CLEAR_SELECTION
:
833 icon_select_only(NULL
);
836 g_warning("Unsupported action : %d\n", action
);
841 static gint
panel_button_release(GtkWidget
*widget
,
842 GdkEventButton
*event
,
845 if (dnd_motion_release(event
))
848 perform_action(panel
, NULL
, event
);
853 static gint
panel_button_press(GtkWidget
*widget
,
854 GdkEventButton
*event
,
857 if (dnd_motion_press(panel
->window
, event
))
858 perform_action(panel
, NULL
, event
);
863 static gint
icon_button_release(GtkWidget
*widget
,
864 GdkEventButton
*event
,
867 if (pi
->socket
&& event
->button
== 1)
868 return FALSE
; /* Restart button */
870 if (dnd_motion_release(event
))
873 perform_action(pi
->panel
, pi
, event
);
878 static gint
icon_button_press(GtkWidget
*widget
,
879 GdkEventButton
*event
,
882 if (pi
->socket
&& event
->button
== 1)
883 return FALSE
; /* Restart button */
885 if (dnd_motion_press(widget
, event
))
886 perform_action(pi
->panel
, pi
, event
);
891 static void reposition_panel(GtkWidget
*window
,
892 GtkAllocation
*alloc
, Panel
*panel
)
895 PanelSide side
= panel
->side
;
897 if (side
== PANEL_LEFT
|| side
== PANEL_RIGHT
)
899 if (side
== PANEL_RIGHT
)
900 x
= screen_width
- alloc
->width
;
902 if (current_panel
[PANEL_TOP
])
904 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
905 y
+= win
->allocation
.height
;
909 if (side
== PANEL_BOTTOM
)
910 y
= screen_height
- alloc
->height
;
912 gtk_window_move(GTK_WINDOW(panel
->window
), x
, y
);
913 gdk_window_move(panel
->window
->window
, x
, y
);
915 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
917 if (current_panel
[PANEL_RIGHT
])
918 gtk_widget_queue_resize(
919 current_panel
[PANEL_RIGHT
]->window
);
920 if (current_panel
[PANEL_LEFT
])
921 gtk_widget_queue_resize(
922 current_panel
[PANEL_LEFT
]->window
);
926 /* Same as drag_set_dest(), but for panel icons */
927 static void drag_set_panel_dest(PanelIcon
*pi
)
929 GtkWidget
*obj
= pi
->widget
;
931 make_drop_target(pi
->widget
, 0);
933 g_signal_connect(obj
, "drag_motion", G_CALLBACK(drag_motion
), pi
);
934 g_signal_connect(obj
, "drag_leave", G_CALLBACK(drag_leave
), pi
);
935 g_signal_connect(obj
, "drag_end", G_CALLBACK(drag_end
), pi
);
938 static gboolean
drag_motion(GtkWidget
*widget
,
939 GdkDragContext
*context
,
945 GdkDragAction action
= context
->suggested_action
;
946 const char *type
= NULL
;
947 Icon
*icon
= (Icon
*) pi
;
948 DirItem
*item
= icon
->item
;
950 panel_drag_motion(widget
, context
, x
, y
, time
, pi
->panel
);
953 goto out
; /* Can't drag a selection to itself */
955 type
= dnd_motion_item(context
, &item
);
960 /* We actually must pretend to accept the drop, even if the
961 * directory isn't writeable, so that the spring-opening
965 /* Don't allow drops to non-writeable directories */
966 if (o_dnd_spring_open
.int_value
== FALSE
&&
967 type
== drop_dest_dir
&&
968 access(icon
->path
, W_OK
) != 0)
973 g_dataset_set_data(context
, "drop_dest_type", (gpointer
) type
);
976 gdk_drag_status(context
, action
, time
);
977 g_dataset_set_data_full(context
, "drop_dest_path",
978 g_strdup(icon
->path
), g_free
);
979 if (type
== drop_dest_dir
)
980 dnd_spring_load(context
, NULL
);
982 if (dnd_highlight
&& dnd_highlight
!= pi
->widget
)
984 gtk_drag_unhighlight(dnd_highlight
);
985 dnd_highlight
= NULL
;
988 if (dnd_highlight
== NULL
)
990 gtk_drag_highlight(pi
->widget
);
991 dnd_highlight
= pi
->widget
;
999 static void add_uri_list(GtkWidget
*widget
,
1000 GdkDragContext
*context
,
1003 GtkSelectionData
*selection_data
,
1008 gboolean after
= FALSE
;
1011 if (!selection_data
->data
)
1014 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
1016 if (g_object_get_data(G_OBJECT(widget
), "after"))
1019 uris
= uri_list_to_glist(selection_data
->data
);
1021 for (next
= uris
; next
; next
= next
->next
)
1025 path
= get_local_path((guchar
*) next
->data
);
1028 panel_add_item(panel
, path
, NULL
, after
, NULL
);
1034 static void drag_end(GtkWidget
*widget
,
1035 GdkDragContext
*context
,
1038 if (tmp_icon_selected
)
1040 icon_select_only(NULL
);
1041 tmp_icon_selected
= FALSE
;
1045 static void drag_leave(GtkWidget
*widget
,
1046 GdkDragContext
*context
,
1050 panel_drag_leave(widget
, context
, time
, ((PanelIcon
*) icon
)->panel
);
1052 if (dnd_highlight
&& dnd_highlight
== widget
)
1054 gtk_drag_unhighlight(dnd_highlight
);
1055 dnd_highlight
= NULL
;
1061 /* Create XML icon nodes for these widgets.
1062 * Always frees the widgets list.
1064 static void make_widgets(xmlNodePtr side
, GList
*widgets
)
1068 for (next
= widgets
; next
; next
= next
->next
)
1073 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
1077 g_warning("Can't find Icon from widget\n");
1081 tree
= xmlNewTextChild(side
, NULL
, "icon", icon
->src_path
);
1083 xmlSetProp(tree
, "label", icon
->item
->leafname
);
1085 xmlSetProp(tree
, "shortcut", icon
->shortcut
);
1089 g_list_free(widgets
);
1092 void panel_save(Panel
*panel
)
1096 guchar
*save
= NULL
;
1097 guchar
*save_new
= NULL
;
1099 g_return_if_fail(panel
!= NULL
);
1101 if (strchr(panel
->name
, '/'))
1102 save
= g_strdup(panel
->name
);
1107 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
1108 save
= choices_find_path_save(leaf
, PROJECT
, TRUE
);
1115 doc
= xmlNewDoc("1.0");
1116 xmlDocSetRootElement(doc
, xmlNewDocNode(doc
, NULL
, "panel", NULL
));
1118 root
= xmlDocGetRootElement(doc
);
1119 make_widgets(xmlNewChild(root
, NULL
, "start", NULL
),
1120 gtk_container_get_children(GTK_CONTAINER(panel
->before
)));
1122 make_widgets(xmlNewChild(root
, NULL
, "end", NULL
),
1123 g_list_reverse(gtk_container_get_children(
1124 GTK_CONTAINER(panel
->after
))));
1126 save_new
= g_strconcat(save
, ".new", NULL
);
1127 if (save_xml_file(doc
, save_new
) || rename(save_new
, save
))
1128 delayed_error(_("Error saving panel %s: %s"),
1129 save
, g_strerror(errno
));
1137 /* Create a frame widget which can be used to add icons to the panel */
1138 static GtkWidget
*make_insert_frame(Panel
*panel
)
1141 GtkTargetEntry target_table
[] = {
1142 {"text/uri-list", 0, TARGET_URI_LIST
},
1145 frame
= gtk_frame_new(NULL
);
1146 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
1147 gtk_widget_set_size_request(frame
, 16, 16);
1149 g_signal_connect(frame
, "drag-motion",
1150 G_CALLBACK(panel_drag_motion
), panel
);
1151 g_signal_connect(frame
, "drag-leave",
1152 G_CALLBACK(panel_drag_leave
), panel
);
1154 g_signal_connect(frame
, "drag-data-received",
1155 G_CALLBACK(add_uri_list
), panel
);
1156 gtk_drag_dest_set(frame
,
1157 GTK_DEST_DEFAULT_ALL
,
1159 sizeof(target_table
) / sizeof(*target_table
),
1165 static gboolean
enter_icon(GtkWidget
*widget
,
1166 GdkEventCrossing
*event
,
1169 icon_may_update(icon
);
1174 static gint
panel_leave_event(GtkWidget
*widget
,
1175 GdkEventCrossing
*event
,
1178 GdkWindow
*pinboard
;
1180 pinboard
= pinboard_get_window();
1181 window_put_just_above(panel
->window
->window
, pinboard
);
1186 /* If (x, y) is at the edge of the panel then raise */
1187 static void motion_may_raise(Panel
*panel
, int x
, int y
)
1191 if (panel
->side
== PANEL_TOP
)
1193 else if (panel
->side
== PANEL_BOTTOM
)
1194 raise
= y
== panel
->window
->allocation
.height
- 1;
1195 else if (panel
->side
== PANEL_LEFT
)
1198 raise
= x
== panel
->window
->allocation
.width
- 1;
1201 gdk_window_raise(panel
->window
->window
);
1204 static gint
panel_motion_event(GtkWidget
*widget
,
1205 GdkEventMotion
*event
,
1209 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1211 motion_may_raise(panel
, event
->x
, event
->y
);
1213 if (motion_state
!= MOTION_REPOSITION
)
1217 delta
= event
->x_root
- drag_start_x
;
1219 delta
= event
->y_root
- drag_start_y
;
1221 new = slide_from_value
- delta
;
1222 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
1224 gtk_adjustment_set_value(panel
->adj
, new);
1229 static gint
icon_motion_event(GtkWidget
*widget
,
1230 GdkEventMotion
*event
,
1233 Panel
*panel
= pi
->panel
;
1235 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1239 if (motion_state
== MOTION_READY_FOR_DND
)
1241 if (dnd_motion_moved(event
))
1242 start_drag(pi
, event
);
1245 else if (motion_state
!= MOTION_REPOSITION
)
1248 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1249 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1250 list
= g_list_concat(list
,
1251 gtk_container_get_children(GTK_CONTAINER(panel
->after
)));
1252 me
= g_list_find(list
, widget
);
1254 g_return_val_if_fail(me
!= NULL
, TRUE
);
1256 val
= horz
? event
->x_root
: event
->y_root
;
1264 prev
= GTK_WIDGET(me
->prev
->data
);
1268 gdk_window_get_origin(prev
->window
, &x
, &y
);
1270 if (val
<= (horz
? x
: y
))
1274 if (dir
== 0 && me
->next
)
1280 next
= GTK_WIDGET(me
->next
->data
);
1284 gdk_window_get_origin(next
->window
, &x
, &y
);
1286 gdk_drawable_get_size(next
->window
, &w
, &h
);
1291 if (val
>= (horz
? x
: y
))
1293 if (next
== panel
->gap
)
1301 reposition_icon(pi
, g_list_index(list
, widget
) + dir
);
1306 static void reposition_icon_on_side(GtkWidget
*side
, GtkWidget
*widget
,
1311 list
= gtk_container_get_children(GTK_CONTAINER(side
));
1313 /* Want to move icon to the list in the given 'side'. Is it there
1317 if (!g_list_find(list
, widget
))
1320 gtk_grab_remove(widget
);
1321 gtk_widget_reparent(widget
, side
);
1322 dnd_motion_grab_pointer();
1323 gtk_grab_add(widget
);
1326 gtk_box_reorder_child(GTK_BOX(side
), widget
, index
);
1331 /* Move icon to this index in the complete widget list.
1332 * 0 makes the icon the left-most icon. The gap in the middle has
1333 * an index number, which allows you to specify that the icon should
1334 * go on the left or right side.
1336 static void reposition_icon(PanelIcon
*pi
, int index
)
1338 Panel
*panel
= pi
->panel
;
1339 GtkWidget
*widget
= pi
->widget
;
1343 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1344 before_len
= g_list_length(list
);
1347 if (index
<= before_len
)
1348 reposition_icon_on_side(panel
->before
, widget
, index
);
1350 reposition_icon_on_side(panel
->after
, widget
,
1351 index
- (before_len
+ 1));
1356 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
)
1358 GtkWidget
*widget
= pi
->widget
;
1359 Icon
*icon
= (Icon
*) pi
;
1361 if (!icon
->selected
)
1363 if (event
->state
& GDK_BUTTON1_MASK
)
1365 /* Select just this one */
1366 icon_select_only(icon
);
1367 tmp_icon_selected
= TRUE
;
1370 icon_set_selected(icon
, TRUE
);
1373 g_return_if_fail(icon_selection
!= NULL
);
1375 if (icon_selection
->next
== NULL
)
1376 drag_one_item(widget
, event
, icon
->path
, icon
->item
, NULL
);
1381 uri_list
= icon_create_uri_list();
1382 drag_selection(widget
, event
, uri_list
);
1387 static void applet_died(GtkWidget
*socket
)
1389 gboolean never_plugged
;
1391 never_plugged
= (!g_object_get_data(G_OBJECT(socket
), "lost_plug"))
1392 && !GTK_SOCKET(socket
)->plug_window
;
1397 _("Applet quit without ever creating a widget!"));
1398 gtk_widget_destroy(socket
);
1401 gtk_widget_unref(socket
);
1404 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1406 g_object_set_data(G_OBJECT(socket
), "lost_plug", "yes");
1408 gtk_widget_unref(socket
);
1410 gtk_widget_destroy(widget
); /* Remove from panel */
1413 panel_save(g_object_get_data(G_OBJECT(socket
), "panel"));
1416 /* Try to run this applet.
1419 * - No executable AppletRun:
1420 * icon->socket == NULL (unchanged) on return.
1422 * Otherwise, create socket (setting icon->socket) and ref it twice.
1424 * - AppletRun quits without connecting a plug:
1425 * On child death lost_plug is unset and socket is empty.
1427 * Report error and destroy widget (to 'socket destroyed').
1429 * - AppletRun quits while plug is in socket:
1430 * Unref socket once. Socket will be destroyed later.
1432 * - Socket is destroyed.
1433 * Set lost_plug = "yes" and remove widget from panel.
1436 static void run_applet(PanelIcon
*pi
)
1438 GError
*error
= NULL
;
1441 Icon
*icon
= (Icon
*) pi
;
1443 argv
[0] = (char *) make_path(icon
->path
, "AppletRun");
1445 if (access(argv
[0], X_OK
) != 0)
1448 pi
->socket
= gtk_socket_new();
1450 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->socket
);
1451 gtk_widget_show_all(pi
->socket
);
1452 gtk_widget_realize(pi
->socket
);
1456 PanelSide side
= pi
->panel
->side
;
1458 /* Set a hint to let applets position their menus correctly */
1459 pos
= g_strdup_printf("%s,%d",
1460 side
== PANEL_TOP
? "Top" :
1461 side
== PANEL_BOTTOM
? "Bottom" :
1462 side
== PANEL_LEFT
? "Left" :
1463 "Right", MENU_MARGIN(side
));
1464 gdk_property_change(pi
->socket
->window
,
1465 gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE
),
1466 gdk_atom_intern("STRING", FALSE
),
1467 8, GDK_PROP_MODE_REPLACE
,
1472 g_object_set_data(G_OBJECT(pi
->widget
), "icon", pi
);
1473 g_object_set_data(G_OBJECT(pi
->socket
), "panel", pi
->panel
);
1475 argv
[1] = g_strdup_printf("%ld",
1476 GDK_WINDOW_XWINDOW(pi
->socket
->window
));
1479 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_DO_NOT_REAP_CHILD
,
1480 NULL
, NULL
, &pid
, &error
))
1482 delayed_error(_("Error running applet:\n%s"), error
->message
);
1483 g_error_free(error
);
1484 gtk_widget_destroy(pi
->socket
);
1489 gtk_widget_ref(pi
->socket
);
1490 on_child_death(pid
, (CallbackFn
) applet_died
, pi
->socket
);
1492 gtk_widget_ref(pi
->socket
);
1493 g_signal_connect(pi
->socket
, "destroy",
1494 G_CALLBACK(socket_destroyed
), pi
->widget
);
1500 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
1502 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1504 req
->width
= screen_width
;
1505 req
->height
+= EDGE_WIDTH
;
1509 int h
= screen_height
;
1511 if (current_panel
[PANEL_TOP
])
1513 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1514 h
-= win
->allocation
.height
;
1517 if (current_panel
[PANEL_BOTTOM
])
1519 GtkWidget
*win
= current_panel
[PANEL_BOTTOM
]->window
;
1520 h
-= win
->allocation
.height
;
1524 req
->width
+= EDGE_WIDTH
;
1528 static void update_side(GtkWidget
*side
)
1532 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
1533 for (next
= kids
; next
; next
= next
->next
)
1536 pi
= g_object_get_data(next
->data
, "icon");
1537 panel_icon_set_tip(pi
);
1542 /* Tips or style has changed -- update everything on this panel */
1543 static void panel_set_style(Panel
*panel
)
1545 update_side(panel
->before
);
1546 update_side(panel
->after
);
1547 gtk_widget_queue_resize(panel
->window
);
1550 static gboolean
recreate_panels(char **names
)
1554 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1558 panel_new(names
[i
], i
);
1568 static void panel_style_changed(void)
1572 if (o_override_redirect
.has_changed
)
1576 names
= g_new(char *, PANEL_NUMBER_OF_SIDES
);
1578 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1580 Panel
*panel
= current_panel
[i
];
1581 names
[i
] = panel
? g_strdup(panel
->name
) : NULL
;
1585 g_idle_add((GtkFunction
) recreate_panels
, names
);
1588 if (o_panel_style
.has_changed
)
1590 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1592 if (current_panel
[i
])
1593 panel_set_style(current_panel
[i
]);
1598 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
1601 int x
, y
, width
, height
;
1603 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1605 width
= screen_width
;
1606 height
= EDGE_WIDTH
;
1609 if (panel
->side
== PANEL_BOTTOM
)
1612 y
= widget
->allocation
.height
- EDGE_WIDTH
;
1617 height
= screen_height
;
1620 if (panel
->side
== PANEL_RIGHT
)
1623 x
= widget
->allocation
.width
- EDGE_WIDTH
;
1626 gdk_draw_rectangle(widget
->window
,
1627 widget
->style
->fg_gc
[GTK_STATE_NORMAL
], TRUE
,
1628 x
, y
, width
, height
);
1633 static gpointer parent_class
;
1635 static void panel_icon_destroy(Icon
*icon
)
1637 PanelIcon
*pi
= (PanelIcon
*) icon
;
1639 g_return_if_fail(pi
->widget
!= NULL
);
1641 gtk_widget_destroy(pi
->widget
);
1644 static void panel_remove_items(void)
1648 g_return_if_fail(icon_selection
!= NULL
);
1650 panel
= ((PanelIcon
*) icon_selection
->data
)->panel
;
1652 while (icon_selection
)
1653 icon_destroy((Icon
*) icon_selection
->data
);
1658 static void panel_icon_redraw(Icon
*icon
)
1660 gtk_widget_queue_draw(PANEL_ICON(icon
)->widget
);
1663 static void panel_icon_update(Icon
*icon
)
1665 PanelIcon
*pi
= (PanelIcon
*) icon
;
1667 gtk_widget_queue_draw(pi
->widget
);
1668 gtk_label_set_text(GTK_LABEL(pi
->label
), icon
->item
->leafname
);
1669 panel_icon_set_tip(pi
);
1670 panel_save(pi
->panel
);
1673 /* The point of this is to clear the selection if the existing icons
1674 * aren't from the same panel...
1676 static gboolean
panel_icon_same_group(Icon
*icon
, Icon
*other
)
1678 if (IS_PANEL_ICON(other
))
1680 PanelIcon
*a
= (PanelIcon
*) icon
;
1681 PanelIcon
*b
= (PanelIcon
*) other
;
1683 return a
->panel
== b
->panel
;
1689 static void panel_icon_class_init(gpointer gclass
, gpointer data
)
1691 IconClass
*icon
= (IconClass
*) gclass
;
1693 parent_class
= g_type_class_peek_parent(gclass
);
1695 icon
->destroy
= panel_icon_destroy
;
1696 icon
->redraw
= panel_icon_redraw
;
1697 icon
->update
= panel_icon_update
;
1698 icon
->remove_items
= panel_remove_items
;
1699 icon
->same_group
= panel_icon_same_group
;
1700 icon
->wink
= panel_icon_wink
;
1703 static void panel_icon_init(GTypeInstance
*object
, gpointer gclass
)
1705 PanelIcon
*pi
= (PanelIcon
*) object
;
1712 static GType
panel_icon_get_type(void)
1714 static GType type
= 0;
1718 static const GTypeInfo info
=
1720 sizeof (PanelIconClass
),
1721 NULL
, /* base_init */
1722 NULL
, /* base_finalise */
1723 panel_icon_class_init
,
1724 NULL
, /* class_finalise */
1725 NULL
, /* class_data */
1727 0, /* n_preallocs */
1731 type
= g_type_register_static(icon_get_type(),
1732 "PanelIcon", &info
, 0);
1738 static PanelIcon
*panel_icon_new(Panel
*panel
,
1739 const char *pathname
,
1745 pi
= g_object_new(panel_icon_get_type(), NULL
);
1748 icon_set_path(icon
, pathname
, name
);
1754 static gboolean
panel_want_show_text(PanelIcon
*pi
)
1756 Icon
*icon
= (Icon
*) pi
;
1758 if (o_panel_style
.int_value
== SHOW_BOTH
)
1760 if (o_panel_style
.int_value
== SHOW_ICON
)
1763 if (icon
->item
->flags
& ITEM_FLAG_APPDIR
)
1769 static void panel_position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
,
1770 gboolean
*push_in
, gpointer data
)
1772 int *pos
= (int *) data
;
1773 GtkRequisition requisition
;
1774 int margin
= pos
[2];
1776 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
1779 *x
= screen_width
- margin
- requisition
.width
;
1780 else if (pos
[0] == -2)
1783 *x
= pos
[0] - (requisition
.width
>> 2);
1786 *y
= screen_height
- margin
- requisition
.height
;
1787 else if (pos
[1] == -2)
1790 *y
= pos
[1] - (requisition
.height
>> 2);
1792 *x
= CLAMP(*x
, 0, screen_width
- requisition
.width
);
1793 *y
= CLAMP(*y
, 0, screen_height
- requisition
.height
);
1798 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
)
1800 PanelSide side
= panel
->side
;
1803 pos
[0] = event
->x_root
;
1804 pos
[1] = event
->y_root
;
1805 pos
[2] = MENU_MARGIN(side
);
1807 icon_prepare_menu((Icon
*) pi
, FALSE
);
1809 if (side
== PANEL_LEFT
)
1811 else if (side
== PANEL_RIGHT
)
1814 if (side
== PANEL_TOP
)
1816 else if (side
== PANEL_BOTTOM
)
1819 gtk_menu_popup(GTK_MENU(icon_menu
), NULL
, NULL
,
1820 panel_position_menu
,
1821 (gpointer
) pos
, event
->button
, event
->time
);
1824 /* Note: also called from icon handler */
1825 static gboolean
panel_drag_motion(GtkWidget
*widget
,
1826 GdkDragContext
*context
,
1832 int panel_x
, panel_y
;
1834 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
1836 motion_may_raise(panel
, panel_x
, panel_y
);
1837 gdk_drag_status(context
, 0, time
);
1841 /* Note: also called from icon handler */
1842 static void panel_drag_leave(GtkWidget
*widget
,
1843 GdkDragContext
*context
,
1847 GdkWindow
*pinboard
, *window
;
1848 GtkAllocation
*alloc
= &panel
->window
->allocation
;
1851 window
= panel
->window
->window
;
1852 gdk_window_get_pointer(window
, &x
, &y
, NULL
);
1853 if (x
< 0 || y
< 0 || x
> alloc
->width
|| y
> alloc
->height
)
1855 pinboard
= pinboard_get_window();
1856 window_put_just_above(panel
->window
->window
, pinboard
);