Fix string errors reported by Christian Kirbach
[nautilus-actions.git] / src / nact / nact-gtk-utils.c
blob0c108635eabaa31bcb186fa45dea747b4b05d622
1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program 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.
14 * This Program 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
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <glib.h>
36 #include <string.h>
38 #include <core/na-iprefs.h>
39 #include <core/na-updater.h>
41 #include "base-iprefs.h"
42 #include "nact-gtk-utils.h"
43 #include "nact-application.h"
45 #define NACT_PROP_TOGGLE_BUTTON "nact-prop-toggle-button"
46 #define NACT_PROP_TOGGLE_HANDLER "nact-prop-toggle-handler"
47 #define NACT_PROP_TOGGLE_USER_DATA "nact-prop-toggle-user-data"
49 #define DEFAULT_WIDTH 22
50 #define DEFAULT_HEIGHT 22
52 static GtkWidget *search_for_child_widget( GtkContainer *container, const gchar *name );
54 /**
55 * nact_gtk_utils_set_editable:
56 * @widget: the #GtkWdiget.
57 * @editable: whether the @widget is editable or not.
59 * Try to set a visual indication of whether the @widget is editable or not.
61 * Having a GtkWidget should be enough, but we also deal with a GtkTreeViewColumn.
62 * So the most-bottom common ancestor is just GObject (since GtkObject having been
63 * deprecated in Gtk+-3.0)
65 void
66 nact_gtk_utils_set_editable( GObject *widget, gboolean editable )
68 GList *renderers, *irender;
70 /* GtkComboBoxEntry is deprecated from Gtk+3
71 * see. http://git.gnome.org/browse/gtk+/commit/?id=9612c648176378bf237ad0e1a8c6c995b0ca7c61
72 * while 'has_entry' property exists since 2.24
74 #if GTK_CHECK_VERSION( 2, 24, 0 )
75 if( GTK_IS_COMBO_BOX( widget ) && gtk_combo_box_get_has_entry( GTK_COMBO_BOX( widget ))){
76 #else
77 if( GTK_IS_COMBO_BOX_ENTRY( widget )){
78 #endif
79 /* idem as GtkEntry */
80 gtk_editable_set_editable( GTK_EDITABLE( gtk_bin_get_child( GTK_BIN( widget ))), editable );
81 g_object_set( G_OBJECT( gtk_bin_get_child( GTK_BIN( widget ))), "can-focus", editable, NULL );
82 /* disable the listbox button itself */
83 gtk_combo_box_set_button_sensitivity( GTK_COMBO_BOX( widget ), editable ? GTK_SENSITIVITY_ON : GTK_SENSITIVITY_OFF );
85 } else if( GTK_IS_COMBO_BOX( widget )){
86 /* disable the listbox button itself */
87 gtk_combo_box_set_button_sensitivity( GTK_COMBO_BOX( widget ), editable ? GTK_SENSITIVITY_ON : GTK_SENSITIVITY_OFF );
89 } else if( GTK_IS_ENTRY( widget )){
90 gtk_editable_set_editable( GTK_EDITABLE( widget ), editable );
91 /* removing the frame leads to a disturbing modification of the
92 * height of the control */
93 /*g_object_set( G_OBJECT( widget ), "has-frame", editable, NULL );*/
94 /* this prevents the caret to be displayed when we click in the entry */
95 g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
97 } else if( GTK_IS_TEXT_VIEW( widget )){
98 g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
99 gtk_text_view_set_editable( GTK_TEXT_VIEW( widget ), editable );
101 } else if( GTK_IS_TOGGLE_BUTTON( widget )){
102 /* transforms to a quasi standard GtkButton */
103 /*g_object_set( G_OBJECT( widget ), "draw-indicator", editable, NULL );*/
104 /* this at least prevent the keyboard focus to go to the button
105 * (which is better than nothing) */
106 g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
108 } else if( GTK_IS_TREE_VIEW_COLUMN( widget )){
109 renderers = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( GTK_TREE_VIEW_COLUMN( widget )));
110 for( irender = renderers ; irender ; irender = irender->next ){
111 if( GTK_IS_CELL_RENDERER_TEXT( irender->data )){
112 g_object_set( G_OBJECT( irender->data ), "editable", editable, "editable-set", TRUE, NULL );
115 g_list_free( renderers );
117 } else if( GTK_IS_BUTTON( widget )){
118 gtk_widget_set_sensitive( GTK_WIDGET( widget ), editable );
123 * nact_gtk_utils_radio_set_initial_state:
124 * @button: the #GtkRadioButton button which is initially active.
125 * @handler: the corresponding "toggled" handler.
126 * @user_data: the user data associated to the handler.
127 * @editable: whether this radio button group is editable.
128 * @sensitive: whether this radio button group is sensitive.
130 * This function should be called for the button which is initially active
131 * inside of a radio button group when the radio group may happen to not be
132 * editable.
133 * This function should be called only once for the radio button group.
135 * It does the following operations:
136 * - set the button as active
137 * - set other buttons of the radio button group as inactive
138 * - set all buttons of radio button group as @editable
140 * The initially active @button, along with its @handler, are recorded
141 * as properties of the radio button group (actually as properties of each
142 * radio button of the group), so that they can later be used to reset the
143 * initial state.
145 void
146 nact_gtk_utils_radio_set_initial_state( GtkRadioButton *button,
147 GCallback handler, void *user_data, gboolean editable, gboolean sensitive )
149 GSList *group, *ig;
150 GtkRadioButton *other;
152 group = gtk_radio_button_get_group( button );
154 for( ig = group ; ig ; ig = ig->next ){
155 other = GTK_RADIO_BUTTON( ig->data );
156 g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_BUTTON, button );
157 g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_HANDLER, handler );
158 g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_USER_DATA, user_data );
159 g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_EDITABLE, GUINT_TO_POINTER( editable ));
160 nact_gtk_utils_set_editable( G_OBJECT( other ), editable );
161 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( other ), FALSE );
162 gtk_widget_set_sensitive( GTK_WIDGET( other ), sensitive );
165 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), TRUE );
169 * nact_gtk_utils_radio_reset_initial_state:
170 * @button: the #GtkRadioButton being toggled.
171 * @handler: the corresponding "toggled" handler.
172 * @data: data associated with the @handler callback.
174 * When clicking on a read-only radio button, this function ensures that
175 * the radio button is not modified. It may be called whether the radio
176 * button group is editable or not (does nothing if group is actually
177 * editable).
179 void
180 nact_gtk_utils_radio_reset_initial_state( GtkRadioButton *button, GCallback handler )
182 GtkToggleButton *initial_button;
183 GCallback initial_handler;
184 gboolean active;
185 gboolean editable;
186 gpointer user_data;
188 active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
189 editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
191 if( active && !editable ){
192 initial_button = GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_BUTTON ));
193 initial_handler = G_CALLBACK( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_HANDLER ));
194 user_data = g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_USER_DATA );
196 if( handler ){
197 g_signal_handlers_block_by_func(( gpointer ) button, handler, user_data );
199 g_signal_handlers_block_by_func(( gpointer ) initial_button, initial_handler, user_data );
201 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), FALSE );
202 gtk_toggle_button_set_active( initial_button, TRUE );
204 g_signal_handlers_unblock_by_func(( gpointer ) initial_button, initial_handler, user_data );
205 if( handler ){
206 g_signal_handlers_unblock_by_func(( gpointer ) button, handler, user_data );
212 * nact_gtk_utils_toggle_set_initial_state:
213 * @button: the #GtkToggleButton button.
214 * @handler: the corresponding "toggled" handler.
215 * @window: the toplevel #BaseWindow which embeds the button;
216 * it will be passed as user_data when connecting the signal.
217 * @active: whether the check button is initially active (checked).
218 * @editable: whether this radio button group is editable.
219 * @sensitive: whether this radio button group is sensitive.
221 * This function should be called for a check button which may happen to be
222 * read-only..
224 * It does the following operations:
225 * - connect the 'toggled' handler to the button
226 * - set the button as active or inactive depending of @active
227 * - set the button as editable or not depending of @editable
228 * - set the button as sensitive or not depending of @sensitive
229 * - explictely triggers the 'toggled' handler
231 void
232 nact_gtk_utils_toggle_set_initial_state( BaseWindow *window,
233 const gchar *button_name, GCallback handler,
234 gboolean active, gboolean editable, gboolean sensitive )
236 typedef void ( *toggle_handler )( GtkToggleButton *, BaseWindow * );
237 GtkToggleButton *button;
239 button = GTK_TOGGLE_BUTTON( base_window_get_widget( window, button_name ));
241 if( button ){
242 base_window_signal_connect( window, G_OBJECT( button ), "toggled", handler );
244 g_object_set_data( G_OBJECT( button ), NACT_PROP_TOGGLE_HANDLER, handler );
245 g_object_set_data( G_OBJECT( button ), NACT_PROP_TOGGLE_USER_DATA, window );
246 g_object_set_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE, GUINT_TO_POINTER( editable ));
248 nact_gtk_utils_set_editable( G_OBJECT( button ), editable );
249 gtk_widget_set_sensitive( GTK_WIDGET( button ), sensitive );
250 gtk_toggle_button_set_active( button, active );
252 ( *( toggle_handler ) handler )( button, window );
257 * nact_gtk_utils_toggle_reset_initial_state:
258 * @button: the #GtkToggleButton check button.
260 * When clicking on a read-only check button, this function ensures that
261 * the check button is not modified. It may be called whether the button
262 * is editable or not (does nothing if button is actually editable).
264 void
265 nact_gtk_utils_toggle_reset_initial_state( GtkToggleButton *button )
267 gboolean editable;
268 GCallback handler;
269 gpointer user_data;
270 gboolean active;
272 editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
274 if( !editable ){
275 active = gtk_toggle_button_get_active( button );
276 handler = G_CALLBACK( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_HANDLER ));
277 user_data = g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_USER_DATA );
279 g_signal_handlers_block_by_func(( gpointer ) button, handler, user_data );
280 gtk_toggle_button_set_active( button, !active );
281 g_signal_handlers_unblock_by_func(( gpointer ) button, handler, user_data );
286 * nact_utils_get_pixbuf:
287 * @name: the name of the file or an icon.
288 * widget: the widget on which the imagecshould be rendered.
289 * size: the desired size.
291 * Returns a pixbuf for the given widget.
293 GdkPixbuf *
294 nact_gtk_utils_get_pixbuf( const gchar *name, GtkWidget *widget, GtkIconSize size )
296 static const gchar *thisfn = "nact_gtk_utils_get_pixbuf";
297 GdkPixbuf* pixbuf;
298 GError *error;
299 gint width, height;
300 GtkIconTheme *icon_theme;
302 error = NULL;
303 pixbuf = NULL;
305 if( !gtk_icon_size_lookup( size, &width, &height )){
306 width = DEFAULT_WIDTH;
307 height = DEFAULT_HEIGHT;
310 if( name && strlen( name )){
311 if( g_path_is_absolute( name )){
312 pixbuf = gdk_pixbuf_new_from_file_at_size( name, width, height, &error );
313 if( error ){
314 if( error->code != G_FILE_ERROR_NOENT ){
315 g_warning( "%s: gdk_pixbuf_new_from_file_at_size: name=%s, error=%s (%d)", thisfn, name, error->message, error->code );
317 g_error_free( error );
318 error = NULL;
319 pixbuf = NULL;
322 } else {
323 /* gtk_widget_render_icon() is deprecated since Gtk+ 3.0
324 * see http://library.gnome.org/devel/gtk/unstable/GtkWidget.html#gtk-widget-render-icon
325 * and http://git.gnome.org/browse/gtk+/commit/?id=07eeae15825403037b7df139acf9bfa104d5559d
327 #if GTK_CHECK_VERSION( 2, 91, 7 )
328 pixbuf = gtk_widget_render_icon_pixbuf( widget, name, size );
329 #else
330 pixbuf = gtk_widget_render_icon( widget, name, size, NULL );
331 #endif
332 if( !pixbuf ){
333 icon_theme = gtk_icon_theme_get_default();
334 pixbuf = gtk_icon_theme_load_icon(
335 icon_theme, name, width, GTK_ICON_LOOKUP_GENERIC_FALLBACK, &error );
336 if( error ){
337 /* it happens that the message "Icon 'xxxx' not present in theme"
338 * is generated with a domain of 'gtk-icon-theme-error-quark' and
339 * an error code of zero - it seems difficult to just test zero
340 * so does not display warning, but just debug
342 g_debug( "%s: %s (%s:%d)",
343 thisfn, error->message, g_quark_to_string( error->domain ), error->code );
344 g_error_free( error );
350 if( !pixbuf ){
351 g_debug( "%s: null pixbuf, loading transparent image", thisfn );
352 pixbuf = gdk_pixbuf_new_from_file_at_size( PKGDATADIR "/transparent.png", width, height, NULL );
355 return( pixbuf );
359 * nact_utils_render:
360 * @name: the name of the file or an icon, or %NULL.
361 * widget: the widget on which the image should be rendered.
362 * size: the desired size.
364 * Displays the (maybe themed) image on the given widget.
366 void
367 nact_gtk_utils_render( const gchar *name, GtkImage *widget, GtkIconSize size )
369 static const gchar *thisfn = "nact_gtk_utils_render";
370 GdkPixbuf* pixbuf;
371 gint width, height;
373 g_debug( "%s: name=%s, widget=%p, size=%d", thisfn, name, ( void * ) widget, size );
375 if( name ){
376 pixbuf = nact_gtk_utils_get_pixbuf( name, GTK_WIDGET( widget ), size );
378 } else {
379 if( !gtk_icon_size_lookup( size, &width, &height )){
380 width = DEFAULT_WIDTH;
381 height = DEFAULT_HEIGHT;
383 pixbuf = gdk_pixbuf_new_from_file_at_size( PKGDATADIR "/transparent.png", width, height, NULL );
386 if( pixbuf ){
387 gtk_image_set_from_pixbuf( widget, pixbuf );
388 g_object_unref( pixbuf );
393 * nact_gtk_utils_select_file:
394 * @window: the #BaseWindow which will be the parent of the dialog box.
395 * @title: the title of the dialog box.
396 * @dialog_name: the name of the dialog box in Preferences to read/write
397 * its size and position.
398 * @entry: the #GtkEntry which is associated with the selected file.
399 * @entry_name: the name of the entry in Preferences to be read/written.
401 * Opens a #GtkFileChooserDialog and let the user choose an existing file
402 * -> choose and display an existing file name
403 * -> record the dirname URI.
405 * If the user validates its selection, the choosen file pathname will be
406 * written in the @entry #GtkEntry, while the corresponding dirname
407 * URI will be written as @entry_name in Preferences.
409 void
410 nact_gtk_utils_select_file( BaseWindow *window,
411 const gchar *title, const gchar *dialog_name,
412 GtkWidget *entry, const gchar *entry_name )
414 nact_gtk_utils_select_file_with_preview(
415 window, title, dialog_name, entry, entry_name, NULL );
419 * nact_gtk_utils_select_file_with_preview:
420 * @window: the #BaseWindow which will be the parent of the dialog box.
421 * @title: the title of the dialog box.
422 * @dialog_name: the name of the dialog box in Preferences to read/write
423 * its size and position.
424 * @entry: the #GtkEntry which is associated with the selected file.
425 * @entry_name: the name of the entry in Preferences to be read/written.
426 * @update_preview_cb: the callback function in charge of updating the
427 * preview widget. May be NULL.
429 * Opens a #GtkFileChooserDialog and let the user choose an existing file
430 * -> choose and display an existing file name
431 * -> record the dirname URI.
433 * If the user validates its selection, the choosen file pathname will be
434 * written in the @entry #GtkEntry, while the corresponding dirname
435 * URI will be written as @entry_name in Preferences.
437 void
438 nact_gtk_utils_select_file_with_preview( BaseWindow *window,
439 const gchar *title, const gchar *dialog_name,
440 GtkWidget *entry, const gchar *entry_name,
441 GCallback update_preview_cb )
443 NactApplication *application;
444 NAUpdater *updater;
445 GtkWindow *toplevel;
446 GtkWidget *dialog;
447 const gchar *text;
448 gchar *filename, *uri;
449 GtkWidget *preview;
450 NASettings *settings;
452 application = NACT_APPLICATION( base_window_get_application( window ));
453 updater = nact_application_get_updater( application );
454 settings = na_pivot_get_settings( NA_PIVOT( updater ));
455 toplevel = base_window_get_gtk_toplevel( window );
457 dialog = gtk_file_chooser_dialog_new(
458 title,
459 toplevel,
460 GTK_FILE_CHOOSER_ACTION_OPEN,
461 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
462 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
463 NULL
466 if( update_preview_cb ){
467 preview = gtk_image_new();
468 gtk_file_chooser_set_preview_widget( GTK_FILE_CHOOSER( dialog ), preview );
469 g_signal_connect( dialog, "update-preview", update_preview_cb, preview );
472 base_iprefs_position_named_window( window, GTK_WINDOW( dialog ), dialog_name );
474 text = gtk_entry_get_text( GTK_ENTRY( entry ));
476 if( text && strlen( text )){
477 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( dialog ), text );
479 } else {
480 uri = na_settings_get_string( settings, entry_name, NULL, NULL );
481 if( uri ){
482 gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( dialog ), uri );
483 g_free( uri );
487 if( gtk_dialog_run( GTK_DIALOG( dialog )) == GTK_RESPONSE_ACCEPT ){
488 filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( dialog ));
489 gtk_entry_set_text( GTK_ENTRY( entry ), filename );
490 g_free( filename );
493 uri = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( dialog ));
494 na_settings_set_string( settings, entry_name, uri );
495 g_free( uri );
497 base_iprefs_save_named_window_position( window, GTK_WINDOW( dialog ), dialog_name );
499 gtk_widget_destroy( dialog );
503 * nact_gtk_utils_select_dir:
504 * @window: the #BaseWindow which will be the parent of the dialog box.
505 * @title: the title of the dialog box.
506 * @dialog_name: the name of the dialog box in Preferences to read/write
507 * its size and position.
508 * @entry: the #GtkEntry which is associated with the field.
509 * @entry_name: the name of the entry in Preferences to be read/written.
510 * @default_dir_uri: the URI of the directory which should be set in there is
511 * not yet any preference (see @entry_name)
513 * Opens a #GtkFileChooserDialog and let the user choose an existing directory
514 * -> choose and display an existing dir name
515 * -> record the dirname URI of this dir name.
517 * If the user validates its selection, the choosen file pathname will be
518 * written in the @entry #GtkEntry, while the corresponding dirname
519 * URI will be written as @entry_name in Preferences.
521 void
522 nact_gtk_utils_select_dir( BaseWindow *window,
523 const gchar *title, const gchar *dialog_name,
524 GtkWidget *entry, const gchar *entry_name )
526 NactApplication *application;
527 NAUpdater *updater;
528 GtkWindow *toplevel;
529 GtkWidget *dialog;
530 const gchar *text;
531 gchar *dir, *uri;
532 NASettings *settings;
534 application = NACT_APPLICATION( base_window_get_application( window ));
535 updater = nact_application_get_updater( application );
536 settings = na_pivot_get_settings( NA_PIVOT( updater ));
537 toplevel = base_window_get_gtk_toplevel( window );
539 dialog = gtk_file_chooser_dialog_new(
540 title,
541 toplevel,
542 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
543 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
544 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
545 NULL
548 base_iprefs_position_named_window( window, GTK_WINDOW( dialog ), dialog_name );
550 text = gtk_entry_get_text( GTK_ENTRY( entry ));
552 if( text && strlen( text )){
553 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( dialog ), text );
555 } else {
556 uri = na_settings_get_string( settings, entry_name, NULL, NULL );
557 if( uri ){
558 gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( dialog ), uri );
559 g_free( uri );
563 if( gtk_dialog_run( GTK_DIALOG( dialog )) == GTK_RESPONSE_ACCEPT ){
564 dir = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( dialog ));
565 gtk_entry_set_text( GTK_ENTRY( entry ), dir );
566 g_free( dir );
569 uri = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( dialog ));
570 na_settings_set_string( settings, entry_name, uri );
571 g_free( uri );
573 base_iprefs_save_named_window_position( window, GTK_WINDOW( dialog ), dialog_name );
575 gtk_widget_destroy( dialog );
579 * nact_gtk_utils_get_widget_by_name:
580 * @toplevel: the #GtkWindow toplevel.
581 * @name: the name of the searched child.
583 * Returns: a pointer to the named widget which is a child of @toplevel,
584 * or %NULL. the returned pointer is owned by #GtkBuilder instance, and
585 * should not be released by the caller.
587 GtkWidget *
588 nact_gtk_utils_get_widget_by_name( GtkWindow *toplevel, const gchar *name )
590 static const gchar *thisfn = "nact_gtk_utils_get_widget_by_name";
591 GtkWidget *widget = NULL;
593 g_return_val_if_fail( GTK_IS_WINDOW( toplevel ), NULL );
595 widget = search_for_child_widget( GTK_CONTAINER( toplevel ), name );
597 if( !widget ){
598 g_warning( "%s: widget not found: %s", thisfn, name );
600 } else {
601 g_return_val_if_fail( GTK_IS_WIDGET( widget ), NULL );
604 return( widget );
607 static GtkWidget *
608 search_for_child_widget( GtkContainer *container, const gchar *name )
610 GList *children = gtk_container_get_children( container );
611 GList *ic;
612 GtkWidget *found = NULL;
613 GtkWidget *child;
614 const gchar *child_name;
616 for( ic = children ; ic ; ic = ic->next ){
617 if( GTK_IS_WIDGET( ic->data )){
618 child = GTK_WIDGET( ic->data );
619 child_name = gtk_buildable_get_name( GTK_BUILDABLE( child ));
620 if( child_name && strlen( child_name )){
621 /*g_debug( "%s: child=%s", thisfn, child_name );*/
622 if( !g_ascii_strcasecmp( name, child_name )){
623 found = child;
624 break;
626 } else if( GTK_IS_CONTAINER( child )){
627 found = search_for_child_widget( GTK_CONTAINER( child ), name );
628 if( found ){
629 break;
636 g_list_free( children );
637 return( found );