1 /*
2  * Nautilus-Actions
3  * A Nautilus extension which offers configurable context menu actions.
4  *
5  * Copyright (C) 2005 The GNOME Foundation
6  * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7  * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8  *
9  * Nautilus-Actions is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * Nautilus-Actions is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Nautilus-Actions; see the file COPYING. If not, see
21  * <http://www.gnu.org/licenses/>.
22  *
23  * Authors:
24  *   Frederic Ruaudel <grumz@grumz.net>
25  *   Rodrigo Moya <rodrigo@gnome-db.org>
26  *   Pierre Wieser <pwieser@trychlos.org>
27  *   ... and many others (see AUTHORS)
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include "nact-application.h"
35 #include "nact-main-toolbar.h"
36 
37 typedef struct {
38 	int      id;
39 	gchar   *prefs_key;
40 	gboolean displayed_per_default;
41 	gchar   *ui_item;
42 	gchar   *ui_path;
43 }
44 	ToolbarProps;
45 
46 static ToolbarProps toolbar_props[] = {
47 		{ MAIN_TOOLBAR_FILE_ID , NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY,   TRUE, "ViewFileToolbarItem" , "/ui/FileToolbar" },
48 		{ MAIN_TOOLBAR_EDIT_ID , NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY,  FALSE, "ViewEditToolbarItem" , "/ui/EditToolbar" },
49 		{ MAIN_TOOLBAR_TOOLS_ID, NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY, FALSE, "ViewToolsToolbarItem", "/ui/ToolsToolbar" },
50 		{ MAIN_TOOLBAR_HELP_ID , NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY,   TRUE, "ViewHelpToolbarItem" , "/ui/HelpToolbar" }
51 };
52 
53 /* defines the relative position of the main toolbars
54  * that is: they are listed here in the order they should be displayed
55  */
56 static int toolbar_pos[] = {
57 		MAIN_TOOLBAR_FILE_ID,
58 		MAIN_TOOLBAR_EDIT_ID,
59 		MAIN_TOOLBAR_TOOLS_ID,
60 		MAIN_TOOLBAR_HELP_ID
61 };
62 
63 static void          init_toolbar( BaseWindow *window, GtkActionGroup *group, int toolbar_id );
64 static void          reorder_toolbars( GtkWidget *hbox, int toolbar_id, GtkWidget *handle );
65 #if !GTK_CHECK_VERSION( 3,4,0 )
66 static void          on_handle_finalize( gpointer data, GObject *handle );
67 static void          on_attach_toolbar( GtkHandleBox *handle, GtkToolbar *toolbar, NactMainWindow *window );
68 static void          on_detach_toolbar( GtkHandleBox *handle, GtkToolbar *toolbar, NactMainWindow *window );
69 #endif
70 static ToolbarProps *get_toolbar_properties( int toolbar_id );
71 
72 /**
73  * nact_main_toolbar_init:
74  * @window: this #NactMainWindow window.
75  *
76  * Setup the initial display of the standard main toolbars.
77  *
78  * This actually only setup the initial state of the toggle options in
79  * View > Toolbars menu; when an option is activated, this will trigger
80  * the 'on_view_toolbar_activated()' which will actually display the
81  * toolbar.
82  */
83 void
nact_main_toolbar_init(BaseWindow * window,GtkActionGroup * group)84 nact_main_toolbar_init( BaseWindow *window, GtkActionGroup *group )
85 {
86 	static const gchar *thisfn = "nact_main_toolbar_init";
87 	int i;
88 
89 	g_debug( "%s: window=%p, group=%p", thisfn, ( void * ) window, ( void * ) group );
90 
91 	for( i = 0 ; i < G_N_ELEMENTS( toolbar_pos ) ; ++i ){
92 		init_toolbar( window, group, toolbar_pos[i] );
93 	}
94 }
95 
96 static void
init_toolbar(BaseWindow * window,GtkActionGroup * group,int toolbar_id)97 init_toolbar( BaseWindow *window, GtkActionGroup *group, int toolbar_id )
98 {
99 	ToolbarProps *props;
100 	gboolean is_active;
101 	GtkToggleAction *action;
102 
103 	props = get_toolbar_properties( toolbar_id );
104 	if( props ){
105 		is_active = na_settings_get_boolean( props->prefs_key, NULL, NULL );
106 		if( is_active ){
107 			action = GTK_TOGGLE_ACTION( gtk_action_group_get_action( group, props->ui_item ));
108 			gtk_toggle_action_set_active( action, TRUE );
109 		}
110 	}
111 }
112 
113 /**
114  * nact_main_toolbar_activate:
115  * @window: this #NactMainWindow.
116  * @toolbar_id: the id of the activated toolbar.
117  * @ui_manager: the #GtkUIManager.
118  * @is_active: whether this toolbar is activated or not.
119  *
120  * Activate or desactivate the toolbar.
121  *
122  * pwi 2013-09-07
123  * GtkHandleBox has been deprecated starting with Gtk 3.4 and there is
124  * no replacement (see https://developer.gnome.org/gtk3/stable/GtkHandleBox.html).
125  * So exit floating toolbars :(
126  */
127 void
nact_main_toolbar_activate(NactMainWindow * window,int toolbar_id,GtkUIManager * ui_manager,gboolean is_active)128 nact_main_toolbar_activate( NactMainWindow *window, int toolbar_id, GtkUIManager *ui_manager, gboolean is_active )
129 {
130 	static const gchar *thisfn = "nact_main_toolbar_activate";
131 	ToolbarProps *props;
132 	GtkWidget *toolbar, *hbox;
133 
134 	props = get_toolbar_properties( toolbar_id );
135 	if( !props ){
136 		return;
137 	}
138 
139 	toolbar = gtk_ui_manager_get_widget( ui_manager, props->ui_path );
140 	g_debug( "%s: toolbar=%p, path=%s, ref_count=%d", thisfn, ( void * ) toolbar, props->ui_path, G_OBJECT( toolbar )->ref_count );
141 	hbox = base_window_get_widget( BASE_WINDOW( window ), "ToolbarHBox" );
142 
143 #if GTK_CHECK_VERSION( 3,4,0 )
144 	if( is_active ){
145 		gtk_container_add( GTK_CONTAINER( hbox ), toolbar );
146 		reorder_toolbars( hbox, toolbar_id, toolbar );
147 		gtk_widget_show_all( toolbar );
148 
149 	} else {
150 		gtk_container_remove( GTK_CONTAINER( hbox ), toolbar );
151 	}
152 #else
153 	GtkWidget *handle;
154 	gulong attach_id, detach_id;
155 
156 	if( is_active ){
157 		handle = gtk_handle_box_new();
158 		gtk_handle_box_set_snap_edge( GTK_HANDLE_BOX( handle ), GTK_POS_LEFT );
159 		g_object_set_data( G_OBJECT( toolbar ), "nact-main-toolbar-handle", handle );
160 		attach_id = g_signal_connect( handle, "child-attached", (GCallback ) on_attach_toolbar, window );
161 		g_object_set_data( G_OBJECT( handle ), "nact-handle-attach-id", ( gpointer ) attach_id );
162 		detach_id = g_signal_connect( handle, "child-detached", (GCallback ) on_detach_toolbar, window );
163 		g_object_set_data( G_OBJECT( handle ), "nact-handle-detach-id", ( gpointer ) detach_id );
164 		g_object_weak_ref( G_OBJECT( handle ), ( GWeakNotify ) on_handle_finalize, NULL );
165 		gtk_container_add( GTK_CONTAINER( handle ), toolbar );
166 		gtk_container_add( GTK_CONTAINER( hbox ), handle );
167 		reorder_toolbars( hbox, toolbar_id, handle );
168 		gtk_widget_show_all( handle );
169 
170 	} else {
171 		handle = ( GtkWidget * ) g_object_get_data( G_OBJECT( toolbar ), "nact-main-toolbar-handle" );
172 		detach_id = ( gulong ) g_object_get_data( G_OBJECT( handle ), "nact-handle-detach-id" );
173 		g_signal_handler_disconnect( handle, detach_id );
174 		attach_id = ( gulong ) g_object_get_data( G_OBJECT( handle ), "nact-handle-attach-id" );
175 		g_signal_handler_disconnect( handle, attach_id );
176 		gtk_container_remove( GTK_CONTAINER( handle ), toolbar );
177 		gtk_container_remove( GTK_CONTAINER( hbox ), handle );
178 	}
179 #endif
180 
181 	na_settings_set_boolean( props->prefs_key, is_active );
182 }
183 
184 /*
185  * @hbox: the GtkHBox container
186  * @toolbar_id: toolbar identifier
187  * @handle: hbox child, which used to be a GtkHandleBox (for moveable
188  *  toolbars), and becomes the GtkToolbar itself starting with Gtk 3.4
189  *
190  * reposition the newly activated toolbar in handle
191  * so that the relative positions of toolbars are respected in hbox
192  */
193 static void
reorder_toolbars(GtkWidget * hbox,int toolbar_id,GtkWidget * handle)194 reorder_toolbars( GtkWidget *hbox, int toolbar_id, GtkWidget *handle )
195 {
196 	int this_canonic_rel_pos;
197 	int i;
198 	GList *children, *ic;
199 	int pos;
200 	int canonic_pos;
201 
202 	this_canonic_rel_pos = 0;
203 	for( i = 0 ; i < G_N_ELEMENTS( toolbar_pos ); ++ i ){
204 		if( toolbar_pos[i] == toolbar_id ){
205 			this_canonic_rel_pos = i;
206 			break;
207 		}
208 	}
209 	g_object_set_data( G_OBJECT( handle ), "toolbar-canonic-pos", GINT_TO_POINTER( this_canonic_rel_pos ));
210 
211 	pos = 0;
212 	children = gtk_container_get_children( GTK_CONTAINER( hbox ));
213 	for( ic = children ; ic ; ic = ic->next ){
214 		canonic_pos = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( ic->data ), "toolbar-canonic-pos" ));
215 		if( canonic_pos >= this_canonic_rel_pos ){
216 			break;
217 		}
218 		pos += 1;
219 	}
220 
221 	gtk_box_reorder_child( GTK_BOX( hbox ), handle, pos );
222 }
223 
224 #if !GTK_CHECK_VERSION( 3,4,0 )
225 static void
on_handle_finalize(gpointer data,GObject * handle)226 on_handle_finalize( gpointer data, GObject *handle )
227 {
228 	g_debug( "nact_main_toolbar_on_handle_finalize: handle=%p", ( void * ) handle );
229 }
230 
231 static void
on_attach_toolbar(GtkHandleBox * handle,GtkToolbar * toolbar,NactMainWindow * window)232 on_attach_toolbar( GtkHandleBox *handle, GtkToolbar *toolbar, NactMainWindow *window )
233 {
234 	static const gchar *thisfn = "nact_main_toolbar_on_attach_toolbar";
235 
236 	g_debug( "%s: handle=%p, toolbar=%p, window=%p", thisfn, ( void * ) handle, ( void * ) toolbar, ( void * ) window );
237 
238 	gtk_toolbar_set_show_arrow( toolbar, TRUE );
239 }
240 
241 static void
on_detach_toolbar(GtkHandleBox * handle,GtkToolbar * toolbar,NactMainWindow * window)242 on_detach_toolbar( GtkHandleBox *handle, GtkToolbar *toolbar, NactMainWindow *window )
243 {
244 	static const gchar *thisfn = "nact_main_toolbar_on_detach_toolbar";
245 
246 	g_debug( "%s: handle=%p, toolbar=%p, window=%p", thisfn, ( void * ) handle, ( void * ) toolbar, ( void * ) window );
247 
248 	gtk_toolbar_set_show_arrow( toolbar, FALSE );
249 }
250 #endif
251 
252 static ToolbarProps *
get_toolbar_properties(int toolbar_id)253 get_toolbar_properties( int toolbar_id )
254 {
255 	static const gchar *thisfn = "nact_main_toolbar_get_toolbar_properties";
256 	ToolbarProps *props;
257 	int i;
258 
259 	props = NULL;
260 
261 	for( i = 0 ; i < G_N_ELEMENTS( toolbar_props ) && props == NULL ; ++i ){
262 		if( toolbar_props[i].id == toolbar_id ){
263 			props = &toolbar_props[i];
264 		}
265 	}
266 
267 	if( !props ){
268 		g_warning( "%s: unable to find toolbar properties for id=%d", thisfn, toolbar_id );
269 	}
270 
271 	return( props );
272 }
273