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"
56 #include "pinboard.h" /* For pinboard_get_window() */
58 /* The width of the separator at the inner edge of the panel */
61 /* The gap between panel icons */
62 #define PANEL_ICON_SPACING 8
64 enum {TEXT_BESIDE_ICON
, TEXT_UNDER_ICON
};
66 static gboolean tmp_icon_selected
= FALSE
; /* When dragging */
68 typedef struct _PanelIconClass PanelIconClass
;
69 typedef struct _PanelIcon PanelIcon
;
71 struct _PanelIconClass
{
80 GtkWidget
*widget
; /* The drawing area for the icon */
82 GtkWidget
*socket
; /* For applets */
87 #define PANEL_ICON(obj) GTK_CHECK_CAST((obj), panel_icon_get_type(), PanelIcon)
88 #define IS_PANEL_ICON(obj) \
89 G_TYPE_CHECK_INSTANCE_TYPE((obj), panel_icon_get_type())
91 Panel
*current_panel
[PANEL_NUMBER_OF_SIDES
];
93 /* NULL => Not loading a panel */
94 static Panel
*loading_panel
= NULL
;
96 /* Static prototypes */
97 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
);
98 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
);
99 static const char *pan_from_file(gchar
*line
);
100 static gint
icon_button_release(GtkWidget
*widget
,
101 GdkEventButton
*event
,
103 static gint
icon_button_press(GtkWidget
*widget
,
104 GdkEventButton
*event
,
106 static void reposition_panel(GtkWidget
*window
,
107 GtkAllocation
*alloc
, Panel
*panel
);
108 static gint
expose_icon_background(GtkWidget
*widget
,
109 GdkEventExpose
*event
,
111 static gint
expose_icon(GtkWidget
*widget
,
112 GdkEventExpose
*event
,
114 static gint
draw_icon(GtkWidget
*widget
,
115 GdkRectangle
*badarea
,
117 static gint
panel_button_release(GtkWidget
*widget
,
118 GdkEventButton
*event
,
120 static gint
panel_button_press(GtkWidget
*widget
,
121 GdkEventButton
*event
,
123 static void panel_post_resize(GtkWidget
*box
,
124 GtkRequisition
*req
, Panel
*panel
);
125 static void drag_set_panel_dest(PanelIcon
*pi
);
126 static void add_uri_list(GtkWidget
*widget
,
127 GdkDragContext
*context
,
130 GtkSelectionData
*selection_data
,
134 static void panel_add_item(Panel
*panel
,
138 const gchar
*shortcut
);
139 static gboolean
panel_drag_motion(GtkWidget
*widget
,
140 GdkDragContext
*context
,
145 static gboolean
insert_drag_motion(GtkWidget
*widget
,
146 GdkDragContext
*context
,
151 static gboolean
drag_motion(GtkWidget
*widget
,
152 GdkDragContext
*context
,
157 static void panel_drag_leave(GtkWidget
*widget
,
158 GdkDragContext
*context
,
161 static void drag_leave(GtkWidget
*widget
,
162 GdkDragContext
*context
,
165 static GtkWidget
*make_insert_frame(Panel
*panel
);
166 static gboolean
enter_icon(GtkWidget
*widget
,
167 GdkEventCrossing
*event
,
169 static gint
icon_motion_event(GtkWidget
*widget
,
170 GdkEventMotion
*event
,
172 static gint
panel_leave_event(GtkWidget
*widget
,
173 GdkEventCrossing
*event
,
175 static gint
panel_motion_event(GtkWidget
*widget
,
176 GdkEventMotion
*event
,
178 static void reposition_icon(PanelIcon
*pi
, int index
);
179 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
);
180 static void drag_end(GtkWidget
*widget
,
181 GdkDragContext
*context
,
183 static void perform_action(Panel
*panel
,
185 GdkEventButton
*event
);
186 static void run_applet(PanelIcon
*pi
);
187 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
);
188 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
);
189 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
191 static PanelIcon
*panel_icon_new(Panel
*panel
,
192 const char *pathname
,
194 static GType
panel_icon_get_type(void);
195 static gboolean
panel_want_show_text(PanelIcon
*pi
);
196 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
);
197 static void panel_style_changed(void);
198 static void motion_may_raise(Panel
*panel
, int x
, int y
);
199 static void panel_update(Panel
*panel
);
200 static gboolean
panel_check_xinerama(void);
201 static GList
*build_monitor_number(Option
*option
,
202 xmlNode
*node
, guchar
*label
);
203 static gboolean
may_autoscroll(Panel
*panel
);
206 static GtkWidget
*dnd_highlight
= NULL
; /* (stops flickering) */
209 #define SHOW_APPS_SMALL 1
211 static Option o_panel_style
;
212 static Option o_panel_width
;
213 static Option o_panel_xinerama
;
214 static Option o_panel_monitor
;
215 static Option o_panel_avoid
;
217 static gint panel_monitor
= -1;
218 GdkRectangle panel_geometry
;
220 static int closing_panel
= 0; /* Don't panel_save; destroying! */
222 /****************************************************************
223 * EXTERNAL INTERFACE *
224 ****************************************************************/
226 void panel_init(void)
228 option_add_int(&o_panel_style
, "panel_style", SHOW_APPS_SMALL
);
229 option_add_int(&o_panel_width
, "panel_width", 52);
231 option_add_int(&o_panel_xinerama
, "panel_xinerama", 0);
232 option_add_int(&o_panel_monitor
, "panel_monitor", 0);
234 option_add_int(&o_panel_avoid
, "panel_avoid", TRUE
);
236 option_add_notify(panel_style_changed
);
238 option_register_widget("monitor-number", build_monitor_number
);
240 panel_check_xinerama();
243 /* 'name' may be NULL or "" to remove the panel */
244 Panel
*panel_new(const gchar
*name
, PanelSide side
)
248 GtkWidget
*vp
, *box
, *frame
, *align
;
250 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, NULL
);
251 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
253 if (name
&& *name
== '\0')
256 if (current_panel
[side
])
261 gtk_widget_destroy(current_panel
[side
]->window
);
267 if (name
== NULL
|| *name
== '\0')
270 panel
= g_new(Panel
, 1);
271 panel
->name
= g_strdup(name
);
273 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
274 panel
->autoscroll_speed
= 0;
275 gtk_window_set_resizable(GTK_WINDOW(panel
->window
), FALSE
);
276 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
277 gtk_widget_set_name(panel
->window
, "rox-panel");
278 gtk_widget_set_events(panel
->window
,
279 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
280 GDK_POINTER_MOTION_MASK
| GDK_LEAVE_NOTIFY_MASK
);
282 /* We make the panel a drop target only so that we can auto-raise! */
283 gtk_drag_dest_set(panel
->window
, 0, NULL
, 0, GDK_ACTION_PRIVATE
);
284 g_signal_connect(panel
->window
, "drag_leave",
285 G_CALLBACK(panel_drag_leave
), panel
);
286 g_signal_connect(panel
->window
, "drag_motion",
287 G_CALLBACK(panel_drag_motion
), panel
);
289 g_signal_connect(panel
->window
, "delete-event",
290 G_CALLBACK(panel_delete
), panel
);
291 g_signal_connect(panel
->window
, "destroy",
292 G_CALLBACK(panel_destroyed
), panel
);
293 g_signal_connect(panel
->window
, "button_press_event",
294 G_CALLBACK(panel_button_press
), panel
);
295 g_signal_connect(panel
->window
, "button_release_event",
296 G_CALLBACK(panel_button_release
), panel
);
297 g_signal_connect(panel
->window
, "motion-notify-event",
298 G_CALLBACK(panel_motion_event
), panel
);
299 g_signal_connect(panel
->window
, "leave-notify-event",
300 G_CALLBACK(panel_leave_event
), panel
);
302 if (strchr(name
, '/'))
303 load_path
= g_strdup(name
);
308 leaf
= g_strconcat("pan_", name
, NULL
);
309 load_path
= choices_find_path_load(leaf
, PROJECT
);
313 if (panel
->side
== PANEL_RIGHT
)
314 align
= gtk_alignment_new(1.0, 0.0, 0.0, 1.0);
315 else if (panel
->side
== PANEL_BOTTOM
)
316 align
= gtk_alignment_new(0.0, 1.0, 1.0, 0.0);
317 else if (panel
->side
== PANEL_TOP
)
318 align
= gtk_alignment_new(0.0, 0.0, 1.0, 0.0);
320 align
= gtk_alignment_new(0.0, 0.0, 0.0, 1.0);
322 gtk_container_add(GTK_CONTAINER(panel
->window
), align
);
324 vp
= gtk_viewport_new(NULL
, NULL
);
325 gtk_container_set_resize_mode(GTK_CONTAINER(vp
), GTK_RESIZE_PARENT
);
326 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_NONE
);
327 gtk_container_add(GTK_CONTAINER(align
), vp
);
329 g_signal_connect(align
, "expose-event",
330 G_CALLBACK(draw_panel_edge
), panel
);
332 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
334 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
335 box
= gtk_hbox_new(FALSE
, 0);
336 panel
->before
= gtk_hbox_new(FALSE
, 0);
337 panel
->after
= gtk_hbox_new(FALSE
, 0);
341 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
342 box
= gtk_vbox_new(FALSE
, 0);
343 panel
->before
= gtk_vbox_new(FALSE
, 0);
344 panel
->after
= gtk_vbox_new(FALSE
, 0);
347 gtk_container_add(GTK_CONTAINER(vp
), box
);
348 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
349 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
351 frame
= make_insert_frame(panel
);
352 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
354 /* This is used so that we can find the middle easily! */
355 panel
->gap
= gtk_event_box_new();
356 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
358 frame
= make_insert_frame(panel
);
359 g_object_set_data(G_OBJECT(frame
), "after", "yes");
360 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
362 gtk_widget_realize(panel
->window
);
363 make_panel_window(panel
->window
);
364 if (!(gtk_major_version
== 2 && gtk_minor_version
== 0))
365 gtk_window_stick(GTK_WINDOW(panel
->window
));
367 gtk_widget_show_all(align
);
369 loading_panel
= panel
;
370 if (load_path
&& access(load_path
, F_OK
) == 0)
373 doc
= xmlParseFile(load_path
);
376 panel_load_from_xml(panel
, doc
);
381 parse_file(load_path
, pan_from_file
);
382 info_message(_("Your old panel file has been "
383 "converted to the new XML format."));
389 /* Don't scare users with an empty panel... */
392 panel_add_item(panel
, "~", "Home", FALSE
, NULL
);
394 apps
= pathdup(make_path(app_dir
, ".."));
397 panel_add_item(panel
, apps
, "Apps", FALSE
, NULL
);
401 loading_panel
= NULL
;
404 current_panel
[side
] = panel
;
406 gtk_widget_queue_resize(box
);
407 g_signal_connect(panel
->window
, "size-request",
408 G_CALLBACK(panel_post_resize
), panel
);
409 g_signal_connect(panel
->window
, "size-allocate",
410 G_CALLBACK(reposition_panel
), panel
);
413 gdk_window_lower(panel
->window
->window
);
414 gtk_widget_show(panel
->window
);
419 pinboard
= pinboard_get_window();
420 /* (if pinboard is NULL, will go right to the back) */
421 window_put_just_above(panel
->window
->window
, pinboard
);
427 /* Externally visible function to add an item to a panel */
428 gboolean
panel_add(PanelSide side
,
429 const gchar
*path
, const gchar
*label
, gboolean after
)
431 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
433 g_return_val_if_fail(current_panel
[side
] != NULL
, FALSE
);
435 panel_add_item(current_panel
[side
], path
, label
, after
, NULL
);
440 /* Add the area covered by the panels to the region */
441 void panel_mark_used(GdkRegion
*used
)
445 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
447 Panel
*panel
= current_panel
[i
];
453 gdk_window_get_root_origin(panel
->window
->window
,
455 rect
.width
= panel
->window
->allocation
.width
;
456 rect
.height
= panel
->window
->allocation
.height
;
458 gdk_region_union_with_rect(used
, &rect
);
462 /* On xrandr screen size changes, update all panels */
463 void panel_update_size(void)
467 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
469 if (current_panel
[i
])
470 panel_update(current_panel
[i
]);
474 /****************************************************************
475 * INTERNAL FUNCTIONS *
476 ****************************************************************/
478 /* User has tried to close the panel via the window manager - confirm */
479 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
481 return !confirm(_("You have tried to close a panel via the window "
482 "manager - I usually find that this is accidental... "
484 GTK_STOCK_CLOSE
, NULL
);
487 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
489 if (current_panel
[panel
->side
] == panel
)
490 current_panel
[panel
->side
] = NULL
;
492 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
494 if (current_panel
[PANEL_RIGHT
])
495 gtk_widget_queue_resize(
496 current_panel
[PANEL_RIGHT
]->window
);
497 if (current_panel
[PANEL_LEFT
])
498 gtk_widget_queue_resize(
499 current_panel
[PANEL_LEFT
]->window
);
502 if (panel
->autoscroll_speed
)
503 g_source_remove(panel
->autoscroll_to
);
511 static void panel_load_side(Panel
*panel
, xmlNodePtr side
, gboolean after
)
514 char *label
, *path
, *shortcut
;
516 for (node
= side
->xmlChildrenNode
; node
; node
= node
->next
)
518 if (node
->type
!= XML_ELEMENT_NODE
)
520 if (strcmp(node
->name
, "icon") != 0)
523 label
= xmlGetProp(node
, "label");
525 label
= g_strdup("<missing label>");
526 path
= xmlNodeGetContent(node
);
528 path
= g_strdup("<missing path>");
529 shortcut
= xmlGetProp(node
, "shortcut");
531 panel_add_item(panel
, path
, label
, after
, shortcut
);
539 /* Create one panel icon for each icon in the doc */
540 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
)
544 root
= xmlDocGetRootElement(doc
);
545 panel_load_side(panel
, get_subnode(root
, NULL
, "start"), FALSE
);
546 panel_load_side(panel
, get_subnode(root
, NULL
, "end"), TRUE
);
549 /* Called for each line in the config file while loading a new panel */
550 static const char *pan_from_file(gchar
*line
)
554 g_return_val_if_fail(line
!= NULL
, NULL
);
555 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
560 sep
= strpbrk(line
, "<>");
562 return _("Missing < or > in panel config file");
565 leaf
= g_strndup(line
, sep
- line
);
569 panel_add_item(loading_panel
, sep
+ 1, leaf
, sep
[0] == '>', NULL
);
576 static gboolean
icon_pointer_in(GtkWidget
*widget
,
577 GdkEventCrossing
*event
,
580 gtk_widget_set_state(widget
,
581 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_PRELIGHT
);
586 static gboolean
icon_pointer_out(GtkWidget
*widget
,
587 GdkEventCrossing
*event
,
590 gtk_widget_set_state(widget
,
591 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_NORMAL
);
596 static void panel_icon_destroyed(PanelIcon
*pi
)
598 g_return_if_fail(pi
->widget
!= NULL
);
605 /* Set the tooltip AND hide/show the label */
606 static void panel_icon_set_tip(PanelIcon
*pi
)
610 Icon
*icon
= (Icon
*) pi
;
612 g_return_if_fail(pi
!= NULL
);
616 if (panel_want_show_text(pi
))
617 gtk_widget_show(pi
->label
);
619 gtk_widget_hide(pi
->label
);
625 ai
= appinfo_get(icon
->path
, icon
->item
);
627 if (ai
&& ((node
= xml_get_section(ai
, NULL
, "Summary"))))
630 str
= xmlNodeListGetString(node
->doc
,
631 node
->xmlChildrenNode
, 1);
634 gtk_tooltips_set_tip(tooltips
, pi
->widget
, str
, NULL
);
638 else if ((!panel_want_show_text(pi
)) && !pi
->socket
)
640 gtk_tooltips_set_tip(tooltips
, pi
->widget
,
641 icon
->item
->leafname
, NULL
);
644 gtk_tooltips_set_tip(tooltips
, pi
->widget
, NULL
, NULL
);
650 /* Add an icon with this path to the panel. If after is TRUE then the
651 * icon is added to the right/bottom end of the panel.
653 * If name is NULL a suitable name is taken from path.
655 static void panel_add_item(Panel
*panel
,
659 const gchar
*shortcut
)
665 g_return_if_fail(panel
!= NULL
);
666 g_return_if_fail(path
!= NULL
);
668 widget
= gtk_event_box_new();
669 gtk_widget_set_events(widget
,
670 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
671 GDK_BUTTON3_MOTION_MASK
|
672 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
673 GDK_BUTTON_RELEASE_MASK
);
675 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
676 widget
, FALSE
, TRUE
, 0);
678 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
680 gtk_widget_realize(widget
);
682 pi
= panel_icon_new(panel
, path
, name
);
685 /* Widget takes the initial ref of Icon */
686 g_object_set_data(G_OBJECT(widget
), "icon", pi
);
689 g_object_ref(widget
);
691 gtk_widget_set_name(pi
->widget
, "panel-icon");
693 g_signal_connect_swapped(widget
, "destroy",
694 G_CALLBACK(panel_icon_destroyed
), pi
);
696 if (icon
->item
->base_type
== TYPE_DIRECTORY
)
699 g_signal_connect(widget
, "button_release_event",
700 G_CALLBACK(icon_button_release
), pi
);
701 g_signal_connect(widget
, "button_press_event",
702 G_CALLBACK(icon_button_press
), pi
);
703 g_signal_connect(widget
, "motion-notify-event",
704 G_CALLBACK(icon_motion_event
), pi
);
705 g_signal_connect(widget
, "enter-notify-event",
706 G_CALLBACK(icon_pointer_in
), pi
);
707 g_signal_connect(widget
, "leave-notify-event",
708 G_CALLBACK(icon_pointer_out
), pi
);
712 g_signal_connect(widget
, "enter-notify-event",
713 G_CALLBACK(enter_icon
), pi
);
714 g_signal_connect(widget
, "expose_event",
715 G_CALLBACK(expose_icon_background
), pi
);
716 g_signal_connect_after(widget
, "expose_event",
717 G_CALLBACK(expose_icon
), pi
);
718 g_signal_connect(widget
, "drag_data_get",
719 G_CALLBACK(drag_data_get
), NULL
);
721 g_signal_connect(widget
, "size_request",
722 G_CALLBACK(size_request
), pi
);
724 drag_set_panel_dest(pi
);
726 pi
->label
= gtk_label_new(icon
->item
->leafname
);
727 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->label
);
728 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
729 gtk_misc_set_padding(GTK_MISC(pi
->label
), 1, 2);
732 icon_set_shortcut(icon
, shortcut
);
737 panel_icon_set_tip(pi
);
738 gtk_widget_show(widget
);
741 /* Called when Gtk+ wants to know how much space an icon needs.
742 * 'req' is already big enough for the label, if shown.
744 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
)
746 Icon
*icon
= (Icon
*) pi
;
747 gboolean horz
= (pi
->panel
->side
== PANEL_TOP
||
748 pi
->panel
->side
== PANEL_BOTTOM
);
750 int max_height
= 100;
751 int image_width
, image_height
;
754 max_height
= o_panel_width
.int_value
- req
->height
;
756 max_width
= MAX(o_panel_width
.int_value
, req
->width
);
758 /* TODO: really need to recreate? */
760 g_object_unref(pi
->image
);
762 pi
->image
= scale_pixbuf(icon
->item
->image
->src_pixbuf
,
763 MAX(20, max_width
), MAX(20, max_height
));
765 image_width
= gdk_pixbuf_get_width(pi
->image
);
766 image_height
= gdk_pixbuf_get_height(pi
->image
);
768 if (req
->height
> 0 && max_height
< req
->height
)
770 pi
->style
= TEXT_BESIDE_ICON
;
771 req
->width
+= image_width
;
772 req
->height
= MAX(req
->height
, image_height
);
773 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 1, 0.5);
777 pi
->style
= TEXT_UNDER_ICON
;
778 req
->width
= MAX(req
->width
, image_width
);
779 req
->height
+= image_height
;
780 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
784 req
->width
+= PANEL_ICON_SPACING
;
786 req
->height
+= PANEL_ICON_SPACING
;
789 static gint
expose_icon_background(GtkWidget
*widget
,
790 GdkEventExpose
*event
,
793 if (((Icon
*) pi
)->selected
)
794 gtk_paint_flat_box(widget
->style
, widget
->window
,
795 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
796 &event
->area
, widget
, NULL
, 0, 0,
797 widget
->allocation
.width
,
798 widget
->allocation
.height
);
803 static gint
expose_icon(GtkWidget
*widget
,
804 GdkEventExpose
*event
,
807 return draw_icon(widget
, &event
->area
, pi
);
810 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, PanelIcon
*pi
)
814 Icon
*icon
= (Icon
*) pi
;
820 gdk_drawable_get_size(widget
->window
, &area
.width
, &area
.height
);
822 if (panel_want_show_text(pi
))
823 text_height
= pi
->label
->requisition
.height
;
825 g_return_val_if_fail(pi
->image
!= NULL
, FALSE
);
829 width
= gdk_pixbuf_get_width(image
);
830 height
= gdk_pixbuf_get_height(image
);
832 if (pi
->style
== TEXT_UNDER_ICON
)
834 image_x
= (area
.width
- width
) >> 1;
835 image_y
= (area
.height
- height
- text_height
) >> 1;
839 image_x
= PANEL_ICON_SPACING
- 2;
840 image_y
= (area
.height
- height
) >> 1;
843 gdk_pixbuf_render_to_drawable_alpha(
847 image_x
, image_y
, /* dest */
849 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
850 GDK_RGB_DITHER_NORMAL
, 0, 0);
852 if (icon
->item
->flags
& ITEM_FLAG_SYMLINK
)
854 gdk_pixbuf_render_to_drawable_alpha(im_symlink
->pixbuf
,
857 image_x
, image_y
+ 2, /* dest */
859 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
860 GDK_RGB_DITHER_NORMAL
, 0, 0);
862 if (icon
->item
->flags
& ITEM_FLAG_MOUNT_POINT
)
864 MaskedPixmap
*mp
= icon
->item
->flags
& ITEM_FLAG_MOUNTED
868 gdk_pixbuf_render_to_drawable_alpha(mp
->pixbuf
,
871 image_x
, image_y
+ 2, /* dest */
873 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
874 GDK_RGB_DITHER_NORMAL
, 0, 0);
879 static void panel_icon_wink(Icon
*icon
)
881 PanelIcon
*pi
= (PanelIcon
*) icon
;
883 wink_widget(pi
->widget
);
886 /* icon may be NULL if the event is on the background */
887 static void perform_action(Panel
*panel
, PanelIcon
*pi
, GdkEventButton
*event
)
890 Icon
*icon
= (Icon
*) pi
;
892 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
894 if (pi
&& pi
->socket
)
895 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
902 wink_widget(pi
->widget
);
903 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, FALSE
);
907 wink_widget(pi
->widget
);
908 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, TRUE
);
912 panel_show_menu(event
, pi
, panel
);
915 dnd_motion_start(MOTION_REPOSITION
);
917 case ACT_PRIME_AND_SELECT
:
919 icon_select_only(icon
);
920 dnd_motion_start(MOTION_READY_FOR_DND
);
922 case ACT_PRIME_AND_TOGGLE
:
923 icon_set_selected(icon
, !icon
->selected
);
924 dnd_motion_start(MOTION_READY_FOR_DND
);
926 case ACT_PRIME_FOR_DND
:
927 dnd_motion_start(MOTION_READY_FOR_DND
);
929 case ACT_TOGGLE_SELECTED
:
930 icon_set_selected(icon
, !icon
->selected
);
932 case ACT_SELECT_EXCL
:
933 icon_set_selected(icon
, TRUE
);
937 case ACT_CLEAR_SELECTION
:
939 icon_select_only(NULL
);
942 g_warning("Unsupported action : %d\n", action
);
947 static gint
panel_button_release(GtkWidget
*widget
,
948 GdkEventButton
*event
,
951 if (dnd_motion_release(event
))
954 perform_action(panel
, NULL
, event
);
959 static gint
panel_button_press(GtkWidget
*widget
,
960 GdkEventButton
*event
,
963 if (dnd_motion_press(panel
->window
, event
))
964 perform_action(panel
, NULL
, event
);
969 static gint
icon_button_release(GtkWidget
*widget
,
970 GdkEventButton
*event
,
973 if (pi
->socket
&& event
->button
== 1)
974 return FALSE
; /* Restart button */
976 if (dnd_motion_release(event
))
979 perform_action(pi
->panel
, pi
, event
);
984 static gint
icon_button_press(GtkWidget
*widget
,
985 GdkEventButton
*event
,
988 if (pi
->socket
&& event
->button
== 1)
989 return FALSE
; /* Restart button */
991 if (dnd_motion_press(widget
, event
))
992 perform_action(pi
->panel
, pi
, event
);
997 static void reposition_panel(GtkWidget
*window
,
998 GtkAllocation
*alloc
, Panel
*panel
)
1000 int x
= panel_geometry
.x
;
1001 int y
= panel_geometry
.y
;
1003 PanelSide side
= panel
->side
;
1005 if (side
== PANEL_LEFT
|| side
== PANEL_RIGHT
)
1007 if (side
== PANEL_RIGHT
)
1008 x
+= panel_geometry
.width
- alloc
->width
;
1010 if (current_panel
[PANEL_TOP
])
1012 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1013 y
+= win
->allocation
.height
;
1017 if (side
== PANEL_BOTTOM
)
1018 y
+= panel_geometry
.height
- alloc
->height
;
1020 gtk_window_move(GTK_WINDOW(panel
->window
), x
, y
);
1021 gdk_window_move(panel
->window
->window
, x
, y
);
1023 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
1025 if (current_panel
[PANEL_RIGHT
])
1026 gtk_widget_queue_resize(
1027 current_panel
[PANEL_RIGHT
]->window
);
1028 if (current_panel
[PANEL_LEFT
])
1029 gtk_widget_queue_resize(
1030 current_panel
[PANEL_LEFT
]->window
);
1033 /* Stop windows from maximising over all/part of us */
1036 guint32 left
, right
, top
, bottom
;
1037 guint32 left_start_y
, left_end_y
;
1038 guint32 right_start_y
, right_end_y
;
1039 guint32 top_start_x
, top_end_x
;
1040 guint32 bottom_start_x
, bottom_end_x
;
1041 } strut
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1043 if (o_panel_avoid
.int_value
== FALSE
)
1045 else if (panel
->side
== PANEL_TOP
||
1046 panel
->side
== PANEL_BOTTOM
)
1047 thickness
= alloc
->height
;
1049 thickness
= alloc
->width
;
1051 switch (panel
->side
)
1054 if (!o_panel_xinerama
.int_value
||
1056 [o_panel_monitor
.int_value
].left
)
1058 strut
.left
= panel_geometry
.x
+
1060 strut
.left_start_y
= panel_geometry
.y
;
1061 strut
.left_end_y
= panel_geometry
.y
+
1062 panel_geometry
.height
- 1;
1064 /* else there is (part of) a monitor
1072 if (!o_panel_xinerama
.int_value
||
1074 [o_panel_monitor
.int_value
].right
)
1076 /* RHS of monitor might not abut edge
1077 * of total virtual screen */
1078 strut
.right
= screen_width
-
1080 panel_geometry
.width
+
1082 strut
.right_start_y
= panel_geometry
.y
;
1083 strut
.right_end_y
= panel_geometry
.y
+
1084 panel_geometry
.height
- 1;
1086 /* else there is (part of) a monitor
1094 if (!o_panel_xinerama
.int_value
||
1096 [o_panel_monitor
.int_value
].top
)
1098 strut
.top
= panel_geometry
.y
+
1100 strut
.top_start_x
= panel_geometry
.x
;
1101 strut
.top_end_x
= panel_geometry
.x
+
1102 panel_geometry
.width
- 1;
1104 /* else there is (part of) a monitor above */
1110 default: /* PANEL_BOTTOM */
1111 if (!o_panel_xinerama
.int_value
||
1113 [o_panel_monitor
.int_value
].bottom
)
1115 /* Bottom of monitor might not abut
1116 * edge of total virtual screen */
1117 strut
.bottom
= screen_height
-
1119 panel_geometry
.height
+
1121 strut
.bottom_start_x
= panel_geometry
.x
;
1122 strut
.bottom_end_x
= panel_geometry
.x
+
1123 panel_geometry
.width
- 1;
1125 /* else there is (part of) a monitor below */
1135 /* Set full-width strut as well as partial in case
1136 * partial isn't supported by wm */
1137 gdk_property_change(panel
->window
->window
,
1138 gdk_atom_intern("_NET_WM_STRUT",
1140 gdk_atom_intern("CARDINAL", FALSE
),
1141 32, GDK_PROP_MODE_REPLACE
,
1142 (gchar
*) &strut
, 4);
1143 gdk_property_change(panel
->window
->window
,
1144 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1146 gdk_atom_intern("CARDINAL", FALSE
),
1147 32, GDK_PROP_MODE_REPLACE
,
1148 (gchar
*) &strut
, 12);
1152 gdk_property_delete(panel
->window
->window
,
1153 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1155 gdk_property_delete(panel
->window
->window
,
1156 gdk_atom_intern("_NET_WM_STRUT",
1163 /* Same as drag_set_dest(), but for panel icons */
1164 static void drag_set_panel_dest(PanelIcon
*pi
)
1166 GtkWidget
*obj
= pi
->widget
;
1168 make_drop_target(pi
->widget
, 0);
1170 g_signal_connect(obj
, "drag_motion", G_CALLBACK(drag_motion
), pi
);
1171 g_signal_connect(obj
, "drag_leave", G_CALLBACK(drag_leave
), pi
);
1172 g_signal_connect(obj
, "drag_end", G_CALLBACK(drag_end
), pi
);
1175 static gboolean
drag_motion(GtkWidget
*widget
,
1176 GdkDragContext
*context
,
1182 GdkDragAction action
= context
->suggested_action
;
1183 const char *type
= NULL
;
1184 Icon
*icon
= (Icon
*) pi
;
1185 DirItem
*item
= icon
->item
;
1186 int panel_x
, panel_y
;
1188 gdk_window_get_pointer(pi
->panel
->window
->window
,
1189 &panel_x
, &panel_y
, NULL
);
1190 motion_may_raise(pi
->panel
, panel_x
, panel_y
);
1192 /* Should we scroll the panel when dragging? */
1193 if (motion_state
!= MOTION_REPOSITION
)
1194 if (pi
->panel
->autoscroll_speed
== 0)
1195 may_autoscroll(pi
->panel
);
1198 goto out
; /* Can't drag a selection to itself */
1200 type
= dnd_motion_item(context
, &item
);
1202 if ((context
->actions
& GDK_ACTION_ASK
) && o_dnd_left_menu
.int_value
1203 && type
!= drop_dest_prog
)
1206 gdk_window_get_pointer(NULL
, NULL
, NULL
, &state
);
1207 if (state
& GDK_BUTTON1_MASK
)
1208 action
= GDK_ACTION_ASK
;
1214 /* We actually must pretend to accept the drop, even if the
1215 * directory isn't writeable, so that the spring-opening
1219 /* Don't allow drops to non-writeable directories */
1220 if (o_dnd_spring_open
.int_value
== FALSE
&&
1221 type
== drop_dest_dir
&&
1222 access(icon
->path
, W_OK
) != 0)
1227 g_dataset_set_data(context
, "drop_dest_type", (gpointer
) type
);
1230 gdk_drag_status(context
, action
, time
);
1231 g_dataset_set_data_full(context
, "drop_dest_path",
1232 g_strdup(icon
->path
), g_free
);
1233 if (type
== drop_dest_dir
)
1234 dnd_spring_load(context
, NULL
);
1236 if (dnd_highlight
&& dnd_highlight
!= pi
->widget
)
1238 gtk_drag_unhighlight(dnd_highlight
);
1239 dnd_highlight
= NULL
;
1242 if (dnd_highlight
== NULL
)
1244 gtk_drag_highlight(pi
->widget
);
1245 dnd_highlight
= pi
->widget
;
1249 return type
!= NULL
;
1253 static void add_uri_list(GtkWidget
*widget
,
1254 GdkDragContext
*context
,
1257 GtkSelectionData
*selection_data
,
1262 gboolean after
= FALSE
;
1265 if (!selection_data
->data
)
1268 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
1270 if (g_object_get_data(G_OBJECT(widget
), "after"))
1273 uris
= uri_list_to_glist(selection_data
->data
);
1275 for (next
= uris
; next
; next
= next
->next
)
1279 path
= get_local_path((guchar
*) next
->data
);
1282 panel_add_item(panel
, path
, NULL
, after
, NULL
);
1290 static void drag_end(GtkWidget
*widget
,
1291 GdkDragContext
*context
,
1294 if (tmp_icon_selected
)
1296 icon_select_only(NULL
);
1297 tmp_icon_selected
= FALSE
;
1301 static void drag_leave(GtkWidget
*widget
,
1302 GdkDragContext
*context
,
1306 panel_drag_leave(widget
, context
, time
, ((PanelIcon
*) icon
)->panel
);
1308 if (dnd_highlight
&& dnd_highlight
== widget
)
1310 gtk_drag_unhighlight(dnd_highlight
);
1311 dnd_highlight
= NULL
;
1317 /* Create XML icon nodes for these widgets.
1318 * Always frees the widgets list.
1320 static void make_widgets(xmlNodePtr side
, GList
*widgets
)
1324 for (next
= widgets
; next
; next
= next
->next
)
1329 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
1333 g_warning("Can't find Icon from widget\n");
1337 tree
= xmlNewTextChild(side
, NULL
, "icon", icon
->src_path
);
1339 xmlSetProp(tree
, "label", icon
->item
->leafname
);
1341 xmlSetProp(tree
, "shortcut", icon
->shortcut
);
1345 g_list_free(widgets
);
1348 void panel_save(Panel
*panel
)
1352 guchar
*save
= NULL
;
1353 guchar
*save_new
= NULL
;
1355 g_return_if_fail(panel
!= NULL
);
1357 if (strchr(panel
->name
, '/'))
1358 save
= g_strdup(panel
->name
);
1363 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
1364 save
= choices_find_path_save(leaf
, PROJECT
, TRUE
);
1371 doc
= xmlNewDoc("1.0");
1372 xmlDocSetRootElement(doc
, xmlNewDocNode(doc
, NULL
, "panel", NULL
));
1374 root
= xmlDocGetRootElement(doc
);
1375 make_widgets(xmlNewChild(root
, NULL
, "start", NULL
),
1376 gtk_container_get_children(GTK_CONTAINER(panel
->before
)));
1378 make_widgets(xmlNewChild(root
, NULL
, "end", NULL
),
1379 g_list_reverse(gtk_container_get_children(
1380 GTK_CONTAINER(panel
->after
))));
1382 save_new
= g_strconcat(save
, ".new", NULL
);
1383 if (save_xml_file(doc
, save_new
) || rename(save_new
, save
))
1384 delayed_error(_("Error saving panel %s: %s"),
1385 save
, g_strerror(errno
));
1393 /* Create a frame widget which can be used to add icons to the panel */
1394 static GtkWidget
*make_insert_frame(Panel
*panel
)
1397 GtkTargetEntry target_table
[] = {
1398 {"text/uri-list", 0, TARGET_URI_LIST
},
1401 frame
= gtk_frame_new(NULL
);
1402 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
1403 gtk_widget_set_size_request(frame
, 16, 16);
1405 g_signal_connect(frame
, "drag-motion",
1406 G_CALLBACK(insert_drag_motion
), panel
);
1407 g_signal_connect(frame
, "drag-leave",
1408 G_CALLBACK(panel_drag_leave
), panel
);
1410 g_signal_connect(frame
, "drag-data-received",
1411 G_CALLBACK(add_uri_list
), panel
);
1412 gtk_drag_dest_set(frame
,
1413 GTK_DEST_DEFAULT_ALL
,
1415 sizeof(target_table
) / sizeof(*target_table
),
1421 static gboolean
enter_icon(GtkWidget
*widget
,
1422 GdkEventCrossing
*event
,
1425 icon_may_update(icon
);
1426 panel_icon_set_tip((PanelIcon
*) icon
);
1431 static gint
panel_leave_event(GtkWidget
*widget
,
1432 GdkEventCrossing
*event
,
1435 GdkWindow
*pinboard
;
1437 if (event
->mode
!= GDK_CROSSING_NORMAL
)
1438 return FALSE
; /* Grab for menu, DnD, etc */
1440 pinboard
= pinboard_get_window();
1441 window_put_just_above(panel
->window
->window
, pinboard
);
1446 /* If (x, y) is at the edge of the panel then raise */
1447 static void motion_may_raise(Panel
*panel
, int x
, int y
)
1451 if (panel
->side
== PANEL_TOP
)
1453 else if (panel
->side
== PANEL_BOTTOM
)
1454 raise
= y
== panel
->window
->allocation
.height
- 1;
1455 else if (panel
->side
== PANEL_LEFT
)
1458 raise
= x
== panel
->window
->allocation
.width
- 1;
1461 gdk_window_raise(panel
->window
->window
);
1464 static gboolean
may_autoscroll(Panel
*panel
)
1466 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1467 gint max
, panel_x
, panel_y
, delta
, new;
1469 if (panel
->adj
->upper
<= panel
->adj
->page_size
)
1470 goto stop_scrolling
; /* Can see everything already */
1472 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
1477 max
= panel
->window
->allocation
.width
;
1478 if (panel_y
< 0 || panel_y
> panel
->window
->allocation
.height
)
1479 goto stop_scrolling
; /* Not over the panel */
1484 max
= panel
->window
->allocation
.height
;
1485 if (panel_x
< 0 || panel_x
> panel
->window
->allocation
.width
)
1486 goto stop_scrolling
; /* Not over the panel */
1489 if (delta
>= 20 && delta
<= max
- 20)
1490 goto stop_scrolling
; /* Not at either end */
1492 panel
->autoscroll_speed
= MIN(panel
->autoscroll_speed
+ 2, 200);
1494 new = panel
->adj
->value
- ((delta
< 20) ? panel
->autoscroll_speed
1495 : -panel
->autoscroll_speed
);
1496 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
1497 gtk_adjustment_set_value(panel
->adj
, new);
1499 panel
->autoscroll_to
= g_timeout_add(40,
1500 (GSourceFunc
) may_autoscroll
, panel
);
1505 panel
->autoscroll_speed
= 0;
1509 static gint
panel_motion_event(GtkWidget
*widget
,
1510 GdkEventMotion
*event
,
1513 motion_may_raise(panel
, event
->x
, event
->y
);
1515 if (motion_state
!= MOTION_REPOSITION
)
1516 if (panel
->autoscroll_speed
== 0)
1517 may_autoscroll(panel
);
1522 static gint
icon_motion_event(GtkWidget
*widget
,
1523 GdkEventMotion
*event
,
1526 Panel
*panel
= pi
->panel
;
1528 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1532 if (motion_state
== MOTION_READY_FOR_DND
)
1534 if (dnd_motion_moved(event
))
1535 start_drag(pi
, event
);
1538 else if (motion_state
!= MOTION_REPOSITION
)
1541 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1542 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1543 list
= g_list_concat(list
,
1544 gtk_container_get_children(GTK_CONTAINER(panel
->after
)));
1545 me
= g_list_find(list
, widget
);
1547 g_return_val_if_fail(me
!= NULL
, TRUE
);
1549 val
= horz
? event
->x_root
: event
->y_root
;
1557 prev
= GTK_WIDGET(me
->prev
->data
);
1561 gdk_window_get_origin(prev
->window
, &x
, &y
);
1563 if (val
<= (horz
? x
: y
))
1567 if (dir
== 0 && me
->next
)
1573 next
= GTK_WIDGET(me
->next
->data
);
1577 gdk_window_get_origin(next
->window
, &x
, &y
);
1579 gdk_drawable_get_size(next
->window
, &w
, &h
);
1584 if (val
>= (horz
? x
: y
)-1)
1586 if (next
== panel
->gap
)
1594 reposition_icon(pi
, g_list_index(list
, widget
) + dir
);
1599 static void reposition_icon_on_side(GtkWidget
*side
, GtkWidget
*widget
,
1604 list
= gtk_container_get_children(GTK_CONTAINER(side
));
1606 /* Want to move icon to the list in the given 'side'. Is it there
1610 if (!g_list_find(list
, widget
))
1613 gtk_grab_remove(widget
);
1614 gtk_widget_reparent(widget
, side
);
1615 dnd_motion_grab_pointer();
1616 gtk_grab_add(widget
);
1619 gtk_box_reorder_child(GTK_BOX(side
), widget
, index
);
1624 /* Move icon to this index in the complete widget list.
1625 * 0 makes the icon the left-most icon. The gap in the middle has
1626 * an index number, which allows you to specify that the icon should
1627 * go on the left or right side.
1629 static void reposition_icon(PanelIcon
*pi
, int index
)
1631 Panel
*panel
= pi
->panel
;
1632 GtkWidget
*widget
= pi
->widget
;
1636 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1637 before_len
= g_list_length(list
);
1640 if (index
<= before_len
)
1641 reposition_icon_on_side(panel
->before
, widget
, index
);
1643 reposition_icon_on_side(panel
->after
, widget
,
1644 index
- (before_len
+ 1));
1649 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
)
1651 GtkWidget
*widget
= pi
->widget
;
1652 Icon
*icon
= (Icon
*) pi
;
1654 if (!icon
->selected
)
1656 if (event
->state
& GDK_BUTTON1_MASK
)
1658 /* Select just this one */
1659 icon_select_only(icon
);
1660 tmp_icon_selected
= TRUE
;
1663 icon_set_selected(icon
, TRUE
);
1666 g_return_if_fail(icon_selection
!= NULL
);
1668 if (icon_selection
->next
== NULL
)
1669 drag_one_item(widget
, event
, icon
->path
, icon
->item
, NULL
);
1674 uri_list
= icon_create_uri_list();
1675 drag_selection(widget
, event
, uri_list
);
1680 static void applet_died(GtkWidget
*socket
)
1682 gboolean never_plugged
;
1684 never_plugged
= (!g_object_get_data(G_OBJECT(socket
), "lost_plug"))
1685 && !GTK_SOCKET(socket
)->plug_window
;
1690 _("Applet quit without ever creating a widget!"));
1691 gtk_widget_destroy(socket
);
1694 gtk_widget_unref(socket
);
1697 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1699 g_object_set_data(G_OBJECT(socket
), "lost_plug", "yes");
1701 gtk_widget_unref(socket
);
1703 gtk_widget_destroy(widget
); /* Remove from panel */
1706 panel_save(g_object_get_data(G_OBJECT(socket
), "panel"));
1709 /* Try to run this applet.
1712 * - No executable AppletRun:
1713 * icon->socket == NULL (unchanged) on return.
1715 * Otherwise, create socket (setting icon->socket) and ref it twice.
1717 * - AppletRun quits without connecting a plug:
1718 * On child death lost_plug is unset and socket is empty.
1720 * Report error and destroy widget (to 'socket destroyed').
1722 * - AppletRun quits while plug is in socket:
1723 * Unref socket once. Socket will be destroyed later.
1725 * - Socket is destroyed.
1726 * Set lost_plug = "yes" and remove widget from panel.
1729 static void run_applet(PanelIcon
*pi
)
1731 GError
*error
= NULL
;
1734 Icon
*icon
= (Icon
*) pi
;
1736 argv
[0] = (char *) make_path(icon
->path
, "AppletRun");
1738 if (access(argv
[0], X_OK
) != 0)
1741 pi
->socket
= gtk_socket_new();
1743 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->socket
);
1744 gtk_widget_show_all(pi
->socket
);
1745 gtk_widget_realize(pi
->socket
);
1747 /* Always get button-2 events so we can drag */
1748 XGrabButton(gdk_display
, Button2
, AnyModifier
,
1749 GDK_WINDOW_XWINDOW(pi
->socket
->window
),
1751 ButtonPressMask
| ButtonReleaseMask
| Button2MotionMask
,
1752 GrabModeAsync
, /* Pointer */
1753 GrabModeAsync
, /* Keyboard */
1758 PanelSide side
= pi
->panel
->side
;
1760 /* Set a hint to let applets position their menus correctly */
1761 pos
= g_strdup_printf("%s,%d",
1762 side
== PANEL_TOP
? "Top" :
1763 side
== PANEL_BOTTOM
? "Bottom" :
1764 side
== PANEL_LEFT
? "Left" :
1765 "Right", MENU_MARGIN(side
));
1766 gdk_property_change(pi
->socket
->window
,
1767 gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE
),
1768 gdk_atom_intern("STRING", FALSE
),
1769 8, GDK_PROP_MODE_REPLACE
,
1774 g_object_set_data(G_OBJECT(pi
->widget
), "icon", pi
);
1775 g_object_set_data(G_OBJECT(pi
->socket
), "panel", pi
->panel
);
1777 argv
[1] = g_strdup_printf("%ld",
1778 GDK_WINDOW_XWINDOW(pi
->socket
->window
));
1781 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_DO_NOT_REAP_CHILD
,
1782 NULL
, NULL
, &pid
, &error
))
1784 delayed_error(_("Error running applet:\n%s"), error
->message
);
1785 g_error_free(error
);
1786 gtk_widget_destroy(pi
->socket
);
1791 gtk_widget_ref(pi
->socket
);
1792 on_child_death(pid
, (CallbackFn
) applet_died
, pi
->socket
);
1794 gtk_widget_ref(pi
->socket
);
1795 g_signal_connect(pi
->socket
, "destroy",
1796 G_CALLBACK(socket_destroyed
), pi
->widget
);
1802 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
1804 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1806 req
->width
= panel_geometry
.width
;
1807 req
->height
+= EDGE_WIDTH
;
1811 int h
= panel_geometry
.height
;
1813 if (current_panel
[PANEL_TOP
])
1815 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1816 h
-= win
->allocation
.height
;
1819 if (current_panel
[PANEL_BOTTOM
])
1821 GtkWidget
*win
= current_panel
[PANEL_BOTTOM
]->window
;
1822 h
-= win
->allocation
.height
;
1826 req
->width
+= EDGE_WIDTH
;
1830 static void update_side(GtkWidget
*side
)
1834 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
1835 for (next
= kids
; next
; next
= next
->next
)
1838 pi
= g_object_get_data(next
->data
, "icon");
1839 panel_icon_set_tip(pi
);
1844 /* Tips or style has changed -- update everything on this panel */
1845 static void panel_set_style(Panel
*panel
)
1847 update_side(panel
->before
);
1848 update_side(panel
->after
);
1849 gtk_widget_queue_resize(panel
->window
);
1852 static gboolean
recreate_panels(char **names
)
1856 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1860 panel_new(names
[i
], i
);
1870 static void update_side_size(GtkWidget
*side
)
1874 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
1875 for (next
= kids
; next
; next
= next
->next
)
1878 pi
= g_object_get_data(next
->data
, "icon");
1879 gtk_widget_queue_resize(pi
->widget
);
1884 /* Update panel size and redraw */
1885 static void panel_update(Panel
*panel
)
1887 update_side_size(panel
->before
);
1888 update_side_size(panel
->after
);
1889 gtk_widget_queue_resize(panel
->window
);
1890 gtk_widget_queue_draw(panel
->window
);
1893 static void panel_style_changed(void)
1897 if (o_override_redirect
.has_changed
)
1901 names
= g_new(char *, PANEL_NUMBER_OF_SIDES
);
1903 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1905 Panel
*panel
= current_panel
[i
];
1906 names
[i
] = panel
? g_strdup(panel
->name
) : NULL
;
1910 g_idle_add((GtkFunction
) recreate_panels
, names
);
1913 if (o_panel_style
.has_changed
)
1915 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1917 if (current_panel
[i
])
1918 panel_set_style(current_panel
[i
]);
1921 if (o_panel_width
.has_changed
)
1923 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1925 if (current_panel
[i
])
1926 panel_update(current_panel
[i
]);
1930 if (o_panel_xinerama
.has_changed
|| o_panel_monitor
.has_changed
||
1931 o_panel_avoid
.has_changed
)
1933 if (panel_check_xinerama() || o_panel_avoid
.has_changed
)
1935 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
1937 if (current_panel
[i
])
1940 current_panel
[i
]->window
,
1944 gtk_widget_queue_resize(
1945 current_panel
[i
]->window
);
1952 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
1955 int x
, y
, width
, height
;
1957 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1959 width
= panel_geometry
.width
;
1960 height
= EDGE_WIDTH
;
1963 if (panel
->side
== PANEL_BOTTOM
)
1966 y
= widget
->allocation
.height
- EDGE_WIDTH
;
1971 height
= panel_geometry
.height
;
1974 if (panel
->side
== PANEL_RIGHT
)
1977 x
= widget
->allocation
.width
- EDGE_WIDTH
;
1980 gdk_draw_rectangle(widget
->window
,
1981 widget
->style
->fg_gc
[GTK_STATE_NORMAL
], TRUE
,
1982 x
, y
, width
, height
);
1987 static gpointer parent_class
;
1989 static void panel_icon_destroy(Icon
*icon
)
1991 PanelIcon
*pi
= (PanelIcon
*) icon
;
1993 g_return_if_fail(pi
!= NULL
);
1996 g_object_unref(pi
->image
);
1998 g_return_if_fail(pi
->widget
!= NULL
);
2000 gtk_widget_destroy(pi
->widget
);
2003 static void panel_remove_items(void)
2007 g_return_if_fail(icon_selection
!= NULL
);
2009 panel
= ((PanelIcon
*) icon_selection
->data
)->panel
;
2011 while (icon_selection
)
2012 icon_destroy((Icon
*) icon_selection
->data
);
2017 static void panel_icon_redraw(Icon
*icon
)
2019 gtk_widget_set_state(((PanelIcon
*) icon
)->widget
,
2020 icon
->selected
? GTK_STATE_SELECTED
2021 : GTK_STATE_NORMAL
);
2022 gtk_widget_queue_draw(PANEL_ICON(icon
)->widget
);
2025 static void panel_icon_update(Icon
*icon
)
2027 PanelIcon
*pi
= (PanelIcon
*) icon
;
2029 gtk_widget_queue_draw(pi
->widget
);
2030 gtk_label_set_text(GTK_LABEL(pi
->label
), icon
->item
->leafname
);
2031 panel_icon_set_tip(pi
);
2032 panel_save(pi
->panel
);
2035 /* The point of this is to clear the selection if the existing icons
2036 * aren't from the same panel...
2038 static gboolean
panel_icon_same_group(Icon
*icon
, Icon
*other
)
2040 if (IS_PANEL_ICON(other
))
2042 PanelIcon
*a
= (PanelIcon
*) icon
;
2043 PanelIcon
*b
= (PanelIcon
*) other
;
2045 return a
->panel
== b
->panel
;
2051 static void panel_icon_class_init(gpointer gclass
, gpointer data
)
2053 IconClass
*icon
= (IconClass
*) gclass
;
2055 parent_class
= g_type_class_peek_parent(gclass
);
2057 icon
->destroy
= panel_icon_destroy
;
2058 icon
->redraw
= panel_icon_redraw
;
2059 icon
->update
= panel_icon_update
;
2060 icon
->remove_items
= panel_remove_items
;
2061 icon
->same_group
= panel_icon_same_group
;
2062 icon
->wink
= panel_icon_wink
;
2065 static void panel_icon_init(GTypeInstance
*object
, gpointer gclass
)
2067 PanelIcon
*pi
= (PanelIcon
*) object
;
2073 pi
->style
= TEXT_UNDER_ICON
;
2076 static GType
panel_icon_get_type(void)
2078 static GType type
= 0;
2082 static const GTypeInfo info
=
2084 sizeof (PanelIconClass
),
2085 NULL
, /* base_init */
2086 NULL
, /* base_finalise */
2087 panel_icon_class_init
,
2088 NULL
, /* class_finalise */
2089 NULL
, /* class_data */
2091 0, /* n_preallocs */
2095 type
= g_type_register_static(icon_get_type(),
2096 "PanelIcon", &info
, 0);
2102 static PanelIcon
*panel_icon_new(Panel
*panel
,
2103 const char *pathname
,
2109 pi
= g_object_new(panel_icon_get_type(), NULL
);
2112 icon_set_path(icon
, pathname
, name
);
2118 static gboolean
panel_want_show_text(PanelIcon
*pi
)
2120 Icon
*icon
= (Icon
*) pi
;
2122 if (!icon
->item
->leafname
[0])
2125 if (o_panel_style
.int_value
== SHOW_BOTH
)
2127 if (o_panel_style
.int_value
== SHOW_ICON
)
2130 if (icon
->item
->flags
& ITEM_FLAG_APPDIR
)
2136 static void panel_position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
,
2137 gboolean
*push_in
, gpointer data
)
2139 int *pos
= (int *) data
;
2140 GtkRequisition requisition
;
2141 int margin
= pos
[2];
2143 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
2146 *x
= screen_width
- margin
- requisition
.width
;
2147 else if (pos
[0] == -2)
2150 *x
= pos
[0] - (requisition
.width
>> 2);
2153 *y
= screen_height
- margin
- requisition
.height
;
2154 else if (pos
[1] == -2)
2157 *y
= pos
[1] - (requisition
.height
>> 2);
2159 *x
= CLAMP(*x
, 0, screen_width
- requisition
.width
);
2160 *y
= CLAMP(*y
, 0, screen_height
- requisition
.height
);
2165 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
)
2167 PanelSide side
= panel
->side
;
2170 pos
[0] = event
->x_root
;
2171 pos
[1] = event
->y_root
;
2172 pos
[2] = MENU_MARGIN(side
);
2174 icon_prepare_menu((Icon
*) pi
, FALSE
);
2176 if (side
== PANEL_LEFT
)
2178 else if (side
== PANEL_RIGHT
)
2181 if (side
== PANEL_TOP
)
2183 else if (side
== PANEL_BOTTOM
)
2186 gtk_menu_popup(GTK_MENU(icon_menu
), NULL
, NULL
,
2187 panel_position_menu
,
2188 (gpointer
) pos
, event
->button
, event
->time
);
2191 /* Note: also called from icon handler */
2192 static gboolean
panel_drag_motion(GtkWidget
*widget
,
2193 GdkDragContext
*context
,
2199 int panel_x
, panel_y
;
2201 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2203 motion_may_raise(panel
, panel_x
, panel_y
);
2204 gdk_drag_status(context
, 0, time
);
2209 static gboolean
insert_drag_motion(GtkWidget
*widget
,
2210 GdkDragContext
*context
,
2216 int panel_x
, panel_y
;
2218 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2219 motion_may_raise(panel
, panel_x
, panel_y
);
2224 /* Note: also called from icon handler */
2225 static void panel_drag_leave(GtkWidget
*widget
,
2226 GdkDragContext
*context
,
2230 GdkWindow
*pinboard
, *window
;
2231 GtkAllocation
*alloc
= &panel
->window
->allocation
;
2234 window
= panel
->window
->window
;
2235 gdk_window_get_pointer(window
, &x
, &y
, NULL
);
2236 if (x
< 0 || y
< 0 || x
> alloc
->width
|| y
> alloc
->height
)
2238 pinboard
= pinboard_get_window();
2239 window_put_just_above(panel
->window
->window
, pinboard
);
2243 static gboolean
panel_check_xinerama(void)
2245 gint old_monitor
= panel_monitor
;
2249 if (o_panel_xinerama
.int_value
)
2251 if (o_panel_monitor
.int_value
< n_monitors
)
2253 panel_monitor
= o_panel_monitor
.int_value
;
2257 g_warning(_("Xinerama monitor %d unavailable"),
2258 o_panel_monitor
.int_value
);
2262 if (panel_monitor
== -1)
2264 panel_geometry
.x
= panel_geometry
.y
= 0;
2265 panel_geometry
.width
= screen_width
;
2266 panel_geometry
.height
= screen_height
;
2270 panel_geometry
= monitor_geom
[panel_monitor
];
2273 return old_monitor
!= panel_monitor
;
2276 static GList
*build_monitor_number(Option
*option
, xmlNode
*node
, guchar
*label
)
2280 adj
= gtk_adjustment_new(MAX(0, panel_monitor
),
2281 0, n_monitors
- 1, 1, 10, 1);
2282 return build_numentry_base(option
, node
, label
, GTK_ADJUSTMENT(adj
));