1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* nautilus-side-pane.c
5 * Copyright (C) 2002 Ximian Inc.
7 * Nautilus is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * Nautilus is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Author: Dave Camp <dave@ximian.com>
25 #include "nautilus-side-pane.h"
27 #include <eel/eel-glib-extensions.h>
28 #include <eel/eel-gtk-macros.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtkarrow.h>
31 #include <gtk/gtkbutton.h>
32 #include <gtk/gtkframe.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtkimage.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkimagemenuitem.h>
37 #include <gtk/gtknotebook.h>
38 #include <gtk/gtkstock.h>
39 #include <gtk/gtktogglebutton.h>
40 #include <glib/gi18n.h>
50 struct _NautilusSidePaneDetails
{
54 GtkWidget
*title_frame
;
55 GtkWidget
*title_hbox
;
56 GtkWidget
*title_label
;
57 GtkWidget
*shortcut_box
;
61 static void nautilus_side_pane_class_init (NautilusSidePaneClass
*klass
);
62 static void nautilus_side_pane_init (GObject
*object
);
63 static void nautilus_side_pane_dispose (GObject
*object
);
64 static void nautilus_side_pane_finalize (GObject
*object
);
72 static guint signals
[LAST_SIGNAL
];
74 EEL_CLASS_BOILERPLATE (NautilusSidePane
, nautilus_side_pane
, GTK_TYPE_VBOX
)
77 panel_for_widget (NautilusSidePane
*side_pane
, GtkWidget
*widget
)
82 for (l
= side_pane
->details
->panels
; l
!= NULL
; l
= l
->next
) {
84 if (panel
->widget
== widget
) {
93 side_panel_free (SidePanel
*panel
)
95 g_free (panel
->title
);
96 g_free (panel
->tooltip
);
97 g_slice_free (SidePanel
, panel
);
101 switch_page_callback (GtkWidget
*notebook
,
102 GtkNotebookPage
*page
,
106 NautilusSidePane
*side_pane
;
109 side_pane
= NAUTILUS_SIDE_PANE (user_data
);
111 panel
= panel_for_widget (side_pane
,
112 gtk_notebook_get_nth_page (GTK_NOTEBOOK (side_pane
->details
->notebook
),
115 if (panel
&& side_pane
->details
->title_label
) {
116 gtk_label_set_text (GTK_LABEL (side_pane
->details
->title_label
),
120 g_signal_emit (side_pane
, signals
[SWITCH_PAGE
], 0,
121 panel
? panel
->widget
: NULL
);
125 select_panel (NautilusSidePane
*side_pane
, SidePanel
*panel
)
129 page_num
= gtk_notebook_page_num
130 (GTK_NOTEBOOK (side_pane
->details
->notebook
), panel
->widget
);
131 gtk_notebook_set_current_page
132 (GTK_NOTEBOOK (side_pane
->details
->notebook
), page_num
);
136 nautilus_side_pane_size_allocate (GtkWidget
*widget
,
137 GtkAllocation
*allocation
)
140 GtkAllocation child_allocation
;
141 NautilusSidePane
*pane
;
144 GtkRequisition child_requisition
;
146 GTK_WIDGET_CLASS (parent_class
)->size_allocate (widget
, allocation
);
148 pane
= NAUTILUS_SIDE_PANE(widget
);
149 frame
= pane
->details
->title_frame
;
150 hbox
= pane
->details
->title_hbox
;
152 gtk_widget_get_child_requisition (hbox
, &child_requisition
);
153 width
= child_requisition
.width
;
155 child_allocation
= frame
->allocation
;
156 child_allocation
.width
= MAX (width
, frame
->allocation
.width
);
158 gtk_widget_size_allocate (frame
, &child_allocation
);
161 /* initializing the class object by installing the operations we override */
163 nautilus_side_pane_class_init (NautilusSidePaneClass
*klass
)
165 GObjectClass
*gobject_class
;
166 GtkWidgetClass
*widget_class
;
168 gobject_class
= G_OBJECT_CLASS (klass
);
169 widget_class
= GTK_WIDGET_CLASS (klass
);
171 gobject_class
->finalize
= nautilus_side_pane_finalize
;
172 gobject_class
->dispose
= nautilus_side_pane_dispose
;
173 widget_class
->size_allocate
= nautilus_side_pane_size_allocate
;
175 signals
[CLOSE_REQUESTED
] = g_signal_new
177 G_TYPE_FROM_CLASS (klass
),
179 G_STRUCT_OFFSET (NautilusSidePaneClass
,
182 g_cclosure_marshal_VOID__VOID
,
184 signals
[SWITCH_PAGE
] = g_signal_new
186 G_TYPE_FROM_CLASS (klass
),
188 G_STRUCT_OFFSET (NautilusSidePaneClass
,
191 g_cclosure_marshal_VOID__OBJECT
,
192 G_TYPE_NONE
, 1, GTK_TYPE_WIDGET
);
194 g_type_class_add_private (gobject_class
, sizeof (NautilusSidePaneDetails
));
198 panel_item_activate_callback (GtkMenuItem
*item
,
201 NautilusSidePane
*side_pane
;
204 side_pane
= NAUTILUS_SIDE_PANE (user_data
);
206 panel
= g_object_get_data (G_OBJECT (item
), "panel-item");
208 select_panel (side_pane
, panel
);
213 menu_position_under (GtkMenu
*menu
,
221 g_return_if_fail (GTK_IS_BUTTON (user_data
));
222 g_return_if_fail (GTK_WIDGET_NO_WINDOW (user_data
));
224 widget
= GTK_WIDGET (user_data
);
226 gdk_window_get_origin (widget
->window
, x
, y
);
228 *x
+= widget
->allocation
.x
;
229 *y
+= widget
->allocation
.y
+ widget
->allocation
.height
;
235 select_button_press_callback (GtkWidget
*widget
,
236 GdkEventButton
*event
,
239 NautilusSidePane
*side_pane
;
241 side_pane
= NAUTILUS_SIDE_PANE (user_data
);
243 if ((event
->type
== GDK_BUTTON_PRESS
) && event
->button
== 1) {
244 gtk_widget_grab_focus (widget
);
246 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget
), TRUE
);
247 gtk_menu_popup (GTK_MENU (side_pane
->details
->menu
),
248 NULL
, NULL
, menu_position_under
, widget
,
249 event
->button
, event
->time
);
257 select_button_key_press_callback (GtkWidget
*widget
,
261 NautilusSidePane
*side_pane
;
263 side_pane
= NAUTILUS_SIDE_PANE (user_data
);
265 if (event
->keyval
== GDK_space
||
266 event
->keyval
== GDK_KP_Space
||
267 event
->keyval
== GDK_Return
||
268 event
->keyval
== GDK_KP_Enter
) {
269 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget
), TRUE
);
270 gtk_menu_popup (GTK_MENU (side_pane
->details
->menu
),
271 NULL
, NULL
, menu_position_under
, widget
,
280 close_clicked_callback (GtkWidget
*widget
,
283 NautilusSidePane
*side_pane
;
285 side_pane
= NAUTILUS_SIDE_PANE (user_data
);
287 g_signal_emit (side_pane
, signals
[CLOSE_REQUESTED
], 0);
291 menu_deactivate_callback (GtkWidget
*widget
,
294 GtkWidget
*menu_button
;
296 menu_button
= GTK_WIDGET (user_data
);
298 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (menu_button
), FALSE
);
302 menu_detach_callback (GtkWidget
*widget
,
305 NautilusSidePane
*side_pane
;
307 side_pane
= NAUTILUS_SIDE_PANE (widget
);
309 side_pane
->details
->menu
= NULL
;
313 nautilus_side_pane_init (GObject
*object
)
315 NautilusSidePane
*side_pane
;
318 GtkWidget
*close_button
;
319 GtkWidget
*select_button
;
320 GtkWidget
*select_hbox
;
324 side_pane
= NAUTILUS_SIDE_PANE (object
);
326 side_pane
->details
= G_TYPE_INSTANCE_GET_PRIVATE (object
, NAUTILUS_TYPE_SIDE_PANE
, NautilusSidePaneDetails
);
328 frame
= gtk_frame_new (NULL
);
329 side_pane
->details
->title_frame
= frame
;
330 gtk_widget_show (frame
);
331 gtk_box_pack_start (GTK_BOX (side_pane
), frame
, FALSE
, FALSE
, 0);
333 hbox
= gtk_hbox_new (FALSE
, 0);
334 side_pane
->details
->title_hbox
= hbox
;
335 gtk_widget_show (hbox
);
336 gtk_container_add (GTK_CONTAINER (frame
), hbox
);
338 select_button
= gtk_toggle_button_new ();
339 gtk_button_set_relief (GTK_BUTTON (select_button
), GTK_RELIEF_NONE
);
340 gtk_widget_show (select_button
);
342 g_signal_connect (select_button
,
343 "button_press_event",
344 G_CALLBACK (select_button_press_callback
),
346 g_signal_connect (select_button
,
348 G_CALLBACK (select_button_key_press_callback
),
351 select_hbox
= gtk_hbox_new (FALSE
, 0);
352 gtk_widget_show (select_hbox
);
354 side_pane
->details
->title_label
= gtk_label_new ("");
355 eel_add_weak_pointer (&side_pane
->details
->title_label
);
357 gtk_widget_show (side_pane
->details
->title_label
);
358 gtk_box_pack_start (GTK_BOX (select_hbox
),
359 side_pane
->details
->title_label
,
362 arrow
= gtk_arrow_new (GTK_ARROW_DOWN
, GTK_SHADOW_NONE
);
363 gtk_widget_show (arrow
);
364 gtk_box_pack_end (GTK_BOX (select_hbox
), arrow
, FALSE
, FALSE
, 0);
366 gtk_container_add (GTK_CONTAINER (select_button
), select_hbox
);
367 gtk_box_pack_start (GTK_BOX (hbox
), select_button
, FALSE
, FALSE
, 0);
369 close_button
= gtk_button_new ();
370 gtk_button_set_relief (GTK_BUTTON (close_button
), GTK_RELIEF_NONE
);
371 g_signal_connect (close_button
,
373 G_CALLBACK (close_clicked_callback
),
376 gtk_widget_show (close_button
);
378 image
= gtk_image_new_from_stock (GTK_STOCK_CLOSE
,
380 gtk_widget_show (image
);
382 gtk_container_add (GTK_CONTAINER (close_button
), image
);
384 gtk_box_pack_end (GTK_BOX (hbox
), close_button
, FALSE
, FALSE
, 0);
386 side_pane
->details
->shortcut_box
= gtk_hbox_new (TRUE
, 0);
387 gtk_widget_show (side_pane
->details
->shortcut_box
);
388 gtk_box_pack_end (GTK_BOX (hbox
),
389 side_pane
->details
->shortcut_box
,
392 side_pane
->details
->notebook
= gtk_notebook_new ();
393 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (side_pane
->details
->notebook
),
395 gtk_notebook_set_show_border (GTK_NOTEBOOK (side_pane
->details
->notebook
),
397 g_signal_connect_object (side_pane
->details
->notebook
,
399 G_CALLBACK (switch_page_callback
),
403 gtk_widget_show (side_pane
->details
->notebook
);
405 gtk_box_pack_start (GTK_BOX (side_pane
), side_pane
->details
->notebook
,
408 side_pane
->details
->menu
= gtk_menu_new ();
409 g_signal_connect (side_pane
->details
->menu
,
411 G_CALLBACK (menu_deactivate_callback
),
413 gtk_menu_attach_to_widget (GTK_MENU (side_pane
->details
->menu
),
414 GTK_WIDGET (side_pane
),
415 menu_detach_callback
);
417 gtk_widget_show (side_pane
->details
->menu
);
419 gtk_widget_set_tooltip_text (close_button
,
420 _("Close the side pane"));
424 nautilus_side_pane_dispose (GObject
*object
)
426 NautilusSidePane
*side_pane
;
428 side_pane
= NAUTILUS_SIDE_PANE (object
);
430 if (side_pane
->details
->menu
) {
431 gtk_menu_detach (GTK_MENU (side_pane
->details
->menu
));
432 side_pane
->details
->menu
= NULL
;
435 EEL_CALL_PARENT (G_OBJECT_CLASS
, dispose
, (object
));
439 nautilus_side_pane_finalize (GObject
*object
)
441 NautilusSidePane
*side_pane
;
444 side_pane
= NAUTILUS_SIDE_PANE (object
);
446 for (l
= side_pane
->details
->panels
; l
!= NULL
; l
= l
->next
) {
447 side_panel_free (l
->data
);
450 g_list_free (side_pane
->details
->panels
);
452 EEL_CALL_PARENT (G_OBJECT_CLASS
, finalize
, (object
));
456 nautilus_side_pane_new (void)
458 return NAUTILUS_SIDE_PANE (gtk_widget_new (nautilus_side_pane_get_type (), NULL
));
462 nautilus_side_pane_add_panel (NautilusSidePane
*side_pane
,
469 g_return_if_fail (side_pane
!= NULL
);
470 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane
));
471 g_return_if_fail (widget
!= NULL
);
472 g_return_if_fail (GTK_IS_WIDGET (widget
));
473 g_return_if_fail (title
!= NULL
);
474 g_return_if_fail (tooltip
!= NULL
);
476 panel
= g_slice_new0 (SidePanel
);
477 panel
->title
= g_strdup (title
);
478 panel
->tooltip
= g_strdup (tooltip
);
479 panel
->widget
= widget
;
481 gtk_widget_show (widget
);
483 panel
->menu_item
= gtk_image_menu_item_new_with_label (title
);
484 gtk_widget_show (panel
->menu_item
);
485 gtk_menu_shell_append (GTK_MENU_SHELL (side_pane
->details
->menu
),
487 g_object_set_data (G_OBJECT (panel
->menu_item
), "panel-item", panel
);
489 g_signal_connect (panel
->menu_item
,
491 G_CALLBACK (panel_item_activate_callback
),
494 side_pane
->details
->panels
= g_list_append (side_pane
->details
->panels
,
497 gtk_notebook_append_page (GTK_NOTEBOOK (side_pane
->details
->notebook
),
503 nautilus_side_pane_remove_panel (NautilusSidePane
*side_pane
,
509 g_return_if_fail (side_pane
!= NULL
);
510 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane
));
511 g_return_if_fail (widget
!= NULL
);
512 g_return_if_fail (GTK_IS_WIDGET (widget
));
514 panel
= panel_for_widget (side_pane
, widget
);
516 g_return_if_fail (panel
!= NULL
);
519 page_num
= gtk_notebook_page_num (GTK_NOTEBOOK (side_pane
->details
->notebook
),
521 gtk_notebook_remove_page (GTK_NOTEBOOK (side_pane
->details
->notebook
),
523 gtk_container_remove (GTK_CONTAINER (side_pane
->details
->menu
),
526 side_pane
->details
->panels
=
527 g_list_remove (side_pane
->details
->panels
,
530 side_panel_free (panel
);
535 nautilus_side_pane_show_panel (NautilusSidePane
*side_pane
,
541 g_return_if_fail (side_pane
!= NULL
);
542 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane
));
543 g_return_if_fail (widget
!= NULL
);
544 g_return_if_fail (GTK_IS_WIDGET (widget
));
546 panel
= panel_for_widget (side_pane
, widget
);
548 g_return_if_fail (panel
!= NULL
);
550 page_num
= gtk_notebook_page_num (GTK_NOTEBOOK (side_pane
->details
->notebook
),
552 gtk_notebook_set_current_page (GTK_NOTEBOOK (side_pane
->details
->notebook
),
558 shortcut_clicked_callback (GtkWidget
*button
,
561 NautilusSidePane
*side_pane
;
564 side_pane
= NAUTILUS_SIDE_PANE (user_data
);
566 page
= GTK_WIDGET (g_object_get_data (G_OBJECT (button
), "side-page"));
568 nautilus_side_pane_show_panel (side_pane
, page
);
572 create_shortcut (NautilusSidePane
*side_pane
,
579 button
= gtk_button_new ();
580 gtk_button_set_relief (GTK_BUTTON (button
), GTK_RELIEF_NONE
);
582 g_object_set_data (G_OBJECT (button
), "side-page", panel
->widget
);
583 g_signal_connect (button
, "clicked",
584 G_CALLBACK (shortcut_clicked_callback
), side_pane
);
586 gtk_widget_set_tooltip_text (button
, panel
->tooltip
);
588 image
= gtk_image_new_from_pixbuf (pixbuf
);
589 gtk_widget_show (image
);
590 gtk_container_add (GTK_CONTAINER (button
), image
);
596 nautilus_side_pane_set_panel_image (NautilusSidePane
*side_pane
,
603 g_return_if_fail (side_pane
!= NULL
);
604 g_return_if_fail (NAUTILUS_IS_SIDE_PANE (side_pane
));
605 g_return_if_fail (widget
!= NULL
);
606 g_return_if_fail (GTK_IS_WIDGET (widget
));
607 g_return_if_fail (pixbuf
== NULL
|| GDK_IS_PIXBUF (pixbuf
));
609 panel
= panel_for_widget (side_pane
, widget
);
611 g_return_if_fail (panel
!= NULL
);
614 image
= gtk_image_new_from_pixbuf (pixbuf
);
615 gtk_widget_show (image
);
620 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (panel
->menu_item
),
623 if (panel
->shortcut
) {
624 gtk_widget_destroy (panel
->shortcut
);
625 panel
->shortcut
= NULL
;
629 panel
->shortcut
= create_shortcut (side_pane
, panel
, pixbuf
);
630 gtk_widget_show (panel
->shortcut
);
631 gtk_box_pack_start (GTK_BOX (side_pane
->details
->shortcut_box
),
638 nautilus_side_pane_get_current_panel (NautilusSidePane
*side_pane
)
642 index
= gtk_notebook_get_current_page (GTK_NOTEBOOK (side_pane
->details
->notebook
));
643 return gtk_notebook_get_nth_page (GTK_NOTEBOOK (side_pane
->details
->notebook
), index
);