2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* panel.c - code for dealing with panel windows */
30 #include <libxml/parser.h>
42 #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 enum {TEXT_BESIDE_ICON
, TEXT_UNDER_ICON
};
65 static gboolean tmp_icon_selected
= FALSE
; /* When dragging */
67 typedef struct _PanelIconClass PanelIconClass
;
68 typedef struct _PanelIcon PanelIcon
;
70 struct _PanelIconClass
{
79 GtkWidget
*widget
; /* The drawing area for the icon */
81 GtkWidget
*socket
; /* For applets */
86 #define PANEL_ICON(obj) GTK_CHECK_CAST((obj), panel_icon_get_type(), PanelIcon)
87 #define IS_PANEL_ICON(obj) \
88 G_TYPE_CHECK_INSTANCE_TYPE((obj), panel_icon_get_type())
90 Panel
*current_panel
[PANEL_NUMBER_OF_SIDES
];
92 /* NULL => Not loading a panel */
93 static Panel
*loading_panel
= NULL
;
95 static GtkWidget
*panel_options_dialog
= NULL
;
97 /* Static prototypes */
98 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
);
99 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
);
100 static const char *pan_from_file(gchar
*line
);
101 static gint
icon_button_release(GtkWidget
*widget
,
102 GdkEventButton
*event
,
104 static gint
icon_button_press(GtkWidget
*widget
,
105 GdkEventButton
*event
,
107 static void reposition_panel(GtkWidget
*window
,
108 GtkAllocation
*alloc
, Panel
*panel
);
109 static gint
expose_icon(GtkWidget
*widget
,
110 GdkEventExpose
*event
,
112 static gint
draw_icon(GtkWidget
*widget
,
113 GdkRectangle
*badarea
,
115 static gint
panel_button_release(GtkWidget
*widget
,
116 GdkEventButton
*event
,
118 static gint
panel_button_press(GtkWidget
*widget
,
119 GdkEventButton
*event
,
121 static void panel_post_resize(GtkWidget
*box
,
122 GtkRequisition
*req
, Panel
*panel
);
123 static void drag_set_panel_dest(PanelIcon
*pi
);
124 static void add_uri_list(GtkWidget
*widget
,
125 GdkDragContext
*context
,
128 GtkSelectionData
*selection_data
,
132 static void panel_add_item(Panel
*panel
,
136 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 GList
*build_monitor_number(Option
*option
,
201 xmlNode
*node
, guchar
*label
);
202 static gboolean
may_autoscroll(Panel
*panel
);
203 static void panel_update_geometry(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
;
216 static Option o_panel_is_dock
;
218 static gint panel_monitor
= -1;
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
);
235 option_add_int(&o_panel_is_dock
, "panel_is_dock", FALSE
);
237 option_add_notify(panel_style_changed
);
239 option_register_widget("monitor-number", build_monitor_number
);
242 /* Return a free edge for a new panel.
243 * If no edge is free, returns PANEL_BOTTOM.
245 static PanelSide
find_free_side()
247 if (!current_panel
[PANEL_BOTTOM
])
250 if (!current_panel
[PANEL_TOP
])
253 if (!current_panel
[PANEL_LEFT
])
256 if (!current_panel
[PANEL_RIGHT
])
262 /* Returns TRUE and sets *target if the property exists, otherwise returns
263 * FALSE and leaves *target unchanged */
264 static gboolean
get_int_prop(xmlNodePtr node
, const char *name
, int *target
)
266 char *prop
= xmlGetProp(node
, name
);
270 *target
= atoi(prop
);
277 static void set_int_prop(xmlNodePtr node
, const char *name
, int value
)
281 sprintf(prop
, "%d", value
);
282 xmlSetProp(node
, name
, prop
);
285 static void panel_load_options_from_xml(Panel
*panel
, xmlDocPtr doc
)
290 root
= xmlDocGetRootElement(doc
);
291 options
= get_subnode(root
, NULL
, "options");
294 get_int_prop(options
, "style", &panel
->style
);
295 get_int_prop(options
, "width", &panel
->width
);
296 get_int_prop(options
, "avoid", &panel
->avoid
);
297 get_int_prop(options
, "xinerama", &panel
->xinerama
);
298 get_int_prop(options
, "monitor", &panel
->monitor
);
301 /* 'name' may be NULL or "" to remove the panel */
302 Panel
*panel_new(const gchar
*name
, PanelSide side
)
306 GtkWidget
*vp
, *box
, *frame
, *align
;
307 xmlDocPtr panel_doc
= NULL
;
308 gboolean need_resave
= FALSE
;
310 g_return_val_if_fail(side
== PANEL_DEFAULT_SIDE
||
311 (side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
), NULL
);
312 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
314 if (name
&& *name
== '\0')
319 else if (strchr(name
, '/'))
320 load_path
= g_strdup(name
);
325 leaf
= g_strconcat("pan_", name
, NULL
);
326 load_path
= choices_find_xdg_path_load(leaf
, PROJECT
, SITE
);
330 if (load_path
&& access(load_path
, F_OK
) == 0)
335 panel_doc
= xmlParseFile(load_path
);
336 root
= xmlDocGetRootElement(panel_doc
);
338 saved_side
= xmlGetProp(root
, "side");
342 old_side
= panel_name_to_side(saved_side
);
345 if (side
== PANEL_DEFAULT_SIDE
)
347 else if (side
!= old_side
)
354 if (side
== PANEL_DEFAULT_SIDE
)
355 side
= find_free_side();
357 if (current_panel
[side
])
362 gtk_widget_destroy(current_panel
[side
]->window
);
368 if (name
== NULL
|| *name
== '\0')
371 panel
= g_new(Panel
, 1);
372 panel
->name
= g_strdup(name
);
374 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
375 panel
->autoscroll_speed
= 0;
377 /* These are fallbacks from legacy global options */
378 panel
->style
= o_panel_style
.int_value
;
379 panel
->width
= o_panel_width
.int_value
;
380 panel
->xinerama
= o_panel_xinerama
.int_value
;
381 panel
->monitor
= o_panel_monitor
.int_value
;
382 panel
->avoid
= o_panel_avoid
.int_value
;
384 /* Now try to load options from this panel's XML */
387 panel_load_options_from_xml(panel
, panel_doc
);
391 /* Otherwise ensure old settings are migrated */
395 panel_update_geometry(panel
);
397 gtk_window_set_resizable(GTK_WINDOW(panel
->window
), FALSE
);
398 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
399 gtk_widget_set_name(panel
->window
, "rox-panel");
400 gtk_widget_set_events(panel
->window
,
401 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
402 GDK_POINTER_MOTION_MASK
| GDK_LEAVE_NOTIFY_MASK
);
404 /* We make the panel a drop target only so that we can auto-raise! */
405 gtk_drag_dest_set(panel
->window
, 0, NULL
, 0, GDK_ACTION_PRIVATE
);
406 g_signal_connect(panel
->window
, "drag_leave",
407 G_CALLBACK(panel_drag_leave
), panel
);
408 g_signal_connect(panel
->window
, "drag_motion",
409 G_CALLBACK(panel_drag_motion
), panel
);
411 g_signal_connect(panel
->window
, "delete-event",
412 G_CALLBACK(panel_delete
), panel
);
413 g_signal_connect(panel
->window
, "destroy",
414 G_CALLBACK(panel_destroyed
), panel
);
415 g_signal_connect(panel
->window
, "button_press_event",
416 G_CALLBACK(panel_button_press
), panel
);
417 g_signal_connect(panel
->window
, "button_release_event",
418 G_CALLBACK(panel_button_release
), panel
);
419 g_signal_connect(panel
->window
, "motion-notify-event",
420 G_CALLBACK(panel_motion_event
), panel
);
421 g_signal_connect(panel
->window
, "leave-notify-event",
422 G_CALLBACK(panel_leave_event
), panel
);
424 if (panel
->side
== PANEL_RIGHT
)
425 align
= gtk_alignment_new(1.0, 0.0, 0.0, 1.0);
426 else if (panel
->side
== PANEL_BOTTOM
)
427 align
= gtk_alignment_new(0.0, 1.0, 1.0, 0.0);
428 else if (panel
->side
== PANEL_TOP
)
429 align
= gtk_alignment_new(0.0, 0.0, 1.0, 0.0);
431 align
= gtk_alignment_new(0.0, 0.0, 0.0, 1.0);
433 gtk_container_add(GTK_CONTAINER(panel
->window
), align
);
435 vp
= gtk_viewport_new(NULL
, NULL
);
436 gtk_container_set_resize_mode(GTK_CONTAINER(vp
), GTK_RESIZE_PARENT
);
437 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_NONE
);
438 gtk_container_add(GTK_CONTAINER(align
), vp
);
440 g_signal_connect(align
, "expose-event",
441 G_CALLBACK(draw_panel_edge
), panel
);
443 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
445 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
446 box
= gtk_hbox_new(FALSE
, 0);
447 panel
->before
= gtk_hbox_new(FALSE
, 0);
448 panel
->after
= gtk_hbox_new(FALSE
, 0);
452 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
453 box
= gtk_vbox_new(FALSE
, 0);
454 panel
->before
= gtk_vbox_new(FALSE
, 0);
455 panel
->after
= gtk_vbox_new(FALSE
, 0);
458 gtk_container_add(GTK_CONTAINER(vp
), box
);
459 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
460 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
462 frame
= make_insert_frame(panel
);
463 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
465 /* This is used so that we can find the middle easily! */
466 panel
->gap
= gtk_event_box_new();
467 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
469 frame
= make_insert_frame(panel
);
470 g_object_set_data(G_OBJECT(frame
), "after", "yes");
471 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
473 if (o_panel_is_dock
.int_value
)
474 gtk_window_set_type_hint(GTK_WINDOW(panel
->window
),
475 GDK_WINDOW_TYPE_HINT_DOCK
);
477 gtk_widget_realize(panel
->window
);
478 make_panel_window(panel
->window
);
479 gtk_window_stick(GTK_WINDOW(panel
->window
));
481 gtk_widget_show_all(align
);
483 loading_panel
= panel
;
486 panel_load_from_xml(panel
, panel_doc
);
487 xmlFreeDoc(panel_doc
);
494 parse_file(load_path
, pan_from_file
);
495 info_message(_("Your old panel file has been "
496 "converted to the new XML format."));
501 /* Don't scare users with an empty panel... */
504 panel_add_item(panel
, "~", "Home", FALSE
, NULL
, NULL
, FALSE
);
506 apps
= pathdup(make_path(app_dir
, ".."));
509 panel_add_item(panel
, apps
, "Apps", FALSE
, NULL
, NULL
, FALSE
);
513 loading_panel
= NULL
;
516 current_panel
[side
] = panel
;
518 gtk_widget_queue_resize(box
);
519 g_signal_connect(panel
->window
, "size-request",
520 G_CALLBACK(panel_post_resize
), panel
);
521 g_signal_connect(panel
->window
, "size-allocate",
522 G_CALLBACK(reposition_panel
), panel
);
525 gdk_window_lower(panel
->window
->window
);
526 gtk_widget_show(panel
->window
);
527 /* This has no effect until after window is showing; GTK+ bug? */
528 keep_below(panel
->window
->window
, TRUE
);
533 pinboard
= pinboard_get_window();
534 /* (if pinboard is NULL, will go right to the back) */
535 window_put_just_above(panel
->window
->window
, pinboard
);
541 /* Externally visible function to add an item to a panel */
542 gboolean
panel_add(PanelSide side
,
543 const gchar
*path
, const gchar
*label
, gboolean after
, const gchar
*shortcut
, const gchar
*args
,
546 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
548 g_return_val_if_fail(current_panel
[side
] != NULL
, FALSE
);
550 panel_add_item(current_panel
[side
], path
, label
, after
, shortcut
, args
, locked
);
555 /* Add the area covered by the panels to the region */
556 void panel_mark_used(GdkRegion
*used
)
560 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
562 Panel
*panel
= current_panel
[i
];
568 gdk_window_get_root_origin(panel
->window
->window
,
570 rect
.width
= panel
->window
->allocation
.width
;
571 rect
.height
= panel
->window
->allocation
.height
;
573 gdk_region_union_with_rect(used
, &rect
);
577 /* On xrandr screen size changes, update all panels */
578 void panel_update_size(void)
582 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
584 if (current_panel
[i
])
586 reposition_panel(current_panel
[i
]->window
,
587 ¤t_panel
[i
]->window
->allocation
,
589 gtk_widget_queue_resize(current_panel
[i
]->window
);
594 /****************************************************************
595 * INTERNAL FUNCTIONS *
596 ****************************************************************/
598 /* User has tried to close the panel via the window manager - confirm */
599 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
601 return !confirm(_("You have tried to close a panel via the window "
602 "manager - I usually find that this is accidental... "
604 GTK_STOCK_CLOSE
, NULL
);
607 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
609 if (panel_options_dialog
)
611 Panel
*dlg_panel
= g_object_get_data(G_OBJECT(panel_options_dialog
),
614 if (dlg_panel
== panel
)
615 gtk_widget_destroy(panel_options_dialog
);
618 if (current_panel
[panel
->side
] == panel
)
619 current_panel
[panel
->side
] = NULL
;
621 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
623 if (current_panel
[PANEL_RIGHT
])
624 gtk_widget_queue_resize(
625 current_panel
[PANEL_RIGHT
]->window
);
626 if (current_panel
[PANEL_LEFT
])
627 gtk_widget_queue_resize(
628 current_panel
[PANEL_LEFT
]->window
);
631 if (panel
->autoscroll_speed
)
632 g_source_remove(panel
->autoscroll_to
);
640 static void panel_load_side(Panel
*panel
, xmlNodePtr side
, gboolean after
)
643 char *label
, *path
, *shortcut
, *args
, *tmp
;
646 for (node
= side
->xmlChildrenNode
; node
; node
= node
->next
)
648 if (node
->type
!= XML_ELEMENT_NODE
)
650 if (strcmp(node
->name
, "icon") != 0)
653 label
= xmlGetProp(node
, "label");
655 label
= g_strdup("<missing label>");
656 path
= xmlNodeGetContent(node
);
658 path
= g_strdup("<missing path>");
659 shortcut
= xmlGetProp(node
, "shortcut");
660 args
= xmlGetProp(node
, "args");
661 tmp
= xmlGetProp(node
, "locked");
664 locked
= text_to_boolean(tmp
, FALSE
);
670 panel_add_item(panel
, path
, label
, after
, shortcut
, args
, locked
);
679 /* Create one panel icon for each icon in the doc */
680 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
)
684 root
= xmlDocGetRootElement(doc
);
685 panel_load_side(panel
, get_subnode(root
, NULL
, "start"), FALSE
);
686 panel_load_side(panel
, get_subnode(root
, NULL
, "end"), TRUE
);
689 /* Called for each line in the config file while loading a new panel */
690 static const char *pan_from_file(gchar
*line
)
694 g_return_val_if_fail(line
!= NULL
, NULL
);
695 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
700 sep
= strpbrk(line
, "<>");
702 return _("Missing < or > in panel config file");
705 leaf
= g_strndup(line
, sep
- line
);
709 panel_add_item(loading_panel
, sep
+ 1, leaf
, sep
[0] == '>',
717 static gboolean
icon_pointer_in(GtkWidget
*widget
,
718 GdkEventCrossing
*event
,
721 gtk_widget_set_state(widget
,
722 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_PRELIGHT
);
727 static gboolean
icon_pointer_out(GtkWidget
*widget
,
728 GdkEventCrossing
*event
,
731 gtk_widget_set_state(widget
,
732 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_NORMAL
);
737 static void panel_icon_destroyed(PanelIcon
*pi
)
739 g_return_if_fail(pi
->widget
!= NULL
);
746 /* Set the tooltip AND hide/show the label */
747 static void panel_icon_set_tip(PanelIcon
*pi
)
751 Icon
*icon
= (Icon
*) pi
;
753 g_return_if_fail(pi
!= NULL
);
757 if (panel_want_show_text(pi
))
758 gtk_widget_show(pi
->label
);
760 gtk_widget_hide(pi
->label
);
766 ai
= appinfo_get(icon
->path
, icon
->item
);
768 if (ai
&& ((node
= xml_get_section(ai
, NULL
, "Summary"))))
771 str
= xmlNodeListGetString(node
->doc
,
772 node
->xmlChildrenNode
, 1);
775 gtk_tooltips_set_tip(tooltips
, pi
->widget
, str
, NULL
);
779 else if ((!panel_want_show_text(pi
)) && !pi
->socket
)
781 if (icon
->item
->leafname
&& icon
->item
->leafname
[0])
782 gtk_tooltips_set_tip(tooltips
, pi
->widget
,
783 icon
->item
->leafname
, NULL
);
786 gtk_tooltips_set_tip(tooltips
, pi
->widget
, NULL
, NULL
);
792 /* Add an icon with this path to the panel. If after is TRUE then the
793 * icon is added to the right/bottom end of the panel.
795 * If name is NULL a suitable name is taken from path.
797 static void panel_add_item(Panel
*panel
,
801 const gchar
*shortcut
,
809 g_return_if_fail(panel
!= NULL
);
810 g_return_if_fail(path
!= NULL
);
812 widget
= gtk_event_box_new();
813 gtk_widget_set_events(widget
,
814 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
815 GDK_BUTTON3_MOTION_MASK
|
816 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
817 GDK_BUTTON_RELEASE_MASK
);
819 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
820 widget
, FALSE
, TRUE
, 0);
822 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
824 gtk_widget_realize(widget
);
826 pi
= panel_icon_new(panel
, path
, name
);
829 /* Widget takes the initial ref of Icon */
830 g_object_set_data(G_OBJECT(widget
), "icon", pi
);
833 g_object_ref(widget
);
835 gtk_widget_set_name(pi
->widget
, "panel-icon");
837 g_signal_connect_swapped(widget
, "destroy",
838 G_CALLBACK(panel_icon_destroyed
), pi
);
840 if (icon
->item
->base_type
== TYPE_DIRECTORY
)
843 g_signal_connect(widget
, "button_release_event",
844 G_CALLBACK(icon_button_release
), pi
);
845 g_signal_connect(widget
, "button_press_event",
846 G_CALLBACK(icon_button_press
), pi
);
847 g_signal_connect(widget
, "motion-notify-event",
848 G_CALLBACK(icon_motion_event
), pi
);
849 g_signal_connect(widget
, "enter-notify-event",
850 G_CALLBACK(icon_pointer_in
), pi
);
851 g_signal_connect(widget
, "leave-notify-event",
852 G_CALLBACK(icon_pointer_out
), pi
);
856 g_signal_connect(widget
, "enter-notify-event",
857 G_CALLBACK(enter_icon
), pi
);
858 g_signal_connect_after(widget
, "expose_event",
859 G_CALLBACK(expose_icon
), pi
);
860 g_signal_connect(widget
, "drag_data_get",
861 G_CALLBACK(drag_data_get
), NULL
);
863 g_signal_connect(widget
, "size_request",
864 G_CALLBACK(size_request
), pi
);
866 drag_set_panel_dest(pi
);
868 pi
->label
= gtk_label_new(icon
->item
->leafname
);
869 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->label
);
870 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
871 gtk_misc_set_padding(GTK_MISC(pi
->label
), 1, 2);
874 icon_set_shortcut(icon
, shortcut
);
875 icon_set_arguments(icon
, args
);
876 icon
->locked
= locked
;
881 panel_icon_set_tip(pi
);
882 gtk_widget_show(widget
);
885 static gboolean
remove_item_from_side(GtkWidget
*container
, const gchar
*path
,
889 gboolean found
= FALSE
;
891 kids
= gtk_container_get_children(GTK_CONTAINER(container
));
893 for (next
= kids
; next
; next
= next
->next
)
896 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
900 if ((!path
|| strcmp(path
, icon
->src_path
) == 0) &&
901 (!label
|| strcmp(label
, icon
->item
->leafname
)==0))
903 icon
->locked
= FALSE
;
915 /* Remove an item with this path. If more than one item matches, only
916 * one is removed. If label is not NULL then it must also match the item.
917 * Returns TRUE if an item was successfully removed.
919 gboolean
panel_remove_item(PanelSide side
, const gchar
*path
,
924 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
926 g_return_val_if_fail(path
!= NULL
|| label
!= NULL
, FALSE
);
928 panel
= current_panel
[side
];
931 g_warning("No panel on this side of the screen!");
935 if (remove_item_from_side(panel
->before
, path
, label
) ||
936 remove_item_from_side(panel
->after
, path
, label
))
943 g_warning("Panel item path='%s', label='%s' not found", path
, label
);
947 /* Called when Gtk+ wants to know how much space an icon needs.
948 * 'req' is already big enough for the label, if shown.
950 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
)
952 Icon
*icon
= (Icon
*) pi
;
953 gboolean horz
= (pi
->panel
->side
== PANEL_TOP
||
954 pi
->panel
->side
== PANEL_BOTTOM
);
956 int max_height
= 100;
957 int image_width
, image_height
;
958 Panel
*panel
= pi
->panel
;
961 max_height
= panel
->width
- req
->height
;
963 max_width
= MAX(panel
->width
, req
->width
);
965 /* TODO: really need to recreate? */
967 g_object_unref(pi
->image
);
969 pi
->image
= scale_pixbuf(di_image(icon
->item
)->src_pixbuf
,
970 MAX(20, max_width
), MAX(20, max_height
));
972 image_width
= gdk_pixbuf_get_width(pi
->image
);
973 image_height
= gdk_pixbuf_get_height(pi
->image
);
975 if (req
->height
> 0 && max_height
< req
->height
)
977 pi
->style
= TEXT_BESIDE_ICON
;
978 req
->width
+= image_width
;
979 req
->height
= MAX(req
->height
, image_height
);
980 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 1, 0.5);
984 pi
->style
= TEXT_UNDER_ICON
;
985 req
->width
= MAX(req
->width
, image_width
);
986 req
->height
+= image_height
;
987 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
991 req
->width
+= PANEL_ICON_SPACING
;
993 req
->height
+= PANEL_ICON_SPACING
;
996 static gint
expose_icon(GtkWidget
*widget
,
997 GdkEventExpose
*event
,
1000 return draw_icon(widget
, &event
->area
, pi
);
1003 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, PanelIcon
*pi
)
1007 Icon
*icon
= (Icon
*) pi
;
1011 int text_height
= 0;
1013 gdk_drawable_get_size(widget
->window
, &area
.width
, &area
.height
);
1015 if (panel_want_show_text(pi
))
1016 text_height
= pi
->label
->requisition
.height
;
1018 g_return_val_if_fail(pi
->image
!= NULL
, FALSE
);
1022 width
= gdk_pixbuf_get_width(image
);
1023 height
= gdk_pixbuf_get_height(image
);
1025 if (pi
->style
== TEXT_UNDER_ICON
)
1027 image_x
= (area
.width
- width
) >> 1;
1028 image_y
= (area
.height
- height
- text_height
) >> 1;
1032 image_x
= PANEL_ICON_SPACING
- 2;
1033 image_y
= (area
.height
- height
) >> 1;
1036 gdk_pixbuf_render_to_drawable_alpha(
1040 image_x
, image_y
, /* dest */
1042 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
1043 GDK_RGB_DITHER_NORMAL
, 0, 0);
1045 if (icon
->item
->flags
& ITEM_FLAG_SYMLINK
)
1047 gdk_pixbuf_render_to_drawable_alpha(im_symlink
->pixbuf
,
1050 image_x
, image_y
+ 2, /* dest */
1052 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
1053 GDK_RGB_DITHER_NORMAL
, 0, 0);
1055 if (icon
->item
->flags
& ITEM_FLAG_MOUNT_POINT
)
1057 MaskedPixmap
*mp
= icon
->item
->flags
& ITEM_FLAG_MOUNTED
1061 gdk_pixbuf_render_to_drawable_alpha(mp
->pixbuf
,
1064 image_x
, image_y
+ 2, /* dest */
1066 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
1067 GDK_RGB_DITHER_NORMAL
, 0, 0);
1072 static void panel_icon_wink(Icon
*icon
)
1074 PanelIcon
*pi
= (PanelIcon
*) icon
;
1076 wink_widget(pi
->widget
);
1079 /* icon may be NULL if the event is on the background */
1080 static void perform_action(Panel
*panel
, PanelIcon
*pi
, GdkEventButton
*event
)
1083 Icon
*icon
= (Icon
*) pi
;
1085 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
1087 if (pi
&& pi
->socket
)
1088 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
1094 dnd_motion_ungrab();
1095 wink_widget(pi
->widget
);
1099 dnd_motion_ungrab();
1100 wink_widget(pi
->widget
);
1101 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, TRUE
);
1103 case ACT_POPUP_MENU
:
1104 dnd_motion_ungrab();
1105 panel_show_menu(event
, pi
, panel
);
1108 dnd_motion_start(MOTION_REPOSITION
);
1110 case ACT_PRIME_AND_SELECT
:
1111 if (!icon
->selected
)
1112 icon_select_only(icon
);
1113 dnd_motion_start(MOTION_READY_FOR_DND
);
1115 case ACT_PRIME_AND_TOGGLE
:
1116 icon_set_selected(icon
, !icon
->selected
);
1117 dnd_motion_start(MOTION_READY_FOR_DND
);
1119 case ACT_PRIME_FOR_DND
:
1120 dnd_motion_start(MOTION_READY_FOR_DND
);
1122 case ACT_TOGGLE_SELECTED
:
1123 icon_set_selected(icon
, !icon
->selected
);
1125 case ACT_SELECT_EXCL
:
1126 icon_set_selected(icon
, TRUE
);
1130 case ACT_CLEAR_SELECTION
:
1131 dnd_motion_ungrab();
1132 icon_select_only(NULL
);
1135 g_warning("Unsupported action : %d\n", action
);
1140 static gint
panel_button_release(GtkWidget
*widget
,
1141 GdkEventButton
*event
,
1144 if (dnd_motion_release(event
))
1147 perform_action(panel
, NULL
, event
);
1152 static gint
panel_button_press(GtkWidget
*widget
,
1153 GdkEventButton
*event
,
1156 if (dnd_motion_press(panel
->window
, event
))
1157 perform_action(panel
, NULL
, event
);
1162 static gint
icon_button_release(GtkWidget
*widget
,
1163 GdkEventButton
*event
,
1166 if (pi
->socket
&& event
->button
== 1)
1167 return FALSE
; /* Restart button */
1169 if (dnd_motion_release(event
))
1172 perform_action(pi
->panel
, pi
, event
);
1177 static gint
icon_button_press(GtkWidget
*widget
,
1178 GdkEventButton
*event
,
1181 if (pi
->socket
&& event
->button
== 1)
1182 return FALSE
; /* Restart button */
1184 if (dnd_motion_press(widget
, event
))
1185 perform_action(pi
->panel
, pi
, event
);
1190 /* Stop windows from maximising over all/part of us */
1191 static void panel_setup_struts(Panel
*panel
, GtkAllocation
*alloc
)
1195 gulong left
, right
, top
, bottom
;
1196 gulong left_start_y
, left_end_y
;
1197 gulong right_start_y
, right_end_y
;
1198 gulong top_start_x
, top_end_x
;
1199 gulong bottom_start_x
, bottom_end_x
;
1200 } strut
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1202 if (panel
->avoid
== FALSE
)
1204 else if (panel
->side
== PANEL_TOP
||
1205 panel
->side
== PANEL_BOTTOM
)
1206 thickness
= alloc
->height
;
1208 thickness
= alloc
->width
;
1210 switch (panel
->side
)
1213 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].left
)
1215 strut
.left
= panel
->geometry
.x
+ thickness
;
1216 strut
.left_start_y
= panel
->geometry
.y
;
1217 strut
.left_end_y
= panel
->geometry
.y
+
1218 panel
->geometry
.height
- 1;
1220 /* else there is (part of) a monitor
1228 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].right
)
1230 /* RHS of monitor might not abut edge
1231 * of total virtual screen */
1232 strut
.right
= screen_width
-
1234 panel
->geometry
.width
+
1236 strut
.right_start_y
= panel
->geometry
.y
;
1237 strut
.right_end_y
= panel
->geometry
.y
+
1238 panel
->geometry
.height
- 1;
1240 /* else there is (part of) a monitor
1248 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].top
)
1250 strut
.top
= panel
->geometry
.y
+ thickness
;
1251 strut
.top_start_x
= panel
->geometry
.x
;
1252 strut
.top_end_x
= panel
->geometry
.x
+
1253 panel
->geometry
.width
- 1;
1255 /* else there is (part of) a monitor above */
1261 default: /* PANEL_BOTTOM */
1262 if (!panel
->xinerama
||
1263 !monitor_adjacent
[panel
->monitor
].bottom
)
1265 /* Bottom of monitor might not abut
1266 * edge of total virtual screen */
1267 strut
.bottom
= screen_height
-
1269 panel
->geometry
.height
+
1271 strut
.bottom_start_x
= panel
->geometry
.x
;
1272 strut
.bottom_end_x
= panel
->geometry
.x
+
1273 panel
->geometry
.width
- 1;
1275 /* else there is (part of) a monitor below */
1285 /* Set full-width strut as well as partial in case
1286 * partial isn't supported by wm */
1287 gdk_property_change(panel
->window
->window
,
1288 gdk_atom_intern("_NET_WM_STRUT",
1290 gdk_atom_intern("CARDINAL", FALSE
),
1291 32, GDK_PROP_MODE_REPLACE
,
1292 (gchar
*) &strut
, 4);
1293 gdk_property_change(panel
->window
->window
,
1294 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1296 gdk_atom_intern("CARDINAL", FALSE
),
1297 32, GDK_PROP_MODE_REPLACE
,
1298 (gchar
*) &strut
, 12);
1302 gdk_property_delete(panel
->window
->window
,
1303 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1305 gdk_property_delete(panel
->window
->window
,
1306 gdk_atom_intern("_NET_WM_STRUT",
1311 static void reposition_panel(GtkWidget
*window
,
1312 GtkAllocation
*alloc
, Panel
*panel
)
1314 int x
= panel
->geometry
.x
;
1315 int y
= panel
->geometry
.y
;
1316 PanelSide side
= panel
->side
;
1318 if (side
== PANEL_LEFT
|| side
== PANEL_RIGHT
)
1320 if (side
== PANEL_RIGHT
)
1321 x
+= panel
->geometry
.width
- alloc
->width
;
1323 if (current_panel
[PANEL_TOP
])
1325 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1326 y
+= win
->allocation
.height
;
1330 if (side
== PANEL_BOTTOM
)
1331 y
+= panel
->geometry
.height
- alloc
->height
;
1333 gtk_window_move(GTK_WINDOW(panel
->window
), x
, y
);
1334 gdk_window_move(panel
->window
->window
, x
, y
);
1336 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
1338 if (current_panel
[PANEL_RIGHT
])
1339 gtk_widget_queue_resize(
1340 current_panel
[PANEL_RIGHT
]->window
);
1341 if (current_panel
[PANEL_LEFT
])
1342 gtk_widget_queue_resize(
1343 current_panel
[PANEL_LEFT
]->window
);
1346 panel_setup_struts(panel
, alloc
);
1349 /* Same as drag_set_dest(), but for panel icons */
1350 static void drag_set_panel_dest(PanelIcon
*pi
)
1352 GtkWidget
*obj
= pi
->widget
;
1354 make_drop_target(pi
->widget
, 0);
1356 g_signal_connect(obj
, "drag_motion", G_CALLBACK(drag_motion
), pi
);
1357 g_signal_connect(obj
, "drag_leave", G_CALLBACK(drag_leave
), pi
);
1358 g_signal_connect(obj
, "drag_end", G_CALLBACK(drag_end
), pi
);
1361 static gboolean
drag_motion(GtkWidget
*widget
,
1362 GdkDragContext
*context
,
1368 GdkDragAction action
= context
->suggested_action
;
1369 const char *type
= NULL
;
1370 Icon
*icon
= (Icon
*) pi
;
1371 DirItem
*item
= icon
->item
;
1372 int panel_x
, panel_y
;
1374 gdk_window_get_pointer(pi
->panel
->window
->window
,
1375 &panel_x
, &panel_y
, NULL
);
1376 motion_may_raise(pi
->panel
, panel_x
, panel_y
);
1378 /* Should we scroll the panel when dragging? */
1379 if (motion_state
!= MOTION_REPOSITION
)
1380 if (pi
->panel
->autoscroll_speed
== 0)
1381 may_autoscroll(pi
->panel
);
1384 goto out
; /* Can't drag a selection to itself */
1386 type
= dnd_motion_item(context
, &item
);
1388 if ((context
->actions
& GDK_ACTION_ASK
) && o_dnd_left_menu
.int_value
1389 && type
!= drop_dest_prog
)
1392 gdk_window_get_pointer(NULL
, NULL
, NULL
, &state
);
1393 if (state
& GDK_BUTTON1_MASK
)
1394 action
= GDK_ACTION_ASK
;
1400 /* We actually must pretend to accept the drop, even if the
1401 * directory isn't writeable, so that the spring-opening
1405 /* Don't allow drops to non-writeable directories */
1406 if (o_dnd_spring_open
.int_value
== FALSE
&&
1407 type
== drop_dest_dir
&&
1408 access(icon
->path
, W_OK
) != 0)
1413 g_dataset_set_data(context
, "drop_dest_type", (gpointer
) type
);
1416 gdk_drag_status(context
, action
, time
);
1417 g_dataset_set_data_full(context
, "drop_dest_path",
1418 g_strdup(icon
->path
), g_free
);
1419 if (type
== drop_dest_dir
)
1420 dnd_spring_load(context
, NULL
);
1422 if (dnd_highlight
&& dnd_highlight
!= pi
->widget
)
1424 gtk_drag_unhighlight(dnd_highlight
);
1425 dnd_highlight
= NULL
;
1428 if (dnd_highlight
== NULL
)
1430 gtk_drag_highlight(pi
->widget
);
1431 dnd_highlight
= pi
->widget
;
1435 return type
!= NULL
;
1439 static void add_uri_list(GtkWidget
*widget
,
1440 GdkDragContext
*context
,
1443 GtkSelectionData
*selection_data
,
1448 gboolean after
= FALSE
;
1451 if (!selection_data
->data
)
1454 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
1456 if (g_object_get_data(G_OBJECT(widget
), "after"))
1459 uris
= uri_list_to_glist(selection_data
->data
);
1461 for (next
= uris
; next
; next
= next
->next
)
1465 path
= get_local_path((EscapedPath
*) next
->data
);
1468 panel_add_item(panel
, path
, NULL
, after
, NULL
, NULL
, FALSE
);
1476 static void drag_end(GtkWidget
*widget
,
1477 GdkDragContext
*context
,
1480 if (tmp_icon_selected
)
1482 icon_select_only(NULL
);
1483 tmp_icon_selected
= FALSE
;
1487 static void drag_leave(GtkWidget
*widget
,
1488 GdkDragContext
*context
,
1492 panel_drag_leave(widget
, context
, time
, ((PanelIcon
*) icon
)->panel
);
1494 if (dnd_highlight
&& dnd_highlight
== widget
)
1496 gtk_drag_unhighlight(dnd_highlight
);
1497 dnd_highlight
= NULL
;
1503 /* Create XML icon nodes for these widgets.
1504 * Always frees the widgets list.
1506 static void make_widgets(xmlNodePtr side
, GList
*widgets
)
1510 for (next
= widgets
; next
; next
= next
->next
)
1515 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
1519 g_warning("Can't find Icon from widget\n");
1523 tree
= xmlNewTextChild(side
, NULL
, "icon", icon
->src_path
);
1525 xmlSetProp(tree
, "label", icon
->item
->leafname
);
1527 xmlSetProp(tree
, "shortcut", icon
->shortcut
);
1529 xmlSetProp(tree
, "args", icon
->args
);
1531 xmlSetProp(tree
, "locked", "true");
1535 g_list_free(widgets
);
1538 void panel_save(Panel
*panel
)
1543 guchar
*save
= NULL
;
1544 guchar
*save_new
= NULL
;
1546 g_return_if_fail(panel
!= NULL
);
1548 if (strchr(panel
->name
, '/'))
1549 save
= g_strdup(panel
->name
);
1554 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
1555 save
= choices_find_xdg_path_save(leaf
, PROJECT
, SITE
, TRUE
);
1562 doc
= xmlNewDoc("1.0");
1563 xmlDocSetRootElement(doc
, xmlNewDocNode(doc
, NULL
, "panel", NULL
));
1565 root
= xmlDocGetRootElement(doc
);
1567 xmlSetProp(root
, "side", panel_side_to_name(panel
->side
));
1569 options
= xmlNewChild(root
, NULL
, "options", NULL
);
1570 set_int_prop(options
, "style", panel
->style
);
1571 set_int_prop(options
, "width", panel
->width
);
1572 set_int_prop(options
, "avoid", panel
->avoid
);
1573 set_int_prop(options
, "xinerama", panel
->xinerama
);
1574 set_int_prop(options
, "monitor", panel
->monitor
);
1576 make_widgets(xmlNewChild(root
, NULL
, "start", NULL
),
1577 gtk_container_get_children(GTK_CONTAINER(panel
->before
)));
1579 make_widgets(xmlNewChild(root
, NULL
, "end", NULL
),
1580 g_list_reverse(gtk_container_get_children(
1581 GTK_CONTAINER(panel
->after
))));
1583 save_new
= g_strconcat(save
, ".new", NULL
);
1584 if (save_xml_file(doc
, save_new
) || rename(save_new
, save
))
1585 delayed_error(_("Error saving panel %s: %s"),
1586 save
, g_strerror(errno
));
1594 /* Create a frame widget which can be used to add icons to the panel */
1595 static GtkWidget
*make_insert_frame(Panel
*panel
)
1598 GtkTargetEntry target_table
[] = {
1599 {"text/uri-list", 0, TARGET_URI_LIST
},
1602 frame
= gtk_frame_new(NULL
);
1603 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
1604 gtk_widget_set_size_request(frame
, 16, 16);
1606 g_signal_connect(frame
, "drag-motion",
1607 G_CALLBACK(insert_drag_motion
), panel
);
1608 g_signal_connect(frame
, "drag-leave",
1609 G_CALLBACK(panel_drag_leave
), panel
);
1611 g_signal_connect(frame
, "drag-data-received",
1612 G_CALLBACK(add_uri_list
), panel
);
1613 gtk_drag_dest_set(frame
,
1614 GTK_DEST_DEFAULT_ALL
,
1616 sizeof(target_table
) / sizeof(*target_table
),
1622 static gboolean
enter_icon(GtkWidget
*widget
,
1623 GdkEventCrossing
*event
,
1626 icon_may_update(icon
);
1627 panel_icon_set_tip((PanelIcon
*) icon
);
1632 static gint
panel_leave_event(GtkWidget
*widget
,
1633 GdkEventCrossing
*event
,
1636 GdkWindow
*pinboard
;
1638 if (event
->mode
!= GDK_CROSSING_NORMAL
)
1639 return FALSE
; /* Grab for menu, DnD, etc */
1641 keep_below(panel
->window
->window
, TRUE
);
1643 /* Shouldn't need this as well as keep_below but some WMs don't
1644 * automatically lower as soon as the hint is set */
1645 pinboard
= pinboard_get_window();
1646 window_put_just_above(panel
->window
->window
, pinboard
);
1651 /* If (x, y) is at the edge of the panel then raise */
1652 static void motion_may_raise(Panel
*panel
, int x
, int y
)
1656 if (panel
->side
== PANEL_TOP
)
1658 else if (panel
->side
== PANEL_BOTTOM
)
1659 raise
= y
== panel
->window
->allocation
.height
- 1;
1660 else if (panel
->side
== PANEL_LEFT
)
1663 raise
= x
== panel
->window
->allocation
.width
- 1;
1667 keep_below(panel
->window
->window
, FALSE
);
1669 /* Shouldn't need this as well as keep_below but some WMs don't
1670 * automatically raise as soon as the hint is set */
1671 gdk_window_raise(panel
->window
->window
);
1675 static gboolean
may_autoscroll(Panel
*panel
)
1677 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1678 gint max
, panel_x
, panel_y
, delta
, new;
1680 if (panel
->adj
->upper
<= panel
->adj
->page_size
)
1681 goto stop_scrolling
; /* Can see everything already */
1683 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
1688 max
= panel
->window
->allocation
.width
;
1689 if (panel_y
< 0 || panel_y
> panel
->window
->allocation
.height
)
1690 goto stop_scrolling
; /* Not over the panel */
1695 max
= panel
->window
->allocation
.height
;
1696 if (panel_x
< 0 || panel_x
> panel
->window
->allocation
.width
)
1697 goto stop_scrolling
; /* Not over the panel */
1700 if (delta
>= 20 && delta
<= max
- 20)
1701 goto stop_scrolling
; /* Not at either end */
1703 panel
->autoscroll_speed
= MIN(panel
->autoscroll_speed
+ 2, 200);
1705 new = panel
->adj
->value
- ((delta
< 20) ? panel
->autoscroll_speed
1706 : -panel
->autoscroll_speed
);
1707 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
1708 gtk_adjustment_set_value(panel
->adj
, new);
1710 panel
->autoscroll_to
= g_timeout_add(40,
1711 (GSourceFunc
) may_autoscroll
, panel
);
1716 panel
->autoscroll_speed
= 0;
1720 static gint
panel_motion_event(GtkWidget
*widget
,
1721 GdkEventMotion
*event
,
1724 motion_may_raise(panel
, event
->x
, event
->y
);
1726 if (motion_state
!= MOTION_REPOSITION
)
1727 if (panel
->autoscroll_speed
== 0)
1728 may_autoscroll(panel
);
1733 static gint
icon_motion_event(GtkWidget
*widget
,
1734 GdkEventMotion
*event
,
1737 Panel
*panel
= pi
->panel
;
1739 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1743 if (motion_state
== MOTION_READY_FOR_DND
)
1745 if (dnd_motion_moved(event
))
1746 start_drag(pi
, event
);
1749 else if (motion_state
!= MOTION_REPOSITION
)
1752 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1753 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1754 list
= g_list_concat(list
,
1755 gtk_container_get_children(GTK_CONTAINER(panel
->after
)));
1756 me
= g_list_find(list
, widget
);
1758 g_return_val_if_fail(me
!= NULL
, TRUE
);
1760 val
= horz
? event
->x_root
: event
->y_root
;
1768 prev
= GTK_WIDGET(me
->prev
->data
);
1772 gdk_window_get_origin(prev
->window
, &x
, &y
);
1774 if (val
<= (horz
? x
: y
))
1778 if (dir
== 0 && me
->next
)
1784 next
= GTK_WIDGET(me
->next
->data
);
1788 gdk_window_get_origin(next
->window
, &x
, &y
);
1790 gdk_drawable_get_size(next
->window
, &w
, &h
);
1795 if (val
>= (horz
? x
: y
)-1)
1797 if (next
== panel
->gap
)
1805 reposition_icon(pi
, g_list_index(list
, widget
) + dir
);
1810 static void reposition_icon_on_side(GtkWidget
*side
, GtkWidget
*widget
,
1815 list
= gtk_container_get_children(GTK_CONTAINER(side
));
1817 /* Want to move icon to the list in the given 'side'. Is it there
1821 if (!g_list_find(list
, widget
))
1824 gtk_grab_remove(widget
);
1825 gtk_widget_reparent(widget
, side
);
1826 dnd_motion_grab_pointer();
1827 gtk_grab_add(widget
);
1830 gtk_box_reorder_child(GTK_BOX(side
), widget
, index
);
1835 /* Move icon to this index in the complete widget list.
1836 * 0 makes the icon the left-most icon. The gap in the middle has
1837 * an index number, which allows you to specify that the icon should
1838 * go on the left or right side.
1840 static void reposition_icon(PanelIcon
*pi
, int index
)
1842 Panel
*panel
= pi
->panel
;
1843 GtkWidget
*widget
= pi
->widget
;
1847 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1848 before_len
= g_list_length(list
);
1851 if (index
<= before_len
)
1852 reposition_icon_on_side(panel
->before
, widget
, index
);
1854 reposition_icon_on_side(panel
->after
, widget
,
1855 index
- (before_len
+ 1));
1860 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
)
1862 GtkWidget
*widget
= pi
->widget
;
1863 Icon
*icon
= (Icon
*) pi
;
1865 if (!icon
->selected
)
1867 if (event
->state
& GDK_BUTTON1_MASK
)
1869 /* Select just this one */
1870 icon_select_only(icon
);
1871 tmp_icon_selected
= TRUE
;
1874 icon_set_selected(icon
, TRUE
);
1877 g_return_if_fail(icon_selection
!= NULL
);
1879 if (icon_selection
->next
== NULL
)
1880 drag_one_item(widget
, event
, icon
->path
, icon
->item
, NULL
);
1885 uri_list
= icon_create_uri_list();
1886 drag_selection(widget
, event
, uri_list
);
1891 static void applet_died(GtkWidget
*socket
)
1893 gboolean never_plugged
;
1895 never_plugged
= (!g_object_get_data(G_OBJECT(socket
), "lost_plug"))
1896 && !GTK_SOCKET(socket
)->plug_window
;
1901 _("Applet quit without ever creating a widget!"));
1902 gtk_widget_destroy(socket
);
1905 gtk_widget_unref(socket
);
1908 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1910 g_object_set_data(G_OBJECT(socket
), "lost_plug", "yes");
1912 gtk_widget_unref(socket
);
1914 gtk_widget_destroy(widget
); /* Remove from panel */
1917 panel_save(g_object_get_data(G_OBJECT(socket
), "panel"));
1920 /* Try to run this applet.
1923 * - No executable AppletRun:
1924 * icon->socket == NULL (unchanged) on return.
1926 * Otherwise, create socket (setting icon->socket) and ref it twice.
1928 * - AppletRun quits without connecting a plug:
1929 * On child death lost_plug is unset and socket is empty.
1931 * Report error and destroy widget (to 'socket destroyed').
1933 * - AppletRun quits while plug is in socket:
1934 * Unref socket once. Socket will be destroyed later.
1936 * - Socket is destroyed.
1937 * Set lost_plug = "yes" and remove widget from panel.
1940 static void run_applet(PanelIcon
*pi
)
1942 GError
*error
= NULL
;
1945 Icon
*icon
= (Icon
*) pi
;
1947 argv
[0] = (char *) make_path(icon
->path
, "AppletRun");
1949 if (access(argv
[0], X_OK
) != 0)
1952 pi
->socket
= gtk_socket_new();
1954 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->socket
);
1955 gtk_widget_show_all(pi
->socket
);
1956 gtk_widget_realize(pi
->socket
);
1958 /* Always get button-2 events so we can drag */
1959 XGrabButton(gdk_display
, Button2
, AnyModifier
,
1960 GDK_WINDOW_XWINDOW(pi
->socket
->window
),
1962 ButtonPressMask
| ButtonReleaseMask
| Button2MotionMask
,
1963 GrabModeAsync
, /* Pointer */
1964 GrabModeAsync
, /* Keyboard */
1969 PanelSide side
= pi
->panel
->side
;
1971 /* Set a hint to let applets position their menus correctly */
1972 pos
= g_strdup_printf("%s,%d",
1973 panel_side_to_name(side
), MENU_MARGIN(side
));
1974 gdk_property_change(pi
->socket
->window
,
1975 gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE
),
1976 gdk_atom_intern("STRING", FALSE
),
1977 8, GDK_PROP_MODE_REPLACE
,
1981 /* Ensure that the properties are set before starting the
1987 g_object_set_data(G_OBJECT(pi
->widget
), "icon", pi
);
1988 g_object_set_data(G_OBJECT(pi
->socket
), "panel", pi
->panel
);
1990 argv
[1] = g_strdup_printf("%ld",
1991 GDK_WINDOW_XWINDOW(pi
->socket
->window
));
1994 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_DO_NOT_REAP_CHILD
,
1995 NULL
, NULL
, &pid
, &error
))
1997 delayed_error(_("Error running applet:\n%s"), error
->message
);
1998 g_error_free(error
);
1999 gtk_widget_destroy(pi
->socket
);
2004 gtk_widget_ref(pi
->socket
);
2005 on_child_death(pid
, (CallbackFn
) applet_died
, pi
->socket
);
2007 gtk_widget_ref(pi
->socket
);
2008 g_signal_connect(pi
->socket
, "destroy",
2009 G_CALLBACK(socket_destroyed
), pi
->widget
);
2015 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
2017 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
2019 req
->width
= panel
->geometry
.width
;
2020 req
->height
+= EDGE_WIDTH
;
2024 int h
= panel
->geometry
.height
;
2026 if (current_panel
[PANEL_TOP
])
2028 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
2029 h
-= win
->allocation
.height
;
2032 if (current_panel
[PANEL_BOTTOM
])
2034 GtkWidget
*win
= current_panel
[PANEL_BOTTOM
]->window
;
2035 h
-= win
->allocation
.height
;
2039 req
->width
+= EDGE_WIDTH
;
2043 static void update_side(GtkWidget
*side
)
2047 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
2048 for (next
= kids
; next
; next
= next
->next
)
2051 pi
= g_object_get_data(next
->data
, "icon");
2052 panel_icon_set_tip(pi
);
2057 /* Tips or style has changed -- update everything on this panel */
2058 static void panel_set_style(Panel
*panel
)
2060 update_side(panel
->before
);
2061 update_side(panel
->after
);
2062 gtk_widget_queue_resize(panel
->window
);
2065 static gboolean
recreate_panels(char **names
)
2069 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2073 panel_new(names
[i
], i
);
2083 static void update_side_size(GtkWidget
*side
)
2087 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
2088 for (next
= kids
; next
; next
= next
->next
)
2091 pi
= g_object_get_data(next
->data
, "icon");
2092 gtk_widget_queue_resize(pi
->widget
);
2097 /* Update panel size and redraw */
2098 static void panel_update(Panel
*panel
)
2100 update_side_size(panel
->before
);
2101 update_side_size(panel
->after
);
2102 gtk_widget_queue_resize(panel
->window
);
2103 gtk_widget_queue_draw(panel
->window
);
2106 static void panel_style_changed(void)
2110 if (o_override_redirect
.has_changed
)
2114 names
= g_new(char *, PANEL_NUMBER_OF_SIDES
);
2116 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2118 Panel
*panel
= current_panel
[i
];
2119 names
[i
] = panel
? g_strdup(panel
->name
) : NULL
;
2123 g_idle_add((GtkFunction
) recreate_panels
, names
);
2127 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
2130 int x
, y
, width
, height
;
2132 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
2134 width
= panel
->geometry
.width
;
2135 height
= EDGE_WIDTH
;
2138 if (panel
->side
== PANEL_BOTTOM
)
2141 y
= widget
->allocation
.height
- EDGE_WIDTH
;
2146 height
= panel
->geometry
.height
;
2149 if (panel
->side
== PANEL_RIGHT
)
2152 x
= widget
->allocation
.width
- EDGE_WIDTH
;
2155 gdk_draw_rectangle(widget
->window
,
2156 widget
->style
->fg_gc
[GTK_STATE_NORMAL
], TRUE
,
2157 x
, y
, width
, height
);
2162 static gpointer parent_class
;
2164 static void panel_icon_destroy(Icon
*icon
)
2166 PanelIcon
*pi
= (PanelIcon
*) icon
;
2168 g_return_if_fail(pi
!= NULL
);
2171 g_object_unref(pi
->image
);
2173 g_return_if_fail(pi
->widget
!= NULL
);
2175 gtk_widget_destroy(pi
->widget
);
2178 static void panel_remove_items(void)
2182 g_return_if_fail(icon_selection
!= NULL
);
2184 panel
= ((PanelIcon
*) icon_selection
->data
)->panel
;
2186 while (icon_selection
)
2187 icon_destroy((Icon
*) icon_selection
->data
);
2192 /* Icon's size, shape or appearance has changed - update the display */
2193 static void panel_icon_redraw(Icon
*icon
)
2195 PanelIcon
*pi
= (PanelIcon
*) icon
;
2197 gtk_widget_set_state(pi
->widget
,
2198 icon
->selected
? GTK_STATE_SELECTED
2199 : GTK_STATE_NORMAL
);
2201 /* Will regenerate the scaled icon from the new image */
2202 gtk_widget_queue_resize(pi
->widget
);
2204 panel_icon_set_tip((PanelIcon
*) icon
);
2207 static void panel_icon_update(Icon
*icon
)
2209 PanelIcon
*pi
= (PanelIcon
*) icon
;
2211 gtk_widget_queue_draw(pi
->widget
);
2212 gtk_label_set_text(GTK_LABEL(pi
->label
), icon
->item
->leafname
);
2213 panel_save(pi
->panel
);
2216 /* The point of this is to clear the selection if the existing icons
2217 * aren't from the same panel...
2219 static gboolean
panel_icon_same_group(Icon
*icon
, Icon
*other
)
2221 if (IS_PANEL_ICON(other
))
2223 PanelIcon
*a
= (PanelIcon
*) icon
;
2224 PanelIcon
*b
= (PanelIcon
*) other
;
2226 return a
->panel
== b
->panel
;
2232 static void panel_icon_class_init(gpointer gclass
, gpointer data
)
2234 IconClass
*icon
= (IconClass
*) gclass
;
2236 parent_class
= g_type_class_peek_parent(gclass
);
2238 icon
->destroy
= panel_icon_destroy
;
2239 icon
->redraw
= panel_icon_redraw
;
2240 icon
->update
= panel_icon_update
;
2241 icon
->remove_items
= panel_remove_items
;
2242 icon
->same_group
= panel_icon_same_group
;
2243 icon
->wink
= panel_icon_wink
;
2246 static void panel_icon_init(GTypeInstance
*object
, gpointer gclass
)
2248 PanelIcon
*pi
= (PanelIcon
*) object
;
2254 pi
->style
= TEXT_UNDER_ICON
;
2257 static GType
panel_icon_get_type(void)
2259 static GType type
= 0;
2263 static const GTypeInfo info
=
2265 sizeof (PanelIconClass
),
2266 NULL
, /* base_init */
2267 NULL
, /* base_finalise */
2268 panel_icon_class_init
,
2269 NULL
, /* class_finalise */
2270 NULL
, /* class_data */
2272 0, /* n_preallocs */
2276 type
= g_type_register_static(icon_get_type(),
2277 "PanelIcon", &info
, 0);
2283 static PanelIcon
*panel_icon_new(Panel
*panel
,
2284 const char *pathname
,
2290 pi
= g_object_new(panel_icon_get_type(), NULL
);
2293 icon_set_path(icon
, pathname
, name
);
2299 static gboolean
panel_want_show_text(PanelIcon
*pi
)
2301 Icon
*icon
= (Icon
*) pi
;
2302 Panel
*panel
= pi
->panel
;
2304 if (!icon
->item
->leafname
[0])
2307 if (panel
->style
== SHOW_BOTH
)
2309 if (panel
->style
== SHOW_ICON
)
2312 if (icon
->item
->flags
& ITEM_FLAG_APPDIR
)
2315 if (EXECUTABLE_FILE(icon
->item
))
2321 static void xinerama_sensitive(GladeXML
*glade
, gboolean sensitive
)
2323 gtk_widget_set_sensitive(
2324 glade_xml_get_widget(glade
, "panel_xinerama_monitor"),
2328 inline static Panel
*panel_from_opts_widget(GtkWidget
*widget
)
2330 return g_object_get_data(G_OBJECT(gtk_widget_get_toplevel(widget
)),
2334 static void panel_style_radio_toggled(GtkToggleButton
*widget
, int style
)
2338 if (!gtk_toggle_button_get_active(widget
))
2340 panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2341 if (style
!= panel
->style
)
2343 panel
->style
= style
;
2344 panel_set_style(panel
);
2349 static void panel_xinerama_changed(Panel
*panel
)
2351 panel_update_geometry(panel
);
2352 reposition_panel(panel
->window
, &panel
->window
->allocation
, panel
);
2353 gtk_widget_queue_resize(panel
->window
);
2357 static void panel_side_radio_toggled(GtkWidget
*widget
, PanelSide new_side
)
2361 char *name
, *other_side_name
;
2363 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
2366 panel
= panel_from_opts_widget(widget
);
2367 old_side
= panel
->side
;
2368 if (new_side
== old_side
)
2371 name
= g_strdup(panel
->name
);
2372 other_side_name
= current_panel
[new_side
]
2373 ? g_strdup(current_panel
[new_side
]->name
)
2376 panel_new(name
, new_side
);
2377 g_object_set_data(G_OBJECT(gtk_widget_get_toplevel(widget
)),
2378 "rox-panel", current_panel
[new_side
]);
2379 panel_new(other_side_name
, old_side
);
2382 g_free(other_side_name
);
2385 static void panel_style_radio_0_toggled_cb(GtkToggleButton
*widget
)
2387 panel_style_radio_toggled(widget
, 0);
2390 static void panel_style_radio_1_toggled_cb(GtkToggleButton
*widget
)
2392 panel_style_radio_toggled(widget
, 1);
2395 static void panel_style_radio_2_toggled_cb(GtkToggleButton
*widget
)
2397 panel_style_radio_toggled(widget
, 2);
2400 static void panel_width_changed_cb(GtkSpinButton
*widget
)
2402 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2403 int width
= gtk_spin_button_get_value_as_int(widget
);
2405 if (width
!= panel
->width
)
2407 panel
->width
= width
;
2408 panel_update(panel
);
2413 static void panel_avoid_toggled_cb(GtkToggleButton
*widget
)
2415 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2416 gboolean avoid
= gtk_toggle_button_get_active(widget
);
2418 if (avoid
!= panel
->avoid
)
2420 panel
->avoid
= avoid
;
2421 panel_setup_struts(panel
, &panel
->window
->allocation
);
2426 static void panel_xinerama_confine_toggled_cb(GtkWidget
*widget
)
2428 Panel
*panel
= panel_from_opts_widget(widget
);
2429 gboolean xinerama
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
2431 xinerama_sensitive(glade_get_widget_tree(gtk_widget_get_toplevel(widget
)),
2433 if (xinerama
!= panel
->xinerama
)
2435 panel
->xinerama
= xinerama
;
2436 panel_xinerama_changed(panel
);
2440 static void panel_xinerama_monitor_changed_cb(GtkSpinButton
*widget
)
2442 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2443 int monitor
= gtk_spin_button_get_value_as_int(widget
);
2445 if (monitor
!= panel
->monitor
)
2447 panel
->monitor
= monitor
;
2448 panel_xinerama_changed(panel
);
2452 static void panel_pos_top_toggled_cb(GtkWidget
*widget
)
2454 panel_side_radio_toggled(widget
, PANEL_TOP
);
2457 static void panel_pos_bottom_toggled_cb(GtkWidget
*widget
)
2459 panel_side_radio_toggled(widget
, PANEL_BOTTOM
);
2462 static void panel_pos_left_toggled_cb(GtkWidget
*widget
)
2464 panel_side_radio_toggled(widget
, PANEL_LEFT
);
2467 static void panel_pos_right_toggled_cb(GtkWidget
*widget
)
2469 panel_side_radio_toggled(widget
, PANEL_RIGHT
);
2472 #define CONNECT_GLADE_CB(glade, handler) \
2473 glade_xml_signal_connect(glade, #handler, G_CALLBACK(handler))
2475 static void panel_connect_dialog_signal_handlers(GladeXML
*glade
)
2477 CONNECT_GLADE_CB(glade
, gtk_widget_destroy
);
2478 CONNECT_GLADE_CB(glade
, panel_style_radio_0_toggled_cb
);
2479 CONNECT_GLADE_CB(glade
, panel_style_radio_1_toggled_cb
);
2480 CONNECT_GLADE_CB(glade
, panel_style_radio_2_toggled_cb
);
2481 CONNECT_GLADE_CB(glade
, panel_width_changed_cb
);
2482 CONNECT_GLADE_CB(glade
, panel_avoid_toggled_cb
);
2483 CONNECT_GLADE_CB(glade
, panel_xinerama_confine_toggled_cb
);
2484 CONNECT_GLADE_CB(glade
, panel_xinerama_monitor_changed_cb
);
2485 CONNECT_GLADE_CB(glade
, panel_pos_top_toggled_cb
);
2486 CONNECT_GLADE_CB(glade
, panel_pos_bottom_toggled_cb
);
2487 CONNECT_GLADE_CB(glade
, panel_pos_left_toggled_cb
);
2488 CONNECT_GLADE_CB(glade
, panel_pos_right_toggled_cb
);
2491 static void panel_setup_options_dialog(GladeXML
*glade
, Panel
*panel
)
2494 const char *pos_radio
;
2496 wnm
= g_strdup_printf("panel_style_radio_%d", panel
->style
);
2497 gtk_toggle_button_set_active(
2498 GTK_TOGGLE_BUTTON(glade_xml_get_widget(glade
, wnm
)),
2501 gtk_spin_button_set_value(
2502 GTK_SPIN_BUTTON(glade_xml_get_widget(glade
, "panel_width")),
2504 gtk_toggle_button_set_active(
2505 GTK_TOGGLE_BUTTON(glade_xml_get_widget(glade
, "panel_avoid")),
2507 gtk_toggle_button_set_active(
2508 GTK_TOGGLE_BUTTON(glade_xml_get_widget(glade
,
2509 "panel_xinerama_confine")),
2511 gtk_spin_button_set_adjustment(
2512 GTK_SPIN_BUTTON(glade_xml_get_widget(glade
, "panel_xinerama_monitor")),
2513 GTK_ADJUSTMENT(gtk_adjustment_new(MAX(0, panel
->monitor
),
2514 0, n_monitors
- 1, 1, 10, 1)));
2515 xinerama_sensitive(glade
, panel
->xinerama
);
2516 switch (panel
->side
)
2519 pos_radio
= "panel_pos_top";
2522 pos_radio
= "panel_pos_bottom";
2525 pos_radio
= "panel_pos_left";
2528 pos_radio
= "panel_pos_right";
2534 g_return_if_fail(pos_radio
!= NULL
);
2535 gtk_toggle_button_set_active(
2536 GTK_TOGGLE_BUTTON(glade_xml_get_widget(glade
, pos_radio
)),
2540 static void panel_show_options(Panel
*panel
)
2543 gboolean already_showing
= FALSE
;
2544 GladeXML
*glade
= NULL
;
2546 if (panel_options_dialog
)
2548 dialog
= panel_options_dialog
;
2549 already_showing
= TRUE
;
2550 glade
= glade_get_widget_tree(dialog
);
2554 glade
= get_glade_xml("Panel Options");
2555 dialog
= glade_xml_get_widget(glade
, "Panel Options");
2556 panel_options_dialog
= dialog
;
2557 g_signal_connect(dialog
, "destroy",
2558 G_CALLBACK(gtk_widget_destroyed
),
2559 &panel_options_dialog
);
2560 panel_connect_dialog_signal_handlers(glade
);
2562 g_object_set_data(G_OBJECT(panel_options_dialog
), "rox-panel", panel
);
2564 panel_setup_options_dialog(glade
, panel
);
2566 if (already_showing
)
2568 GtkWindow
*win
= GTK_WINDOW(dialog
);
2570 gtk_widget_hide(dialog
);
2571 /* This extra set_position() should ensure it moves to new position
2573 gtk_window_set_position(win
, GTK_WIN_POS_CENTER_ALWAYS
);
2574 gtk_window_set_position(win
, GTK_WIN_POS_MOUSE
);
2575 gtk_window_present(win
);
2579 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
2580 gtk_widget_show_all(dialog
);
2584 static void panel_position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
,
2585 gboolean
*push_in
, gpointer data
)
2587 int *pos
= (int *) data
;
2588 GtkRequisition requisition
;
2589 int margin
= pos
[2];
2591 int mon_right
= monitor_geom
[mon
].x
+
2592 monitor_geom
[mon
].width
;
2593 int mon_bottom
= monitor_geom
[mon
].y
+
2594 monitor_geom
[mon
].height
;
2596 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
2599 *x
= mon_right
- margin
- requisition
.width
;
2600 else if (pos
[0] == -2)
2601 *x
= monitor_geom
[mon
].x
+ margin
;
2603 *x
= pos
[0] - (requisition
.width
>> 2);
2606 *y
= mon_bottom
- margin
- requisition
.height
;
2607 else if (pos
[1] == -2)
2608 *y
= monitor_geom
[mon
].y
+ margin
;
2610 *y
= pos
[1] - (requisition
.height
>> 2);
2612 *x
= CLAMP(*x
, 0, mon_right
- requisition
.width
);
2613 *y
= CLAMP(*y
, 0, mon_bottom
- requisition
.height
);
2618 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
)
2620 GtkWidget
*option_item
;
2621 PanelSide side
= panel
->side
;
2624 pos
[0] = event
->x_root
;
2625 pos
[1] = event
->y_root
;
2626 pos
[2] = MENU_MARGIN(side
);
2627 /* FIXME: Should we read screen from event's window rather than
2629 pos
[3] = gdk_screen_get_monitor_at_point(
2630 gdk_screen_get_default(),
2631 event
->x_root
, event
->y_root
);
2633 option_item
= gtk_image_menu_item_new_with_label(_("Panel Options..."));
2634 g_signal_connect_swapped(option_item
, "activate",
2635 G_CALLBACK(panel_show_options
), panel
);
2637 icon_prepare_menu((Icon
*) pi
, option_item
, NULL
);
2639 if (side
== PANEL_LEFT
)
2641 else if (side
== PANEL_RIGHT
)
2644 if (side
== PANEL_TOP
)
2646 else if (side
== PANEL_BOTTOM
)
2649 gtk_menu_popup(GTK_MENU(icon_menu
), NULL
, NULL
,
2650 panel_position_menu
,
2651 (gpointer
) pos
, event
->button
, event
->time
);
2654 /* Note: also called from icon handler */
2655 static gboolean
panel_drag_motion(GtkWidget
*widget
,
2656 GdkDragContext
*context
,
2662 int panel_x
, panel_y
;
2664 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2666 motion_may_raise(panel
, panel_x
, panel_y
);
2667 gdk_drag_status(context
, 0, time
);
2672 static gboolean
insert_drag_motion(GtkWidget
*widget
,
2673 GdkDragContext
*context
,
2679 int panel_x
, panel_y
;
2681 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2682 motion_may_raise(panel
, panel_x
, panel_y
);
2687 /* Note: also called from icon handler */
2688 static void panel_drag_leave(GtkWidget
*widget
,
2689 GdkDragContext
*context
,
2693 GdkWindow
*pinboard
, *window
;
2694 GtkAllocation
*alloc
= &panel
->window
->allocation
;
2697 window
= panel
->window
->window
;
2698 gdk_window_get_pointer(window
, &x
, &y
, NULL
);
2699 if (x
< 0 || y
< 0 || x
> alloc
->width
|| y
> alloc
->height
)
2701 keep_below(panel
->window
->window
, TRUE
);
2703 /* Shouldn't need this as well as keep_below but some WMs don't
2704 * automatically lower as soon as the hint is set */
2705 pinboard
= pinboard_get_window();
2706 window_put_just_above(panel
->window
->window
, pinboard
);
2710 static void panel_update_geometry(Panel
*panel
)
2712 if (panel
->xinerama
&& panel
->monitor
>= n_monitors
)
2714 g_warning(_("Xinerama monitor %d unavailable"), panel
->monitor
);
2715 panel
->xinerama
= FALSE
;
2718 if (panel
->xinerama
)
2720 panel
->geometry
= monitor_geom
[panel
->monitor
];
2724 panel
->geometry
.x
= panel
->geometry
.y
= 0;
2725 panel
->geometry
.width
= screen_width
;
2726 panel
->geometry
.height
= screen_height
;
2730 static GList
*build_monitor_number(Option
*option
, xmlNode
*node
, guchar
*label
)
2734 adj
= gtk_adjustment_new(MAX(0, panel_monitor
),
2735 0, n_monitors
- 1, 1, 10, 1);
2736 return build_numentry_base(option
, node
, label
, GTK_ADJUSTMENT(adj
));
2739 static const char *panel_side_to_translated_name(PanelSide side
)
2751 case PANEL_DEFAULT_SIDE
:
2752 return _("Default");
2756 return _("Unknown side");
2759 const char *panel_side_to_name(PanelSide side
)
2771 case PANEL_DEFAULT_SIDE
:
2776 return "UnknownSide";
2779 /* Returns PANEL_NUMBER_OF_SIDES if name is invalid */
2780 PanelSide
panel_name_to_side(gchar
*side
)
2782 if (strcmp(side
, "Top") == 0)
2784 else if (strcmp(side
, "Bottom") == 0)
2785 return PANEL_BOTTOM
;
2786 else if (strcmp(side
, "Left") == 0)
2788 else if (strcmp(side
, "Right") == 0)
2791 g_warning("Unknown panel side '%s'", side
);
2792 return PANEL_NUMBER_OF_SIDES
;
2795 static void panel_add_callback(PanelSide side
)
2797 g_return_if_fail(current_panel
[side
] == NULL
);
2798 panel_new(panel_side_to_name(side
), side
);
2801 GtkWidget
*panel_new_panel_submenu(void)
2803 GtkWidget
*menu
= gtk_menu_new();
2806 for (side
= 0; side
< PANEL_NUMBER_OF_SIDES
; ++side
)
2808 GtkWidget
*item
= gtk_menu_item_new_with_label(
2809 panel_side_to_translated_name(side
));
2811 g_signal_connect_swapped(item
, "activate",
2812 G_CALLBACK(panel_add_callback
), GINT_TO_POINTER(side
));
2813 gtk_widget_set_sensitive(item
, current_panel
[side
] == NULL
);
2814 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
2815 gtk_widget_show(item
);