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
);
204 static gboolean
panel_keep_below(Panel
*panel
, gboolean setting
);
207 static GtkWidget
*dnd_highlight
= NULL
; /* (stops flickering) */
210 #define SHOW_APPS_SMALL 1
212 static Option o_panel_style
;
213 static Option o_panel_width
;
214 static Option o_panel_xinerama
;
215 static Option o_panel_monitor
;
216 static Option o_panel_avoid
;
217 static Option o_panel_is_dock
;
218 static Option o_panel_on_top
;
219 static Option o_panel_obey_workarea
;
221 static gint panel_monitor
= -1;
223 static int closing_panel
= 0; /* Don't panel_save; destroying! */
225 /****************************************************************
226 * EXTERNAL INTERFACE *
227 ****************************************************************/
229 void panel_init(void)
231 option_add_int(&o_panel_style
, "panel_style", SHOW_APPS_SMALL
);
232 option_add_int(&o_panel_width
, "panel_width", 52);
234 option_add_int(&o_panel_xinerama
, "panel_xinerama", 0);
235 option_add_int(&o_panel_monitor
, "panel_monitor", 0);
237 option_add_int(&o_panel_avoid
, "panel_avoid", TRUE
);
238 option_add_int(&o_panel_is_dock
, "panel_is_dock", TRUE
);
239 option_add_int(&o_panel_on_top
, "panel_on_top", FALSE
);
241 option_add_int(&o_panel_obey_workarea
, "panel_obey_workarea", FALSE
);
243 option_add_notify(panel_style_changed
);
245 option_register_widget("monitor-number", build_monitor_number
);
248 /* Return a free edge for a new panel.
249 * If no edge is free, returns PANEL_BOTTOM.
251 static PanelSide
find_free_side()
253 if (!current_panel
[PANEL_BOTTOM
])
256 if (!current_panel
[PANEL_TOP
])
259 if (!current_panel
[PANEL_LEFT
])
262 if (!current_panel
[PANEL_RIGHT
])
268 /* Returns TRUE and sets *target if the property exists, otherwise returns
269 * FALSE and leaves *target unchanged */
270 static gboolean
get_int_prop(xmlNodePtr node
, const char *name
, int *target
)
272 char *prop
= xmlGetProp(node
, name
);
276 *target
= atoi(prop
);
283 static void set_int_prop(xmlNodePtr node
, const char *name
, int value
)
287 sprintf(prop
, "%d", value
);
288 xmlSetProp(node
, name
, prop
);
291 static void panel_load_options_from_xml(Panel
*panel
, xmlDocPtr doc
)
296 root
= xmlDocGetRootElement(doc
);
297 options
= get_subnode(root
, NULL
, "options");
300 get_int_prop(options
, "style", &panel
->style
);
301 get_int_prop(options
, "width", &panel
->width
);
302 get_int_prop(options
, "avoid", &panel
->avoid
);
303 get_int_prop(options
, "xinerama", &panel
->xinerama
);
304 get_int_prop(options
, "monitor", &panel
->monitor
);
307 static void save_panels(void)
309 char *filename
= choices_find_xdg_path_save("panels",
310 "ROX-Filer", "rox.sourceforge.net", TRUE
);
311 char *tmp
= g_strconcat(filename
, ".new", NULL
);
312 FILE *fp
= fopen(tmp
, "w");
318 for (n
= 0; n
< PANEL_NUMBER_OF_SIDES
; ++n
)
320 if (current_panel
[n
])
321 fprintf(fp
, "%s\n", current_panel
[n
]->name
);
324 if (rename(tmp
, filename
))
325 g_critical(_("Unable to replace '%s'"), filename
);
329 g_critical(_("Unable to save '%s'"), tmp
);
335 /* 'name' may be NULL or "" to remove the panel */
336 Panel
*panel_new(const gchar
*name
, PanelSide side
)
340 GtkWidget
*vp
, *box
, *frame
, *align
;
341 xmlDocPtr panel_doc
= NULL
;
342 gboolean need_resave
= FALSE
;
344 g_return_val_if_fail(side
== PANEL_DEFAULT_SIDE
||
345 (side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
), NULL
);
346 g_return_val_if_fail(loading_panel
== NULL
, NULL
);
348 if (name
&& *name
== '\0')
353 else if (strchr(name
, '/'))
354 load_path
= g_strdup(name
);
359 leaf
= g_strconcat("pan_", name
, NULL
);
360 load_path
= choices_find_xdg_path_load(leaf
, PROJECT
, SITE
);
364 if (load_path
&& access(load_path
, F_OK
) == 0)
369 panel_doc
= xmlParseFile(load_path
);
370 root
= xmlDocGetRootElement(panel_doc
);
372 saved_side
= xmlGetProp(root
, "side");
376 old_side
= panel_name_to_side(saved_side
);
379 if (side
== PANEL_DEFAULT_SIDE
)
381 else if (side
!= old_side
)
388 if (side
== PANEL_DEFAULT_SIDE
)
389 side
= find_free_side();
391 if (current_panel
[side
])
396 gtk_widget_destroy(current_panel
[side
]->window
);
402 if (name
== NULL
|| *name
== '\0')
408 panel
= g_new(Panel
, 1);
409 panel
->name
= g_strdup(name
);
411 panel
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
412 panel
->autoscroll_speed
= 0;
414 /* These are fallbacks from legacy global options */
415 panel
->style
= o_panel_style
.int_value
;
416 panel
->width
= o_panel_width
.int_value
;
417 panel
->xinerama
= o_panel_xinerama
.int_value
;
418 panel
->monitor
= o_panel_monitor
.int_value
;
419 panel
->avoid
= o_panel_avoid
.int_value
;
421 /* Now try to load options from this panel's XML */
424 panel_load_options_from_xml(panel
, panel_doc
);
428 /* Otherwise ensure old settings are migrated */
432 panel_update_geometry(panel
);
434 gtk_window_set_resizable(GTK_WINDOW(panel
->window
), FALSE
);
435 gtk_window_set_wmclass(GTK_WINDOW(panel
->window
), "ROX-Panel", PROJECT
);
436 gtk_widget_set_name(panel
->window
, "rox-panel");
437 gtk_widget_set_events(panel
->window
,
438 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
439 GDK_POINTER_MOTION_MASK
| GDK_LEAVE_NOTIFY_MASK
);
441 /* We make the panel a drop target only so that we can auto-raise! */
442 gtk_drag_dest_set(panel
->window
, 0, NULL
, 0, GDK_ACTION_PRIVATE
);
443 g_signal_connect(panel
->window
, "drag_leave",
444 G_CALLBACK(panel_drag_leave
), panel
);
445 g_signal_connect(panel
->window
, "drag_motion",
446 G_CALLBACK(panel_drag_motion
), panel
);
448 g_signal_connect(panel
->window
, "delete-event",
449 G_CALLBACK(panel_delete
), panel
);
450 g_signal_connect(panel
->window
, "destroy",
451 G_CALLBACK(panel_destroyed
), panel
);
452 g_signal_connect(panel
->window
, "button_press_event",
453 G_CALLBACK(panel_button_press
), panel
);
454 g_signal_connect(panel
->window
, "button_release_event",
455 G_CALLBACK(panel_button_release
), panel
);
456 g_signal_connect(panel
->window
, "motion-notify-event",
457 G_CALLBACK(panel_motion_event
), panel
);
458 g_signal_connect(panel
->window
, "leave-notify-event",
459 G_CALLBACK(panel_leave_event
), panel
);
461 if (panel
->side
== PANEL_RIGHT
)
462 align
= gtk_alignment_new(1.0, 0.0, 0.0, 1.0);
463 else if (panel
->side
== PANEL_BOTTOM
)
464 align
= gtk_alignment_new(0.0, 1.0, 1.0, 0.0);
465 else if (panel
->side
== PANEL_TOP
)
466 align
= gtk_alignment_new(0.0, 0.0, 1.0, 0.0);
468 align
= gtk_alignment_new(0.0, 0.0, 0.0, 1.0);
470 gtk_container_add(GTK_CONTAINER(panel
->window
), align
);
472 vp
= gtk_viewport_new(NULL
, NULL
);
473 gtk_container_set_resize_mode(GTK_CONTAINER(vp
), GTK_RESIZE_PARENT
);
474 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp
), GTK_SHADOW_NONE
);
475 gtk_container_add(GTK_CONTAINER(align
), vp
);
477 g_signal_connect(align
, "expose-event",
478 G_CALLBACK(draw_panel_edge
), panel
);
480 if (side
== PANEL_TOP
|| side
== PANEL_BOTTOM
)
482 panel
->adj
= gtk_viewport_get_hadjustment(GTK_VIEWPORT(vp
));
483 box
= gtk_hbox_new(FALSE
, 0);
484 panel
->before
= gtk_hbox_new(FALSE
, 0);
485 panel
->after
= gtk_hbox_new(FALSE
, 0);
489 panel
->adj
= gtk_viewport_get_vadjustment(GTK_VIEWPORT(vp
));
490 box
= gtk_vbox_new(FALSE
, 0);
491 panel
->before
= gtk_vbox_new(FALSE
, 0);
492 panel
->after
= gtk_vbox_new(FALSE
, 0);
495 gtk_container_add(GTK_CONTAINER(vp
), box
);
496 gtk_box_pack_start(GTK_BOX(box
), panel
->before
, FALSE
, TRUE
, 0);
497 gtk_box_pack_end(GTK_BOX(box
), panel
->after
, FALSE
, TRUE
, 0);
499 frame
= make_insert_frame(panel
);
500 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
502 /* This is used so that we can find the middle easily! */
503 panel
->gap
= gtk_event_box_new();
504 gtk_box_pack_start(GTK_BOX(box
), panel
->gap
, FALSE
, FALSE
, 0);
506 frame
= make_insert_frame(panel
);
507 g_object_set_data(G_OBJECT(frame
), "after", "yes");
508 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 4);
510 if (o_panel_is_dock
.int_value
)
511 gtk_window_set_type_hint(GTK_WINDOW(panel
->window
),
512 GDK_WINDOW_TYPE_HINT_DOCK
);
514 gtk_widget_realize(panel
->window
);
515 make_panel_window(panel
->window
);
516 gtk_window_stick(GTK_WINDOW(panel
->window
));
518 gtk_widget_show_all(align
);
520 loading_panel
= panel
;
523 panel_load_from_xml(panel
, panel_doc
);
524 xmlFreeDoc(panel_doc
);
531 parse_file(load_path
, pan_from_file
);
532 info_message(_("Your old panel file has been "
533 "converted to the new XML format."));
538 /* Don't scare users with an empty panel... */
541 panel_add_item(panel
, "~", "Home", FALSE
, NULL
, NULL
, FALSE
);
543 apps
= pathdup(make_path(app_dir
, ".."));
546 panel_add_item(panel
, apps
, "Apps", FALSE
, NULL
, NULL
, FALSE
);
550 loading_panel
= NULL
;
553 current_panel
[side
] = panel
;
555 gtk_widget_queue_resize(box
);
556 g_signal_connect(panel
->window
, "size-request",
557 G_CALLBACK(panel_post_resize
), panel
);
558 g_signal_connect(panel
->window
, "size-allocate",
559 G_CALLBACK(reposition_panel
), panel
);
562 gdk_window_lower(panel
->window
->window
);
563 gtk_widget_show(panel
->window
);
564 /* This has no effect until after window is showing; GTK+ bug? */
565 if (panel_keep_below(panel
, TRUE
))
569 pinboard
= pinboard_get_window();
570 /* (if pinboard is NULL, will go right to the back) */
571 window_put_just_above(panel
->window
->window
, pinboard
);
579 /* Externally visible function to add an item to a panel */
580 gboolean
panel_add(PanelSide side
,
581 const gchar
*path
, const gchar
*label
, gboolean after
, const gchar
*shortcut
, const gchar
*args
,
584 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
586 g_return_val_if_fail(current_panel
[side
] != NULL
, FALSE
);
588 panel_add_item(current_panel
[side
], path
, label
, after
, shortcut
, args
, locked
);
593 /* Add the area covered by the panels to the region */
594 void panel_mark_used(GdkRegion
*used
)
598 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
600 Panel
*panel
= current_panel
[i
];
606 gdk_window_get_root_origin(panel
->window
->window
,
608 rect
.width
= panel
->window
->allocation
.width
;
609 rect
.height
= panel
->window
->allocation
.height
;
611 gdk_region_union_with_rect(used
, &rect
);
615 /* On xrandr screen size changes, update all panels */
616 void panel_update_size(void)
620 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
622 if (current_panel
[i
])
624 panel_update_geometry(current_panel
[i
]);
625 reposition_panel(current_panel
[i
]->window
,
626 ¤t_panel
[i
]->window
->allocation
,
628 gtk_widget_queue_resize(current_panel
[i
]->window
);
633 /****************************************************************
634 * INTERNAL FUNCTIONS *
635 ****************************************************************/
637 /* User has tried to close the panel via the window manager - confirm */
638 static int panel_delete(GtkWidget
*widget
, GdkEvent
*event
, Panel
*panel
)
640 return !confirm(_("You have tried to close a panel via the window "
641 "manager - I usually find that this is accidental... "
643 GTK_STOCK_CLOSE
, NULL
);
646 static void panel_destroyed(GtkWidget
*widget
, Panel
*panel
)
648 if (panel_options_dialog
)
650 Panel
*dlg_panel
= g_object_get_data(G_OBJECT(panel_options_dialog
),
653 if (dlg_panel
== panel
)
654 gtk_widget_destroy(panel_options_dialog
);
657 if (current_panel
[panel
->side
] == panel
)
658 current_panel
[panel
->side
] = NULL
;
660 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
662 if (current_panel
[PANEL_RIGHT
])
663 gtk_widget_queue_resize(
664 current_panel
[PANEL_RIGHT
]->window
);
665 if (current_panel
[PANEL_LEFT
])
666 gtk_widget_queue_resize(
667 current_panel
[PANEL_LEFT
]->window
);
670 if (panel
->autoscroll_speed
)
671 g_source_remove(panel
->autoscroll_to
);
679 static void panel_load_side(Panel
*panel
, xmlNodePtr side
, gboolean after
)
682 char *label
, *path
, *shortcut
, *args
, *tmp
;
685 for (node
= side
->xmlChildrenNode
; node
; node
= node
->next
)
687 if (node
->type
!= XML_ELEMENT_NODE
)
689 if (strcmp(node
->name
, "icon") != 0)
692 label
= xmlGetProp(node
, "label");
694 label
= g_strdup("<missing label>");
695 path
= xmlNodeGetContent(node
);
697 path
= g_strdup("<missing path>");
698 shortcut
= xmlGetProp(node
, "shortcut");
699 args
= xmlGetProp(node
, "args");
700 tmp
= xmlGetProp(node
, "locked");
703 locked
= text_to_boolean(tmp
, FALSE
);
709 panel_add_item(panel
, path
, label
, after
, shortcut
, args
, locked
);
718 /* Create one panel icon for each icon in the doc */
719 static void panel_load_from_xml(Panel
*panel
, xmlDocPtr doc
)
723 root
= xmlDocGetRootElement(doc
);
724 panel_load_side(panel
, get_subnode(root
, NULL
, "start"), FALSE
);
725 panel_load_side(panel
, get_subnode(root
, NULL
, "end"), TRUE
);
728 /* Called for each line in the config file while loading a new panel */
729 static const char *pan_from_file(gchar
*line
)
733 g_return_val_if_fail(line
!= NULL
, NULL
);
734 g_return_val_if_fail(loading_panel
!= NULL
, NULL
);
739 sep
= strpbrk(line
, "<>");
741 return _("Missing < or > in panel config file");
744 leaf
= g_strndup(line
, sep
- line
);
748 panel_add_item(loading_panel
, sep
+ 1, leaf
, sep
[0] == '>',
756 static gboolean
icon_pointer_in(GtkWidget
*widget
,
757 GdkEventCrossing
*event
,
760 gtk_widget_set_state(widget
,
761 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_PRELIGHT
);
766 static gboolean
icon_pointer_out(GtkWidget
*widget
,
767 GdkEventCrossing
*event
,
770 gtk_widget_set_state(widget
,
771 icon
->selected
? GTK_STATE_SELECTED
: GTK_STATE_NORMAL
);
776 static void panel_icon_destroyed(PanelIcon
*pi
)
778 g_return_if_fail(pi
->widget
!= NULL
);
785 /* Set the tooltip AND hide/show the label */
786 static void panel_icon_set_tip(PanelIcon
*pi
)
790 Icon
*icon
= (Icon
*) pi
;
792 g_return_if_fail(pi
!= NULL
);
796 if (panel_want_show_text(pi
))
797 gtk_widget_show(pi
->label
);
799 gtk_widget_hide(pi
->label
);
805 ai
= appinfo_get(icon
->path
, icon
->item
);
807 if (ai
&& ((node
= xml_get_section(ai
, NULL
, "Summary"))))
810 str
= xmlNodeListGetString(node
->doc
,
811 node
->xmlChildrenNode
, 1);
814 gtk_tooltips_set_tip(tooltips
, pi
->widget
, str
, NULL
);
818 else if ((!panel_want_show_text(pi
)) && !pi
->socket
)
820 if (icon
->item
->leafname
&& icon
->item
->leafname
[0])
821 gtk_tooltips_set_tip(tooltips
, pi
->widget
,
822 icon
->item
->leafname
, NULL
);
825 gtk_tooltips_set_tip(tooltips
, pi
->widget
, NULL
, NULL
);
831 /* Add an icon with this path to the panel. If after is TRUE then the
832 * icon is added to the right/bottom end of the panel.
834 * If name is NULL a suitable name is taken from path.
836 static void panel_add_item(Panel
*panel
,
840 const gchar
*shortcut
,
848 g_return_if_fail(panel
!= NULL
);
849 g_return_if_fail(path
!= NULL
);
851 widget
= gtk_event_box_new();
852 gtk_widget_set_events(widget
,
853 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
854 GDK_BUTTON3_MOTION_MASK
|
855 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
856 GDK_BUTTON_RELEASE_MASK
);
858 gtk_box_pack_start(GTK_BOX(after
? panel
->after
: panel
->before
),
859 widget
, FALSE
, TRUE
, 0);
861 gtk_box_reorder_child(GTK_BOX(panel
->after
), widget
, 0);
863 gtk_widget_realize(widget
);
865 pi
= panel_icon_new(panel
, path
, name
);
868 /* Widget takes the initial ref of Icon */
869 g_object_set_data(G_OBJECT(widget
), "icon", pi
);
872 g_object_ref(widget
);
874 gtk_widget_set_name(pi
->widget
, "panel-icon");
876 g_signal_connect_swapped(widget
, "destroy",
877 G_CALLBACK(panel_icon_destroyed
), pi
);
879 if (icon
->item
->base_type
== TYPE_DIRECTORY
)
882 g_signal_connect(widget
, "button_release_event",
883 G_CALLBACK(icon_button_release
), pi
);
884 g_signal_connect(widget
, "button_press_event",
885 G_CALLBACK(icon_button_press
), pi
);
886 g_signal_connect(widget
, "motion-notify-event",
887 G_CALLBACK(icon_motion_event
), pi
);
888 g_signal_connect(widget
, "enter-notify-event",
889 G_CALLBACK(icon_pointer_in
), pi
);
890 g_signal_connect(widget
, "leave-notify-event",
891 G_CALLBACK(icon_pointer_out
), pi
);
895 g_signal_connect(widget
, "enter-notify-event",
896 G_CALLBACK(enter_icon
), pi
);
897 g_signal_connect_after(widget
, "expose_event",
898 G_CALLBACK(expose_icon
), pi
);
899 g_signal_connect(widget
, "drag_data_get",
900 G_CALLBACK(drag_data_get
), NULL
);
902 g_signal_connect(widget
, "size_request",
903 G_CALLBACK(size_request
), pi
);
905 drag_set_panel_dest(pi
);
907 pi
->label
= gtk_label_new(icon
->item
->leafname
);
908 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->label
);
909 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
910 gtk_misc_set_padding(GTK_MISC(pi
->label
), 1, 2);
913 icon_set_shortcut(icon
, shortcut
);
914 icon_set_arguments(icon
, args
);
915 icon
->locked
= locked
;
920 panel_icon_set_tip(pi
);
921 gtk_widget_show(widget
);
924 static gboolean
remove_item_from_side(GtkWidget
*container
, const gchar
*path
,
928 gboolean found
= FALSE
;
930 kids
= gtk_container_get_children(GTK_CONTAINER(container
));
932 for (next
= kids
; next
; next
= next
->next
)
935 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
939 if ((!path
|| strcmp(path
, icon
->src_path
) == 0) &&
940 (!label
|| strcmp(label
, icon
->item
->leafname
)==0))
942 icon
->locked
= FALSE
;
954 /* Remove an item with this path. If more than one item matches, only
955 * one is removed. If label is not NULL then it must also match the item.
956 * Returns TRUE if an item was successfully removed.
958 gboolean
panel_remove_item(PanelSide side
, const gchar
*path
,
963 g_return_val_if_fail(side
>= 0 && side
< PANEL_NUMBER_OF_SIDES
, FALSE
);
965 g_return_val_if_fail(path
!= NULL
|| label
!= NULL
, FALSE
);
967 panel
= current_panel
[side
];
970 g_warning("No panel on this side of the screen!");
974 if (remove_item_from_side(panel
->before
, path
, label
) ||
975 remove_item_from_side(panel
->after
, path
, label
))
982 g_warning("Panel item path='%s', label='%s' not found", path
, label
);
986 /* Called when Gtk+ wants to know how much space an icon needs.
987 * 'req' is already big enough for the label, if shown.
989 static void size_request(GtkWidget
*widget
, GtkRequisition
*req
, PanelIcon
*pi
)
991 Icon
*icon
= (Icon
*) pi
;
992 gboolean horz
= (pi
->panel
->side
== PANEL_TOP
||
993 pi
->panel
->side
== PANEL_BOTTOM
);
995 int max_height
= 100;
996 int image_width
, image_height
;
997 Panel
*panel
= pi
->panel
;
1000 max_height
= panel
->width
- req
->height
;
1002 max_width
= MAX(panel
->width
, req
->width
);
1004 /* TODO: really need to recreate? */
1006 g_object_unref(pi
->image
);
1008 pi
->image
= scale_pixbuf(di_image(icon
->item
)->src_pixbuf
,
1009 MAX(20, max_width
), MAX(20, max_height
));
1011 image_width
= gdk_pixbuf_get_width(pi
->image
);
1012 image_height
= gdk_pixbuf_get_height(pi
->image
);
1014 if (req
->height
> 0 && max_height
< req
->height
)
1016 pi
->style
= TEXT_BESIDE_ICON
;
1017 req
->width
+= image_width
;
1018 req
->height
= MAX(req
->height
, image_height
);
1019 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 1, 0.5);
1023 pi
->style
= TEXT_UNDER_ICON
;
1024 req
->width
= MAX(req
->width
, image_width
);
1025 req
->height
+= image_height
;
1026 gtk_misc_set_alignment(GTK_MISC(pi
->label
), 0.5, 1);
1030 req
->width
+= PANEL_ICON_SPACING
;
1032 req
->height
+= PANEL_ICON_SPACING
;
1035 static gint
expose_icon(GtkWidget
*widget
,
1036 GdkEventExpose
*event
,
1039 return draw_icon(widget
, &event
->area
, pi
);
1042 static gint
draw_icon(GtkWidget
*widget
, GdkRectangle
*badarea
, PanelIcon
*pi
)
1046 Icon
*icon
= (Icon
*) pi
;
1050 int text_height
= 0;
1052 gdk_drawable_get_size(widget
->window
, &area
.width
, &area
.height
);
1054 if (panel_want_show_text(pi
))
1055 text_height
= pi
->label
->requisition
.height
;
1057 g_return_val_if_fail(pi
->image
!= NULL
, FALSE
);
1061 width
= gdk_pixbuf_get_width(image
);
1062 height
= gdk_pixbuf_get_height(image
);
1064 if (pi
->style
== TEXT_UNDER_ICON
)
1066 image_x
= (area
.width
- width
) >> 1;
1067 image_y
= (area
.height
- height
- text_height
) >> 1;
1071 image_x
= PANEL_ICON_SPACING
- 2;
1072 image_y
= (area
.height
- height
) >> 1;
1075 gdk_pixbuf_render_to_drawable_alpha(
1079 image_x
, image_y
, /* dest */
1081 GDK_PIXBUF_ALPHA_FULL
, 128, /* (unused) */
1082 GDK_RGB_DITHER_NORMAL
, 0, 0);
1084 if (icon
->item
->flags
& ITEM_FLAG_SYMLINK
)
1086 draw_emblem_on_icon(widget
->window
, widget
->style
,
1087 ROX_STOCK_SYMLINK
, &image_x
, image_y
+2);
1089 if (icon
->item
->flags
& ITEM_FLAG_MOUNT_POINT
)
1091 draw_emblem_on_icon(widget
->window
, widget
->style
,
1092 icon
->item
->flags
& ITEM_FLAG_MOUNTED
1095 &image_x
, image_y
+2);
1100 static void panel_icon_wink(Icon
*icon
)
1102 PanelIcon
*pi
= (PanelIcon
*) icon
;
1104 wink_widget(pi
->widget
);
1107 /* icon may be NULL if the event is on the background */
1108 static void perform_action(Panel
*panel
, PanelIcon
*pi
, GdkEventButton
*event
)
1111 Icon
*icon
= (Icon
*) pi
;
1113 action
= bind_lookup_bev(icon
? BIND_PANEL_ICON
: BIND_PANEL
, event
);
1115 if (pi
&& pi
->socket
)
1116 if (action
!= ACT_POPUP_MENU
&& action
!= ACT_MOVE_ICON
)
1122 dnd_motion_ungrab();
1123 wink_widget(pi
->widget
);
1127 dnd_motion_ungrab();
1128 wink_widget(pi
->widget
);
1129 run_diritem(icon
->path
, icon
->item
, NULL
, NULL
, TRUE
);
1131 case ACT_POPUP_MENU
:
1132 dnd_motion_ungrab();
1133 panel_show_menu(event
, pi
, panel
);
1136 dnd_motion_start(MOTION_REPOSITION
);
1138 case ACT_PRIME_AND_SELECT
:
1139 if (!icon
->selected
)
1140 icon_select_only(icon
);
1141 dnd_motion_start(MOTION_READY_FOR_DND
);
1143 case ACT_PRIME_AND_TOGGLE
:
1144 icon_set_selected(icon
, !icon
->selected
);
1145 dnd_motion_start(MOTION_READY_FOR_DND
);
1147 case ACT_PRIME_FOR_DND
:
1148 dnd_motion_start(MOTION_READY_FOR_DND
);
1150 case ACT_TOGGLE_SELECTED
:
1151 icon_set_selected(icon
, !icon
->selected
);
1153 case ACT_SELECT_EXCL
:
1154 icon_set_selected(icon
, TRUE
);
1158 case ACT_CLEAR_SELECTION
:
1159 dnd_motion_ungrab();
1160 icon_select_only(NULL
);
1163 g_warning("Unsupported action : %d\n", action
);
1168 static gint
panel_button_release(GtkWidget
*widget
,
1169 GdkEventButton
*event
,
1172 if (dnd_motion_release(event
))
1175 perform_action(panel
, NULL
, event
);
1180 static gint
panel_button_press(GtkWidget
*widget
,
1181 GdkEventButton
*event
,
1184 if (dnd_motion_press(panel
->window
, event
))
1185 perform_action(panel
, NULL
, event
);
1190 static gint
icon_button_release(GtkWidget
*widget
,
1191 GdkEventButton
*event
,
1194 if (pi
->socket
&& event
->button
== 1)
1195 return FALSE
; /* Restart button */
1197 if (dnd_motion_release(event
))
1200 perform_action(pi
->panel
, pi
, event
);
1205 static gint
icon_button_press(GtkWidget
*widget
,
1206 GdkEventButton
*event
,
1209 if (pi
->socket
&& event
->button
== 1)
1210 return FALSE
; /* Restart button */
1212 if (dnd_motion_press(widget
, event
))
1213 perform_action(pi
->panel
, pi
, event
);
1218 /* Stop windows from maximising over all/part of us */
1219 static void panel_setup_struts(Panel
*panel
, GtkAllocation
*alloc
)
1223 gulong left
, right
, top
, bottom
;
1224 gulong left_start_y
, left_end_y
;
1225 gulong right_start_y
, right_end_y
;
1226 gulong top_start_x
, top_end_x
;
1227 gulong bottom_start_x
, bottom_end_x
;
1228 } strut
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1230 if (panel
->avoid
== FALSE
)
1232 else if (panel
->side
== PANEL_TOP
||
1233 panel
->side
== PANEL_BOTTOM
)
1234 thickness
= alloc
->height
;
1236 thickness
= alloc
->width
;
1238 switch (panel
->side
)
1241 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].left
)
1243 strut
.left
= panel
->geometry
.x
+ thickness
;
1244 strut
.left_start_y
= panel
->geometry
.y
;
1245 strut
.left_end_y
= panel
->geometry
.y
+
1246 panel
->geometry
.height
- 1;
1248 /* else there is (part of) a monitor
1256 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].right
)
1258 /* RHS of monitor might not abut edge
1259 * of total virtual screen */
1260 strut
.right
= screen_width
-
1262 panel
->geometry
.width
+
1264 strut
.right_start_y
= panel
->geometry
.y
;
1265 strut
.right_end_y
= panel
->geometry
.y
+
1266 panel
->geometry
.height
- 1;
1268 /* else there is (part of) a monitor
1276 if (!panel
->xinerama
|| !monitor_adjacent
[panel
->monitor
].top
)
1278 strut
.top
= panel
->geometry
.y
+ thickness
;
1279 strut
.top_start_x
= panel
->geometry
.x
;
1280 strut
.top_end_x
= panel
->geometry
.x
+
1281 panel
->geometry
.width
- 1;
1283 /* else there is (part of) a monitor above */
1289 default: /* PANEL_BOTTOM */
1290 if (!panel
->xinerama
||
1291 !monitor_adjacent
[panel
->monitor
].bottom
)
1293 /* Bottom of monitor might not abut
1294 * edge of total virtual screen */
1295 strut
.bottom
= screen_height
-
1297 panel
->geometry
.height
+
1299 strut
.bottom_start_x
= panel
->geometry
.x
;
1300 strut
.bottom_end_x
= panel
->geometry
.x
+
1301 panel
->geometry
.width
- 1;
1303 /* else there is (part of) a monitor below */
1313 /* Set full-width strut as well as partial in case
1314 * partial isn't supported by wm */
1315 gdk_property_change(panel
->window
->window
,
1316 gdk_atom_intern("_NET_WM_STRUT",
1318 gdk_atom_intern("CARDINAL", FALSE
),
1319 32, GDK_PROP_MODE_REPLACE
,
1320 (gchar
*) &strut
, 4);
1321 gdk_property_change(panel
->window
->window
,
1322 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1324 gdk_atom_intern("CARDINAL", FALSE
),
1325 32, GDK_PROP_MODE_REPLACE
,
1326 (gchar
*) &strut
, 12);
1330 gdk_property_delete(panel
->window
->window
,
1331 gdk_atom_intern("_NET_WM_STRUT_PARTIAL",
1333 gdk_property_delete(panel
->window
->window
,
1334 gdk_atom_intern("_NET_WM_STRUT",
1339 static void reposition_panel(GtkWidget
*window
,
1340 GtkAllocation
*alloc
, Panel
*panel
)
1342 int x
= panel
->geometry
.x
;
1343 int y
= panel
->geometry
.y
;
1344 PanelSide side
= panel
->side
;
1346 if (side
== PANEL_LEFT
|| side
== PANEL_RIGHT
)
1348 if (side
== PANEL_RIGHT
)
1349 x
+= panel
->geometry
.width
- alloc
->width
;
1351 if (current_panel
[PANEL_TOP
])
1353 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
1354 y
+= win
->allocation
.height
;
1358 if (side
== PANEL_BOTTOM
)
1359 y
+= panel
->geometry
.height
- alloc
->height
;
1361 gtk_window_move(GTK_WINDOW(panel
->window
), x
, y
);
1362 gdk_window_move(panel
->window
->window
, x
, y
);
1364 if (side
== PANEL_BOTTOM
|| side
== PANEL_TOP
)
1366 if (current_panel
[PANEL_RIGHT
])
1367 gtk_widget_queue_resize(
1368 current_panel
[PANEL_RIGHT
]->window
);
1369 if (current_panel
[PANEL_LEFT
])
1370 gtk_widget_queue_resize(
1371 current_panel
[PANEL_LEFT
]->window
);
1374 panel_setup_struts(panel
, alloc
);
1377 /* Same as drag_set_dest(), but for panel icons */
1378 static void drag_set_panel_dest(PanelIcon
*pi
)
1380 GtkWidget
*obj
= pi
->widget
;
1382 make_drop_target(pi
->widget
, 0);
1384 g_signal_connect(obj
, "drag_motion", G_CALLBACK(drag_motion
), pi
);
1385 g_signal_connect(obj
, "drag_leave", G_CALLBACK(drag_leave
), pi
);
1386 g_signal_connect(obj
, "drag_end", G_CALLBACK(drag_end
), pi
);
1389 static gboolean
drag_motion(GtkWidget
*widget
,
1390 GdkDragContext
*context
,
1396 GdkDragAction action
= context
->suggested_action
;
1397 const char *type
= NULL
;
1398 Icon
*icon
= (Icon
*) pi
;
1399 DirItem
*item
= icon
->item
;
1400 int panel_x
, panel_y
;
1402 gdk_window_get_pointer(pi
->panel
->window
->window
,
1403 &panel_x
, &panel_y
, NULL
);
1404 motion_may_raise(pi
->panel
, panel_x
, panel_y
);
1406 /* Should we scroll the panel when dragging? */
1407 if (motion_state
!= MOTION_REPOSITION
)
1408 if (pi
->panel
->autoscroll_speed
== 0)
1409 may_autoscroll(pi
->panel
);
1412 goto out
; /* Can't drag a selection to itself */
1414 type
= dnd_motion_item(context
, &item
);
1416 if ((context
->actions
& GDK_ACTION_ASK
) && o_dnd_left_menu
.int_value
1417 && type
!= drop_dest_prog
)
1420 gdk_window_get_pointer(NULL
, NULL
, NULL
, &state
);
1421 if (state
& GDK_BUTTON1_MASK
)
1422 action
= GDK_ACTION_ASK
;
1428 /* We actually must pretend to accept the drop, even if the
1429 * directory isn't writeable, so that the spring-opening
1433 /* Don't allow drops to non-writeable directories */
1434 if (o_dnd_spring_open
.int_value
== FALSE
&&
1435 type
== drop_dest_dir
&&
1436 access(icon
->path
, W_OK
) != 0)
1441 g_dataset_set_data(context
, "drop_dest_type", (gpointer
) type
);
1444 gdk_drag_status(context
, action
, time
);
1445 g_dataset_set_data_full(context
, "drop_dest_path",
1446 g_strdup(icon
->path
), g_free
);
1447 if (type
== drop_dest_dir
)
1448 dnd_spring_load(context
, NULL
);
1450 if (dnd_highlight
&& dnd_highlight
!= pi
->widget
)
1452 gtk_drag_unhighlight(dnd_highlight
);
1453 dnd_highlight
= NULL
;
1456 if (dnd_highlight
== NULL
)
1458 gtk_drag_highlight(pi
->widget
);
1459 dnd_highlight
= pi
->widget
;
1463 return type
!= NULL
;
1467 static void add_uri_list(GtkWidget
*widget
,
1468 GdkDragContext
*context
,
1471 GtkSelectionData
*selection_data
,
1476 gboolean after
= FALSE
;
1479 if (!selection_data
->data
)
1482 g_return_if_fail(selection_data
->data
[selection_data
->length
] == '\0');
1484 if (g_object_get_data(G_OBJECT(widget
), "after"))
1487 uris
= uri_list_to_glist(selection_data
->data
);
1489 for (next
= uris
; next
; next
= next
->next
)
1493 path
= get_local_path((EscapedPath
*) next
->data
);
1496 panel_add_item(panel
, path
, NULL
, after
, NULL
, NULL
, FALSE
);
1504 static void drag_end(GtkWidget
*widget
,
1505 GdkDragContext
*context
,
1508 if (tmp_icon_selected
)
1510 icon_select_only(NULL
);
1511 tmp_icon_selected
= FALSE
;
1515 static void drag_leave(GtkWidget
*widget
,
1516 GdkDragContext
*context
,
1520 panel_drag_leave(widget
, context
, time
, ((PanelIcon
*) icon
)->panel
);
1522 if (dnd_highlight
&& dnd_highlight
== widget
)
1524 gtk_drag_unhighlight(dnd_highlight
);
1525 dnd_highlight
= NULL
;
1531 /* Create XML icon nodes for these widgets.
1532 * Always frees the widgets list.
1534 static void make_widgets(xmlNodePtr side
, GList
*widgets
)
1538 for (next
= widgets
; next
; next
= next
->next
)
1543 icon
= g_object_get_data(G_OBJECT(next
->data
), "icon");
1547 g_warning("Can't find Icon from widget\n");
1551 tree
= xmlNewTextChild(side
, NULL
, "icon", icon
->src_path
);
1553 xmlSetProp(tree
, "label", icon
->item
->leafname
);
1555 xmlSetProp(tree
, "shortcut", icon
->shortcut
);
1557 xmlSetProp(tree
, "args", icon
->args
);
1559 xmlSetProp(tree
, "locked", "true");
1563 g_list_free(widgets
);
1566 void panel_save(Panel
*panel
)
1571 guchar
*save
= NULL
;
1572 guchar
*save_new
= NULL
;
1574 g_return_if_fail(panel
!= NULL
);
1576 if (strchr(panel
->name
, '/'))
1577 save
= g_strdup(panel
->name
);
1582 leaf
= g_strconcat("pan_", panel
->name
, NULL
);
1583 save
= choices_find_xdg_path_save(leaf
, PROJECT
, SITE
, TRUE
);
1590 doc
= xmlNewDoc("1.0");
1591 xmlDocSetRootElement(doc
, xmlNewDocNode(doc
, NULL
, "panel", NULL
));
1593 root
= xmlDocGetRootElement(doc
);
1595 xmlSetProp(root
, "side", panel_side_to_name(panel
->side
));
1597 options
= xmlNewChild(root
, NULL
, "options", NULL
);
1598 set_int_prop(options
, "style", panel
->style
);
1599 set_int_prop(options
, "width", panel
->width
);
1600 set_int_prop(options
, "avoid", panel
->avoid
);
1601 set_int_prop(options
, "xinerama", panel
->xinerama
);
1602 set_int_prop(options
, "monitor", panel
->monitor
);
1604 make_widgets(xmlNewChild(root
, NULL
, "start", NULL
),
1605 gtk_container_get_children(GTK_CONTAINER(panel
->before
)));
1607 make_widgets(xmlNewChild(root
, NULL
, "end", NULL
),
1608 g_list_reverse(gtk_container_get_children(
1609 GTK_CONTAINER(panel
->after
))));
1611 save_new
= g_strconcat(save
, ".new", NULL
);
1612 if (save_xml_file(doc
, save_new
) || rename(save_new
, save
))
1613 delayed_error(_("Error saving panel %s: %s"),
1614 save
, g_strerror(errno
));
1622 /* Create a frame widget which can be used to add icons to the panel */
1623 static GtkWidget
*make_insert_frame(Panel
*panel
)
1626 GtkTargetEntry target_table
[] = {
1627 {"text/uri-list", 0, TARGET_URI_LIST
},
1630 frame
= gtk_frame_new(NULL
);
1631 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
1632 gtk_widget_set_size_request(frame
, 16, 16);
1634 g_signal_connect(frame
, "drag-motion",
1635 G_CALLBACK(insert_drag_motion
), panel
);
1636 g_signal_connect(frame
, "drag-leave",
1637 G_CALLBACK(panel_drag_leave
), panel
);
1639 g_signal_connect(frame
, "drag-data-received",
1640 G_CALLBACK(add_uri_list
), panel
);
1641 gtk_drag_dest_set(frame
,
1642 GTK_DEST_DEFAULT_ALL
,
1644 sizeof(target_table
) / sizeof(*target_table
),
1650 static gboolean
enter_icon(GtkWidget
*widget
,
1651 GdkEventCrossing
*event
,
1654 icon_may_update(icon
);
1655 panel_icon_set_tip((PanelIcon
*) icon
);
1660 static gint
panel_leave_event(GtkWidget
*widget
,
1661 GdkEventCrossing
*event
,
1664 GdkWindow
*pinboard
;
1666 if (event
->mode
!= GDK_CROSSING_NORMAL
)
1667 return FALSE
; /* Grab for menu, DnD, etc */
1669 if (event
->x
>= 0 &&
1671 event
->x
< widget
->allocation
.width
&&
1672 event
->y
< widget
->allocation
.height
)
1674 /* Still inside the panel's area.
1675 * Probably we've moved over a panel applet. */
1679 if (panel_keep_below(panel
, TRUE
))
1681 /* Shouldn't need this as well as keep_below but some WMs don't
1682 * automatically lower as soon as the hint is set */
1683 pinboard
= pinboard_get_window();
1684 window_put_just_above(panel
->window
->window
, pinboard
);
1690 /* If (x, y) is at the edge of the panel then raise */
1691 static void motion_may_raise(Panel
*panel
, int x
, int y
)
1695 if (panel
->side
== PANEL_TOP
)
1697 else if (panel
->side
== PANEL_BOTTOM
)
1698 raise
= y
== panel
->window
->allocation
.height
- 1;
1699 else if (panel
->side
== PANEL_LEFT
)
1702 raise
= x
== panel
->window
->allocation
.width
- 1;
1704 if (raise
&& panel_keep_below(panel
, FALSE
))
1706 /* Shouldn't need this as well as keep_below but some WMs don't
1707 * automatically raise as soon as the hint is set */
1708 gdk_window_raise(panel
->window
->window
);
1712 static gboolean
may_autoscroll(Panel
*panel
)
1714 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1715 gint max
, panel_x
, panel_y
, delta
, new;
1717 if (panel
->adj
->upper
<= panel
->adj
->page_size
)
1718 goto stop_scrolling
; /* Can see everything already */
1720 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
1725 max
= panel
->window
->allocation
.width
;
1726 if (panel_y
< 0 || panel_y
> panel
->window
->allocation
.height
)
1727 goto stop_scrolling
; /* Not over the panel */
1732 max
= panel
->window
->allocation
.height
;
1733 if (panel_x
< 0 || panel_x
> panel
->window
->allocation
.width
)
1734 goto stop_scrolling
; /* Not over the panel */
1737 if (delta
>= 20 && delta
<= max
- 20)
1738 goto stop_scrolling
; /* Not at either end */
1740 panel
->autoscroll_speed
= MIN(panel
->autoscroll_speed
+ 2, 200);
1742 new = panel
->adj
->value
- ((delta
< 20) ? panel
->autoscroll_speed
1743 : -panel
->autoscroll_speed
);
1744 new = CLAMP(new, 0, panel
->adj
->upper
- panel
->adj
->page_size
);
1745 gtk_adjustment_set_value(panel
->adj
, new);
1747 panel
->autoscroll_to
= g_timeout_add(40,
1748 (GSourceFunc
) may_autoscroll
, panel
);
1753 panel
->autoscroll_speed
= 0;
1757 static gint
panel_motion_event(GtkWidget
*widget
,
1758 GdkEventMotion
*event
,
1761 motion_may_raise(panel
, event
->x
, event
->y
);
1763 if (motion_state
!= MOTION_REPOSITION
)
1764 if (panel
->autoscroll_speed
== 0)
1765 may_autoscroll(panel
);
1770 static gint
icon_motion_event(GtkWidget
*widget
,
1771 GdkEventMotion
*event
,
1774 Panel
*panel
= pi
->panel
;
1776 gboolean horz
= panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
;
1780 if (motion_state
== MOTION_READY_FOR_DND
)
1782 if (dnd_motion_moved(event
))
1783 start_drag(pi
, event
);
1786 else if (motion_state
!= MOTION_REPOSITION
)
1789 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1790 list
= g_list_append(list
, NULL
); /* The gap in the middle */
1791 list
= g_list_concat(list
,
1792 gtk_container_get_children(GTK_CONTAINER(panel
->after
)));
1793 me
= g_list_find(list
, widget
);
1795 g_return_val_if_fail(me
!= NULL
, TRUE
);
1797 val
= horz
? event
->x_root
: event
->y_root
;
1805 prev
= GTK_WIDGET(me
->prev
->data
);
1809 gdk_window_get_origin(prev
->window
, &x
, &y
);
1811 if (val
<= (horz
? x
: y
))
1815 if (dir
== 0 && me
->next
)
1821 next
= GTK_WIDGET(me
->next
->data
);
1825 gdk_window_get_origin(next
->window
, &x
, &y
);
1827 gdk_drawable_get_size(next
->window
, &w
, &h
);
1832 if (val
>= (horz
? x
: y
)-1)
1834 if (next
== panel
->gap
)
1842 reposition_icon(pi
, g_list_index(list
, widget
) + dir
);
1847 static void reposition_icon_on_side(GtkWidget
*side
, GtkWidget
*widget
,
1852 list
= gtk_container_get_children(GTK_CONTAINER(side
));
1854 /* Want to move icon to the list in the given 'side'. Is it there
1858 if (!g_list_find(list
, widget
))
1861 gtk_grab_remove(widget
);
1862 gtk_widget_reparent(widget
, side
);
1863 dnd_motion_grab_pointer();
1864 gtk_grab_add(widget
);
1867 gtk_box_reorder_child(GTK_BOX(side
), widget
, index
);
1872 /* Move icon to this index in the complete widget list.
1873 * 0 makes the icon the left-most icon. The gap in the middle has
1874 * an index number, which allows you to specify that the icon should
1875 * go on the left or right side.
1877 static void reposition_icon(PanelIcon
*pi
, int index
)
1879 Panel
*panel
= pi
->panel
;
1880 GtkWidget
*widget
= pi
->widget
;
1884 list
= gtk_container_get_children(GTK_CONTAINER(panel
->before
));
1885 before_len
= g_list_length(list
);
1888 if (index
<= before_len
)
1889 reposition_icon_on_side(panel
->before
, widget
, index
);
1891 reposition_icon_on_side(panel
->after
, widget
,
1892 index
- (before_len
+ 1));
1897 static void start_drag(PanelIcon
*pi
, GdkEventMotion
*event
)
1899 GtkWidget
*widget
= pi
->widget
;
1900 Icon
*icon
= (Icon
*) pi
;
1902 if (!icon
->selected
)
1904 if (event
->state
& GDK_BUTTON1_MASK
)
1906 /* Select just this one */
1907 icon_select_only(icon
);
1908 tmp_icon_selected
= TRUE
;
1911 icon_set_selected(icon
, TRUE
);
1914 g_return_if_fail(icon_selection
!= NULL
);
1916 if (icon_selection
->next
== NULL
)
1917 drag_one_item(widget
, event
, icon
->path
, icon
->item
, NULL
);
1922 uri_list
= icon_create_uri_list();
1923 drag_selection(widget
, event
, uri_list
);
1928 static void applet_died(GtkWidget
*socket
)
1930 gboolean never_plugged
;
1932 never_plugged
= (!g_object_get_data(G_OBJECT(socket
), "lost_plug"))
1933 && !GTK_SOCKET(socket
)->plug_window
;
1938 _("Applet quit without ever creating a widget!"));
1939 gtk_widget_destroy(socket
);
1942 gtk_widget_unref(socket
);
1945 static void socket_destroyed(GtkWidget
*socket
, GtkWidget
*widget
)
1947 g_object_set_data(G_OBJECT(socket
), "lost_plug", "yes");
1949 gtk_widget_unref(socket
);
1951 gtk_widget_destroy(widget
); /* Remove from panel */
1954 panel_save(g_object_get_data(G_OBJECT(socket
), "panel"));
1957 /* Try to run this applet.
1960 * - No executable AppletRun:
1961 * icon->socket == NULL (unchanged) on return.
1963 * Otherwise, create socket (setting icon->socket) and ref it twice.
1965 * - AppletRun quits without connecting a plug:
1966 * On child death lost_plug is unset and socket is empty.
1968 * Report error and destroy widget (to 'socket destroyed').
1970 * - AppletRun quits while plug is in socket:
1971 * Unref socket once. Socket will be destroyed later.
1973 * - Socket is destroyed.
1974 * Set lost_plug = "yes" and remove widget from panel.
1977 static void run_applet(PanelIcon
*pi
)
1979 GError
*error
= NULL
;
1982 Icon
*icon
= (Icon
*) pi
;
1984 argv
[0] = (char *) make_path(icon
->path
, "AppletRun");
1986 if (access(argv
[0], X_OK
) != 0)
1989 pi
->socket
= gtk_socket_new();
1991 gtk_container_add(GTK_CONTAINER(pi
->widget
), pi
->socket
);
1992 gtk_widget_show_all(pi
->socket
);
1993 gtk_widget_realize(pi
->socket
);
1995 /* Always get button-2 events so we can drag */
1996 XGrabButton(gdk_display
, Button2
, AnyModifier
,
1997 GDK_WINDOW_XWINDOW(pi
->socket
->window
),
1999 ButtonPressMask
| ButtonReleaseMask
| Button2MotionMask
,
2000 GrabModeAsync
, /* Pointer */
2001 GrabModeAsync
, /* Keyboard */
2006 PanelSide side
= pi
->panel
->side
;
2008 /* Set a hint to let applets position their menus correctly */
2009 pos
= g_strdup_printf("%s,%d",
2010 panel_side_to_name(side
), MENU_MARGIN(side
));
2011 gdk_property_change(pi
->socket
->window
,
2012 gdk_atom_intern("_ROX_PANEL_MENU_POS", FALSE
),
2013 gdk_atom_intern("STRING", FALSE
),
2014 8, GDK_PROP_MODE_REPLACE
,
2018 /* Ensure that the properties are set before starting the
2024 g_object_set_data(G_OBJECT(pi
->widget
), "icon", pi
);
2025 g_object_set_data(G_OBJECT(pi
->socket
), "panel", pi
->panel
);
2027 argv
[1] = g_strdup_printf("%ld",
2028 GDK_WINDOW_XWINDOW(pi
->socket
->window
));
2031 if (!g_spawn_async(NULL
, argv
, NULL
, G_SPAWN_DO_NOT_REAP_CHILD
,
2032 NULL
, NULL
, &pid
, &error
))
2034 delayed_error(_("Error running applet:\n%s"), error
->message
);
2035 g_error_free(error
);
2036 gtk_widget_destroy(pi
->socket
);
2041 gtk_widget_ref(pi
->socket
);
2042 on_child_death(pid
, (CallbackFn
) applet_died
, pi
->socket
);
2044 gtk_widget_ref(pi
->socket
);
2045 g_signal_connect(pi
->socket
, "destroy",
2046 G_CALLBACK(socket_destroyed
), pi
->widget
);
2052 static void panel_post_resize(GtkWidget
*win
, GtkRequisition
*req
, Panel
*panel
)
2054 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
2056 req
->width
= panel
->geometry
.width
;
2057 req
->height
+= EDGE_WIDTH
;
2061 int h
= panel
->geometry
.height
;
2063 if (current_panel
[PANEL_TOP
])
2065 GtkWidget
*win
= current_panel
[PANEL_TOP
]->window
;
2066 h
-= win
->allocation
.height
;
2069 if (current_panel
[PANEL_BOTTOM
])
2071 GtkWidget
*win
= current_panel
[PANEL_BOTTOM
]->window
;
2072 h
-= win
->allocation
.height
;
2076 req
->width
+= EDGE_WIDTH
;
2080 static void update_side(GtkWidget
*side
)
2084 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
2085 for (next
= kids
; next
; next
= next
->next
)
2088 pi
= g_object_get_data(next
->data
, "icon");
2089 panel_icon_set_tip(pi
);
2094 /* Tips or style has changed -- update everything on this panel */
2095 static void panel_set_style(Panel
*panel
)
2097 update_side(panel
->before
);
2098 update_side(panel
->after
);
2099 gtk_widget_queue_resize(panel
->window
);
2102 static gboolean
recreate_panels(char **names
)
2106 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2110 panel_new(names
[i
], i
);
2120 static void update_side_size(GtkWidget
*side
)
2124 kids
= gtk_container_get_children(GTK_CONTAINER(side
));
2125 for (next
= kids
; next
; next
= next
->next
)
2128 pi
= g_object_get_data(next
->data
, "icon");
2129 gtk_widget_queue_resize(pi
->widget
);
2134 /* Update panel size and redraw */
2135 static void panel_update(Panel
*panel
)
2137 update_side_size(panel
->before
);
2138 update_side_size(panel
->after
);
2139 gtk_widget_queue_resize(panel
->window
);
2140 gtk_widget_queue_draw(panel
->window
);
2143 static void panel_style_changed(void)
2147 if (o_override_redirect
.has_changed
)
2151 names
= g_new(char *, PANEL_NUMBER_OF_SIDES
);
2153 for (i
= 0; i
< PANEL_NUMBER_OF_SIDES
; i
++)
2155 Panel
*panel
= current_panel
[i
];
2156 names
[i
] = panel
? g_strdup(panel
->name
) : NULL
;
2160 g_idle_add((GtkFunction
) recreate_panels
, names
);
2164 static gboolean
draw_panel_edge(GtkWidget
*widget
, GdkEventExpose
*event
,
2167 int x
, y
, width
, height
;
2169 if (panel
->side
== PANEL_TOP
|| panel
->side
== PANEL_BOTTOM
)
2171 width
= panel
->geometry
.width
;
2172 height
= EDGE_WIDTH
;
2175 if (panel
->side
== PANEL_BOTTOM
)
2178 y
= widget
->allocation
.height
- EDGE_WIDTH
;
2183 height
= panel
->geometry
.height
;
2186 if (panel
->side
== PANEL_RIGHT
)
2189 x
= widget
->allocation
.width
- EDGE_WIDTH
;
2192 gdk_draw_rectangle(widget
->window
,
2193 widget
->style
->fg_gc
[GTK_STATE_NORMAL
], TRUE
,
2194 x
, y
, width
, height
);
2199 static gpointer parent_class
;
2201 static void panel_icon_destroy(Icon
*icon
)
2203 PanelIcon
*pi
= (PanelIcon
*) icon
;
2205 g_return_if_fail(pi
!= NULL
);
2208 g_object_unref(pi
->image
);
2210 g_return_if_fail(pi
->widget
!= NULL
);
2212 gtk_widget_destroy(pi
->widget
);
2215 static void panel_remove_items(void)
2219 g_return_if_fail(icon_selection
!= NULL
);
2221 panel
= ((PanelIcon
*) icon_selection
->data
)->panel
;
2223 while (icon_selection
)
2224 icon_destroy((Icon
*) icon_selection
->data
);
2229 /* Icon's size, shape or appearance has changed - update the display */
2230 static void panel_icon_redraw(Icon
*icon
)
2232 PanelIcon
*pi
= (PanelIcon
*) icon
;
2234 gtk_widget_set_state(pi
->widget
,
2235 icon
->selected
? GTK_STATE_SELECTED
2236 : GTK_STATE_NORMAL
);
2238 /* Will regenerate the scaled icon from the new image */
2239 gtk_widget_queue_resize(pi
->widget
);
2241 panel_icon_set_tip((PanelIcon
*) icon
);
2244 static void panel_icon_update(Icon
*icon
)
2246 PanelIcon
*pi
= (PanelIcon
*) icon
;
2248 gtk_widget_queue_draw(pi
->widget
);
2249 gtk_label_set_text(GTK_LABEL(pi
->label
), icon
->item
->leafname
);
2250 panel_save(pi
->panel
);
2253 /* The point of this is to clear the selection if the existing icons
2254 * aren't from the same panel...
2256 static gboolean
panel_icon_same_group(Icon
*icon
, Icon
*other
)
2258 if (IS_PANEL_ICON(other
))
2260 PanelIcon
*a
= (PanelIcon
*) icon
;
2261 PanelIcon
*b
= (PanelIcon
*) other
;
2263 return a
->panel
== b
->panel
;
2269 static void panel_icon_class_init(gpointer gclass
, gpointer data
)
2271 IconClass
*icon
= (IconClass
*) gclass
;
2273 parent_class
= g_type_class_peek_parent(gclass
);
2275 icon
->destroy
= panel_icon_destroy
;
2276 icon
->redraw
= panel_icon_redraw
;
2277 icon
->update
= panel_icon_update
;
2278 icon
->remove_items
= panel_remove_items
;
2279 icon
->same_group
= panel_icon_same_group
;
2280 icon
->wink
= panel_icon_wink
;
2283 static void panel_icon_init(GTypeInstance
*object
, gpointer gclass
)
2285 PanelIcon
*pi
= (PanelIcon
*) object
;
2291 pi
->style
= TEXT_UNDER_ICON
;
2294 static GType
panel_icon_get_type(void)
2296 static GType type
= 0;
2300 static const GTypeInfo info
=
2302 sizeof (PanelIconClass
),
2303 NULL
, /* base_init */
2304 NULL
, /* base_finalise */
2305 panel_icon_class_init
,
2306 NULL
, /* class_finalise */
2307 NULL
, /* class_data */
2309 0, /* n_preallocs */
2313 type
= g_type_register_static(icon_get_type(),
2314 "PanelIcon", &info
, 0);
2320 static PanelIcon
*panel_icon_new(Panel
*panel
,
2321 const char *pathname
,
2327 pi
= g_object_new(panel_icon_get_type(), NULL
);
2330 icon_set_path(icon
, pathname
, name
);
2336 static gboolean
panel_want_show_text(PanelIcon
*pi
)
2338 Icon
*icon
= (Icon
*) pi
;
2339 Panel
*panel
= pi
->panel
;
2341 if (!icon
->item
->leafname
[0])
2344 if (panel
->style
== SHOW_BOTH
)
2346 if (panel
->style
== SHOW_ICON
)
2349 if (icon
->item
->flags
& ITEM_FLAG_APPDIR
)
2352 if (EXECUTABLE_FILE(icon
->item
))
2358 static void xinerama_sensitive(GtkBuilder
*builder
, gboolean sensitive
)
2360 gtk_widget_set_sensitive(
2361 GTK_WIDGET(gtk_builder_get_object(builder
, "panel_xinerama_monitor")),
2365 inline static Panel
*panel_from_opts_widget(GtkWidget
*widget
)
2367 return g_object_get_data(G_OBJECT(gtk_widget_get_toplevel(widget
)),
2371 static void panel_style_radio_toggled(GtkToggleButton
*widget
, int style
)
2375 if (!gtk_toggle_button_get_active(widget
))
2377 panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2378 if (style
!= panel
->style
)
2380 panel
->style
= style
;
2381 panel_set_style(panel
);
2386 static void panel_xinerama_changed(Panel
*panel
)
2388 panel_update_geometry(panel
);
2389 reposition_panel(panel
->window
, &panel
->window
->allocation
, panel
);
2390 gtk_widget_queue_resize(panel
->window
);
2394 static void panel_side_radio_toggled(GtkWidget
*widget
, PanelSide new_side
)
2398 char *name
, *other_side_name
;
2400 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
2403 panel
= panel_from_opts_widget(widget
);
2404 old_side
= panel
->side
;
2405 if (new_side
== old_side
)
2408 name
= g_strdup(panel
->name
);
2409 other_side_name
= current_panel
[new_side
]
2410 ? g_strdup(current_panel
[new_side
]->name
)
2413 panel_new(name
, new_side
);
2414 g_object_set_data(G_OBJECT(gtk_widget_get_toplevel(widget
)),
2415 "rox-panel", current_panel
[new_side
]);
2416 panel_new(other_side_name
, old_side
);
2419 g_free(other_side_name
);
2422 static void panel_style_radio_0_toggled_cb(GtkToggleButton
*widget
)
2424 panel_style_radio_toggled(widget
, 0);
2427 static void panel_style_radio_1_toggled_cb(GtkToggleButton
*widget
)
2429 panel_style_radio_toggled(widget
, 1);
2432 static void panel_style_radio_2_toggled_cb(GtkToggleButton
*widget
)
2434 panel_style_radio_toggled(widget
, 2);
2437 static void panel_width_changed_cb(GtkSpinButton
*widget
)
2439 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2440 int width
= gtk_spin_button_get_value_as_int(widget
);
2442 if (width
!= panel
->width
)
2444 panel
->width
= width
;
2445 panel_update(panel
);
2450 static void panel_avoid_toggled_cb(GtkToggleButton
*widget
)
2452 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2453 gboolean avoid
= gtk_toggle_button_get_active(widget
);
2455 if (avoid
!= panel
->avoid
)
2457 panel
->avoid
= avoid
;
2458 panel_setup_struts(panel
, &panel
->window
->allocation
);
2463 static void panel_xinerama_confine_toggled_cb(GtkWidget
*widget
, GtkWidget
*spinner
)
2465 Panel
*panel
= panel_from_opts_widget(widget
);
2466 gboolean xinerama
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
2468 gtk_widget_set_sensitive(spinner
, xinerama
);
2470 if (xinerama
!= panel
->xinerama
)
2472 panel
->xinerama
= xinerama
;
2473 panel_xinerama_changed(panel
);
2477 static void panel_xinerama_monitor_changed_cb(GtkSpinButton
*widget
)
2479 Panel
*panel
= panel_from_opts_widget(GTK_WIDGET(widget
));
2480 int monitor
= gtk_spin_button_get_value_as_int(widget
);
2482 if (monitor
!= panel
->monitor
)
2484 panel
->monitor
= monitor
;
2485 panel_xinerama_changed(panel
);
2489 static void panel_pos_top_toggled_cb(GtkWidget
*widget
)
2491 panel_side_radio_toggled(widget
, PANEL_TOP
);
2494 static void panel_pos_bottom_toggled_cb(GtkWidget
*widget
)
2496 panel_side_radio_toggled(widget
, PANEL_BOTTOM
);
2499 static void panel_pos_left_toggled_cb(GtkWidget
*widget
)
2501 panel_side_radio_toggled(widget
, PANEL_LEFT
);
2504 static void panel_pos_right_toggled_cb(GtkWidget
*widget
)
2506 panel_side_radio_toggled(widget
, PANEL_RIGHT
);
2509 static void panel_connect_dialog_signal_handlers(GtkBuilder
*builder
,
2511 const gchar
*signal_name
,
2512 const gchar
*handler_name
,
2513 GObject
*connect_object
,
2514 GConnectFlags flags
,
2519 if (strcmp(handler_name
, "gtk_widget_destroy") == 0)
2520 fn
= gtk_widget_destroy
;
2521 else if (strcmp(handler_name
, "panel_style_radio_0_toggled_cb") == 0)
2522 fn
= panel_style_radio_0_toggled_cb
;
2523 else if (strcmp(handler_name
, "panel_style_radio_0_toggled_cb") == 0)
2524 fn
= panel_style_radio_0_toggled_cb
;
2525 else if (strcmp(handler_name
, "panel_style_radio_1_toggled_cb") == 0)
2526 fn
= panel_style_radio_1_toggled_cb
;
2527 else if (strcmp(handler_name
, "panel_style_radio_2_toggled_cb") == 0)
2528 fn
= panel_style_radio_2_toggled_cb
;
2529 else if (strcmp(handler_name
, "panel_width_changed_cb") == 0)
2530 fn
= panel_width_changed_cb
;
2531 else if (strcmp(handler_name
, "panel_avoid_toggled_cb") == 0)
2532 fn
= panel_avoid_toggled_cb
;
2533 else if (strcmp(handler_name
, "panel_xinerama_confine_toggled_cb") == 0)
2534 fn
= panel_xinerama_confine_toggled_cb
;
2535 else if (strcmp(handler_name
, "panel_xinerama_monitor_changed_cb") == 0)
2536 fn
= panel_xinerama_monitor_changed_cb
;
2537 else if (strcmp(handler_name
, "panel_pos_top_toggled_cb") == 0)
2538 fn
= panel_pos_top_toggled_cb
;
2539 else if (strcmp(handler_name
, "panel_pos_bottom_toggled_cb") == 0)
2540 fn
= panel_pos_bottom_toggled_cb
;
2541 else if (strcmp(handler_name
, "panel_pos_left_toggled_cb") == 0)
2542 fn
= panel_pos_left_toggled_cb
;
2543 else if (strcmp(handler_name
, "panel_pos_right_toggled_cb") == 0)
2544 fn
= panel_pos_right_toggled_cb
;
2548 g_signal_connect(object
, signal_name
, fn
, connect_object
);
2552 g_warning("Unknown handler '%s'", handler_name
);
2556 static void panel_setup_options_dialog(GtkBuilder
*builder
, Panel
*panel
)
2559 const char *pos_radio
;
2561 wnm
= g_strdup_printf("panel_style_radio_%d", panel
->style
);
2562 gtk_toggle_button_set_active(
2563 GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder
, wnm
)),
2566 gtk_spin_button_set_value(
2567 GTK_SPIN_BUTTON(gtk_builder_get_object(builder
, "panel_width")),
2569 gtk_toggle_button_set_active(
2570 GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder
, "panel_avoid")),
2572 gtk_toggle_button_set_active(
2573 GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder
,
2574 "panel_xinerama_confine")),
2576 gtk_spin_button_set_adjustment(
2577 GTK_SPIN_BUTTON(gtk_builder_get_object(builder
, "panel_xinerama_monitor")),
2578 GTK_ADJUSTMENT(gtk_adjustment_new(MAX(0, panel
->monitor
),
2579 0, n_monitors
- 1, 1, 10, 0)));
2580 xinerama_sensitive(builder
, panel
->xinerama
);
2581 switch (panel
->side
)
2584 pos_radio
= "panel_pos_top";
2587 pos_radio
= "panel_pos_bottom";
2590 pos_radio
= "panel_pos_left";
2593 pos_radio
= "panel_pos_right";
2599 g_return_if_fail(pos_radio
!= NULL
);
2600 gtk_toggle_button_set_active(
2601 GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder
, pos_radio
)),
2605 static void panel_show_options(Panel
*panel
)
2608 gboolean already_showing
= FALSE
;
2609 GtkBuilder
*builder
;
2610 gchar
*ids
[] = {"adjustment1", "adjustment2", "Panel Options", NULL
};
2612 builder
= get_gtk_builder(ids
);
2614 if (panel_options_dialog
)
2616 dialog
= panel_options_dialog
;
2617 already_showing
= TRUE
;
2621 dialog
= GTK_WIDGET(gtk_builder_get_object(builder
, "Panel Options"));
2622 panel_options_dialog
= dialog
;
2623 g_signal_connect(dialog
, "destroy",
2624 G_CALLBACK(gtk_widget_destroyed
),
2625 &panel_options_dialog
);
2626 gtk_builder_connect_signals_full(builder
, &panel_connect_dialog_signal_handlers
, NULL
);
2628 g_object_set_data(G_OBJECT(panel_options_dialog
), "rox-panel", panel
);
2630 panel_setup_options_dialog(builder
, panel
);
2632 if (already_showing
)
2634 GtkWindow
*win
= GTK_WINDOW(dialog
);
2636 gtk_widget_hide(dialog
);
2637 /* This extra set_position() should ensure it moves to new position
2639 gtk_window_set_position(win
, GTK_WIN_POS_CENTER_ALWAYS
);
2640 gtk_window_set_position(win
, GTK_WIN_POS_MOUSE
);
2641 gtk_window_present(win
);
2645 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
2646 gtk_widget_show_all(dialog
);
2649 g_object_unref(builder
);
2652 static void panel_position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
,
2653 gboolean
*push_in
, gpointer data
)
2655 int *pos
= (int *) data
;
2656 GtkRequisition requisition
;
2657 int margin
= pos
[2];
2659 int mon_right
= monitor_geom
[mon
].x
+
2660 monitor_geom
[mon
].width
;
2661 int mon_bottom
= monitor_geom
[mon
].y
+
2662 monitor_geom
[mon
].height
;
2664 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
2667 *x
= mon_right
- margin
- requisition
.width
;
2668 else if (pos
[0] == -2)
2669 *x
= monitor_geom
[mon
].x
+ margin
;
2671 *x
= pos
[0] - (requisition
.width
>> 2);
2674 *y
= mon_bottom
- margin
- requisition
.height
;
2675 else if (pos
[1] == -2)
2676 *y
= monitor_geom
[mon
].y
+ margin
;
2678 *y
= pos
[1] - (requisition
.height
>> 2);
2680 *x
= CLAMP(*x
, 0, mon_right
- requisition
.width
);
2681 *y
= CLAMP(*y
, 0, mon_bottom
- requisition
.height
);
2686 static void panel_remove_callback(PanelSide side
)
2688 GtkWidget
*dialog
= gtk_message_dialog_new(NULL
, GTK_DIALOG_MODAL
,
2689 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_OK_CANCEL
,
2690 _("Are you sure you want to remove this panel from the desktop?"));
2692 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), GTK_RESPONSE_OK
);
2693 gtk_window_set_title(GTK_WINDOW(dialog
), _("Remove Panel"));
2694 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
2695 if (gtk_dialog_run(GTK_DIALOG(dialog
)) == GTK_RESPONSE_OK
)
2696 panel_new(NULL
, side
);
2697 gtk_widget_destroy(dialog
);
2700 static void panel_show_menu(GdkEventButton
*event
, PanelIcon
*pi
, Panel
*panel
)
2702 GtkWidget
*option_item
;
2703 GtkWidget
*del_item
;
2704 PanelSide side
= panel
->side
;
2707 pos
[0] = event
->x_root
;
2708 pos
[1] = event
->y_root
;
2709 pos
[2] = MENU_MARGIN(side
);
2710 /* FIXME: Should we read screen from event's window rather than
2712 pos
[3] = gdk_screen_get_monitor_at_point(
2713 gdk_screen_get_default(),
2714 event
->x_root
, event
->y_root
);
2716 option_item
= gtk_image_menu_item_new_with_label(_("Panel Options..."));
2717 g_signal_connect_swapped(option_item
, "activate",
2718 G_CALLBACK(panel_show_options
), panel
);
2720 del_item
= gtk_image_menu_item_new_with_label(_("Remove Panel"));
2721 add_stock_to_menu_item(del_item
, GTK_STOCK_REMOVE
);
2722 g_signal_connect_swapped(del_item
, "activate",
2723 G_CALLBACK(panel_remove_callback
), GINT_TO_POINTER(side
));
2725 icon_prepare_menu((Icon
*) pi
, option_item
, del_item
, NULL
);
2727 if (side
== PANEL_LEFT
)
2729 else if (side
== PANEL_RIGHT
)
2732 if (side
== PANEL_TOP
)
2734 else if (side
== PANEL_BOTTOM
)
2737 gtk_menu_popup(GTK_MENU(icon_menu
), NULL
, NULL
,
2738 panel_position_menu
,
2739 (gpointer
) pos
, event
->button
, event
->time
);
2742 /* Note: also called from icon handler */
2743 static gboolean
panel_drag_motion(GtkWidget
*widget
,
2744 GdkDragContext
*context
,
2750 int panel_x
, panel_y
;
2752 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2754 motion_may_raise(panel
, panel_x
, panel_y
);
2755 gdk_drag_status(context
, 0, time
);
2760 static gboolean
insert_drag_motion(GtkWidget
*widget
,
2761 GdkDragContext
*context
,
2767 int panel_x
, panel_y
;
2769 gdk_window_get_pointer(panel
->window
->window
, &panel_x
, &panel_y
, NULL
);
2770 motion_may_raise(panel
, panel_x
, panel_y
);
2775 /* Note: also called from icon handler */
2776 static void panel_drag_leave(GtkWidget
*widget
,
2777 GdkDragContext
*context
,
2781 GdkWindow
*pinboard
, *window
;
2782 GtkAllocation
*alloc
= &panel
->window
->allocation
;
2785 window
= panel
->window
->window
;
2786 gdk_window_get_pointer(window
, &x
, &y
, NULL
);
2787 if ((x
< 0 || y
< 0 || x
> alloc
->width
|| y
> alloc
->height
) &&
2788 panel_keep_below(panel
, TRUE
))
2790 /* Shouldn't need this as well as keep_below but some WMs don't
2791 * automatically lower as soon as the hint is set */
2792 pinboard
= pinboard_get_window();
2793 window_put_just_above(panel
->window
->window
, pinboard
);
2797 static void panel_update_geometry(Panel
*panel
)
2799 if (panel
->xinerama
&& panel
->monitor
>= n_monitors
)
2801 g_warning(_("Xinerama monitor %d unavailable"), panel
->monitor
);
2802 panel
->xinerama
= FALSE
;
2805 if (panel
->xinerama
)
2807 panel
->geometry
= monitor_geom
[panel
->monitor
];
2809 else if (o_panel_obey_workarea
.int_value
)
2811 get_work_area(&panel
->geometry
.x
, &panel
->geometry
.y
,
2812 &panel
->geometry
.width
, &panel
->geometry
.height
);
2816 panel
->geometry
.x
= panel
->geometry
.y
= 0;
2817 panel
->geometry
.width
= screen_width
;
2818 panel
->geometry
.height
= screen_height
;
2822 static GList
*build_monitor_number(Option
*option
, xmlNode
*node
, guchar
*label
)
2826 adj
= gtk_adjustment_new(MAX(0, panel_monitor
),
2827 0, n_monitors
- 1, 1, 10, 1);
2828 return build_numentry_base(option
, node
, label
, GTK_ADJUSTMENT(adj
));
2831 static const char *panel_side_to_translated_name(PanelSide side
)
2843 case PANEL_DEFAULT_SIDE
:
2844 return _("Default");
2848 return _("Unknown side");
2851 const char *panel_side_to_name(PanelSide side
)
2863 case PANEL_DEFAULT_SIDE
:
2868 return "UnknownSide";
2871 /* Returns PANEL_NUMBER_OF_SIDES if name is invalid */
2872 PanelSide
panel_name_to_side(gchar
*side
)
2874 if (strcmp(side
, "Top") == 0)
2876 else if (strcmp(side
, "Bottom") == 0)
2877 return PANEL_BOTTOM
;
2878 else if (strcmp(side
, "Left") == 0)
2880 else if (strcmp(side
, "Right") == 0)
2883 g_warning("Unknown panel side '%s'", side
);
2884 return PANEL_NUMBER_OF_SIDES
;
2887 static void panel_add_callback(PanelSide side
)
2889 g_return_if_fail(current_panel
[side
] == NULL
);
2890 panel_new(panel_side_to_name(side
), side
);
2893 GtkWidget
*panel_new_panel_submenu(void)
2895 GtkWidget
*menu
= gtk_menu_new();
2898 for (side
= 0; side
< PANEL_NUMBER_OF_SIDES
; ++side
)
2900 GtkWidget
*item
= gtk_menu_item_new_with_label(
2901 panel_side_to_translated_name(side
));
2903 g_signal_connect_swapped(item
, "activate",
2904 G_CALLBACK(panel_add_callback
), GINT_TO_POINTER(side
));
2905 gtk_widget_set_sensitive(item
, current_panel
[side
] == NULL
);
2906 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
2907 gtk_widget_show(item
);
2912 /* Set the panel to be above/below other windows (setting = TRUE for below),
2915 * If o_panel_on_top is set then do nothing and return FALSE.
2917 static gboolean
panel_keep_below(Panel
*panel
, gboolean setting
)
2919 if (!o_panel_on_top
.int_value
)
2921 keep_below(panel
->window
->window
, setting
);