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 */
29 #include <libxml/parser.h>
41 #include "gui_support.h"
54 #include "pinboard.h" /* For pinboard_get_window() */
56 /* The width of the separator at the inner edge of the panel */
59 /* The gap between panel icons */
60 #define PANEL_ICON_SPACING 8
62 enum {TEXT_BESIDE_ICON
, TEXT_UNDER_ICON
};
64 static gboolean tmp_icon_selected
= FALSE
; /* When dragging */
66 typedef struct _PanelIconClass PanelIconClass
;
67 typedef struct _PanelIcon PanelIcon
;
69 struct _PanelIconClass
{
78 GtkWidget
*widget
; /* The drawing area for the icon */
80 GtkWidget
*socket
; /* For applets */
85 #define PANEL_ICON(obj) GTK_CHECK_CAST((obj), panel_icon_get_type(), PanelIcon)
86 #define IS_PANEL_ICON(obj) \
87 G_TYPE_CHECK_INSTANCE_TYPE((obj), panel_icon_get_type())
89 Panel
*current_panel
[PANEL_NUMBER_OF_SIDES
];
91 /* NULL => Not loading a panel */
92 static Panel
*loading_panel
= NULL
;
94 static GtkWidget
*panel_options_dialog
= 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(GtkWidget
*widget
,
109 GdkEventExpose
*event
,
111 static gint
draw_icon(GtkWidget
*widget
,
112 GdkRectangle
*badarea
,
114 static gint
panel_button_release(GtkWidget
*widget
,
115 GdkEventButton
*event
,
117 static gint
panel_button_press(GtkWidget
*widget
,
118 GdkEventButton
*event
,
120 static void panel_post_resize(GtkWidget
*box
,
121 GtkRequisition
*req
, Panel
*panel
);
122 static void drag_set_panel_dest(PanelIcon
*pi
);
123 static void add_uri_list(GtkWidget
*widget
,
124 GdkDragContext
*context
,
127 GtkSelectionData
*selection_data
,
131 static void panel_add_item(Panel
*panel
,
135 const gchar
*shortcut
,
138 static gboolean
panel_drag_motion(GtkWidget
*widget
,
139 GdkDragContext
*context
,
144 static gboolean
insert_drag_motion(GtkWidget
*widget
,
145 GdkDragContext
*context
,
150 static gboolean
drag_motion(GtkWidget
*widget
,
151 GdkDragContext
*context
,
156 static void panel_drag_leave(GtkWidget
*widget
,
157 GdkDragContext
*context
,
160 static void drag_leave(GtkWidget
*widget
,
161 GdkDragContext
*context
,
164 static GtkWidget
*make_insert_frame(Panel
*panel
);
165 static gboolean
enter_icon(GtkWidget
*widget
,
166 GdkEventCrossing
*event
,
168 static gint
icon_motion_event(GtkWidget
*widget
,
169 GdkEventMotion
*event
,
171 static gint
panel_leave_event(GtkWidget
*widget
,
172 GdkEventCrossing
*event
,
174 static gint
panel_motion_event(GtkWidget
*widget
,
175 GdkEventMotion
*event
,
177 static void reposition_icon(PanelIcon
*pi
, int index
);
178 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
);
179 static void drag_end(GtkWidget
*widget
,
180 GdkDragContext
*context
,
182 static void perform_action(Panel
*panel
,
184 GdkEventButton
*event
);
185 static void run_applet(PanelIcon
*pi
);
186 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
);
187 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
);
188 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
190 static PanelIcon
*panel_icon_new(Panel
*panel
,
191 const char *pathname
,
193 static GType
panel_icon_get_type(void);
194 static gboolean
panel_want_show_text(PanelIcon
*pi
);
195 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
);
196 static void panel_style_changed(void);
197 static void motion_may_raise(Panel
*panel
, int x
, int y
);
198 static void panel_update(Panel
*panel
);
199 static GList
*build_monitor_number(Option
*option
,
200 xmlNode
*node
, guchar
*label
);
201 static gboolean
may_autoscroll(Panel
*panel
);
202 static void panel_update_geometry(Panel
*panel
);
205 static GtkWidget
*dnd_highlight
= NULL
; /* (stops flickering) */
208 #define SHOW_APPS_SMALL 1
210 static Option o_panel_style
;
211 static Option o_panel_width
;
212 static Option o_panel_xinerama
;
213 static Option o_panel_monitor
;
214 static Option o_panel_avoid
;
215 static Option o_panel_is_dock
;
217 static gint panel_monitor
= -1;
219 static int closing_panel
= 0; /* Don't panel_save; destroying! */
221 /****************************************************************
222 * EXTERNAL INTERFACE *
223 ****************************************************************/
225 void panel_init(void)
227 option_add_int(&o_panel_style
, "panel_style", SHOW_APPS_SMALL
);
228 option_add_int(&o_panel_width
, "panel_width", 52);
230 option_add_int(&o_panel_xinerama
, "panel_xinerama", 0);
231 option_add_int(&o_panel_monitor
, "panel_monitor", 0);
233 option_add_int(&o_panel_avoid
, "panel_avoid", TRUE
);
234 option_add_int(&o_panel_is_dock
, "panel_is_dock", FALSE
);
236 option_add_notify(panel_style_changed
);
238 option_register_widget("monitor-number", build_monitor_number
);
241 /* Return a free edge for a new panel.
242 * If no edge is free, returns PANEL_BOTTOM.
244 static PanelSide
find_free_side()
246 if (!current_panel
[PANEL_BOTTOM
])
249 if (!current_panel
[PANEL_TOP
])
252 if (!current_panel
[PANEL_LEFT
])
255 if (!current_panel
[PANEL_RIGHT
])
261 /* 'name' may be NULL or "" to remove the panel */
262 Panel
*panel_new(const gchar
*name
, PanelSide side
)
266 GtkWidget
*vp
, *box
, *frame
, *align
;
267 xmlDocPtr panel_doc
= NULL
;
268 gboolean need_resave
= FALSE
;
270 g_return_val_if_fail(side
== PANEL_DEFAULT_SIDE
||
271 (side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
), NULL
);
272 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
274 if (name
&& *name
== '\0')
279 else if (strchr(name
, '/'))
280 load_path
= g_strdup(name
);
285 leaf
= g_strconcat("pan_", name
, NULL
);
286 load_path
= choices_find_xdg_path_load(leaf
, PROJECT
, SITE
);
290 if (load_path
&& access(load_path
, F_OK
) == 0)
295 panel_doc
= xmlParseFile(load_path
);
296 root
= xmlDocGetRootElement(panel_doc
);
298 saved_side
= xmlGetProp(root
, "side");
302 old_side
= panel_name_to_side(saved_side
);
305 if (side
== PANEL_DEFAULT_SIDE
)
307 else if (side
!= old_side
)
314 if (side
== PANEL_DEFAULT_SIDE
)
315 side
= find_free_side();
317 if (current_panel
[side
])
322 gtk_widget_destroy(current_panel
[side
]->window
);
328 if (name
== NULL
|| *name
== '\0')
331 panel
= g_new(Panel
, 1);
332 panel
->name
= g_strdup(name
);
334 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
335 panel
->autoscroll_speed
= 0;
337 panel
->style
= o_panel_style
.int_value
;
338 panel
->width
= o_panel_width
.int_value
;
339 panel
->xinerama
= o_panel_xinerama
.int_value
;
340 panel
->monitor
= o_panel_monitor
.int_value
;
341 panel
->avoid
= o_panel_avoid
.int_value
;
342 panel_update_geometry(panel
);
344 gtk_window_set_resizable(GTK_WINDOW(panel
->window
), FALSE
);
345 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
346 gtk_widget_set_name(panel
->window
, "rox-panel");
347 gtk_widget_set_events(panel
->window
,
348 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
349 GDK_POINTER_MOTION_MASK
| GDK_LEAVE_NOTIFY_MASK
);
351 /* We make the panel a drop target only so that we can auto-raise! */
352 gtk_drag_dest_set(panel
->window
, 0, NULL
, 0, GDK_ACTION_PRIVATE
);
353 g_signal_connect(panel
->window
, "drag_leave",
354 G_CALLBACK(panel_drag_leave
), panel
);
355 g_signal_connect(panel
->window
, "drag_motion",
356 G_CALLBACK(panel_drag_motion
), panel
);
358 g_signal_connect(panel
->window
, "delete-event",
359 G_CALLBACK(panel_delete
), panel
);
360 g_signal_connect(panel
->window
, "destroy",
361 G_CALLBACK(panel_destroyed
), panel
);
362 g_signal_connect(panel
->window
, "button_press_event",
363 G_CALLBACK(panel_button_press
), panel
);
364 g_signal_connect(panel
->window
, "button_release_event",
365 G_CALLBACK(panel_button_release
), panel
);
366 g_signal_connect(panel
->window
, "motion-notify-event",
367 G_CALLBACK(panel_motion_event
), panel
);
368 g_signal_connect(panel
->window
, "leave-notify-event",
369 G_CALLBACK(panel_leave_event
), panel
);
371 if (panel
->side
== PANEL_RIGHT
)
372 align
= gtk_alignment_new(1.0, 0.0, 0.0, 1.0);
373 else if (panel
->side
== PANEL_BOTTOM
)
374 align
= gtk_alignment_new(0.0, 1.0, 1.0, 0.0);
375 else if (panel
->side
== PANEL_TOP
)
376 align
= gtk_alignment_new(0.0, 0.0, 1.0, 0.0);
378 align
= gtk_alignment_new(0.0, 0.0, 0.0, 1.0);
380 gtk_container_add(GTK_CONTAINER(panel
->window
), align
);
382 vp
= gtk_viewport_new(NULL
, NULL
);
383 gtk_container_set_resize_mode(GTK_CONTAINER(vp
), GTK_RESIZE_PARENT
);
384 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_NONE
);
385 gtk_container_add(GTK_CONTAINER(align
), vp
);
387 g_signal_connect(align
, "expose-event",
388 G_CALLBACK(draw_panel_edge
), panel
);
390 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
392 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
393 box
= gtk_hbox_new(FALSE
, 0);
394 panel
->before
= gtk_hbox_new(FALSE
, 0);
395 panel
->after
= gtk_hbox_new(FALSE
, 0);
399 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
400 box
= gtk_vbox_new(FALSE
, 0);
401 panel
->before
= gtk_vbox_new(FALSE
, 0);
402 panel
->after
= gtk_vbox_new(FALSE
, 0);
405 gtk_container_add(GTK_CONTAINER(vp
), box
);
406 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
407 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
409 frame
= make_insert_frame(panel
);
410 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
412 /* This is used so that we can find the middle easily! */
413 panel
->gap
= gtk_event_box_new();
414 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
416 frame
= make_insert_frame(panel
);
417 g_object_set_data(G_OBJECT(frame
), "after", "yes");
418 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
420 if (o_panel_is_dock
.int_value
)
421 gtk_window_set_type_hint(GTK_WINDOW(panel
->window
),
422 GDK_WINDOW_TYPE_HINT_DOCK
);
424 gtk_widget_realize(panel
->window
);
425 make_panel_window(panel
->window
);
426 gtk_window_stick(GTK_WINDOW(panel
->window
));
428 gtk_widget_show_all(align
);
430 loading_panel
= panel
;
433 panel_load_from_xml(panel
, panel_doc
);
434 xmlFreeDoc(panel_doc
);
441 parse_file(load_path
, pan_from_file
);
442 info_message(_("Your old panel file has been "
443 "converted to the new XML format."));
448 /* Don't scare users with an empty panel... */
451 panel_add_item(panel
, "~", "Home", FALSE
, NULL
, NULL
, FALSE
);
453 apps
= pathdup(make_path(app_dir
, ".."));
456 panel_add_item(panel
, apps
, "Apps", FALSE
, NULL
, NULL
, FALSE
);
460 loading_panel
= NULL
;
463 current_panel
[side
] = panel
;
465 gtk_widget_queue_resize(box
);
466 g_signal_connect(panel
->window
, "size-request",
467 G_CALLBACK(panel_post_resize
), panel
);
468 g_signal_connect(panel
->window
, "size-allocate",
469 G_CALLBACK(reposition_panel
), panel
);
472 gdk_window_lower(panel
->window
->window
);
473 gtk_widget_show(panel
->window
);
474 /* This has no effect until after window is showing; GTK+ bug? */
475 keep_below(panel
->window
->window
, TRUE
);
480 pinboard
= pinboard_get_window();
481 /* (if pinboard is NULL, will go right to the back) */
482 window_put_just_above(panel
->window
->window
, pinboard
);
488 /* Externally visible function to add an item to a panel */
489 gboolean
panel_add(PanelSide side
,
490 const gchar
*path
, const gchar
*label
, gboolean after
, const gchar
*shortcut
, const gchar
*args
,
493 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
495 g_return_val_if_fail(current_panel
[side
] != NULL
, FALSE
);
497 panel_add_item(current_panel
[side
], path
, label
, after
, shortcut
, args
, locked
);
502 /* Add the area covered by the panels to the region */
503 void panel_mark_used(GdkRegion
*used
)
507 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
509 Panel
*panel
= current_panel
[i
];
515 gdk_window_get_root_origin(panel
->window
->window
,
517 rect
.width
= panel
->window
->allocation
.width
;
518 rect
.height
= panel
->window
->allocation
.height
;
520 gdk_region_union_with_rect(used
, &rect
);
524 /* On xrandr screen size changes, update all panels */
525 void panel_update_size(void)
529 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
531 if (current_panel
[i
])
533 reposition_panel(current_panel
[i
]->window
,
534 ¤t_panel
[i
]->window
->allocation
,
536 gtk_widget_queue_resize(current_panel
[i
]->window
);
541 /****************************************************************
542 * INTERNAL FUNCTIONS *
543 ****************************************************************/
545 /* User has tried to close the panel via the window manager - confirm */
546 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
548 return !confirm(_("You have tried to close a panel via the window "
549 "manager - I usually find that this is accidental... "
551 GTK_STOCK_CLOSE
, NULL
);
554 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
556 if (panel_options_dialog
)
558 Panel
*dlg_panel
= g_object_get_data(G_OBJECT(panel_options_dialog
),
561 if (dlg_panel
== panel
)
562 gtk_widget_destroy(panel_options_dialog
);
565 if (current_panel
[panel
->side
] == panel
)
566 current_panel
[panel
->side
] = NULL
;
568 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
570 if (current_panel
[PANEL_RIGHT
])
571 gtk_widget_queue_resize(
572 current_panel
[PANEL_RIGHT
]->window
);
573 if (current_panel
[PANEL_LEFT
])
574 gtk_widget_queue_resize(
575 current_panel
[PANEL_LEFT
]->window
);
578 if (panel
->autoscroll_speed
)
579 g_source_remove(panel
->autoscroll_to
);
587 static void panel_load_side(Panel
*panel
, xmlNodePtr side
, gboolean after
)
590 char *label
, *path
, *shortcut
, *args
, *tmp
;
593 for (node
= side
->xmlChildrenNode
; node
; node
= node
->next
)
595 if (node
->type
!= XML_ELEMENT_NODE
)
597 if (strcmp(node
->name
, "icon") != 0)
600 label
= xmlGetProp(node
, "label");
602 label
= g_strdup("<missing label>");
603 path
= xmlNodeGetContent(node
);
605 path
= g_strdup("<missing path>");
606 shortcut
= xmlGetProp(node
, "shortcut");
607 args
= xmlGetProp(node
, "args");
608 tmp
= xmlGetProp(node
, "locked");
611 locked
= text_to_boolean(tmp
, FALSE
);
617 panel_add_item(panel
, path
, label
, after
, shortcut
, args
, locked
);
626 /* Create one panel icon for each icon in the doc */
627 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
)
631 root
= xmlDocGetRootElement(doc
);
632 panel_load_side(panel
, get_subnode(root
, NULL
, "start"), FALSE
);
633 panel_load_side(panel
, get_subnode(root
, NULL
, "end"), TRUE
);
636 /* Called for each line in the config file while loading a new panel */
637 static const char *pan_from_file(gchar
*line
)
641 g_return_val_if_fail(line
!= NULL
, NULL
);
642 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
647 sep
= strpbrk(line
, "<>");
649 return _("Missing < or > in panel config file");
652 leaf
= g_strndup(line
, sep
- line
);
656 panel_add_item(loading_panel
, sep
+ 1, leaf
, sep
[0] == '>',
664 static gboolean
icon_pointer_in(GtkWidget
*widget
,
665 GdkEventCrossing
*event
,
668 gtk_widget_set_state(widget
,
669 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_PRELIGHT
);
674 static gboolean
icon_pointer_out(GtkWidget
*widget
,
675 GdkEventCrossing
*event
,
678 gtk_widget_set_state(widget
,
679 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_NORMAL
);
684 static void panel_icon_destroyed(PanelIcon
*pi
)
686 g_return_if_fail(pi
->widget
!= NULL
);
693 /* Set the tooltip AND hide/show the label */
694 static void panel_icon_set_tip(PanelIcon
*pi
)
698 Icon
*icon
= (Icon
*) pi
;
700 g_return_if_fail(pi
!= NULL
);
704 if (panel_want_show_text(pi
))
705 gtk_widget_show(pi
->label
);
707 gtk_widget_hide(pi
->label
);
713 ai
= appinfo_get(icon
->path
, icon
->item
);
715 if (ai
&& ((node
= xml_get_section(ai
, NULL
, "Summary"))))
718 str
= xmlNodeListGetString(node
->doc
,
719 node
->xmlChildrenNode
, 1);
722 gtk_tooltips_set_tip(tooltips
, pi
->widget
, str
, NULL
);
726 else if ((!panel_want_show_text(pi
)) && !pi
->socket
)
728 if (icon
->item
->leafname
&& icon
->item
->leafname
[0])
729 gtk_tooltips_set_tip(tooltips
, pi
->widget
,
730 icon
->item
->leafname
, NULL
);
733 gtk_tooltips_set_tip(tooltips
, pi
->widget
, NULL
, NULL
);
739 /* Add an icon with this path to the panel. If after is TRUE then the
740 * icon is added to the right/bottom end of the panel.
742 * If name is NULL a suitable name is taken from path.
744 static void panel_add_item(Panel
*panel
,
748 const gchar
*shortcut
,
756 g_return_if_fail(panel
!= NULL
);
757 g_return_if_fail(path
!= NULL
);
759 widget
= gtk_event_box_new();
760 gtk_widget_set_events(widget
,
761 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
762 GDK_BUTTON3_MOTION_MASK
|
763 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
764 GDK_BUTTON_RELEASE_MASK
);
766 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
767 widget
, FALSE
, TRUE
, 0);
769 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
771 gtk_widget_realize(widget
);
773 pi
= panel_icon_new(panel
, path
, name
);
776 /* Widget takes the initial ref of Icon */
777 g_object_set_data(G_OBJECT(widget
), "icon", pi
);
780 g_object_ref(widget
);
782 gtk_widget_set_name(pi
->widget
, "panel-icon");
784 g_signal_connect_swapped(widget
, "destroy",
785 G_CALLBACK(panel_icon_destroyed
), pi
);
787 if (icon
->item
->base_type
== TYPE_DIRECTORY
)
790 g_signal_connect(widget
, "button_release_event",
791 G_CALLBACK(icon_button_release
), pi
);
792 g_signal_connect(widget
, "button_press_event",
793 G_CALLBACK(icon_button_press
), pi
);
794 g_signal_connect(widget
, "motion-notify-event",
795 G_CALLBACK(icon_motion_event
), pi
);
796 g_signal_connect(widget
, "enter-notify-event",
797 G_CALLBACK(icon_pointer_in
), pi
);
798 g_signal_connect(widget
, "leave-notify-event",
799 G_CALLBACK(icon_pointer_out
), pi
);
803 g_signal_connect(widget
, "enter-notify-event",
804 G_CALLBACK(enter_icon
), pi
);
805 g_signal_connect_after(widget
, "expose_event",
806 G_CALLBACK(expose_icon
), pi
);
807 g_signal_connect(widget
, "drag_data_get",
808 G_CALLBACK(drag_data_get
), NULL
);
810 g_signal_connect(widget
, "size_request",
811 G_CALLBACK(size_request
), pi
);
813 drag_set_panel_dest(pi
);
815 pi
->label
= gtk_label_new(icon
->item
->leafname
);
816 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->label
);
817 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
818 gtk_misc_set_padding(GTK_MISC(pi
->label
), 1, 2);
821 icon_set_shortcut(icon
, shortcut
);
822 icon_set_arguments(icon
, args
);
823 icon
->locked
= locked
;
828 panel_icon_set_tip(pi
);
829 gtk_widget_show(widget
);
832 static gboolean
remove_item_from_side(GtkWidget
*container
, const gchar
*path
,
836 gboolean found
= FALSE
;
838 kids
= gtk_container_get_children(GTK_CONTAINER(container
));
840 for (next
= kids
; next
; next
= next
->next
)
843 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
847 if ((!path
|| strcmp(path
, icon
->src_path
) == 0) &&
848 (!label
|| strcmp(label
, icon
->item
->leafname
)==0))
850 icon
->locked
= FALSE
;
862 /* Remove an item with this path. If more than one item matches, only
863 * one is removed. If label is not NULL then it must also match the item.
864 * Returns TRUE if an item was successfully removed.
866 gboolean
panel_remove_item(PanelSide side
, const gchar
*path
,
871 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
873 g_return_val_if_fail(path
!= NULL
|| label
!= NULL
, FALSE
);
875 panel
= current_panel
[side
];
878 g_warning("No panel on this side of the screen!");
882 if (remove_item_from_side(panel
->before
, path
, label
) ||
883 remove_item_from_side(panel
->after
, path
, label
))
890 g_warning("Panel item path='%s', label='%s' not found", path
, label
);
894 /* Called when Gtk+ wants to know how much space an icon needs.
895 * 'req' is already big enough for the label, if shown.
897 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
)
899 Icon
*icon
= (Icon
*) pi
;
900 gboolean horz
= (pi
->panel
->side
== PANEL_TOP
||
901 pi
->panel
->side
== PANEL_BOTTOM
);
903 int max_height
= 100;
904 int image_width
, image_height
;
905 Panel
*panel
= pi
->panel
;
908 max_height
= panel
->width
- req
->height
;
910 max_width
= MAX(panel
->width
, req
->width
);
912 /* TODO: really need to recreate? */
914 g_object_unref(pi
->image
);
916 pi
->image
= scale_pixbuf(di_image(icon
->item
)->src_pixbuf
,
917 MAX(20, max_width
), MAX(20, max_height
));
919 image_width
= gdk_pixbuf_get_width(pi
->image
);
920 image_height
= gdk_pixbuf_get_height(pi
->image
);
922 if (req
->height
> 0 && max_height
< req
->height
)
924 pi
->style
= TEXT_BESIDE_ICON
;
925 req
->width
+= image_width
;
926 req
->height
= MAX(req
->height
, image_height
);
927 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 1, 0.5);
931 pi
->style
= TEXT_UNDER_ICON
;
932 req
->width
= MAX(req
->width
, image_width
);
933 req
->height
+= image_height
;
934 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
938 req
->width
+= PANEL_ICON_SPACING
;
940 req
->height
+= PANEL_ICON_SPACING
;
943 static gint
expose_icon(GtkWidget
*widget
,
944 GdkEventExpose
*event
,
947 return draw_icon(widget
, &event
->area
, pi
);
950 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, PanelIcon
*pi
)
954 Icon
*icon
= (Icon
*) pi
;
960 gdk_drawable_get_size(widget
->window
, &area
.width
, &area
.height
);
962 if (panel_want_show_text(pi
))
963 text_height
= pi
->label
->requisition
.height
;
965 g_return_val_if_fail(pi
->image
!= NULL
, FALSE
);
969 width
= gdk_pixbuf_get_width(image
);
970 height
= gdk_pixbuf_get_height(image
);
972 if (pi
->style
== TEXT_UNDER_ICON
)
974 image_x
= (area
.width
- width
) >> 1;
975 image_y
= (area
.height
- height
- text_height
) >> 1;
979 image_x
= PANEL_ICON_SPACING
- 2;
980 image_y
= (area
.height
- height
) >> 1;
983 gdk_pixbuf_render_to_drawable_alpha(
987 image_x
, image_y
, /* dest */
989 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
990 GDK_RGB_DITHER_NORMAL
, 0, 0);
992 if (icon
->item
->flags
& ITEM_FLAG_SYMLINK
)
994 gdk_pixbuf_render_to_drawable_alpha(im_symlink
->pixbuf
,
997 image_x
, image_y
+ 2, /* dest */
999 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
1000 GDK_RGB_DITHER_NORMAL
, 0, 0);
1002 if (icon
->item
->flags
& ITEM_FLAG_MOUNT_POINT
)
1004 MaskedPixmap
*mp
= icon
->item
->flags
& ITEM_FLAG_MOUNTED
1008 gdk_pixbuf_render_to_drawable_alpha(mp
->pixbuf
,
1011 image_x
, image_y
+ 2, /* dest */
1013 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
1014 GDK_RGB_DITHER_NORMAL
, 0, 0);
1019 static void panel_icon_wink(Icon
*icon
)
1021 PanelIcon
*pi
= (PanelIcon
*) icon
;
1023 wink_widget(pi
->widget
);
1026 /* icon may be NULL if the event is on the background */
1027 static void perform_action(Panel
*panel
, PanelIcon
*pi
, GdkEventButton
*event
)
1030 Icon
*icon
= (Icon
*) pi
;
1032 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
1034 if (pi
&& pi
->socket
)
1035 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
1041 dnd_motion_ungrab();
1042 wink_widget(pi
->widget
);
1046 dnd_motion_ungrab();
1047 wink_widget(pi
->widget
);
1048 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, TRUE
);
1050 case ACT_POPUP_MENU
:
1051 dnd_motion_ungrab();
1052 panel_show_menu(event
, pi
, panel
);
1055 dnd_motion_start(MOTION_REPOSITION
);
1057 case ACT_PRIME_AND_SELECT
:
1058 if (!icon
->selected
)
1059 icon_select_only(icon
);
1060 dnd_motion_start(MOTION_READY_FOR_DND
);
1062 case ACT_PRIME_AND_TOGGLE
:
1063 icon_set_selected(icon
, !icon
->selected
);
1064 dnd_motion_start(MOTION_READY_FOR_DND
);
1066 case ACT_PRIME_FOR_DND
:
1067 dnd_motion_start(MOTION_READY_FOR_DND
);
1069 case ACT_TOGGLE_SELECTED
:
1070 icon_set_selected(icon
, !icon
->selected
);
1072 case ACT_SELECT_EXCL
:
1073 icon_set_selected(icon
, TRUE
);
1077 case ACT_CLEAR_SELECTION
:
1078 dnd_motion_ungrab();
1079 icon_select_only(NULL
);
1082 g_warning("Unsupported action : %d\n", action
);
1087 static gint
panel_button_release(GtkWidget
*widget
,
1088 GdkEventButton
*event
,
1091 if (dnd_motion_release(event
))
1094 perform_action(panel
, NULL
, event
);
1099 static gint
panel_button_press(GtkWidget
*widget
,
1100 GdkEventButton
*event
,
1103 if (dnd_motion_press(panel
->window
, event
))
1104 perform_action(panel
, NULL
, event
);
1109 static gint
icon_button_release(GtkWidget
*widget
,
1110 GdkEventButton
*event
,
1113 if (pi
->socket
&& event
->button
== 1)
1114 return FALSE
; /* Restart button */
1116 if (dnd_motion_release(event
))
1119 perform_action(pi
->panel
, pi
, event
);
1124 static gint
icon_button_press(GtkWidget
*widget
,
1125 GdkEventButton
*event
,
1128 if (pi
->socket
&& event
->button
== 1)
1129 return FALSE
; /* Restart button */
1131 if (dnd_motion_press(widget
, event
))
1132 perform_action(pi
->panel
, pi
, event
);
1137 static void reposition_panel(GtkWidget
*window
,
1138 GtkAllocation
*alloc
, Panel
*panel
)
1140 int x
= panel
->geometry
.x
;
1141 int y
= panel
->geometry
.y
;
1143 PanelSide side
= panel
->side
;
1145 if (side
== PANEL_LEFT
|| side
== PANEL_RIGHT
)
1147 if (side
== PANEL_RIGHT
)
1148 x
+= panel
->geometry
.width
- alloc
->width
;
1150 if (current_panel
[PANEL_TOP
])
1152 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1153 y
+= win
->allocation
.height
;
1157 if (side
== PANEL_BOTTOM
)
1158 y
+= panel
->geometry
.height
- alloc
->height
;
1160 gtk_window_move(GTK_WINDOW(panel
->window
), x
, y
);
1161 gdk_window_move(panel
->window
->window
, x
, y
);
1163 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
1165 if (current_panel
[PANEL_RIGHT
])
1166 gtk_widget_queue_resize(
1167 current_panel
[PANEL_RIGHT
]->window
);
1168 if (current_panel
[PANEL_LEFT
])
1169 gtk_widget_queue_resize(
1170 current_panel
[PANEL_LEFT
]->window
);
1173 /* Stop windows from maximising over all/part of us */
1176 gulong left
, right
, top
, bottom
;
1177 gulong left_start_y
, left_end_y
;
1178 gulong right_start_y
, right_end_y
;
1179 gulong top_start_x
, top_end_x
;
1180 gulong bottom_start_x
, bottom_end_x
;
1181 } strut
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1183 if (panel
->avoid
== FALSE
)
1185 else if (panel
->side
== PANEL_TOP
||
1186 panel
->side
== PANEL_BOTTOM
)
1187 thickness
= alloc
->height
;
1189 thickness
= alloc
->width
;
1191 switch (panel
->side
)
1194 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].left
)
1196 strut
.left
= panel
->geometry
.x
+ thickness
;
1197 strut
.left_start_y
= panel
->geometry
.y
;
1198 strut
.left_end_y
= panel
->geometry
.y
+
1199 panel
->geometry
.height
- 1;
1201 /* else there is (part of) a monitor
1209 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].right
)
1211 /* RHS of monitor might not abut edge
1212 * of total virtual screen */
1213 strut
.right
= screen_width
-
1215 panel
->geometry
.width
+
1217 strut
.right_start_y
= panel
->geometry
.y
;
1218 strut
.right_end_y
= panel
->geometry
.y
+
1219 panel
->geometry
.height
- 1;
1221 /* else there is (part of) a monitor
1229 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].top
)
1231 strut
.top
= panel
->geometry
.y
+ thickness
;
1232 strut
.top_start_x
= panel
->geometry
.x
;
1233 strut
.top_end_x
= panel
->geometry
.x
+
1234 panel
->geometry
.width
- 1;
1236 /* else there is (part of) a monitor above */
1242 default: /* PANEL_BOTTOM */
1243 if (!panel
->xinerama
||
1244 !monitor_adjacent
[panel
->monitor
].bottom
)
1246 /* Bottom of monitor might not abut
1247 * edge of total virtual screen */
1248 strut
.bottom
= screen_height
-
1250 panel
->geometry
.height
+
1252 strut
.bottom_start_x
= panel
->geometry
.x
;
1253 strut
.bottom_end_x
= panel
->geometry
.x
+
1254 panel
->geometry
.width
- 1;
1256 /* else there is (part of) a monitor below */
1266 /* Set full-width strut as well as partial in case
1267 * partial isn't supported by wm */
1268 gdk_property_change(panel
->window
->window
,
1269 gdk_atom_intern("_NET_WM_STRUT",
1271 gdk_atom_intern("CARDINAL", FALSE
),
1272 32, GDK_PROP_MODE_REPLACE
,
1273 (gchar
*) &strut
, 4);
1274 gdk_property_change(panel
->window
->window
,
1275 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1277 gdk_atom_intern("CARDINAL", FALSE
),
1278 32, GDK_PROP_MODE_REPLACE
,
1279 (gchar
*) &strut
, 12);
1283 gdk_property_delete(panel
->window
->window
,
1284 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1286 gdk_property_delete(panel
->window
->window
,
1287 gdk_atom_intern("_NET_WM_STRUT",
1294 /* Same as drag_set_dest(), but for panel icons */
1295 static void drag_set_panel_dest(PanelIcon
*pi
)
1297 GtkWidget
*obj
= pi
->widget
;
1299 make_drop_target(pi
->widget
, 0);
1301 g_signal_connect(obj
, "drag_motion", G_CALLBACK(drag_motion
), pi
);
1302 g_signal_connect(obj
, "drag_leave", G_CALLBACK(drag_leave
), pi
);
1303 g_signal_connect(obj
, "drag_end", G_CALLBACK(drag_end
), pi
);
1306 static gboolean
drag_motion(GtkWidget
*widget
,
1307 GdkDragContext
*context
,
1313 GdkDragAction action
= context
->suggested_action
;
1314 const char *type
= NULL
;
1315 Icon
*icon
= (Icon
*) pi
;
1316 DirItem
*item
= icon
->item
;
1317 int panel_x
, panel_y
;
1319 gdk_window_get_pointer(pi
->panel
->window
->window
,
1320 &panel_x
, &panel_y
, NULL
);
1321 motion_may_raise(pi
->panel
, panel_x
, panel_y
);
1323 /* Should we scroll the panel when dragging? */
1324 if (motion_state
!= MOTION_REPOSITION
)
1325 if (pi
->panel
->autoscroll_speed
== 0)
1326 may_autoscroll(pi
->panel
);
1329 goto out
; /* Can't drag a selection to itself */
1331 type
= dnd_motion_item(context
, &item
);
1333 if ((context
->actions
& GDK_ACTION_ASK
) && o_dnd_left_menu
.int_value
1334 && type
!= drop_dest_prog
)
1337 gdk_window_get_pointer(NULL
, NULL
, NULL
, &state
);
1338 if (state
& GDK_BUTTON1_MASK
)
1339 action
= GDK_ACTION_ASK
;
1345 /* We actually must pretend to accept the drop, even if the
1346 * directory isn't writeable, so that the spring-opening
1350 /* Don't allow drops to non-writeable directories */
1351 if (o_dnd_spring_open
.int_value
== FALSE
&&
1352 type
== drop_dest_dir
&&
1353 access(icon
->path
, W_OK
) != 0)
1358 g_dataset_set_data(context
, "drop_dest_type", (gpointer
) type
);
1361 gdk_drag_status(context
, action
, time
);
1362 g_dataset_set_data_full(context
, "drop_dest_path",
1363 g_strdup(icon
->path
), g_free
);
1364 if (type
== drop_dest_dir
)
1365 dnd_spring_load(context
, NULL
);
1367 if (dnd_highlight
&& dnd_highlight
!= pi
->widget
)
1369 gtk_drag_unhighlight(dnd_highlight
);
1370 dnd_highlight
= NULL
;
1373 if (dnd_highlight
== NULL
)
1375 gtk_drag_highlight(pi
->widget
);
1376 dnd_highlight
= pi
->widget
;
1380 return type
!= NULL
;
1384 static void add_uri_list(GtkWidget
*widget
,
1385 GdkDragContext
*context
,
1388 GtkSelectionData
*selection_data
,
1393 gboolean after
= FALSE
;
1396 if (!selection_data
->data
)
1399 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
1401 if (g_object_get_data(G_OBJECT(widget
), "after"))
1404 uris
= uri_list_to_glist(selection_data
->data
);
1406 for (next
= uris
; next
; next
= next
->next
)
1410 path
= get_local_path((EscapedPath
*) next
->data
);
1413 panel_add_item(panel
, path
, NULL
, after
, NULL
, NULL
, FALSE
);
1421 static void drag_end(GtkWidget
*widget
,
1422 GdkDragContext
*context
,
1425 if (tmp_icon_selected
)
1427 icon_select_only(NULL
);
1428 tmp_icon_selected
= FALSE
;
1432 static void drag_leave(GtkWidget
*widget
,
1433 GdkDragContext
*context
,
1437 panel_drag_leave(widget
, context
, time
, ((PanelIcon
*) icon
)->panel
);
1439 if (dnd_highlight
&& dnd_highlight
== widget
)
1441 gtk_drag_unhighlight(dnd_highlight
);
1442 dnd_highlight
= NULL
;
1448 /* Create XML icon nodes for these widgets.
1449 * Always frees the widgets list.
1451 static void make_widgets(xmlNodePtr side
, GList
*widgets
)
1455 for (next
= widgets
; next
; next
= next
->next
)
1460 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
1464 g_warning("Can't find Icon from widget\n");
1468 tree
= xmlNewTextChild(side
, NULL
, "icon", icon
->src_path
);
1470 xmlSetProp(tree
, "label", icon
->item
->leafname
);
1472 xmlSetProp(tree
, "shortcut", icon
->shortcut
);
1474 xmlSetProp(tree
, "args", icon
->args
);
1476 xmlSetProp(tree
, "locked", "true");
1480 g_list_free(widgets
);
1483 void panel_save(Panel
*panel
)
1487 guchar
*save
= NULL
;
1488 guchar
*save_new
= NULL
;
1490 g_return_if_fail(panel
!= NULL
);
1492 if (strchr(panel
->name
, '/'))
1493 save
= g_strdup(panel
->name
);
1498 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
1499 save
= choices_find_xdg_path_save(leaf
, PROJECT
, SITE
, TRUE
);
1506 doc
= xmlNewDoc("1.0");
1507 xmlDocSetRootElement(doc
, xmlNewDocNode(doc
, NULL
, "panel", NULL
));
1509 root
= xmlDocGetRootElement(doc
);
1511 xmlSetProp(root
, "side",
1512 panel
->side
== PANEL_TOP
? "Top" :
1513 panel
->side
== PANEL_BOTTOM
? "Bottom" :
1514 panel
->side
== PANEL_LEFT
? "Left" :
1517 make_widgets(xmlNewChild(root
, NULL
, "start", NULL
),
1518 gtk_container_get_children(GTK_CONTAINER(panel
->before
)));
1520 make_widgets(xmlNewChild(root
, NULL
, "end", NULL
),
1521 g_list_reverse(gtk_container_get_children(
1522 GTK_CONTAINER(panel
->after
))));
1524 save_new
= g_strconcat(save
, ".new", NULL
);
1525 if (save_xml_file(doc
, save_new
) || rename(save_new
, save
))
1526 delayed_error(_("Error saving panel %s: %s"),
1527 save
, g_strerror(errno
));
1535 /* Create a frame widget which can be used to add icons to the panel */
1536 static GtkWidget
*make_insert_frame(Panel
*panel
)
1539 GtkTargetEntry target_table
[] = {
1540 {"text/uri-list", 0, TARGET_URI_LIST
},
1543 frame
= gtk_frame_new(NULL
);
1544 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
1545 gtk_widget_set_size_request(frame
, 16, 16);
1547 g_signal_connect(frame
, "drag-motion",
1548 G_CALLBACK(insert_drag_motion
), panel
);
1549 g_signal_connect(frame
, "drag-leave",
1550 G_CALLBACK(panel_drag_leave
), panel
);
1552 g_signal_connect(frame
, "drag-data-received",
1553 G_CALLBACK(add_uri_list
), panel
);
1554 gtk_drag_dest_set(frame
,
1555 GTK_DEST_DEFAULT_ALL
,
1557 sizeof(target_table
) / sizeof(*target_table
),
1563 static gboolean
enter_icon(GtkWidget
*widget
,
1564 GdkEventCrossing
*event
,
1567 icon_may_update(icon
);
1568 panel_icon_set_tip((PanelIcon
*) icon
);
1573 static gint
panel_leave_event(GtkWidget
*widget
,
1574 GdkEventCrossing
*event
,
1577 GdkWindow
*pinboard
;
1579 if (event
->mode
!= GDK_CROSSING_NORMAL
)
1580 return FALSE
; /* Grab for menu, DnD, etc */
1582 keep_below(panel
->window
->window
, TRUE
);
1584 /* Shouldn't need this as well as keep_below but some WMs don't
1585 * automatically lower as soon as the hint is set */
1586 pinboard
= pinboard_get_window();
1587 window_put_just_above(panel
->window
->window
, pinboard
);
1592 /* If (x, y) is at the edge of the panel then raise */
1593 static void motion_may_raise(Panel
*panel
, int x
, int y
)
1597 if (panel
->side
== PANEL_TOP
)
1599 else if (panel
->side
== PANEL_BOTTOM
)
1600 raise
= y
== panel
->window
->allocation
.height
- 1;
1601 else if (panel
->side
== PANEL_LEFT
)
1604 raise
= x
== panel
->window
->allocation
.width
- 1;
1608 keep_below(panel
->window
->window
, FALSE
);
1610 /* Shouldn't need this as well as keep_below but some WMs don't
1611 * automatically raise as soon as the hint is set */
1612 gdk_window_raise(panel
->window
->window
);
1616 static gboolean
may_autoscroll(Panel
*panel
)
1618 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1619 gint max
, panel_x
, panel_y
, delta
, new;
1621 if (panel
->adj
->upper
<= panel
->adj
->page_size
)
1622 goto stop_scrolling
; /* Can see everything already */
1624 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
1629 max
= panel
->window
->allocation
.width
;
1630 if (panel_y
< 0 || panel_y
> panel
->window
->allocation
.height
)
1631 goto stop_scrolling
; /* Not over the panel */
1636 max
= panel
->window
->allocation
.height
;
1637 if (panel_x
< 0 || panel_x
> panel
->window
->allocation
.width
)
1638 goto stop_scrolling
; /* Not over the panel */
1641 if (delta
>= 20 && delta
<= max
- 20)
1642 goto stop_scrolling
; /* Not at either end */
1644 panel
->autoscroll_speed
= MIN(panel
->autoscroll_speed
+ 2, 200);
1646 new = panel
->adj
->value
- ((delta
< 20) ? panel
->autoscroll_speed
1647 : -panel
->autoscroll_speed
);
1648 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
1649 gtk_adjustment_set_value(panel
->adj
, new);
1651 panel
->autoscroll_to
= g_timeout_add(40,
1652 (GSourceFunc
) may_autoscroll
, panel
);
1657 panel
->autoscroll_speed
= 0;
1661 static gint
panel_motion_event(GtkWidget
*widget
,
1662 GdkEventMotion
*event
,
1665 motion_may_raise(panel
, event
->x
, event
->y
);
1667 if (motion_state
!= MOTION_REPOSITION
)
1668 if (panel
->autoscroll_speed
== 0)
1669 may_autoscroll(panel
);
1674 static gint
icon_motion_event(GtkWidget
*widget
,
1675 GdkEventMotion
*event
,
1678 Panel
*panel
= pi
->panel
;
1680 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1684 if (motion_state
== MOTION_READY_FOR_DND
)
1686 if (dnd_motion_moved(event
))
1687 start_drag(pi
, event
);
1690 else if (motion_state
!= MOTION_REPOSITION
)
1693 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1694 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1695 list
= g_list_concat(list
,
1696 gtk_container_get_children(GTK_CONTAINER(panel
->after
)));
1697 me
= g_list_find(list
, widget
);
1699 g_return_val_if_fail(me
!= NULL
, TRUE
);
1701 val
= horz
? event
->x_root
: event
->y_root
;
1709 prev
= GTK_WIDGET(me
->prev
->data
);
1713 gdk_window_get_origin(prev
->window
, &x
, &y
);
1715 if (val
<= (horz
? x
: y
))
1719 if (dir
== 0 && me
->next
)
1725 next
= GTK_WIDGET(me
->next
->data
);
1729 gdk_window_get_origin(next
->window
, &x
, &y
);
1731 gdk_drawable_get_size(next
->window
, &w
, &h
);
1736 if (val
>= (horz
? x
: y
)-1)
1738 if (next
== panel
->gap
)
1746 reposition_icon(pi
, g_list_index(list
, widget
) + dir
);
1751 static void reposition_icon_on_side(GtkWidget
*side
, GtkWidget
*widget
,
1756 list
= gtk_container_get_children(GTK_CONTAINER(side
));
1758 /* Want to move icon to the list in the given 'side'. Is it there
1762 if (!g_list_find(list
, widget
))
1765 gtk_grab_remove(widget
);
1766 gtk_widget_reparent(widget
, side
);
1767 dnd_motion_grab_pointer();
1768 gtk_grab_add(widget
);
1771 gtk_box_reorder_child(GTK_BOX(side
), widget
, index
);
1776 /* Move icon to this index in the complete widget list.
1777 * 0 makes the icon the left-most icon. The gap in the middle has
1778 * an index number, which allows you to specify that the icon should
1779 * go on the left or right side.
1781 static void reposition_icon(PanelIcon
*pi
, int index
)
1783 Panel
*panel
= pi
->panel
;
1784 GtkWidget
*widget
= pi
->widget
;
1788 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1789 before_len
= g_list_length(list
);
1792 if (index
<= before_len
)
1793 reposition_icon_on_side(panel
->before
, widget
, index
);
1795 reposition_icon_on_side(panel
->after
, widget
,
1796 index
- (before_len
+ 1));
1801 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
)
1803 GtkWidget
*widget
= pi
->widget
;
1804 Icon
*icon
= (Icon
*) pi
;
1806 if (!icon
->selected
)
1808 if (event
->state
& GDK_BUTTON1_MASK
)
1810 /* Select just this one */
1811 icon_select_only(icon
);
1812 tmp_icon_selected
= TRUE
;
1815 icon_set_selected(icon
, TRUE
);
1818 g_return_if_fail(icon_selection
!= NULL
);
1820 if (icon_selection
->next
== NULL
)
1821 drag_one_item(widget
, event
, icon
->path
, icon
->item
, NULL
);
1826 uri_list
= icon_create_uri_list();
1827 drag_selection(widget
, event
, uri_list
);
1832 static void applet_died(GtkWidget
*socket
)
1834 gboolean never_plugged
;
1836 never_plugged
= (!g_object_get_data(G_OBJECT(socket
), "lost_plug"))
1837 && !GTK_SOCKET(socket
)->plug_window
;
1842 _("Applet quit without ever creating a widget!"));
1843 gtk_widget_destroy(socket
);
1846 gtk_widget_unref(socket
);
1849 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1851 g_object_set_data(G_OBJECT(socket
), "lost_plug", "yes");
1853 gtk_widget_unref(socket
);
1855 gtk_widget_destroy(widget
); /* Remove from panel */
1858 panel_save(g_object_get_data(G_OBJECT(socket
), "panel"));
1861 /* Try to run this applet.
1864 * - No executable AppletRun:
1865 * icon->socket == NULL (unchanged) on return.
1867 * Otherwise, create socket (setting icon->socket) and ref it twice.
1869 * - AppletRun quits without connecting a plug:
1870 * On child death lost_plug is unset and socket is empty.
1872 * Report error and destroy widget (to 'socket destroyed').
1874 * - AppletRun quits while plug is in socket:
1875 * Unref socket once. Socket will be destroyed later.
1877 * - Socket is destroyed.
1878 * Set lost_plug = "yes" and remove widget from panel.
1881 static void run_applet(PanelIcon
*pi
)
1883 GError
*error
= NULL
;
1886 Icon
*icon
= (Icon
*) pi
;
1888 argv
[0] = (char *) make_path(icon
->path
, "AppletRun");
1890 if (access(argv
[0], X_OK
) != 0)
1893 pi
->socket
= gtk_socket_new();
1895 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->socket
);
1896 gtk_widget_show_all(pi
->socket
);
1897 gtk_widget_realize(pi
->socket
);
1899 /* Always get button-2 events so we can drag */
1900 XGrabButton(gdk_display
, Button2
, AnyModifier
,
1901 GDK_WINDOW_XWINDOW(pi
->socket
->window
),
1903 ButtonPressMask
| ButtonReleaseMask
| Button2MotionMask
,
1904 GrabModeAsync
, /* Pointer */
1905 GrabModeAsync
, /* Keyboard */
1910 PanelSide side
= pi
->panel
->side
;
1912 /* Set a hint to let applets position their menus correctly */
1913 pos
= g_strdup_printf("%s,%d",
1914 side
== PANEL_TOP
? "Top" :
1915 side
== PANEL_BOTTOM
? "Bottom" :
1916 side
== PANEL_LEFT
? "Left" :
1917 "Right", MENU_MARGIN(side
));
1918 gdk_property_change(pi
->socket
->window
,
1919 gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE
),
1920 gdk_atom_intern("STRING", FALSE
),
1921 8, GDK_PROP_MODE_REPLACE
,
1925 /* Ensure that the properties are set before starting the
1931 g_object_set_data(G_OBJECT(pi
->widget
), "icon", pi
);
1932 g_object_set_data(G_OBJECT(pi
->socket
), "panel", pi
->panel
);
1934 argv
[1] = g_strdup_printf("%ld",
1935 GDK_WINDOW_XWINDOW(pi
->socket
->window
));
1938 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_DO_NOT_REAP_CHILD
,
1939 NULL
, NULL
, &pid
, &error
))
1941 delayed_error(_("Error running applet:\n%s"), error
->message
);
1942 g_error_free(error
);
1943 gtk_widget_destroy(pi
->socket
);
1948 gtk_widget_ref(pi
->socket
);
1949 on_child_death(pid
, (CallbackFn
) applet_died
, pi
->socket
);
1951 gtk_widget_ref(pi
->socket
);
1952 g_signal_connect(pi
->socket
, "destroy",
1953 G_CALLBACK(socket_destroyed
), pi
->widget
);
1959 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
1961 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
1963 req
->width
= panel
->geometry
.width
;
1964 req
->height
+= EDGE_WIDTH
;
1968 int h
= panel
->geometry
.height
;
1970 if (current_panel
[PANEL_TOP
])
1972 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1973 h
-= win
->allocation
.height
;
1976 if (current_panel
[PANEL_BOTTOM
])
1978 GtkWidget
*win
= current_panel
[PANEL_BOTTOM
]->window
;
1979 h
-= win
->allocation
.height
;
1983 req
->width
+= EDGE_WIDTH
;
1987 static void update_side(GtkWidget
*side
)
1991 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
1992 for (next
= kids
; next
; next
= next
->next
)
1995 pi
= g_object_get_data(next
->data
, "icon");
1996 panel_icon_set_tip(pi
);
2001 /* Tips or style has changed -- update everything on this panel */
2002 static void panel_set_style(Panel
*panel
)
2004 update_side(panel
->before
);
2005 update_side(panel
->after
);
2006 gtk_widget_queue_resize(panel
->window
);
2009 static gboolean
recreate_panels(char **names
)
2013 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2017 panel_new(names
[i
], i
);
2027 static void update_side_size(GtkWidget
*side
)
2031 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
2032 for (next
= kids
; next
; next
= next
->next
)
2035 pi
= g_object_get_data(next
->data
, "icon");
2036 gtk_widget_queue_resize(pi
->widget
);
2041 /* Update panel size and redraw */
2042 static void panel_update(Panel
*panel
)
2044 update_side_size(panel
->before
);
2045 update_side_size(panel
->after
);
2046 gtk_widget_queue_resize(panel
->window
);
2047 gtk_widget_queue_draw(panel
->window
);
2050 static void panel_style_changed(void)
2054 if (o_override_redirect
.has_changed
)
2058 names
= g_new(char *, PANEL_NUMBER_OF_SIDES
);
2060 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2062 Panel
*panel
= current_panel
[i
];
2063 names
[i
] = panel
? g_strdup(panel
->name
) : NULL
;
2067 g_idle_add((GtkFunction
) recreate_panels
, names
);
2070 if (o_panel_style
.has_changed
)
2072 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2074 if (current_panel
[i
])
2075 panel_set_style(current_panel
[i
]);
2078 if (o_panel_width
.has_changed
)
2080 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2082 if (current_panel
[i
])
2083 panel_update(current_panel
[i
]);
2087 if (o_panel_xinerama
.has_changed
|| o_panel_monitor
.has_changed
||
2088 o_panel_avoid
.has_changed
)
2090 //if (panel_check_xinerama() || o_panel_avoid.has_changed)
2092 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2094 if (current_panel
[i
])
2097 current_panel
[i
]->window
,
2101 gtk_widget_queue_resize(
2102 current_panel
[i
]->window
);
2109 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
2112 int x
, y
, width
, height
;
2114 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
2116 width
= panel
->geometry
.width
;
2117 height
= EDGE_WIDTH
;
2120 if (panel
->side
== PANEL_BOTTOM
)
2123 y
= widget
->allocation
.height
- EDGE_WIDTH
;
2128 height
= panel
->geometry
.height
;
2131 if (panel
->side
== PANEL_RIGHT
)
2134 x
= widget
->allocation
.width
- EDGE_WIDTH
;
2137 gdk_draw_rectangle(widget
->window
,
2138 widget
->style
->fg_gc
[GTK_STATE_NORMAL
], TRUE
,
2139 x
, y
, width
, height
);
2144 static gpointer parent_class
;
2146 static void panel_icon_destroy(Icon
*icon
)
2148 PanelIcon
*pi
= (PanelIcon
*) icon
;
2150 g_return_if_fail(pi
!= NULL
);
2153 g_object_unref(pi
->image
);
2155 g_return_if_fail(pi
->widget
!= NULL
);
2157 gtk_widget_destroy(pi
->widget
);
2160 static void panel_remove_items(void)
2164 g_return_if_fail(icon_selection
!= NULL
);
2166 panel
= ((PanelIcon
*) icon_selection
->data
)->panel
;
2168 while (icon_selection
)
2169 icon_destroy((Icon
*) icon_selection
->data
);
2174 /* Icon's size, shape or appearance has changed - update the display */
2175 static void panel_icon_redraw(Icon
*icon
)
2177 PanelIcon
*pi
= (PanelIcon
*) icon
;
2179 gtk_widget_set_state(pi
->widget
,
2180 icon
->selected
? GTK_STATE_SELECTED
2181 : GTK_STATE_NORMAL
);
2183 /* Will regenerate the scaled icon from the new image */
2184 gtk_widget_queue_resize(pi
->widget
);
2186 panel_icon_set_tip((PanelIcon
*) icon
);
2189 static void panel_icon_update(Icon
*icon
)
2191 PanelIcon
*pi
= (PanelIcon
*) icon
;
2193 gtk_widget_queue_draw(pi
->widget
);
2194 gtk_label_set_text(GTK_LABEL(pi
->label
), icon
->item
->leafname
);
2195 panel_save(pi
->panel
);
2198 /* The point of this is to clear the selection if the existing icons
2199 * aren't from the same panel...
2201 static gboolean
panel_icon_same_group(Icon
*icon
, Icon
*other
)
2203 if (IS_PANEL_ICON(other
))
2205 PanelIcon
*a
= (PanelIcon
*) icon
;
2206 PanelIcon
*b
= (PanelIcon
*) other
;
2208 return a
->panel
== b
->panel
;
2214 static void panel_icon_class_init(gpointer gclass
, gpointer data
)
2216 IconClass
*icon
= (IconClass
*) gclass
;
2218 parent_class
= g_type_class_peek_parent(gclass
);
2220 icon
->destroy
= panel_icon_destroy
;
2221 icon
->redraw
= panel_icon_redraw
;
2222 icon
->update
= panel_icon_update
;
2223 icon
->remove_items
= panel_remove_items
;
2224 icon
->same_group
= panel_icon_same_group
;
2225 icon
->wink
= panel_icon_wink
;
2228 static void panel_icon_init(GTypeInstance
*object
, gpointer gclass
)
2230 PanelIcon
*pi
= (PanelIcon
*) object
;
2236 pi
->style
= TEXT_UNDER_ICON
;
2239 static GType
panel_icon_get_type(void)
2241 static GType type
= 0;
2245 static const GTypeInfo info
=
2247 sizeof (PanelIconClass
),
2248 NULL
, /* base_init */
2249 NULL
, /* base_finalise */
2250 panel_icon_class_init
,
2251 NULL
, /* class_finalise */
2252 NULL
, /* class_data */
2254 0, /* n_preallocs */
2258 type
= g_type_register_static(icon_get_type(),
2259 "PanelIcon", &info
, 0);
2265 static PanelIcon
*panel_icon_new(Panel
*panel
,
2266 const char *pathname
,
2272 pi
= g_object_new(panel_icon_get_type(), NULL
);
2275 icon_set_path(icon
, pathname
, name
);
2281 static gboolean
panel_want_show_text(PanelIcon
*pi
)
2283 Icon
*icon
= (Icon
*) pi
;
2284 Panel
*panel
= pi
->panel
;
2286 if (!icon
->item
->leafname
[0])
2289 if (panel
->style
== SHOW_BOTH
)
2291 if (panel
->style
== SHOW_ICON
)
2294 if (icon
->item
->flags
& ITEM_FLAG_APPDIR
)
2297 if (EXECUTABLE_FILE(icon
->item
))
2303 static void panel_show_options(Panel
*panel
)
2306 gboolean already_showing
= FALSE
;
2307 GladeXML
*glade
= NULL
;
2309 if (panel_options_dialog
)
2311 dialog
= panel_options_dialog
;
2312 already_showing
= TRUE
;
2313 glade
= glade_get_widget_tree(dialog
);
2317 glade
= get_glade_xml("Panel Options");
2318 dialog
= glade_xml_get_widget(glade
, "Panel Options");
2319 panel_options_dialog
= dialog
;
2320 g_signal_connect(dialog
, "destroy",
2321 G_CALLBACK(gtk_widget_destroyed
),
2322 &panel_options_dialog
);
2323 glade_xml_signal_autoconnect(glade
);
2324 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), GTK_RESPONSE_CLOSE
);
2326 g_object_set_data(G_OBJECT(panel_options_dialog
), "rox-panel", panel
);
2328 gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(
2329 glade_xml_get_widget(glade
, "panel_xinerama_monitor")),
2330 GTK_ADJUSTMENT(gtk_adjustment_new(MAX(0, panel
->monitor
),
2331 0, n_monitors
- 1, 1, 10, 1)));
2333 if (already_showing
)
2335 GtkWindow
*win
= GTK_WINDOW(dialog
);
2337 gtk_widget_hide(dialog
);
2338 /* This extra set_position() should ensure it moves to new position
2340 gtk_window_set_position(win
, GTK_WIN_POS_CENTER_ALWAYS
);
2341 gtk_window_set_position(win
, GTK_WIN_POS_MOUSE
);
2342 gtk_window_present(win
);
2346 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
2347 gtk_widget_show_all(dialog
);
2351 static void panel_position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
,
2352 gboolean
*push_in
, gpointer data
)
2354 int *pos
= (int *) data
;
2355 GtkRequisition requisition
;
2356 int margin
= pos
[2];
2358 int mon_right
= monitor_geom
[mon
].x
+
2359 monitor_geom
[mon
].width
;
2360 int mon_bottom
= monitor_geom
[mon
].y
+
2361 monitor_geom
[mon
].height
;
2363 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
2366 *x
= mon_right
- margin
- requisition
.width
;
2367 else if (pos
[0] == -2)
2368 *x
= monitor_geom
[mon
].x
+ margin
;
2370 *x
= pos
[0] - (requisition
.width
>> 2);
2373 *y
= mon_bottom
- margin
- requisition
.height
;
2374 else if (pos
[1] == -2)
2375 *y
= monitor_geom
[mon
].y
+ margin
;
2377 *y
= pos
[1] - (requisition
.height
>> 2);
2379 *x
= CLAMP(*x
, 0, mon_right
- requisition
.width
);
2380 *y
= CLAMP(*y
, 0, mon_bottom
- requisition
.height
);
2385 static void side_radio_toggled(GtkCheckMenuItem
*item
, Panel
*panel
)
2389 char *name
, *other_side_name
;
2391 if (!gtk_check_menu_item_get_active(item
))
2393 new_side
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item
),
2395 old_side
= panel
->side
;
2396 if (new_side
== old_side
)
2399 name
= g_strdup(panel
->name
);
2400 other_side_name
= current_panel
[new_side
]
2401 ? g_strdup(current_panel
[new_side
]->name
)
2404 panel_new(name
, new_side
);
2405 panel_new(other_side_name
, old_side
);
2408 g_free(other_side_name
);
2411 static void append_pos_to_menu(GtkWidget
*menu
, const char *label
,
2412 PanelSide side
, PanelSide current_side
, GSList
**pgroup
, Panel
*panel
)
2414 GtkWidget
*item
= gtk_radio_menu_item_new_with_label(*pgroup
, label
);
2416 *pgroup
= gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item
));
2417 if (side
== current_side
)
2418 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item
), TRUE
);
2419 g_object_set_data(G_OBJECT(item
), "rox-panel-side", GINT_TO_POINTER(side
));
2420 g_signal_connect(item
, "toggled", G_CALLBACK(side_radio_toggled
), panel
);
2421 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
2422 gtk_widget_show(item
);
2425 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
)
2427 GtkWidget
*option_item
;
2428 PanelSide side
= panel
->side
;
2430 GtkWidget
*pos_submenu
;
2431 GtkWidget
*change_side_item
;
2432 GSList
*pos_radio_group
= NULL
;
2434 pos
[0] = event
->x_root
;
2435 pos
[1] = event
->y_root
;
2436 pos
[2] = MENU_MARGIN(side
);
2437 /* FIXME: Should we read screen from event's window rather than
2439 pos
[3] = gdk_screen_get_monitor_at_point(
2440 gdk_screen_get_default(),
2441 event
->x_root
, event
->y_root
);
2443 option_item
= gtk_image_menu_item_new_with_label(_("Panel Options..."));
2444 g_signal_connect_swapped(option_item
, "activate",
2445 G_CALLBACK(panel_show_options
), panel
);
2447 pos_submenu
= gtk_menu_new();
2448 append_pos_to_menu(pos_submenu
, _("Top Edge"), PANEL_TOP
, side
,
2449 &pos_radio_group
, panel
);
2450 append_pos_to_menu(pos_submenu
, _("Bottom Edge"), PANEL_BOTTOM
, side
,
2451 &pos_radio_group
, panel
);
2452 append_pos_to_menu(pos_submenu
, _("Left Edge"), PANEL_LEFT
, side
,
2453 &pos_radio_group
, panel
);
2454 append_pos_to_menu(pos_submenu
, _("Right Edge"), PANEL_RIGHT
, side
,
2455 &pos_radio_group
, panel
);
2456 change_side_item
= gtk_menu_item_new_with_label(_("Change panel side"));
2457 gtk_menu_item_set_submenu(GTK_MENU_ITEM(change_side_item
), pos_submenu
);
2459 icon_prepare_menu((Icon
*) pi
, option_item
, change_side_item
, NULL
);
2461 if (side
== PANEL_LEFT
)
2463 else if (side
== PANEL_RIGHT
)
2466 if (side
== PANEL_TOP
)
2468 else if (side
== PANEL_BOTTOM
)
2471 gtk_menu_popup(GTK_MENU(icon_menu
), NULL
, NULL
,
2472 panel_position_menu
,
2473 (gpointer
) pos
, event
->button
, event
->time
);
2476 /* Note: also called from icon handler */
2477 static gboolean
panel_drag_motion(GtkWidget
*widget
,
2478 GdkDragContext
*context
,
2484 int panel_x
, panel_y
;
2486 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2488 motion_may_raise(panel
, panel_x
, panel_y
);
2489 gdk_drag_status(context
, 0, time
);
2494 static gboolean
insert_drag_motion(GtkWidget
*widget
,
2495 GdkDragContext
*context
,
2501 int panel_x
, panel_y
;
2503 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2504 motion_may_raise(panel
, panel_x
, panel_y
);
2509 /* Note: also called from icon handler */
2510 static void panel_drag_leave(GtkWidget
*widget
,
2511 GdkDragContext
*context
,
2515 GdkWindow
*pinboard
, *window
;
2516 GtkAllocation
*alloc
= &panel
->window
->allocation
;
2519 window
= panel
->window
->window
;
2520 gdk_window_get_pointer(window
, &x
, &y
, NULL
);
2521 if (x
< 0 || y
< 0 || x
> alloc
->width
|| y
> alloc
->height
)
2523 keep_below(panel
->window
->window
, TRUE
);
2525 /* Shouldn't need this as well as keep_below but some WMs don't
2526 * automatically lower as soon as the hint is set */
2527 pinboard
= pinboard_get_window();
2528 window_put_just_above(panel
->window
->window
, pinboard
);
2532 static void panel_update_geometry(Panel
*panel
)
2534 if (panel
->xinerama
&& panel
->monitor
>= n_monitors
)
2536 g_warning(_("Xinerama monitor %d unavailable"), panel
->monitor
);
2537 panel
->xinerama
= FALSE
;
2540 if (panel
->xinerama
)
2542 panel
->geometry
= monitor_geom
[panel
->monitor
];
2546 panel
->geometry
.x
= panel
->geometry
.y
= 0;
2547 panel
->geometry
.width
= screen_width
;
2548 panel
->geometry
.height
= screen_height
;
2552 static GList
*build_monitor_number(Option
*option
, xmlNode
*node
, guchar
*label
)
2556 adj
= gtk_adjustment_new(MAX(0, panel_monitor
),
2557 0, n_monitors
- 1, 1, 10, 1);
2558 return build_numentry_base(option
, node
, label
, GTK_ADJUSTMENT(adj
));
2561 /* Returns PANEL_NUMBER_OF_SIDES if name is invalid */
2562 PanelSide
panel_name_to_side(gchar
*side
)
2564 if (strcmp(side
, "Top") == 0)
2566 else if (strcmp(side
, "Bottom") == 0)
2567 return PANEL_BOTTOM
;
2568 else if (strcmp(side
, "Left") == 0)
2570 else if (strcmp(side
, "Right") == 0)
2573 g_warning("Unknown panel side '%s'", side
);
2574 return PANEL_NUMBER_OF_SIDES
;
2577 inline static Panel
*panel_from_opts_widget(GtkWidget
*widget
)
2579 return g_object_get_data(G_OBJECT(gtk_widget_get_toplevel(widget
)),
2583 static void panel_style_radio_toggled(GtkToggleButton
*widget
, int which
)
2587 if (!gtk_toggle_button_get_active(widget
))
2589 panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2592 /* Handlers autoconnected by glade can't be static but aren't called from
2593 * elsewhere so declare prototypes first to prevent warnings */
2594 void panel_style_radio_0_toggled_cb(GtkToggleButton
*widget
);
2595 void panel_style_radio_1_toggled_cb(GtkToggleButton
*widget
);
2596 void panel_style_radio_2_toggled_cb(GtkToggleButton
*widget
);
2597 void panel_width_changed_cb(GtkSpinButton
*widget
);
2598 void panel_dont_cover_toggled_cb(GtkToggleButton
*widget
);
2599 void panel_xinerama_confine_toggled_cb(GtkToggleButton
*widget
);
2600 void panel_xinerama_monitor_changed_cb(GtkSpinButton
*widget
);
2602 void panel_style_radio_0_toggled_cb(GtkToggleButton
*widget
)
2604 panel_style_radio_toggled(widget
, 0);
2607 void panel_style_radio_1_toggled_cb(GtkToggleButton
*widget
)
2609 panel_style_radio_toggled(widget
, 1);
2612 void panel_style_radio_2_toggled_cb(GtkToggleButton
*widget
)
2614 panel_style_radio_toggled(widget
, 2);
2617 void panel_width_changed_cb(GtkSpinButton
*widget
)
2619 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2622 void panel_dont_cover_toggled_cb(GtkToggleButton
*widget
)
2624 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2627 void panel_xinerama_confine_toggled_cb(GtkToggleButton
*widget
)
2629 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2632 void panel_xinerama_monitor_changed_cb(GtkSpinButton
*widget
)
2634 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));