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 <string.h>
35 
36 #include <api/na-object-api.h>
37 
38 #include "base-gtk-utils.h"
39 #include "nact-main-tab.h"
40 #include "nact-iexecution-tab.h"
41 
42 /* private interface data
43  */
44 struct _NactIExecutionTabInterfacePrivate {
45 	void *empty;						/* so that gcc -pedantic is happy */
46 };
47 
48 /* data set against the instance
49  */
50 typedef struct {
51 	gboolean on_selection_change;
52 }
53 	IExecutionData;
54 
55 #define IEXECUTION_TAB_PROP_DATA		"nact-iexecution-tab-data"
56 
57 static guint st_initializations = 0;	/* interface initialization count */
58 
59 static GType           register_type( void );
60 static void            interface_base_init( NactIExecutionTabInterface *klass );
61 static void            interface_base_finalize( NactIExecutionTabInterface *klass );
62 
63 static void            on_base_initialize_window( NactIExecutionTab *instance, gpointer user_data );
64 
65 static void            on_main_selection_changed( NactIExecutionTab *instance, GList *selected_items, gpointer user_data );
66 
67 static void            on_normal_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance );
68 static void            on_terminal_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance );
69 static void            on_embedded_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance );
70 static void            on_display_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance );
71 static void            execution_mode_toggle( NactIExecutionTab *instance, GtkToggleButton *togglebutton, GCallback cb, const gchar *mode );
72 static void            on_startup_notify_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance );
73 static void            on_startup_class_changed( GtkEntry *entry, NactIExecutionTab *instance );
74 static void            on_execute_as_changed( GtkEntry *entry, NactIExecutionTab *instance );
75 
76 static IExecutionData *get_iexecution_data( NactIExecutionTab *instance );
77 static void            on_instance_finalized( gpointer user_data, NactIExecutionTab *instance );
78 
79 GType
nact_iexecution_tab_get_type(void)80 nact_iexecution_tab_get_type( void )
81 {
82 	static GType iface_type = 0;
83 
84 	if( !iface_type ){
85 		iface_type = register_type();
86 	}
87 
88 	return( iface_type );
89 }
90 
91 static GType
register_type(void)92 register_type( void )
93 {
94 	static const gchar *thisfn = "nact_iexecution_tab_register_type";
95 	GType type;
96 
97 	static const GTypeInfo info = {
98 		sizeof( NactIExecutionTabInterface ),
99 		( GBaseInitFunc ) interface_base_init,
100 		( GBaseFinalizeFunc ) interface_base_finalize,
101 		NULL,
102 		NULL,
103 		NULL,
104 		0,
105 		0,
106 		NULL
107 	};
108 
109 	g_debug( "%s", thisfn );
110 
111 	type = g_type_register_static( G_TYPE_INTERFACE, "NactIExecutionTab", &info, 0 );
112 
113 	g_type_interface_add_prerequisite( type, BASE_TYPE_WINDOW );
114 
115 	return( type );
116 }
117 
118 static void
interface_base_init(NactIExecutionTabInterface * klass)119 interface_base_init( NactIExecutionTabInterface *klass )
120 {
121 	static const gchar *thisfn = "nact_iexecution_tab_interface_base_init";
122 
123 	if( !st_initializations ){
124 
125 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
126 
127 		klass->private = g_new0( NactIExecutionTabInterfacePrivate, 1 );
128 	}
129 
130 	st_initializations += 1;
131 }
132 
133 static void
interface_base_finalize(NactIExecutionTabInterface * klass)134 interface_base_finalize( NactIExecutionTabInterface *klass )
135 {
136 	static const gchar *thisfn = "nact_iexecution_tab_interface_base_finalize";
137 
138 	st_initializations -= 1;
139 
140 	if( !st_initializations ){
141 
142 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
143 
144 		g_free( klass->private );
145 	}
146 }
147 
148 /**
149  * nact_iexecution_tab_init:
150  * @instance: this #NactIExecutionTab instance.
151  *
152  * Initialize the interface
153  * Connect to #BaseWindow signals
154  */
155 void
nact_iexecution_tab_init(NactIExecutionTab * instance)156 nact_iexecution_tab_init( NactIExecutionTab *instance )
157 {
158 	static const gchar *thisfn = "nact_iexecution_tab_init";
159 	IExecutionData *data;
160 
161 	g_return_if_fail( NACT_IS_IEXECUTION_TAB( instance ));
162 
163 	g_debug( "%s: instance=%p (%s)",
164 			thisfn,
165 			( void * ) instance, G_OBJECT_TYPE_NAME( instance ));
166 
167 	base_window_signal_connect(
168 			BASE_WINDOW( instance ),
169 			G_OBJECT( instance ),
170 			BASE_SIGNAL_INITIALIZE_WINDOW,
171 			G_CALLBACK( on_base_initialize_window ));
172 
173 	nact_main_tab_init( NACT_MAIN_WINDOW( instance ), TAB_EXECUTION );
174 
175 	data = get_iexecution_data( instance );
176 	data->on_selection_change = FALSE;
177 
178 	g_object_weak_ref( G_OBJECT( instance ), ( GWeakNotify ) on_instance_finalized, NULL );
179 }
180 
181 /*
182  * on_base_initialize_window:
183  * @window: this #NactIExecutionTab instance.
184  *
185  * Initializes the tab widget at each time the widget will be displayed.
186  * Connect signals and setup runtime values.
187  */
188 static void
on_base_initialize_window(NactIExecutionTab * instance,void * user_data)189 on_base_initialize_window( NactIExecutionTab *instance, void *user_data )
190 {
191 	static const gchar *thisfn = "nact_iexecution_tab_on_base_initialize_window";
192 
193 	g_return_if_fail( NACT_IS_IEXECUTION_TAB( instance ));
194 
195 	g_debug( "%s: instance=%p (%s), user_data=%p",
196 			thisfn,
197 			( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
198 			( void * ) user_data );
199 
200 	base_window_signal_connect(
201 			BASE_WINDOW( instance ),
202 			G_OBJECT( instance ),
203 			MAIN_SIGNAL_SELECTION_CHANGED,
204 			G_CALLBACK( on_main_selection_changed ));
205 
206 	base_window_signal_connect_by_name(
207 			BASE_WINDOW( instance ),
208 			"ExecutionModeNormal",
209 			"toggled",
210 			G_CALLBACK( on_normal_mode_toggled ));
211 
212 	base_window_signal_connect_by_name(
213 			BASE_WINDOW( instance ),
214 			"ExecutionModeTerminal",
215 			"toggled",
216 			G_CALLBACK( on_terminal_mode_toggled ));
217 
218 	base_window_signal_connect_by_name(
219 			BASE_WINDOW( instance ),
220 			"ExecutionModeEmbedded",
221 			"toggled",
222 			G_CALLBACK( on_embedded_mode_toggled ));
223 
224 	base_window_signal_connect_by_name(
225 			BASE_WINDOW( instance ),
226 			"ExecutionModeDisplayOutput",
227 			"toggled",
228 			G_CALLBACK( on_display_mode_toggled ));
229 
230 	base_window_signal_connect_by_name(
231 			BASE_WINDOW( instance ),
232 			"StartupNotifyButton",
233 			"toggled",
234 			G_CALLBACK( on_startup_notify_toggled ));
235 
236 	base_window_signal_connect_by_name(
237 			BASE_WINDOW( instance ),
238 			"StartupWMClassEntry",
239 			"changed",
240 			G_CALLBACK( on_startup_class_changed ));
241 
242 	base_window_signal_connect_by_name(
243 			BASE_WINDOW( instance ),
244 			"ExecuteAsEntry",
245 			"changed",
246 			G_CALLBACK( on_execute_as_changed ));
247 }
248 
249 static void
on_main_selection_changed(NactIExecutionTab * instance,GList * selected_items,gpointer user_data)250 on_main_selection_changed( NactIExecutionTab *instance, GList *selected_items, gpointer user_data )
251 {
252 	static const gchar *thisfn = "nact_iexecution_tab_on_main_selection_changed";
253 	NAObjectProfile *profile;
254 	gboolean editable;
255 	gboolean enable_tab;
256 	gchar *mode;
257 	GtkWidget *normal_toggle, *terminal_toggle, *embedded_toggle, *display_toggle;
258 	gboolean notify;
259 	GtkWidget *notify_check, *frame;
260 	gchar *class, *user;
261 	GtkWidget *entry;
262 	IExecutionData *data;
263 
264 	g_return_if_fail( NACT_IS_IEXECUTION_TAB( instance ));
265 
266 	g_debug( "%s: instance=%p (%s), selected_items=%p (count=%d)",
267 			thisfn,
268 			( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
269 			( void * ) selected_items, g_list_length( selected_items ));
270 
271 	g_object_get(
272 			G_OBJECT( instance ),
273 			MAIN_PROP_PROFILE, &profile,
274 			MAIN_PROP_EDITABLE, &editable,
275 			NULL );
276 
277 	enable_tab = ( profile != NULL );
278 	nact_main_tab_enable_page( NACT_MAIN_WINDOW( instance ), TAB_EXECUTION, enable_tab );
279 
280 	data = get_iexecution_data( instance );
281 	data->on_selection_change = TRUE;
282 
283 	normal_toggle = base_window_get_widget( BASE_WINDOW( instance ), "ExecutionModeNormal" );
284 	terminal_toggle = base_window_get_widget( BASE_WINDOW( instance ), "ExecutionModeTerminal" );
285 	embedded_toggle = base_window_get_widget( BASE_WINDOW( instance ), "ExecutionModeEmbedded" );
286 	display_toggle = base_window_get_widget( BASE_WINDOW( instance ), "ExecutionModeDisplayOutput" );
287 
288 	mode = profile ? na_object_get_execution_mode( profile ) : g_strdup( "Normal" );
289 	gtk_toggle_button_set_inconsistent( GTK_TOGGLE_BUTTON( normal_toggle ), profile == NULL );
290 
291 	if( !strcmp( mode, "Normal" )){
292 		base_gtk_utils_radio_set_initial_state(
293 				GTK_RADIO_BUTTON( normal_toggle ),
294 				G_CALLBACK( on_normal_mode_toggled ), instance, editable, ( profile != NULL ));
295 
296 	} else if( !strcmp( mode, "Terminal" )){
297 		base_gtk_utils_radio_set_initial_state(
298 				GTK_RADIO_BUTTON( terminal_toggle ),
299 				G_CALLBACK( on_terminal_mode_toggled ), instance, editable, ( profile != NULL ));
300 
301 	} else if( !strcmp( mode, "Embedded" )){
302 		base_gtk_utils_radio_set_initial_state(
303 				GTK_RADIO_BUTTON( embedded_toggle ),
304 				G_CALLBACK( on_embedded_mode_toggled ), instance, editable, ( profile != NULL ));
305 
306 	} else if( !strcmp( mode, "DisplayOutput" )){
307 		base_gtk_utils_radio_set_initial_state(
308 				GTK_RADIO_BUTTON( display_toggle ),
309 				G_CALLBACK( on_display_mode_toggled ), instance, editable, ( profile != NULL ));
310 
311 	} else {
312 		g_warning( "%s: unable to setup execution mode '%s'", thisfn, mode );
313 	}
314 
315 	g_free( mode );
316 
317 	frame = base_window_get_widget( BASE_WINDOW( instance ), "StartupModeFrame" );
318 	gtk_widget_set_sensitive( frame, FALSE );
319 
320 	notify = profile ? na_object_get_startup_notify( profile ) : FALSE;
321 	notify_check = base_window_get_widget( BASE_WINDOW( instance ), "StartupNotifyButton" );
322 	base_gtk_utils_set_editable( G_OBJECT( notify_check ), editable );
323 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( notify_check ), notify );
324 
325 	class = profile ? na_object_get_startup_class( profile ) : g_strdup( "" );
326 	entry = base_window_get_widget( BASE_WINDOW( instance ), "StartupWMClassEntry" );
327 	gtk_entry_set_text( GTK_ENTRY( entry ), class );
328 	base_gtk_utils_set_editable( G_OBJECT( entry ), editable );
329 	g_free( class );
330 
331 	frame = base_window_get_widget( BASE_WINDOW( instance ), "UserFrame" );
332 	gtk_widget_set_sensitive( frame, FALSE );
333 
334 	user = profile ? na_object_get_execute_as( profile ) : g_strdup( "" );
335 	entry = base_window_get_widget( BASE_WINDOW( instance ), "ExecuteAsEntry" );
336 	gtk_entry_set_text( GTK_ENTRY( entry ), user );
337 	base_gtk_utils_set_editable( G_OBJECT( entry ), editable );
338 	g_free( user );
339 
340 	data->on_selection_change = FALSE;
341 }
342 
343 static void
on_normal_mode_toggled(GtkToggleButton * togglebutton,NactIExecutionTab * instance)344 on_normal_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance )
345 {
346 	execution_mode_toggle( instance, togglebutton, G_CALLBACK( on_normal_mode_toggled ), "Normal" );
347 }
348 
349 static void
on_terminal_mode_toggled(GtkToggleButton * togglebutton,NactIExecutionTab * instance)350 on_terminal_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance )
351 {
352 	execution_mode_toggle( instance, togglebutton, G_CALLBACK( on_terminal_mode_toggled ), "Terminal" );
353 }
354 
355 static void
on_embedded_mode_toggled(GtkToggleButton * togglebutton,NactIExecutionTab * instance)356 on_embedded_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance )
357 {
358 	execution_mode_toggle( instance, togglebutton, G_CALLBACK( on_embedded_mode_toggled ), "Embedded" );
359 }
360 
361 static void
on_display_mode_toggled(GtkToggleButton * togglebutton,NactIExecutionTab * instance)362 on_display_mode_toggled( GtkToggleButton *togglebutton, NactIExecutionTab *instance )
363 {
364 	execution_mode_toggle( instance, togglebutton, G_CALLBACK( on_display_mode_toggled ), "DisplayOutput" );
365 }
366 
367 static void
execution_mode_toggle(NactIExecutionTab * instance,GtkToggleButton * toggle_button,GCallback cb,const gchar * mode)368 execution_mode_toggle( NactIExecutionTab *instance, GtkToggleButton *toggle_button, GCallback cb, const gchar *mode )
369 {
370 	NAObjectProfile *profile;
371 	gboolean editable;
372 	gboolean active;
373 	gboolean is_normal;
374 	GtkWidget *widget;
375 
376 	g_object_get(
377 			G_OBJECT( instance ),
378 			MAIN_PROP_PROFILE, &profile,
379 			MAIN_PROP_EDITABLE, &editable,
380 			NULL );
381 
382 	if( profile ){
383 		active = gtk_toggle_button_get_active( toggle_button );
384 
385 		if( editable ){
386 			if( active ){
387 				na_object_set_execution_mode( profile, mode );
388 
389 				is_normal = ( strcmp( mode, "Normal" ) == 0 );
390 				widget = base_window_get_widget( BASE_WINDOW( instance ), "StartupNotifyButton" );
391 				gtk_widget_set_sensitive( widget, is_normal );
392 				widget = base_window_get_widget( BASE_WINDOW( instance ), "StartupWMClassEntry" );
393 				gtk_widget_set_sensitive( widget, is_normal );
394 
395 				g_signal_emit_by_name( G_OBJECT( instance ), TAB_UPDATABLE_SIGNAL_ITEM_UPDATED, profile, 0 );
396 			}
397 
398 		} else {
399 			base_gtk_utils_radio_reset_initial_state( GTK_RADIO_BUTTON( toggle_button ), cb );
400 		}
401 	}
402 }
403 
404 static void
on_startup_notify_toggled(GtkToggleButton * toggle_button,NactIExecutionTab * instance)405 on_startup_notify_toggled( GtkToggleButton *toggle_button, NactIExecutionTab *instance )
406 {
407 	NAObjectProfile *profile;
408 	gboolean editable;
409 	gboolean active;
410 
411 	g_object_get(
412 			G_OBJECT( instance ),
413 			MAIN_PROP_PROFILE, &profile,
414 			MAIN_PROP_EDITABLE, &editable,
415 			NULL );
416 
417 	if( profile ){
418 		active = gtk_toggle_button_get_active( toggle_button );
419 
420 		if( editable ){
421 			na_object_set_startup_notify( profile, active );
422 			g_signal_emit_by_name( G_OBJECT( instance ), TAB_UPDATABLE_SIGNAL_ITEM_UPDATED, profile, 0 );
423 
424 		} else {
425 			g_signal_handlers_block_by_func(( gpointer ) toggle_button, on_startup_notify_toggled, instance );
426 			gtk_toggle_button_set_active( toggle_button, !active );
427 			g_signal_handlers_unblock_by_func(( gpointer ) toggle_button, on_startup_notify_toggled, instance );
428 		}
429 	}
430 }
431 
432 static void
on_startup_class_changed(GtkEntry * entry,NactIExecutionTab * instance)433 on_startup_class_changed( GtkEntry *entry, NactIExecutionTab *instance )
434 {
435 	NAObjectProfile *profile;
436 	const gchar *text;
437 
438 	g_object_get(
439 			G_OBJECT( instance ),
440 			MAIN_PROP_PROFILE, &profile,
441 			NULL );
442 
443 	if( profile ){
444 		text = gtk_entry_get_text( entry );
445 		na_object_set_startup_class( profile, text );
446 		g_signal_emit_by_name( G_OBJECT( instance ), TAB_UPDATABLE_SIGNAL_ITEM_UPDATED, profile, 0 );
447 	}
448 }
449 
450 static void
on_execute_as_changed(GtkEntry * entry,NactIExecutionTab * instance)451 on_execute_as_changed( GtkEntry *entry, NactIExecutionTab *instance )
452 {
453 	NAObjectProfile *profile;
454 	const gchar *text;
455 
456 	g_object_get(
457 			G_OBJECT( instance ),
458 			MAIN_PROP_PROFILE, &profile,
459 			NULL );
460 
461 	if( profile ){
462 		text = gtk_entry_get_text( entry );
463 		na_object_set_execute_as( profile, text );
464 		g_signal_emit_by_name( G_OBJECT( instance ), TAB_UPDATABLE_SIGNAL_ITEM_UPDATED, profile, 0 );
465 	}
466 }
467 
468 static IExecutionData *
get_iexecution_data(NactIExecutionTab * instance)469 get_iexecution_data( NactIExecutionTab *instance )
470 {
471 	IExecutionData *data;
472 
473 	data = ( IExecutionData * ) g_object_get_data( G_OBJECT( instance ), IEXECUTION_TAB_PROP_DATA );
474 
475 	if( !data ){
476 		data = g_new0( IExecutionData, 1 );
477 		g_object_set_data( G_OBJECT( instance ), IEXECUTION_TAB_PROP_DATA, data );
478 	}
479 
480 	return( data );
481 }
482 
483 static void
on_instance_finalized(gpointer user_data,NactIExecutionTab * instance)484 on_instance_finalized( gpointer user_data, NactIExecutionTab *instance )
485 {
486 	static const gchar *thisfn = "nact_iexecution_tab_on_instance_finalized";
487 	IExecutionData *data;
488 
489 	g_debug( "%s: instance=%p, user_data=%p", thisfn, ( void * ) instance, ( void * ) user_data );
490 
491 	data = get_iexecution_data( instance );
492 
493 	g_free( data );
494 }
495