diff options
author | Perberos <[email protected]> | 2011-12-01 22:24:23 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-12-01 22:24:23 -0300 |
commit | 0e004c696b0e68b2cff37a4c3315b022a35eaf43 (patch) | |
tree | 43261e815529cb9518ed7be37af13b846af8b26b /eel | |
download | caja-0e004c696b0e68b2cff37a4c3315b022a35eaf43.tar.bz2 caja-0e004c696b0e68b2cff37a4c3315b022a35eaf43.tar.xz |
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'eel')
79 files changed, 45487 insertions, 0 deletions
diff --git a/eel/ChangeLog b/eel/ChangeLog new file mode 100644 index 00000000..ef98ce08 --- /dev/null +++ b/eel/ChangeLog @@ -0,0 +1,9642 @@ +=== caja 2.26.2 === +=== caja 2.26.1 === + +2009-03-24 Alexander Larsson <[email protected]> + + * eel-background.c: + Ensure that we correctly free root pixmaps that are never set + as desktop background, so that they are not leaked. + +2009-03-16 Cosimo Cecchi <[email protected]> + + * Makefile.am: remove -version-info LDFLAG from eel, + as this is not a private library anymore. + +=== caja 2.26.0 === +=== caja 2.25.93 === + +2009-03-09 Alexander Larsson <[email protected]> + + * eel-editable-label.c: + (eel_editable_label_move_forward_word): + Don't move past end of string (#569165). + +2009-03-09 Alexander Larsson <[email protected]> + + * eel-editable-label.c: + (eel_editable_label_move_cursor): + Revert wrong cursor move change. + +2009-02-24 Alexander Larsson <[email protected]> + + * eel-background.c (eel_background_get_image_uri): + Don't spew warning if there is no uri. + +2009-02-17 Alexander Larsson <[email protected]> + + * eel-background.c (eel_background_ensure_realized): + Ignore pending background changes when we've realized the + background to avoid an unnecessary re-set of the pixmap. + +=== caja 2.25.91 === +=== caja 2.25.4 === + +2009-01-28 Cosimo Cecchi <[email protected]> + + * eel-editable-label.c: (eel_editable_label_move_cursor): + make sure we take care about UTF-8/byte conversion when we move + around the cursor (#569165). + +2009-01-22 A. Walton <[email protected]> + + * eel-debug-drawing.c (eel_debug_show_pixbuf_in_external_viewer): + Use g_mkstemp() instead of mkstemp(). Pointed out by Paolo Borelli. + +2009-01-21 A. Walton <[email protected]> + + * eel-debug-drawing.c (eel_debug_show_pixbuf_in_external_viewer): + Really fix bug #568630, replace mktemp() with mkstemp(). + +2009-01-21 A. Walton <[email protected]> + + * eel-debug-drawing.c (eel_debug_show_pixbuf_in_external_viewer): + Last commit is wrong; mkstemp is not a drop in replacement for + mktemp. + +2009-01-21 A. Walton <[email protected]> + + * eel-debug-drawing.c (eel_debug_show_pixbuf_in_external_viewer): + Bug 568630 eel should use mkstemp() instead of mktemp() + mktemp() is deprecated and should not be used. + Patch by Jasper Lievisse Adriaanse. + +2009-01-20 Cosimo Cecchi <[email protected]> + + * eel-background.c: (on_bg_changed), (on_bg_transitioned), + (eel_background_init), (free_fade), (eel_background_finalize), + (set_root_pixmap), (fade_to_pixmap), + (eel_background_set_up_widget), (on_background_changed), + (init_fade), (eel_widget_queue_background_change), + (widget_style_set_cb), (widget_realized_setup), + (on_widget_destroyed), (eel_get_widget_background): + Support fading between backgrounds. + Bug #552859, patch by Ray Strode. + +=== caja 2.25.2 === + +2008-12-15 Alexander Larsson <[email protected]> + + * Makefile.am: + Don't install headers + +2008-12-10 Alexander Larsson <[email protected]> + + * eel/eel-enumeration.[ch]: + * eel/eel-preferences-builder.c: + * eel/eel-preferences.[ch]: + Make enums uint (so we can use larger values for thumbnail limit). + +2008-12-08 Cosimo Cecchi <[email protected]> + + * test/test.h: + Flip include orders to fix the build (#563731). + +2008-12-07 Cosimo Cecchi <[email protected]> + + * eel/eel-background.c: + * test/test.h: + Remove more useless includes. + Thanks to Luis Menina (#563569). + +2008-12-07 Cosimo Cecchi <[email protected]> + + * eel/check-program.c: + * eel/eel-gdk-pixbuf-extensions.c: + * test/test-eel-background.c: + * test/test-eel-image-table.c: + Use single gdk-pixbuf and GTK+ headers includes. + +2008-12-01 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +==================== 2.25.1 ==================== + +2008-12-01 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2008-11-18 Cosimo Cecchi <[email protected]> + + * eel/eel-preferences.c: + (eel_preferences_add_auto_string_array_as_quarks): + Plug a leak. + +2008-10-09 Alexander Larsson <[email protected]> + + * eel/eel-gdk-extensions.[ch]: + Remove old now unused function eel_gdk_color_parse() + +2008-10-07 Alexander Larsson <[email protected]> + + * configure.in: + * eel-2.0-uninstalled.pc.in: + * eel-2.0.pc.in: + Remove deps on startup-notify, libmate* and libglade + + * eel/eel-mate-extensions.[ch]: + Remove MateIconSelector functions. + Remove glade functions + + * eel/eel-preferences-glade.c: Removed. + * eel/eel-preferences-builder.c: Added. + * eel/eel-preferences-glade.h: Removed + * eel/eel-preferences.h: + Move eel-preferences-glade.c to eel-preferences-builder.c and use + GtkBuilder instead of Glade. + Remove eel-preferences-glade.h and move GtkBuilder functions + into eel-preferences.h + + * eel/Makefile.am: + Update for file renamed/deletions + + * eel/check-program.c: + * eel/eel-stock-dialogs.c: + Don't include libmate headers. + +2008-10-07 Alexander Larsson <[email protected]> + + * eel/eel-mate-extensions.[ch]: + Remove mate_icon_selector code + +2008-10-06 Alexander Larsson <[email protected]> + + * eel/check-program.c: + * test/test-eel-widgets.c: + * test/test.c: + Don't use MateProgram + +2008-10-06 Alexander Larsson <[email protected]> + + * eel/eel-stock-dialogs.c (timed_wait_callback): + Don't call mate_authentication_manager_dialog_is_visible() + anymore, not needed with no mate-vfs. + +2008-10-06 Alexander Larsson <[email protected]> + + * eel/eel-debug-drawing.c (eel_debug_show_pixbuf_in_external_viewer): + Better ignoring of system return value. Fixes build (#555264) + +2008-10-06 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-mount-operation.[ch]: + Remove EelMountOperation + +2008-10-01 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.25.1. + Stable version lives on the mate-2-24 branch. + +2008-09-22 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.24.1 + +==================== 2.24.0 ==================== + +2008-09-22 Christian Neumair <[email protected]> + + * NEWS: + Update for release. + +2008-09-15 Christian Neumair <[email protected]> + + * eel/eel-mount-operation.c (ask_password): + Do not make password dialog modal. Fixes #539966. + +2008-09-13 Cosimo Cecchi <[email protected]> + + * eel/eel-preferences.c: (update_auto_string_array_as_quarks): + Fix a warning for an uninitialized variable. + Patch by Christian Kirbach (#552135). + +2008-09-10 Christian Neumair <[email protected]> + + * eel/eel-preferences.c (update_auto_string_array_as_quarks), + (preferences_entry_update_auto_storage), + (preferences_entry_remove_auto_storage), + (eel_preferences_add_auto_string_array_as_quarks): + * eel/eel-preferences.h: + Add eel_preferences_add_auto_string_array_as_quarks(), which maps a + string array to a quark array. No remove function yet, since up to now + it is not needed. Parly fixes #551576. + +2008-09-08 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.40.0 + +==================== 2.23.92 ==================== + +2008-09-08 Christian Neumair <[email protected]> + + * NEWS: + Update for release. + +2008-09-08 Christian Neumair <[email protected]> + + * eel/Makefile.am: + * eel/eel-app-launch-context.c: + * eel/eel-app-launch-context.h: + Remove in favor of GdkAppLaunchContext. + +2008-09-06 Christian Neumair <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c (pixbuf_loader_size_prepared): + Explicitly cast to float when determining aspect ratio. Fixes #550997. + +2008-09-02 Cosimo Cecchi <[email protected]> + + * eel/*.[ch]: use single headers GTK/GDK/Pango includes. + +2008-09-01 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.23.92. + +==================== 2.23.91 ==================== + +2008-09-01 Christian Neumair <[email protected]> + + * NEWS: + Update for release. + +2008-09-01 Christian Neumair <[email protected]> + + * eel/eel-vfs-extensions.c (eel_filename_strip_extension), + (eel_filename_get_rename_region): + * eel/eel-vfs-extensions.h: + Add eel_filename_strip_extension(), and use it in + eel_filename_get_rename_region(). Part of #309510. Thanks to Paolo + Borelli <[email protected]> and Jared Moore <[email protected]>. + +2008-09-01 Christian Neumair <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c + (eel_gdk_pixbuf_load_from_stream), (pixbuf_loader_size_prepared), + (eel_gdk_pixbuf_load_from_stream_at_size): + * eel/eel-gdk-pixbuf-extensions.h: + Add eel_gdk_pixbuf_load_from_stream_at_size(), which sets the size of + the pixbuf loader when loading. Part of #529371. + +2008-08-03 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.23.91. + +==================== 2.23.90 ==================== + +2008-08-03 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.23.90. + +==================== 2.23.6 ==================== + +2008-07-21 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.23.6. + +==================== 2.23.5 ==================== + +2008-06-16 Christian Neumair <[email protected]> + + * configure.in: post-release bump to 2.23.5. + +==================== 2.23.4 ==================== + +2008-06-16 Christian Neumair <[email protected]> + + * configure.in: actually pre-release bump to 2.23.4. + +2008-06-16 Christian Neumair <[email protected]> + + * NEWS: Update for release. + * configure.in: pre-release bump to 2.23.4. + +2008-06-10 Christian Neumair <[email protected]> + + * eel/eel-editable-label.c + (eel_editable_label_get_block_cursor_location), + (eel_editable_label_draw_cursor), + (eel_editable_label_toggle_overwrite): + Use block cursor in insert mode. Fixes #511617. Thanks to Arthur + Taylor. + +2008-06-03 Vincent Untz <[email protected]> + + * configure.in: post-release bump to 2.23.3 + +==================== 2.23.2 ==================== + +2008-06-03 Christian Neumair <[email protected]> + + * NEWS: + * configure.in: + Require libmate 2.23.0. + +2008-06-03 Christian Neumair <[email protected]> + + * NEWS: + Update for release. + +Sun Jun 1 21:04:04 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c (struct EelBackgroundDetails): Remove + unused image_mtime + +Sun Jun 1 21:02:00 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c: Don't store the image_uri - instead rely + on getting it from MateBG. + +Sun Jun 1 20:39:03 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c: Don't monitor the file anymore; this is + done by MateBG. + +Sun Jun 1 20:24:12 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c (struct EelBackgroundDetails): Don't store + an EelBackgroundPlacement; instead compute it from the MateBG. + +Sun Jun 1 19:30:16 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c (eel_background_save_to_mateconf): New function. + +Sat May 31 02:23:16 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c (eel_background_reload_image): Deal with + the case where image_uri is NULL. + +Sat May 31 00:39:25 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c (eel_background_reload_image): Use + mate_bg_set_filename(). + + * configure.in: Require new mate-desktop + +Fri May 30 23:23:53 2008 Søren Sandmann <[email protected]> + + * Revert last commit, since we still need to deal with file uris. + +Fri May 30 22:13:51 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.[ch]: Rename eel_background_set/get_image_uri() + to set/get_image_filename() to reflect the fact that only local + files works. + +Fri May 30 21:31:09 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.h: Remove unused + eel_background_set_image_uri_sync() function. + +2008-04-21 Christian Neumair <[email protected]> + + * configure.in: + post release version bump + +=== eel 2.23.1 === + +2008-04-21 Christian Neumair <[email protected]> + + * NEWS: + Update for release. + +2008-03-29 Christian Neumair <[email protected]> + + * configure.in: + Use a slightly cleaner method of detecting libstartup-notification, + using macros instead of manually calling pkg-config (#507811). + Thanks to Loïc Minier <[email protected]>. + +2008-03-29 Christian Neumair <[email protected]> + + * eel/eel-debug-drawing.c + (eel_debug_show_pixbuf_in_external_viewer): + Cast system() call result to void, to avoid complier warnings + (#502579). + +2008-03-28 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.23.1 + Mate 2.22 work continues on mate-2-22 branch + +2008-03-28 Christian Neumair <[email protected]> + + * eel/eel-accessibility.h: + * eel/eel-background.c (eel_background_set_image_uri_helper), + (eel_background_is_set): + * eel/eel-canvas-rect-ellipse.c (eel_canvas_re_destroy), + (eel_canvas_re_set_property), (eel_canvas_re_get_property): + * eel/eel-canvas.c (eel_canvas_item_set_property), + (eel_canvas_item_get_property), (eel_canvas_item_dispose), + (eel_canvas_item_invoke_update), (eel_canvas_group_set_property), + (eel_canvas_group_get_property), (eel_canvas_group_destroy), + (group_remove), (eel_canvas_accessible_get_n_children), + (eel_canvas_accessible_ref_child), (eel_canvas_accessible_create), + (eel_canvas_accessible_factory_create_accessible), + (eel_canvas_destroy), (eel_canvas_map), (eel_canvas_unmap), + (eel_canvas_realize), (eel_canvas_unrealize), + (eel_canvas_size_allocate), (eel_canvas_button), + (eel_canvas_motion), (eel_canvas_key), (eel_canvas_crossing), + (eel_canvas_expose), (do_update), + (eel_canvas_item_accessible_get_extents), + (eel_canvas_item_accessible_get_mdi_zorder), + (eel_canvas_item_accessible_component_interface_init), + (eel_canvas_item_accessible_create), + (eel_canvas_item_accessible_factory_create_accessible): + * eel/eel-debug-drawing.c (debug_pixbuf_viewer_size_request), + (debug_pixbuf_viewer_expose_event), + (debug_pixbuf_viewer_set_pixbuf): + * eel/eel-editable-label.c (add_move_binding), + (eel_editable_label_finalize), (eel_editable_label_size_request), + (eel_editable_label_style_set), (_eel_draw_insertion_cursor), + (eel_editable_label_expose), + (eel_editable_label_select_region_index), (popup_position_func), + (atk_text_interface_init), (atk_editable_text_interface_init), + (eel_editable_label_accessible_get_name): + * eel/eel-enumeration.c (eel_enumeration_new), + (eel_enumeration_new_from_entries): + * eel/eel-mateconf-extensions.c (simple_value_is_equal): + * eel/eel-gdk-extensions.c (eel_gradient_new), + (eel_gradient_set_edge_color), (eel_gradient_set_left_color_spec), + (eel_gradient_set_top_color_spec), + (eel_gradient_set_right_color_spec), + (eel_gradient_set_bottom_color_spec), + (eel_gdk_color_parse_with_white_default): + * eel/eel-gdk-pixbuf-extensions.c (pixbuf_destroy_callback): + * eel/eel-graphic-effects.c (create_new_pixbuf), + (create_new_pixbuf_with_alpha): + * eel/eel-gtk-extensions.c (while_realized_disconnecter): + * eel/eel-image-table.c (eel_image_table_realize), + (eel_image_table_unrealize), (eel_image_table_remove), + (image_table_emit_signal), (image_table_handle_motion), + (ancestor_enter_notify_event), (ancestor_leave_notify_event), + (ancestor_motion_notify_event), (ancestor_button_press_event), + (ancestor_button_release_event): + * eel/eel-labeled-image.c (eel_labeled_image_set_property), + (eel_labeled_image_get_property), (eel_labeled_image_size_request), + (eel_labeled_image_size_allocate), + (eel_labeled_image_expose_event), (eel_labeled_image_map), + (eel_labeled_image_unmap), (eel_labeled_image_add), + (eel_labeled_image_remove), (eel_labeled_image_forall), + (labeled_image_get_image_dimensions), + (labeled_image_get_label_dimensions), + (labeled_image_get_image_bounds_fill), + (labeled_image_get_label_bounds_fill), + (labeled_image_update_alignments), + (labeled_image_get_content_dimensions), + (labeled_image_get_content_bounds), (labeled_image_ensure_label), + (labeled_image_ensure_image), (labeled_image_show_image), + (labeled_image_show_label), (eel_labled_set_mnemonic_widget), + (button_leave_callback), (button_focus_out_event_callback): + * eel/eel-preferences.c (preferences_mateconf_value_get_int), + (preferences_mateconf_value_get_bool), + (preferences_mateconf_value_get_string), + (preferences_mateconf_value_get_string_array), + (preferences_peek_storage_path), (preferences_set_storage_path), + (preferences_get_value), (preferences_preference_is_mateconf_key), + (preferences_key_make), (preferences_get_default_value), + (eel_preferences_get_is_invisible), (string_array_is_valid), + (preferences_callback_entry_invoke_function), + (preferences_entry_invoke_callbacks), (update_auto_string), + (update_auto_string_array), (update_auto_integer_or_boolean), + (preferences_something_changed_notice), + (preferences_entry_ensure_mateconf_connection), + (preferences_entry_add_callback), + (preferences_entry_add_auto_storage), + (preferences_entry_remove_callback), + (preferences_entry_remove_auto_storage), + (preferences_callback_entry_free), + (preferences_callback_entry_free_func), (preferences_entry_free), + (preferences_global_table_lookup), + (preferences_global_table_insert), + (preferences_global_table_lookup_or_insert), + (preferences_set_emergency_fallback_stealing_value): + * eel/eel-wrap-table.c (eel_wrap_table_set_property), + (eel_wrap_table_get_property), (eel_wrap_table_size_request), + (eel_wrap_table_size_allocate), (eel_wrap_table_expose_event), + (eel_wrap_table_map), (eel_wrap_table_unmap), + (eel_wrap_table_realize), (eel_wrap_table_add), + (eel_wrap_table_remove), (eel_wrap_table_forall), + (wrap_table_get_num_fitting), (wrap_table_layout), + (wrap_table_irect_max_dimensions), + (wrap_table_get_max_child_dimensions), + (wrap_table_get_content_dimensions), + (wrap_table_get_content_bounds), (wrap_table_child_focus_in): + g_assert() in static functions instead of using + g_return(_val)_if_fail() (#320246). Thanks to Aaditya Sood. + +2008-03-28 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.22.1 === + +2008-03-28 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2008-03-24 Christian Neumair <[email protected]> + + * eel/eel-string.c (skip_argv), (custom1_skip), (custom2_skip): + Fix compiler warnings about unused value by casting va_arg + calls with unused return values to void (#523899). + +2008-03-11 Christian Neumair <[email protected]> + + * eel/eel-background.c: (background_image_file_changed), + (eel_background_update_file_monitor), + (eel_background_set_image_uri_helper): Update EelBackground if the + image file changes. Fixes #106613. + +2008-03-11 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.c: + (ask_question): + Don't pass in NULL as primary if there + is no newline in the message. + +2008-03-10 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Post release version bump + +=== eel 2.22.0 === + +2008-03-10 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + + * configure.in (LIBGLADE_REQUIRED): + Bump version to 2.22.0 + +2008-02-25 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.21.92 === + +2008-02-25 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2008-02-22 Carlos Garcia Campos <[email protected]> + + * eel/eel-mount-operation.c: (ask_question): + Use the first line of the question message as primary text for the + dialog so that it's formatted. + +2008-02-21 Cosimo Cecchi <[email protected]> + + * eel/eel-background.c: (eel_background_ensure_realized): + Better fix for bug #517681. + +2008-02-21 Cosimo Cecchi <[email protected]> + + * eel/eel-background.c: (eel_background_ensure_realized): + Fix compilation warning. (#517681) + Patch from Rodrigo Moya. + +2008-02-21 Cosimo Cecchi <[email protected]> + + * eel-2.0-uninstalled.pc.in: + * eel-2.0.pc.in: + Update dependencies (#505831). + +2008-02-18 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.c: + Handle the save-password flags (#516997) + Patch from Carlos Garcia Campos + +2008-02-13 Christian Persch <[email protected]> + + * eel/eel-editable-label.c: + (eel_editable_label_select_region_index): Update text targets list. + Bug #516230. + +2008-02-13 Christian Persch <[email protected]> + + * configure.in: + * eel/eel-string.c: (eel_strdup_vprintf_with_custom): Use G_VA_COPY. + Bug #516232. + +2008-02-13 Alexander Larsson <[email protected]> + + * configure.in: + Check for va_copy and define a replacement if not availible (#513199) + Patch from Jens Granseuer + +2008-02-11 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.21.91 === + +2008-02-11 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2008-01-28 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.21.90 === + +2008-01-28 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + + * configure.in: + Bump version to 2.21.90 + +2008-01-28 Alexander Larsson <[email protected]> + + * test/test-eel-image-table.c: + Use G_STRFUNC instead of deprecated G_GNUC_FUNCTION + +Fri Jan 25 14:08:11 2008 Søren Sandmann <[email protected]> + + * eel/eel-background.c: Add #define MATE_DESKTOP_USE_UNSTABLE_API + before including mate-bg.h + + * eel/eel-background.c: Delete eel_background_set_is_constant_size(). + +2008-01-22 Alexander Larsson <[email protected]> + + * eel/eel-string.c: + (eel_ref_str_unref): + Fix leak and tighten up a possible race + condition when a unique string is ressurected. + +2008-01-14 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Post release version bump + +=== eel 2.21.5 === + +2008-01-14 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Bump version to 2.21.5 + + * NEWS: + Updated for release + +2008-01-09 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.c: + Update for gio API changes + +2007-12-20 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.21.1 === + +2007-12-20 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + + * configure.in: + Require glib 2.15.0 + +2007-12-20 Alexander Larsson <[email protected]> + + * eel/eel-app-launch-context.c: + Update to new file attribute names + +2007-12-14 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.c: + Update to new flag enum names and values + +2007-12-14 Alexander Larsson <[email protected]> + + * eel/eel-app-launch-context.c: + * eel/eel-app-launch-context.h: + * eel/eel-background.c: + * eel/eel-gdk-pixbuf-extensions.c: + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-mount-operation.h: + * eel/eel-vfs-extensions.c: + Only use <gio/gio.h> include + +2007-12-13 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.c: + (ask_password): + G_PASSWORD_FLAGS_ANON_SUPPORTED -> G_PASSWORD_FLAGS_ANONYMOUS_SUPPORTED + +2007-12-10 Alexander Larsson <[email protected]> + + * eel/eel-app-launch-context.c (add_startup_timeout): + Correct set_data name + +2007-11-30 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Bump version to 2.21.1 + Remove extraversion + +2007-11-29 Alexander Larsson <[email protected]> + + * eel/eel-app-launch-context.c: + * eel/eel-vfs-extensions.c: + Update code to handle glib version of gio + +2007-11-22 Alexander Larsson <[email protected]> + + * eel/eel-string.c (handlers): + Make handlers static + +2007-11-22 Alexander Larsson <[email protected]> + + * eel/eel-string.[ch]: + Added eel_strdup_vprintf_with_custom and + eel_strdup_printf_with_custom + +2007-11-06 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.c: + Fix build for new gio + +2007-11-06 Alexander Larsson <[email protected]> + + * configure.in: + Look for libstartupnotify + + * eel/Makefile.am: + * eel/eel-app-launch-context.[ch]: + Add EelAppLaunchContext + +2007-11-02 Paolo Borelli <[email protected]> + + * eel/eel-string.c: + * eel/eel-string.h: + Remove two functions that were just used in eel-string-list. + +2007-11-02 Paolo Borelli <[email protected]> + + * eel/eel-preferences-glade.c: + * eel/eel-mateconf-extensions.c: + * eel/eel-preferences.c: + * eel/eel-preferences.h: + Introduce eel_preference_[get|set]_string_array and remove + all uses of eel-string-list. + + * eel/eel-enumerations.c: + * eel/eel-enumerations.h: + Simplify implementation and API and avoid use of eel-string-list. + + * eel/eel-string-list.c: + * eel/eel-string-list.h: + * eel/Makefile.am: + Remove eel-string-list.c + +2007-11-02 Alexander Larsson <[email protected]> + + * eel/eel-string.c (eel_str_middle_truncate): + Fix off by one bug + +2007-11-01 Alexander Larsson <[email protected]> + + * eel/eel-string.c: + Make eel_str_middle_truncate handle utf8 strings + correctly. + +2007-10-24 Alexander Larsson <[email protected]> + + * eel/eel-mount-operation.[ch]: + Add active_changed signal + +2007-10-24 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-mount-operation.[ch]: + Add GMountOperation version with gtk+ dialogs + +2007-10-24 Alexander Larsson <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.[ch]: + * eel/eel-background.c: + Convert mate_vfs use to gio + + * configure.in: + * eel/check-program.c: + * test/test-eel-background.c: + * test/test.[ch]: + Remove dependencies on mate-vfs, libmatedesktop, etc + +2007-10-24 Alexander Larsson <[email protected]> + + * eel/eel-art-extensions.[ch]: + * eel/eel-enumeration.c: + * eel/eel-gdk-extensions.[ch]: + * eel/eel-glib-extensions.c: + * eel/eel-gtk-extensions.[ch]: + * eel/eel-pango-extensions.[ch]: + * eel/eel-self-checks.c: + * eel/eel-string-list.[ch]: + * eel/eel-string.[ch]: + Remove even more unused functions + +2007-10-24 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c: + * eel/eelmarshal.list: + Remove unused marshallers + +2007-10-24 Alexander Larsson <[email protected]> + + * eel/eel-art-extensions.[ch]: + * eel/eel-debug-drawing.c: + * eel/eel-gdk-extensions.[ch]: + * eel/eel-gdk-pixbuf-extensions.[ch]: + * eel/eel-glib-extensions.[ch]: + * eel/eel-lib-self-check-functions.h: + * test/Makefile.am: + * test/test-eel-gtk-style.c: Removed. + * test/test-eel-pixbuf-tile.c: Removed. + * test/test.c: + Remove unused functions + +2007-10-23 Alexander Larsson <[email protected]> + + * configure.in: + * eel/eel-art-extensions.[ch]: + * eel/eel-art-gtk-extensions.[ch]: + * eel/eel-background.c: + * eel/eel-debug-drawing.[ch]: + * eel/eel-gdk-pixbuf-extensions.[ch]: + * eel/eel-mate-extensions.c: + * eel/eel-graphic-effects.c: + * eel/eel-gtk-container.[ch]: + * eel/eel-image-table.c: + * eel/eel-labeled-image.[ch]: + * eel/eel-self-checks.[ch]: + * eel/eel-wrap-table.c: + * test/test-eel-gtk-style.c: + * test/test-eel-pixbuf-tile.c: + * test/test.c: + Lift in the small amount of code and typedefs we + need from libart. Remove libart dependency. + +2007-10-23 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-dateedit-extensions.[ch]: Removed. + * eel/eel-mate-extensions.[ch]: + * eel/eel.h: + Remove unneeded eel functions + +2007-10-23 Alexander Larsson <[email protected]> + + * eel/eel-lib-self-check-functions.h: + * eel/eel-vfs-extensions.[ch]: + Remove a bunch of unnecessary mate-vfs functions + +2007-10-11 Alexander Larsson <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.[ch]: + Added eel_gdk_pixbuf_load_from_stream + +2007-10-01 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-mime-application-chooser.[ch]: + * eel/eel-open-with-dialog.[ch]: + Move these to caja + +2007-10-01 Alexander Larsson <[email protected]> + + * eel/eel-mime-application-chooser.c: + * eel/eel-open-with-dialog.c: + Port more stuff to gio mimetype code + + * eel/Makefile.am: + * eel/eel-mime-extensions.[ch]: + Remove unused code + +2007-10-01 Alexander Larsson <[email protected]> + + * configure.in: + Pull in gio when linking + + * eel/eel-open-with-dialog.[ch]: + Update to use GAppInfo and gio APIs. + +2007-09-26 Alexander Larsson <[email protected]> + + * eel/eel-string.h: + Fix up macro definition. + It can't have a space before the param list + +2007-09-26 Alexander Larsson <[email protected]> + + * eel/eel-string.[ch]; + Add eel_ref_str, a set of refcounted and optionally uniquified + string functions. + +2007-09-26 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.[ch]: + Remove more unused code + +2007-09-26 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.c: + Remove code not used by caja anymore + +2007-11-28 Soren Sandmann <[email protected]> + + * configure.in: Require libmatedesktop 2.21.3 + + * eel/eel-background.[ch]: Make EelBackground a thin wrapper + around MateBG from libmatedesktop. + +2007-10-12 Christian Kirbach <[email protected]> + + * eel/eel-debug-drawing.c: + * eel/eel-debug-drawing.h: + (eel_debug_show_pixbuf): unconstify parameter 1 to + unbreak the build on gcc 4.2 + +2007-09-18 Alexander Larsson <[email protected]> + + * configure.in: + Add gio as extraversion + + * eel/eel-gdk-pixbuf-extensions.c: + * eel/eel-vfs-extensions.[ch]: + Use goffset instead of MateVFSFileSize + +=== gio-branch starts here === + +2007-09-18 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.20.0 === + +2007-09-18 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.20.0 + +2007-08-14 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.19.90 === + +2007-08-14 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2007-07-31 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.19.6 === + +2007-07-31 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2007-07-28 Martin Wehner <[email protected]> + + * eel/eel-open-with-dialog.c: (get_all_applications_from_dir): + Don't crash if a menu entry has no exec. Fixes #455949. + Patch from Pascal Terjan <[email protected]> + +2007-07-10 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.19.5 === + +2007-07-10 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2007-07-10 Martin Wehner <[email protected]> + + * configure.in: + Remove AC_ISC_POSIX: It would have to be called after AC_PROG_CC, + but Interactive Unix is obsolete. + Replace obsolete AC_STDC_HEADERS with AC_HEADER_STDC. + Remove AM_SANITY_CHECK: It's an internal macro that is called by + AM_INIT_AUTOMAKE anyway. + Remove unused AC_C_BIGENDIAN. + Remove redundant AC_PROG_AWK call. + +2007-06-23 Martin Wehner <[email protected]> + + * eel/eel-glib-extensions.c: (eel_self_check_glib_extensions): + Set LC_TIME="C" before testing the output of eel_strdup_strftime + instead of having the translators to provide the expected results. + Fixes 'make check' when LC_TIME != LC_MESSAGES. (#348191) + +2007-06-21 Martin Wehner <[email protected]> + + * configure.in: + Don't set both -Wsign-compare and -Wno-sign-compare. + Don't set -Wchar-subscripts as it's included in -Wall. + +2007-06-20 Martin Wehner <[email protected]> + + * configure.in: + Don't set extra warning flags in the user environment CFLAGS. + Fixes 'make distcheck'. + +2007-06-19 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.19.4 === + +2006-06-18 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2007-06-12 Martin Wehner <[email protected]> + + * eel/eel-mime-application-chooser.c: (set_uri_and_mime_type): + Clarify message by replacing "others" with "other files" in the + application chooser dialog. (#150559) + Patch from Björn Lindqvist <[email protected]> + +2006-06-05 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.19.3 === + +2006-06-05 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2007-06-01 Christian Neumair <[email protected]> + + * eel/eel-open-with-dialog.c: (eel_open_with_search_equal_func): Match + application display name and binary path/base path. Fixes #359912. + +=== eel 2.19.2 === + +2007-05-14 Alexander Larsson <[email protected]> + + * configure.in: + * NEWS: + Update for 2.19.2 + +2007-04-10 Alexander Larsson <[email protected]> + + * eel/eel-mateconf-extensions.c: + (eel_mateconf_monitor_add): + (eel_mateconf_monitor_remove): + (eel_mateconf_preload_cache): + Avoid leaked refcounts on default mateconf client. (#235657) + Patch from Matthias Clasen + +2007-03-19 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.19.1 + Mate 2.18 work continues on mate-2-18 branch + +2007-03-12 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + + * eel/eel-gtk-extensions.c (eel_gtk_window_set_initial_geometry): + Fix crasher due to bug sparse cleanup. + +2007-03-12 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.18.0 === + +2007-03-12 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + + * configure.in: + Bump version to 2.18.0 + +2007-03-02 Alexander Larsson <[email protected]> + + * eel/eel-background.c: + * eel/eel-canvas.c: + * eel/eel-enumeration.c: + * eel/eel-gtk-extensions.c: + * eel/eel-image-table.c: + * eel/eel-labeled-image.c: + Sparse cleanups from kjartan + +2007-02-20 Christian Persch <[email protected]> + + * eel/eel.h: Remove eel-ellipsizing-label.h inclusion. + +2007-02-20 Christian Persch <[email protected]> + + * eel/Makefile.am: + R eel/eel-ellipsizing-label.c: + R eel/eel-ellipsizing-label.h: + * test/Makefile.am: + R test/test-eel-ellipsizing.c: Remove EelEllipsisingLabel. Bug + #409272. + +2007-02-20 Christian Persch <[email protected]> + + * eel/Makefile.am: + * eel/eel-editable-label.c: + (eel_editable_label_select_region_index): + * eel/eel-ellipsizing-label.c: + * eel/eel-ellipsizing-label.h: + * eel/eel-string.c: (eel_self_check_string), (main): + * test/Makefile.am: + * test/test-eel-ellipsizing.c: + +2007-01-22 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.17.90 === + +2007-01-22 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.17.90 + +2007-01-18 Christian Persch <[email protected]> + + * eel/eel-accessibility.c: (eel_accessibility_add_simple_text), + (eel_accessible_text_get_type): + * eel/eel-alert-dialog.c: (eel_alert_dialog_get_type): + * eel/eel-canvas.c: (eel_canvas_item_get_type), + (eel_canvas_group_get_type), (eel_canvas_get_type), + (eel_canvas_accessible_factory_get_type), + (eel_canvas_item_accessible_get_type), + (eel_canvas_item_accessible_factory_get_type): + * eel/eel-editable-label.c: (eel_editable_label_get_type), + (eel_editable_label_get_accessible): + * eel/eel-labeled-image.c: (eel_labeled_image_get_accessible): + * eel/eel-mime-application-chooser.c: + (eel_mime_application_chooser_get_type): + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_get_type): No need + to make GTypeInfo and GInterfaceInfo static. Bug #362031. + +2006-12-18 Alexander Larsson <[email protected]> + + * configure.in: + post release version bump + +=== eel 2.17.1 === + +2006-12-18 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2006-12-08 Alexander Larsson <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_intersect): + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-gtk-extensions.c: (eel_gtk_get_system_font): + * eel/eel-gtk-extensions.h: + * eel/eel-pango-extensions.c: + * eel/eel-pango-extensions.h: + Remove all traces of pangoft2 use, as we don't need this + any more. (#377711) + +2006-11-23 Alexander Larsson <[email protected]> + + * eel/eel-open-with-dialog.c: (get_all_applications_from_dir): + Only list appliations that accept file arguments (#345521) + Patch from Tom Parker + +2006-11-23 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.17.1 + Mate 2.16 work continues on mate-2-16 branch + +2006-11-20 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.16.3 === + +2006-11-20 Alexander Larsson <[email protected]> + + * configure.in: + Call it 2.16.3 to match caja release + + * NEWS: + Update for release. + +2006-11-07 Alexander Larsson <[email protected]> + + * configure.in: + post release version bump + +=== eel 2.16.1 === + +2006-11-07 Alexander Larsson <[email protected]> + + * configure.in: + * NEWS: + Update for release. + +2006-10-19 Christian Neumair <[email protected]> + + * eel/eel-preferences.c: + (preferences_callback_entry_compare), + (preferences_entry_add_callback), + (preferences_entry_add_auto_storage), + (preferences_entry_remove_callback), + (preferences_uninitialize), + (preferences_global_table_get_global), + (preferences_while_alive_disconnector): + Bail when trying to add or remove an entry twice, skip entry removal + on object destroy disconnection after eel shutdown. + +=== eel 2.16.0 === + +2006-09-04 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.16.0 + + * NEWS: + Update for release + +2006-09-01 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c: (eel_editable_label_enter_text): + Don't reset im context when commiting text. + +2006-08-25 Alexander Larsson <[email protected]> + + * eel/check-program.c: (main): + Fix build with EEL_OMIT_SELF_CHECK. + +2006-08-23 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.c: (eel_vfs_has_capability): + Fix crash that happened on DnD from firefox in caja. + +2006-08-21 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.15.92 === + +2006-08-21 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2006-08-15 Kjartan Maraas <[email protected]> + + * configure.in: Fix intltool req. + +2006-08-08 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.15.91 === + +2006-08-08 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2006-08-08 Kjartan Maraas <[email protected]> + + * configure.in: Really depend on a newer libmate-menu. + * eel/eel-string-list.c: (eel_self_check_string_list): + * test/test-eel-gtk-style.c: (style_get_color), (style_get_gc), + (color_box_expose_event), (gc_box_expose_event), + (pixmap_box_expose_event): + * test/test-eel-image-table.c: (image_table_child_enter_callback), + (image_table_child_leave_callback): + * test/test-eel-pixbuf-tile.c: Remove and #if 0 out some dead code. + +2006-08-08 Alexander Larsson <[email protected]> + + * eel/eel-background.c: + Fix crash in previous fix. + +2006-08-08 Alexander Larsson <[email protected]> + + * eel/eel-background.c: + Check mtime for background uri changes. (#349962) + Patch from Matthias Clasen + +2006-07-25 Martin Wehner <[email protected]> + + * configure.in: + Post-release version bump + +=== eel 2.15.90 === + +2006-07-25 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2006-07-24 Martin Wehner <[email protected]> + + * eel/eel-mime-application-chooser.c: (refresh_model), + (set_uri_and_mime_type): + * eel/eel-open-with-dialog.c: (set_uri_and_mime_type): + Fix build with gcc 2.95 (#347552) + + Patch from Jens Granseuer <[email protected]> + +2006-07-11 Martin Wehner <[email protected]> + + * configure.in: + Post-release version bump + +=== eel 2.15.4 === + +2006-07-11 Martin Wehner <[email protected]> + + * NEWS: + Update for release + + * configure.in: + Bump version to 2.15.4 + +2006-07-11 Martin Wehner <[email protected]> + + * eel/eel-open-with-dialog.c: (compare_applications), + (eel_open_with_dialog_add_items_idle): + Handle entry name == NULL without crashing. (#339904) + + Based on a patch from Miguel Quiros <[email protected]> + +2006-07-11 Martin Wehner <[email protected]> + + * eel/eel-accessibility.c: + (eel_accessibility_set_up_label_widget_relation): + Set up the atk widget/label relationship correctly. (#341420) + + Patch from Willie Walker <[email protected]> + +2006-06-19 Alexander Larsson <[email protected]> + + * configure.in: + Require new gtk+ + + * eel/eel-mime-application-chooser.c: + word+char wrap label to avoid wide dialogs on large filenames. + Fixes bug #344958 + +2006-06-12 Alexander Larsson <[email protected]> + + * configure.in: + post release version bump + +=== eel 2.15.2 === + +2006-06-12 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2006-05-24 Paolo Borelli <[email protected]> + + * eel/eel-gtk-extensions.[ch]: remove eel_gtk_signal_connect_free_data + and eel_gtk_signal_connect_free_data_custom, since there is + g_signal_connect_data. + +2006-05-24 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-cell-renderer-pixbuf-list.[ch]: + Remove + +2006-05-24 Paolo Borelli <[email protected]> + + * eel/eel-vfs-extensions.[ch]: remove eel_make_uri_from_input, + eel_make_uri_from_input_with_trailing_ws, eel_make_uri_from_shell_arg, + eel_uris_match, eel_uri_get_scheme, eel_uri_make_full_from_relative. + They have been moved into mate-vfs itself for a long time and they + are not used anymore in caja. (bug #342237) + +2006-05-16 Martin Wehner <[email protected]> + + * configure.in: + Post-release version bump. + +=== eel 2.15.1 === + +2006-05-16 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2006-05-07 Martin Wehner <[email protected]> + + * eel/eel-glib-extensions.c: + * eel/eel-glib-extensions.h: + Remove obsolete eel_setenv and eel_unsetenv functions. + + * eel/eel-gtk-extensions.c: (eel_gtk_widget_set_shown): + * eel/eel-gtk-extensions.h: + Remove unused and obsolete eel_gtk_button_* functions (#170126) + +2006-05-07 Martin Wehner <[email protected]> + + * eel/eel-mime-extensions.c: (eel_mime_get_available_mime_types): + * eel/eel-mime-extensions.h: + Fix typo in function name: s/availible/available/ (#326053) + + Patch from Josep Puigdemont <[email protected]> + +2006-05-01 Martin Wehner <[email protected]> + + * eel/eel-mime-application-chooser.c: (refresh_model), + (set_uri_and_mime_type): + * eel/eel-open-with-dialog.c: (set_uri_and_mime_type): + Don't include surrounding markup in translateable messages. + Fixes #150555. + + Patch from Ruben Vermeersch <[email protected]> + +2006-04-28 Martin Wehner <[email protected]> + + * configure.in: + * po/LINGUAS: + Update po/LINGUAS support to new guidelines. (#338017) + + Patch from Przemyslaw Grzegorczyk <[email protected]> + +2006-04-25 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.15.1 + 2.14 development continues on mate-2-14 branch. + +2006-04-15 Martin Wehner <[email protected]> + + * po/LINGUAS: + Remove newlines to fix build with CVS intltool. (#338423) + +2006-04-11 Martin Wehner <[email protected]> + + * configure.in: + Post-release version bump. + +=== eel 2.14.1 === + +2006-04-11 Martin Wehner <[email protected]> + + * NEWS: + Update for release + +2006-04-10 Martin Wehner <[email protected]> + + * Makefile.am: Add intltool artefacts. + + * po/LINGUAS: New file listing all supported languages. + + * configure.in: Require intltool and use po/LINGUAS instead of including + all languages directly in this file. See the wiki for more information: + http://live.gnome.org/MateGoals/PoLinguas + + Patch from Przemyslaw Grzegorczyk <[email protected]> + +2006-04-08 Martin Wehner <[email protected]> + + * configure.in: + Don't check for *env functions anymore. + + * eel/eel-glib-extensions.c: (eel_setenv), (eel_unsetenv): + Just call g_setenv and g_unsetenv. Fixes build on Darwin (#166880). + + Patch from Tony Arnold <[email protected]> + +2006-03-26 Sebastien Bacher <[email protected]> + + * configure.in: popt is not used by eel no need to require it + +2006-03-22 Tommi Vainikainen <[email protected]> + + * configure.in (ALL_LINGUAS): Added Dzongkha (dz). + +2006-03-22 Paolo Borelli <[email protected]> + + * eel/eel-enumeration.c: remove inefficient use of glist. + Fixes bug #335349. + +2006-03-20 Christian Neumair <[email protected]> + + * configure.in: + Depend on libmate-menu 2.13.5. + * eel/eel-open-with-dialog.c: (get_all_applications): + Also request desktop items which have NoDisplay set to TRUE. + +2006-03-13 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.14.0 === + +2006-03-13 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.14.0 + + * NEWS: + Update for release + +2006-03-01 Vladimer SIchinava <[email protected]> + + * configure.in: Added ka (Georgian) to ALL_LINGUAS + +2006-02-28 Bill Haneman <[email protected]> + + * eel/eel-labeled-image.c: + (eel_labeled_image_accessible_get_name): Fixed + segv due to use of labeled_image struct without NULL check. + bug #330995. + +2006-02-27 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.13.92 === + +2006-02-27 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2006-02-19 Erdal Ronahi <[email protected]> + + * configure.in: Added ku (Kurdish) to ALL_LINGUAS + +2006-02-16 Martin Wehner <[email protected]> + + * eel/eel-editable-label.c: + Include config.h to fix i18n of the context menu. + Fixes bug #331377. + Patch from Takao Fujiwara <[email protected]> + +2006-02-16 Martin Wehner <[email protected]> + + * test/test.c: (test_window_set_title_with_pid): + Add a cast to fix build on Solaris. (#117825) + Patch from Fredrik Jonsson <[email protected]> + +2006-02-13 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.13.91 === + +2006-02-13 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2006-02-07 Alexander Larsson <[email protected]> + + * eel/eel-mime-extensions.c (eel_mime_add_application): + Add %f to exec line when creating open-with desktop files. + Patch from Christian Persch <[email protected]> + Bug #169202 + +2006-01-31 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.13.90 === + +2006-01-31 Martin Wehner <[email protected]> + + * NEWS: + Update for release. + + * configure.in: + Bump version to 2.13.90 + +2006-01-21 Luca Ferretti <[email protected]> + + * .cvsignore: + Added missing files to ignore. + * eel/.cvsignore: + Ditto. + +2006-01-16 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.13.4 === + +2006-01-16 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2006-01-12 Alexander Larsson <[email protected]> + + * eel/eel-background.[ch]: + Add EEL_BACKGROUND_ZOOM + + * eel/eel-gdk-pixbuf-extensions.[ch]: + Add eel_gdk_scale_to_min_factor and eel_gdk_pixbuf_scale_to_min + + Patch by Alan Swanson (#320830) + +2005-12-28 Abel Cheung <[email protected]> + + * configure.in: Added "zh_HK" to ALL_LINGUAS. + +2005-12-20 Alexander Larsson <[email protected]> + + * configure.in: + Actuallu bump version. + +2005-12-20 Alexander Larsson <[email protected]> + + * eel/eel-mime-extensions.[ch]: + Add eel_mime_get_availible_mime_types + +2005-12-17 Dennis Cranston <[email protected]> + + * eel/eel-alert-dialog.c: Hide dialog from taskbar, so it + does not display "untitled window". + +2005-12-13 Dennis Cranston <[email protected]> + + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_instance_init): + HIG fixes. + +2005-12-12 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.13.3 === + +2005-12-12 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2005-12-09 Alexander Larsson <[email protected]> + + * eel/eel-alert-dialog.[ch]: + * eel/eel-mateconf-extensions.c: + * eel/eel-mate-extensions.c: + * eel/eel-open-with-dialog.c: + * eel/eel-stock-dialogs.[ch]: + Remove title from alerts. (#323134) + + Patch from [email protected] + +2005-12-08 Alexander Larsson <[email protected]> + + * eel/eel-preferences-glade.[ch]: + Use GtkComboBox, not GtkOptionMenu + Patch from [email protected] + +2005-11-14 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.13.2 === + +2005-11-14 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2005-11-14 Alexander Larsson <[email protected]> + + * eel/eel-alert-dialog.c: + Include config.h so we get translations. + Patch from Yang Hong <[email protected]> + +2005-10-28 Simos Xenitellis <[email protected]> + + * configure.in: Added ky (Kirghiz) to ALL_LINGUAS. + +2005-10-27 Kjartan Maraas <[email protected]> + + * eel/eel-art-gtk-extensions.c: + (eel_gdk_window_clip_dirty_area_to_screen): + * eel/eel-background.c: (eel_background_class_init): + * eel/eel-canvas.c: (item_post_create_setup), + (eel_canvas_group_get_property), (pick_current_item): + * eel/eel-editable-label.c: (eel_editable_label_ensure_layout), + (eel_editable_label_size_allocate), (eel_editable_label_map), + (eel_editable_label_unmap), (window_to_layout_coords), + (eel_editable_label_button_release), + (eel_editable_label_move_line), + (eel_editable_label_move_backward_word): + * eel/eel-ellipsizing-label.c: (real_expose_event): + * eel/eel-mateconf-extensions.c: (simple_value_is_equal): + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_average_value): + * eel/eel-image-table.c: (eel_image_table_realize), + (image_table_emit_signal): + * eel/eel-mime-application-chooser.c: + (eel_mime_application_chooser_destroy): + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_destroy): + * eel/eel-pango-extensions.c: + (eel_pango_layout_set_text_ellipsized): + * eel/eel-stock-dialogs.c: (timed_wait_free): Large amounts of + cleanups. Mostly removal of unused code and some compiler warnings. + +2005-10-24 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.13.1 === + +2005-10-24 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2005-10-19 Christian Neumair <[email protected]> + + * eel/eel-mime-application-chooser.c: (create_tree_view): + Sort applications by display name, filed as part of #310038. + +2005-10-03 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.13.1. Further 2.12.x work is on + mate-2-12 branch. + +2005-10-03 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.12.1 === + +2005-10-03 Alexander Larsson <[email protected]> + + * NEWS: + Update for 2.12.1. + +2005-10-03 Alexander Larsson <[email protected]> + + * eel/eel-accessibility.c: + (eel_accessibility_set_up_label_widget_relation): + Slight cleanup. Patch from Christian Neumair. + +2005-09-05 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.12.0 === + +2005-09-05 Alexander Larsson <[email protected]> + + * NEWS: Update for release. + +2005-08-23 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.11.92 === + +2005-08-23 Martin Wehner <[email protected]> + + * NEWS: + Update for release. + +2005-08-09 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.11.91 === + +2005-08-09 Martin Wehner <[email protected]> + + * NEWS: + Update for release. + +2005-08-05 Christian Neumair <[email protected]> + + * src/eel-wrap-table.c: Get rid of broken scrolled window viewport + code. Fixes #308996. + +2005-08-01 Christian Persch <[email protected]> + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): + Use g_log_set_default_handler instead of adding handlers for + tons of domains (#312268). + +2005-07-25 Martin Wehner <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.11.90 === + +2005-07-25 Martin Wehner <[email protected]> + + * configure.in: + Bump version to 2.11.90 + + * NEWS: + Update for release. + +2005-07-20 Mikael Hallendal <[email protected]> + + * eel/eel-vfs-extensions.[ch] (eel_uri_is_search): + Add x-caja-search URI. + +2005-07-19 Alexander Larsson <[email protected]> + + * eel/eel-mime-application-chooser.c: (set_uri_and_mime_type): + * eel/eel-open-with-dialog.c: (set_uri_and_mime_type): + Add comments for translators. (#150558) + + Patch from Brent Smith + +2005-07-13 Alexander Larsson <[email protected]> + + * eel/eel-wrap-table.c: + Take border width into account when wrapping (#155642) + Patch from Christian Neumair. + +2005-07-11 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.11.4 === + +2005-07-11 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2005-07-06 Kjartan Maraas <[email protected]> + + * eel/eel-open-with-dialog.c: (add_or_find_application): + Fix a small leak. + +2005-07-01 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.11.3 === + +2005-07-01 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2005-06-11 Kjartan Maraas <[email protected]> + + * eel/eel-mime-application-chooser.c: (remove_clicked_cb): Remove + const qualifier now that we free the application id. + +2005-06-11 Kjartan Maraas <[email protected]> + + * eel/eel-mime-application-chooser.c: + (eel_mime_application_chooser_finalize), (remove_clicked_cb): + Plug some leaks. + * eel/eel-open-with-dialog.c: (check_application): Here too. + Closes bug #307268 and bug #307280 + +2005-06-10 Martin Wehner <[email protected]> + + * eel/eel-labeled-image.c: (labeled_image_get_image_bounds_fill), + (eel_labeled_image_get_image_bounds), + (labeled_image_get_label_bounds_fill), + (eel_labeled_image_get_label_bounds): + Add default cases with asserts. + + * eel/eel-mime-extensions.c: (open_temp_cache_file): + Initialize filename in error case. + + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_add_icon_idle): + * eel/eel-preferences.c: (preferences_entry_remove_auto_storage): + Use NULL instead of 0. + + * configure.in: + Add --Wno-pointer-sign + + Fix gcc4 compilation (#300646). Based on patches from + Kjartan Maraas <[email protected]> and + James M. Cape <[email protected]> + +2005-06-08 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Post release version bump. + +=== eel 2.11.2 === + +2005-06-08 Alexander Larsson <[email protected]> + + * eel/eel-open-with-dialog.c: + Fix const warning. + + * NEWS: + Update for release. + +2005-06-07 Kjartan Maraas <[email protected]> + + * eel/eel-open-with-dialog.c: (program_list_selection_changed): + Plug a couple of leaks. Closes bug #306767. + +2005-05-22 Sebastien Bacher <[email protected]> + + * configure.in: + Update of glib and gtk requirements to 2.6.0 (Closes: #304875). + +2005-05-17 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.11.1 === + +2005-05-17 Alexander Larsson <[email protected]> + + * NEWS: + Update for 2.11.1 release + +2005-04-12 Alexander Larsson <[email protected]> + + * eel-2.0.pc.in: + * eel-2.0-uninstalled.pc.in: + Use gmodule-no-export-2.0 instead of gmodule-2.0 to avoid using --export-dynamic. + +2005-04-11 Mark McLoughlin <[email protected]> + + * eel/Makefile.am, eel/eel-open-with-dialog.c: update + for libmate-menu API renaming. + +2005-04-11 Abduxukur Abdurixit <[email protected]> + + * configure.in: Added 'ug' to ALL_LINGUAS. + +2005-04-08 Sebastien Bacher <[email protected]> + + * configure.in: + Update matevfs requirement to 2.9.1. + +2005-04-06 Mark McLoughlin <[email protected]> + + * eel/eel-open-with-dialog.c: (get_all_applications): + Update for slight change in menu_tree_lookup() API. + +2005-03-31 Steve Murphy <[email protected]> + + * configure.in: Added "rw" to ALL_LINGUAS. + +2005-03-28 Martin Wehner <[email protected]> + + * eel/eel-accessibility.c: (get_simple_text): + Return NULL if the gobject is no longer valid. + Fixes bug #168161. + + Patch from Muktha <[email protected]> + +2005-03-27 Martin Wehner <[email protected]> + + * configure.in: + Require libmate-menu 2.11.1 for the new API. + + * eel/eel-open-with-dialog.c: (get_all_applications_from_dir), + (get_all_applications), (eel_open_with_dialog_add_items_idle): + Update to the new libmate-menu API. + + Patch from Christian Neumair <[email protected]> + +2005-03-24 Adi Attar <[email protected]> + + * configure.in: Added 'xh' to ALL_LINGUAS. + +2005-03-22 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.11.1 + Mate 2.10 versions are now on the mate-2-10 branch. + +2005-03-16 Alexander Larsson <[email protected]> + + * eel/eel-background.[ch]: + Move desktop background setting here to be able to share + pixmap with root window. (#169347) + + Patch from Nickolay V. Shmyrev + +2005-03-07 Alexander Larsson <[email protected]> + + * eel/eel-mime-extensions.c: (eel_mime_add_application): + Make sure user added desktop files don't conflict with global ones. + Patch from Christian Persch + +2005-03-07 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.10.0 === + +2005-03-07 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Update for 2.10 release + +2005-03-01 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Post release version bump + +=== eel 2.9.92 === + +2005-03-01 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2005-03-01 James Henstridge <[email protected]> + + Fixes bug #164796 (approved by Alex) + + * autogen.sh: request Automake >= 1.7. + + * eel/eel-gdk-extensions.h (EEL_RGBA_COLOR_PACK): add casts to + guint32. Fixes test failures on 64-bit systems. + +2005-02-24 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.c (eel_read_entire_file): + Just use mate_vfs_read_entire_file(). + We should remove this function eventually. + +2005-02-11 Alexander Larsson <[email protected]> + + * eel/eel-mime-application-chooser.c (refresh_model): + Handle the case with no existing applications better. + +2005-02-10 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Post release version bump. + +=== eel 2.9.91 === + +2005-02-10 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2005-01-26 Alexander Larsson <[email protected]> + + * eel/eel-open-with-dialog.c (eel_open_with_dialog_finalize): + Remove idle handlers when closing window. (#165208) + +2005-01-25 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.9.90 === + +2005-01-25 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + + * configure.in: + Bump version to 2.9.90 + +2005-01-25 Alexander Larsson <[email protected]> + + * eel/eel-open-with-dialog.c (eel_open_with_dialog_add_icon_idle): + Don't crash if no icon . + +2005-01-24 Kjartan Maraas <[email protected]> + + * eel/eel-accessibility.c: (eel_accessible_text_get_type): + * eel/eel-editable-label.c: + (eel_editable_label_accessible_get_selection): + * eel/eel-gdk-extensions.c: (eel_stipple_bitmap): + * eel/eel-gtk-extensions.c: + (eel_gtk_tree_view_set_activate_on_single_click): + * eel/eel-preferences.c: (preferences_get_value), + (eel_preferences_get), (eel_preferences_get_string_list): + * eel/eel-stock-dialogs.c: (eel_show_yes_no_dialog): + * eel/eel-string-list.c: (eel_string_list_find_by_function): + * eel/eel-wrap-table.c: Fix a bunch of warnings from sparse. + +2005-01-24 Alexander Larsson <[email protected]> + + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_instance_init): + Mark string for translation. + Patch from Yang Hong <[email protected]> + +2005-01-23 Martin Wehner <[email protected]> + + * eel/eel-mime-application-chooser.c: (create_tree_view), + (refresh_model): Show application icon in the selector. + + Patch from Fernando Herrera <[email protected]> + +2005-01-21 Alexander Larsson <[email protected]> + + * configure.in: + * eel/Makefile.am: + require libmate-desktop and libmate-menu + + * eel/eel-mime-extensions.[ch]: + (eel_mime_add_custom_mime_type_for_desktop_file), + (eel_mime_check_for_desktop_duplicates): + New function to check for duplicate desktop files handling a mimetype + and to add custom mime types for desktop files. + + * eel/eel-open-with-dialog.c: + Show know applications from .desktop files and move + the entry to an expander to specify a custom app/command line. + + Patch from Fernando Herrera <[email protected]> + +2005-01-13 Alexander Larsson <[email protected]> + + * eel/eel-alert-dialog.c (eel_alert_dialog_set_primary_label): + Escape the text put in the markup string. + +2005-01-11 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.9.2 === + +2005-01-11 Alexander Larsson <[email protected]> + + * NEWS: + Update for release. + +2004-11-25 Marco Pesenti Gritti <[email protected]> + + reviewed by: Alexander Larsson <[email protected]> + + * eel/eel-mime-application-chooser.c: (refresh_model): + * eel/eel-mime-extensions.c: (eel_mime_add_application), + (eel_mime_check_for_duplicates): + + Replcae usage of deprecate mime apis + +2004-11-24 Alexander Larsson <[email protected]> + + * configure.in: + Post release bump + +=== eel 2.9.1 === + +2004-11-24 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2004-11-19 Alexander Larsson <[email protected]> + + * eel/eelmarshal.list: + Add some new needed marshallers. + +2004-10-29 Alexander Larsson <[email protected]> + + * configure.in: + Update version to 2.9.1. + Mate 2.8 versions are now on the mate-2-8 branch. + +==== mate-2-8 branched from here === + +2004-10-28 Alexander Larsson <[email protected]> + + * configure.in: + Post release bump + +=== eel 2.8.2 === + +2004-10-28 Alexander Larsson <[email protected]> + + * NEWS: + Update for release + +2004-10-28 Alexander Larsson <[email protected]> + + * eel/eel-glib-extensions.[ch]: + New function, eel_get_filename_charset. + + * eel/eel-vfs-extensions.c: + Use eel_get_filename_charset to handle filename charset. + +2004-10-21 Alexander Larsson <[email protected]> + + * eel/eel-canvas.c: (eel_canvas_group_draw), (eel_canvas_expose): + Update to latest foocanvas, fix expose returning TRUE. + +2004-10-15 Alexander Larsson <[email protected]> + + * eel/eel-mime-extensions.c: (eel_mime_add_application), + (eel_mime_check_for_duplicates): + Handle null mimetypes (required for property page if + file has no extension). + +2004-10-11 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.8.1 === + +2004-10-11 Alexander Larsson <[email protected]> + + * NEWS: + Update for 2.8.1 + +2004-09-28 Gora Mohanty <[email protected]> + + * configure.in: Added 'or' to ALL_LINGUAS. + +2004-09-13 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump. + +=== eel 2.8.0 === + +2004-09-13 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Update for 2.8.0 + +2004-09-11 Abel Cheung <[email protected]> + + * configure.in: Added "ang" to ALL_LINGUAS. + +2004-09-06 Alexander Larsson <[email protected]> + + * eel/eel-mime-extensions.c: (eel_mime_set_default_application): + Create ~/.local/share/applications as needed. + +2004-08-31 Alexander Larsson <[email protected]> + + * eel/eel-mime-application-chooser.c: + (mime_monitor_data_changed_cb): + Refresh model when mime db changes + + * eel/eel-mime-extensions.c: (mime_update_program_done): + Remove spew + +2004-08-30 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.7.92 === + +2004-08-30 Alexander Larsson <[email protected]> + + * NEWS: + Update for 2.7.92 + + * configure.in: + Require new libmateui + +2004-08-25 Alexander Larsson <[email protected]> + + * eel/eel-stock-dialogs.c (timed_wait_callback): + Don't pop up cancel dialog if password dialog is visible. + +2004-08-16 Kjartan Maraas <[email protected]> + + * configure.in: Added nb to ALL_LINGUAS. + +2004-08-16 Alexander Larsson <[email protected]> + + * configure.in: + Post release bump to 2.7.92 + +=== eel 2.7.4 === + +2004-08-16 Alexander Larsson <[email protected]> + + * NEWS: + Update for 2.7.4 + + * eel/eel-canvas.c: + Update from foocanvas. + + * configure.in: + Require new mate-vfs (for default application file + type change). + +2004-08-12 Alexander Larsson <[email protected]> + + * eel/eel-canvas-rect-ellipse.c: + * eel/eel-canvas.c: (eel_canvas_key): + Update to latest foocanvas. + +2004-08-12 Alexander Larsson <[email protected]> + + * eel/eel-mime-extensions.c (eel_mime_set_default_application): + Use new name for default.list toplevel section. + +2004-08-09 Ray Strode <[email protected]> + + * eel/eel-mime-extensions.c (eel_mime_add_application), + (eel_mime_set_default_application): free strings + when done with them (Spotted by Kjartan Maraas, bug 149718). + +2004-07-23 Christian Neumair <[email protected]> + + * eel/eel-mime-application-chooser.c: + * eel/eel-open-with-dialog.c: Include gi18n-lib.h instead of gi18n.h. + +2004-07-23 Christian Neumair <[email protected]> + + * configure.in: Require MATE-VFS 2.7.5 (HEAD). + +2004-07-23 Tomasz Kłoczko <[email protected]> + + * configure.in: better looking PKG_CHECK_MODULES() output. + +2004-07-22 Dave Camp <[email protected]> + + * configure.in: Post-release version bump + +=== eel 2.7.3 === + +2004-07-22 Dave Camp <[email protected]> + + * configure.in: + * NEWS: 2.7.3 + +2004-07-21 Dave Camp <[email protected]> + + * Merged the eel-new-mime branch. + +2004-07-21 Dave Camp <[email protected]> + + * configure.in: + * eel/Makefile.am: + * eel/eel-mime-extensions.c: (write_desktop_file), + (mime_update_program_done), (eel_mime_add_glob_type), + (open_temp_cache_file), (line_is_for_mime_type), + (eel_mime_set_default_application), + (eel_mime_application_is_user_owned), + (eel_mime_application_remove): + * eel/eel-mime-extensions.h: + * eel/eel-mime-application-chooser.c: + * eel/eel-mime-application-chooser.h: + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_instance_init), + (eel_open_with_dialog_new), (eel_add_application_dialog_new): + * eel/eel-open-with-dialog.h: Add the eel-mime-application-chooser + dialog. + +Wed Jul 21 18:30:25 2004 Jonathan Blandford <[email protected]> + + * eel/eel-mime-extensions.c: (arg_is_exec_param), + (eel_mime_check_for_duplicates): Make fit eel coding guidelines. + + * eel/eel-open-with-dialog.c (get_run_dialog_image): Get the image + from stock. + (eel_open_with_dialog_instance_init): Use the panel mate-run + stock image. + +Wed Jul 21 02:54:32 2004 Jonathan Blandford <[email protected]> + + * eel/eel-mime-extensions.h: New public function: + eel_mime_check_for_duplicates() + + * eel/eel-mime-extensions.c: (mime_update_program_done), + (run_update_command), (eel_mime_add_application), + (eel_mime_add_glob_type), (arg_is_exec_param), + (eel_mime_check_for_duplicates): New function that will check a + command line to see if another application with that name already + exists. Also, the post-mime-update stuff has been modified + slightly. + + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_finalize), + (eel_open_with_dialog_destroy), (check_application), + (get_app_name), (add_or_find_application), (response_cb), + (eel_open_with_dialog_class_init), (chooser_response_cb), + (browse_clicked_cb), (entry_changed_cb), + (eel_open_with_dialog_instance_init), (get_extension), + (set_uri_and_mime_type), (eel_open_with_dialog_get_type): Some + whitespace 'cleanups'. Dialog packing cleanup and behavior + changes. Better error handling is included as well. + +Mon Jul 19 22:10:59 2004 Jonathan Blandford <[email protected]> + + * eel/eel-open-with-dialog.c (eel_open_with_dialog_new): make + function have no return value. + +2004-07-19 Dave Camp <[email protected]> + + * eel/Makefile.am: + * eel/eel-mime-extensions.c: (recursive_mkdir), (get_user_dir), + (ensure_mime_dir), (ensure_application_dir), (write_desktop_file), + (update_application_database), (eel_mime_add_application), + (get_override_filename), (get_override), (write_override), + (create_type_node), (get_type_node), (get_comment_node), + (add_glob_node), (update_mime_database), (eel_mime_add_glob_type): + * eel/eel-mime-extensions.h: + * eel/eel-open-with-dialog.c: (eel_open_with_dialog_finalize), + (eel_open_with_dialog_destroy), (check_application), + (get_app_name), (add_application), (emit_application_selected), + (response_cb), (entry_activate_cb), + (eel_open_with_dialog_class_init), (chooser_response_cb), + (browse_clicked_cb), (eel_open_with_dialog_instance_init), + (get_extension), (set_uri_and_mime_type), + (eel_open_with_dialog_new), (eel_open_with_dialog_get_type): + * eel/eel-open-with-dialog.h: + * eel/eel-preferences.c: (eel_preferences_remove_callback): + Add an Open With dialog that adds mime types and application + mappings. + +2004-07-05 Alexander Larsson <[email protected]> + + * NEWS: + Update for 2.7.2 + +2004-06-01 Alexander Larsson <[email protected]> + + * configure.in: + Post release bump + +=== eel 2.7.1 === + + * NEWS: + Update for 2.7.1 + +2004-05-14 Alexander Larsson <[email protected]> + + * configure.in (LIBGLADE_REQUIRED): + Bump to 2.7.1 on HEAD, 2.6.3 is on mate-2-6 branch + +2004-05-13 Dave Camp <[email protected]> + + * configure.in: Post-release version bump. + +=== eel 2.6.2 === + +2004-05-13 Dave Camp <[email protected]> + + * NEWS: Updated for 2.6.2. + +2004-04-19 Alexander Larsson <[email protected]> + + * configure.in: + Post release version bump + +=== eel 2.6.1 === + +2004-04-19 Alexander Larsson <[email protected]> + + * NEWS: + Updates for 2.6.1 + +2004-04-09 Guntupalli Karunakar <[email protected]> + + * configure.in: Added "gu" (Gujarati) to ALL_LINGUAS. + +2004-03-22 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.6.1 + +=== eel 2.6.0 === + +2004-03-22 Alexander Larsson <[email protected]> + + * configure.in: + Update to 2.6.0 + +2004-03-20 Guntupalli Karunakar <[email protected]> + + * configure.in: Added "pa" (Punjabi) to ALL_LINGUAS. + +=== eel 2.5.91.1 === + +2004-03-16 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Update to 2.5.91.1 + + * eel/eel-editable-label.c (eel_editable_label_retrieve_surrounding_cb): + Use correct index in gtk_im_context_set_surrounding. (#133464) + Patch from Theppitak Karoonboonyanan + +=== eel 2.5.91 === + +2004-03-15 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Update to 2.5.91 + +=== eel 2.5.90 === + +2004-03-08 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Update to 2.5.90 + +2004-03-02 Alexander Larsson <[email protected]> + + * eel/eel-mate-extensions.c (eel_mate_shell_execute_on_screen): + * eel/Makefile.am: + * eel/egg-screen-exec.[c]: + Remove egg-screen-exec. Use gdk_spawn instead. + +2004-03-02 Carlos Garnacho Parro <[email protected]> + + * eel/eel-mate-extensions.c: (eel_mate_icon_selector_new) + made it to use the new GtkFileChooser + +2004-03-02 Alexander Larsson <[email protected]> + + * eel/eel-canvas.h: + * eel/eel-cell-renderer-pixbuf-list.c: + * eel/eel-editable-label.c: (eel_editable_label_key_press), + (popup_position_func): + * eel/eel-gdk-extensions.h: + * eel/eel-glib-extensions.c: (eel_unsetenv): + * eel/eel-labeled-image.c: + * eel/eel-wrap-table.c: + * eel/eel-wrap-table.h: + * test/test-eel-image-table.c: (image_table_child_enter_callback), + (image_table_child_leave_callback), (image_table_size_allocate): + * test/test.c: (test_quit): + * test/test.h: + Portability fixes. Patch from [email protected]. + Fixes #131647. + +2004-03-01 Alexander Larsson <[email protected]> + + Patches from sun. + + * test/test-eel-image-table.c: (labeled_image_new): + Fix forte compiler issue + + * Makefile.am: + * configure.in: + * eel-2.0-uninstalled.pc.in: + Add uninstalled pkg-config file. + +=== eel 2.5.8 === + +2004-02-23 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.5.8 + +2004-02-21 Christian Rose <[email protected]> + + * configure.in: Added "en_CA" to ALL_LINGUAS. + +=== eel 2.5.7 === + +2004-02-11 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.5.7 + +2004-02-06 Alexander Larsson <[email protected]> + + * eel/eel-glib-extensions.c (eel_strdup_strftime): + Fix check + +2004-02-06 Alexander Larsson <[email protected]> + + * configure.in: + * eel/eel-glib-extensions.c (eel_strdup_strftime): + Check for and support SUS modifiers. + +2004-02-05 Padraig O'Briain <[email protected]> + + * eel/eel-alert-dialog.c (eel_alert_dialog_new): Set role of AtkObject + to ATK_ROLE_ALERT. Fixes bug #133273. + +2004-02-05 Tomasz Kӯczko <[email protected]> + + * eel/Makefile.am: + * test/Makefile.am: trivaial fix errors for automake 1.8.x - blank + line following trailing backslash. Fixes are backward compatible with + older automake. + +=== eel 2.5.6=== + +2004-01-30 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.5.6 + +2004-01-27 Alexander Larsson <[email protected]> + + * eel/eel-canvas-util.c: (eel_canvas_get_miter_points): + * eel/eel-canvas.c: (emit_event): + Update from foocanvas. May fix caja event crash. + +2004-01-19 Narayana Pattipati <[email protected]> + + * eel/eel-editable-label.c (eel_editable_label_style_set), + (eel_editable_label_expose): Change the background, foreground, + cursor and outer rectangle colors according to the theme + selected. Fixes bugzilla bug#123207 + +=== eel 2.5.5 === + +2004-01-12 Dave Camp <[email protected]> + + * NEWS: + * configure.in: 2.5.5 + +2004-01-11 Dave Camp <[email protected]> + + * eel/eel-glib-extensions.h: + * eel/eel-glib-extensions.c: (eel_g_str_list_index): New function. + * eel/eel-mateconf-extensions.h: + * eel/eel-mateconf-extensions.c: (eel_mateconf_unset): New function. + * eel/eel-preferences.h: + * eel/eel-preferences.c: (eel_preferences_unset): New functions. + (eel_preferences_get_string_glist), + (eel_preferences_set_string_glist) + (update_auto_string_glist), + (preferences_entry_update_auto_storage), + (eel_preferences_add_auto_string_glist): Added a GList * + interface to string list properties. + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_as_g_slist): + Implemented differently. + (eel_string_list_as_g_list): New function. + +2004-01-03 Anders Carlsson <[email protected]> + + * eel/eel-input-event-box.c: + * eel/eel-input-event-box.h: + Remove these too. + +2004-01-03 Anders Carlsson <[email protected]> + + * test/Makefile.am: Remove test-eel-image-chooser.c + + * eel/eel.h: Remove references to removed headers. + + * eel/Makefile.am: + * eel/eel-caption.c: + * eel/eel-caption.h: + * eel/eel-generous-bin.c: + * eel/eel-generous-bin.h: + * eel/eel-image-chooser.c: + * eel/eel-image-chooser.h: + * eel/eel-radio-button-group.c: + * eel/eel-radio-button-group.h: + * eel/eel-string-picker.c: + * eel/eel-string-picker.h: + * test/Makefile.am: + Remove unused eel stuff. + +2004-01-02 Robert Sedak <[email protected]> + + * configure.in: Added "hr" in ALL_LINGUAS. + +=== eel 2.5.4 === + +2003-12-29 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + 2.5.4 + +2003-12-11 Alexander Larsson <[email protected]> + + * eel/eel-stock-dialogs.c (show_message_dialog): + Connect to response in the right place + +2003-12-11 Alexander Larsson <[email protected]> + + * configure.in: + Require gtk+ 2.3.0 + + * eel/Makefile.am: + * eel/eel-alert-dialog.[ch]: + New hig suporting dialog + + * eel/eel-stock-dialogs.[ch]: + Use new dialog, split up message + in primary and secondary string. + + * eel/eel-mateconf-extensions.c: + * eel/eel-mate-extensions.c: + * test/test-eel-widgets.c: + Use new API + + Patch from [email protected] (with some changes) + +=== eel 2.5.3 === + +2003-12-08 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + 2.5.3 + +2003-11-25 Padraig O'Briain <[email protected]> + + eel/eel-accessibility.c + (eel_accessibility_set_up_label_widget_relation): Call g_object_unref + on AtkRelationSet to avoid memory leak. Fixes bug #127899. + +=== eel 2.5.2 === + +2003-11-24 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.5.2 + +2003-11-21 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c: + Accessibility support, and better support + for GtkEditable signals. + Patch by padraig o'briain <[email protected]> + +=== eel 2.5.1 === + +2003-11-10 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + 2.5.1 + +2003-10-27 Gregory Merchan <[email protected]> + + * eel/eel-gdk-extensions.c (eel_gdk_window_focus): + Use RevertToParent as specified in the ICCCM. + (eel_gdk_window_set_wm_hints_input): + Guard against changes to C booleans. + * eel/eel-mate-extensions.c (eel_mate_icon_selector_new) + * eel/eel-stock-dialogs.c (timed_wait_callback) + * eel/eel-stock-dialogs.c (eel_run_simple_dialog) + * eel/eel-stock-dialogs.c (create_message_dialog) + Don't set WM_CLASS. It should match the application. + * eel/eel-gtk-extensions.c: + Remove comment and unused #define from bad old algorithm. + (eel_gtk_window_event_is_close_accelerator): + Remove Escape from close accelerators; it's not HIG compliant. + This reverts change from 2001-04-30. + +2003-10-22 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * test/Makefile.am: + Disable MATE_DISABLE_DEPRECATED for now + +2003-10-21 Alexander Larsson <[email protected]> + + * eel/eel-preferences.c: + Fix leaks. + Patch from Martin Wehner <[email protected]> + +=== eel 2.5.0 === + +2003-10-20 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.5.0 + +2003-10-15 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * test/Makefile.am: + Disable GTK_DISABLE_DEPRECATED for now, since gtk 2.4 + deprecated various widgets. + +2003-10-06 Christian Rose <[email protected]> + + * configure.in: Added "mr" to ALL_LINGUAS. + +2003-10-02 Padraig O'Briain <[email protected]> + + Merge from foo-canvas.c: + + * eel/eeel-canvas.c + (eel_canvas_item_accessible_ref_state_set): + Do not refer to item->canvas if item can be NULL. (bug #123179) + + (eel_canvas_set_pixels_per_unit) : round + when mapping back to integer coordinates to guard against inadverent + decrement due to lack of precision. + eg zoom of 0.85 == 0.849999999 would lose a pixel + Fix from Jody Goldberg <[email protected]> + + (do_update): + Loop do_update if picking caused need_update to be set again. + (Thanks to George <[email protected]> for noticing this) + Fix from Alexander Larsson <[email protected]> + +2003-09-24 Dave Camp <[email protected]> + + * eel/eelmarshal.list: Added VOID:STRING,LONG,LONG,POINTER. + +2003-09-19 Christian Rose <[email protected]> + + * configure.in: Added "br" to ALL_LINGUAS. + +=== eel 2.4.0 === + +2003-09-08 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + 2.4.0 + +2003-09-04 Alexander Larsson <[email protected]> + + * eel/eel-gdk-extensions.c (eel_gdk_window_focus): + Don't use RevertToNone + +=== eel 2.3.90 === + +2003-09-02 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: 2.3.90 + +2003-08-28 Christian Rose <[email protected]> + + * configure.in: Added "ne" to ALL_LINGUAS. + +=== eel 2.3.9 === + +2003-08-25 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + 2.3.9 + +=== eel 2.3.8 === + +2003-08-08 Alexander Larsson <[email protected]> + + * configure.in: 2.3.8 + +Tue Jul 22 16:18:26 2003 George Lebl <[email protected]> + + * eel/eel-mateconf-extensions.[ch]: add eel_mateconf_key_is_writable, + which calls mateconf_client_key_is_writable + + * eel/eel-preferences.[ch]: add eel_preferences_key_is_writable, + which in turn calls eel_mateconf_key_is_writable on the full key + + * eel/eel-preferences-glade.c: When the key is not writable on + setup, then make the widget insensitive and then monitor the + state to make sure it can't be ever made sensitive (since it can't + be ever written) + +2003-07-21 Dave Camp <[email protected]> + + * NEWS: + * configure.in: + Bumped to 2.3.7. + +2003-07-08 Balamurali Viswanathan <[email protected]> + + * configure.in: Checking for X Development libraries explicitly. + * eel/Makefile.am: Added X_LIBS to libeel_2_la_LDFLAGS + +2003-07-07 Alexander Larsson <[email protected]> + + * eel/eel-canvas-rect-ellipse.c (render_rect_alpha): + Update from foocanvas, fixes #116752 + +=== eel 2.3.6 === + +2003-06-27 Dave Camp <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.3.6. + +=== eel 2.3.5 === + +2003-06-23 Dave Camp <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.3.5. + +2003-06-15 Frederic Crozat <[email protected]> + + * configure.in: + Remove -Wsign-promo and add -Wno-strict-aliasing to the list + of options to test for. Fixes the gcc 3.3 aliasing warnings. + +2003-06-13 Alexander Larsson <[email protected]> + + * eel/eel-canvas-rect-ellipse.c: (get_color_value), + (set_colors_and_stipples), (eel_canvas_re_update_shared), + (eel_canvas_re_realize), (eel_canvas_ellipse_update): + * eel/eel-canvas.c: (eel_canvas_item_dispose), + (eel_canvas_item_unrealize), (eel_canvas_item_invoke_update), + (eel_canvas_item_ungrab), (eel_canvas_item_request_update), + (eel_canvas_group_unrealize), (eel_canvas_group_map), + (eel_canvas_init), (shutdown_transients), (eel_canvas_expose), + (do_update): + * eel/eel-canvas.h: + Update to latest foo-canvas. + +=== eel 2.3.4 === + +2003-06-10 Dave Camp <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.3.4. + +2003-06-05 Kenneth Rohde Christiansen <[email protected]> + + * configure.in: Added li to ALL_LINGUAS. + +2003-06-04 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.3.3. + +2003-05-26 Anders Carlsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-caption-table.c: + * eel/eel-caption-table.h: + * eel/eel-password-dialog.c: + * eel/eel-password-dialog.h: + * eel/eel.h: + * test/Makefile.am: + * test/test-eel-password-dialog.c: + * test/test-eel-widgets.c: (main), (test_radio_changed_callback): + Remove EelCaptionTable and EelPasswordDialog since they're not + used anymore. + +=== eel 2.3.2 === + +2003-05-19 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.3.2. + +2003-05-15 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.[ch]: + New define EEL_DESKTOP_URI and function eel_uri_is_desktop. + +=== eel 2.3.1 === + +2003-05-05 Telsa Gwynne <[email protected]> + + * configure.in: Added cy to ALL_LINGUAS + * po/cy.po: Added + +2003-05-05 Alexander Larsson <[email protected]> + + * NEWS: + Update + + * configure.in: + Bump version + +2003-05-04 Christian Rose <[email protected]> + + * configure.in: Added sr and sr@Latn to ALL_LINGUAS. + +2003-04-23 Masahiro Sakai <[email protected]> + + * configure.in: call AC_LIBTOOL_WIN32_DLL. + * eel/Makefile.am (libeel_2_la_LDFLAGS): add -no-undefined. + + These are necessary for building DLL on win32 platform. + +2003-04-07 Alexander Larsson <[email protected]> + + * eel/eel-canvas.c: + Update foocanvas. + +=== eel 2.2.3 === + +2003-03-31 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.2.3 + +2003-03-27 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.[ch] (eel_filename_get_rename_region): + New function to get the rename region for a filename. + +2003-03-19 Alexander Larsson <[email protected]> + + * eel/eel-accessibility.c (eel_accessibility_set_atk_object_return): + Fix warning. + +2003-03-19 Padraig O'Briain <[email protected]> + + * eel/eel-accessibility.c + (eel_accessibility_destroy): Change function name from + eel_accessibility_weak_unref. Remove call to g_object_unref(). + (eel_accessibility_set_atk_object_return): Use call to + call to g_object_qdata_full() instead of g_object_weak_ref(). + + This fixes bug #107725. + +2003-03-18 Alexander Larsson <[email protected]> + + * eel/eel-canvas.c (eel_canvas_set_pixels_per_unit): + Update from foocanvas. Now less tearing when changing + zoom level. + +2003-03-17 Alexander Larsson <[email protected]> + + * eel/eel-preferences-glade.[ch]: + + Add eel_preferences_glade_connect_string_enum_option_menu_slave + and eel_preferences_glade_connect_bool_slave. + +2003-03-17 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c (eel_editable_label_expose): + Draw frame even if text is "". + +2003-03-13 Christian Rose <[email protected]> + + * configure.in: Added "ml" to ALL_LINGUAS. + +2003-03-12 Balamurali Viswanathan <[email protected]> + + *eel/eel-stock-dialogs.c + connect the "response" signal of the trash dialog + +=== eel 2.2.2 === + +2003-03-10 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.2.2. + +2003-03-04 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + * eel/eel-input-event-box.[ch]: + New widget. Basically GtkEventBox with a INPUT_ONLY window. + +2003-03-04 Alexander Larsson <[email protected]> + + * eel/eel-canvas.c: + Update foocanvas. Fix a11y crash. + +2003-03-04 Alexander Larsson <[email protected]> + + * eel/eel-accessibility.[ch]: + Publicaly export some utility functions. + Patch from [email protected] + +2003-03-04 Alexander Larsson <[email protected]> + + * eel/eel-canvas.c: + Update foocanvas. Gets a11y support from padraig. + +2003-03-03 Alexander Larsson <[email protected]> + + * eel/eel-canvas.c: + Update from foo-canvas. Fixes group movement, + removes silly warning. + +2003-02-28 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.[ch]: + Add eel_editable_label_get_font_description and + eel_editable_label_set_font_description. + +2003-02-27 Taneem Ahmed <[email protected]> + + * configur.in: Added "bn" to ALL_LINGUAS + +2003-02-25 Samúel Jón Gunnarsson <[email protected]> + + * configur.in: Added is to ALL_LINGUAS + +2003-02-21 Paisa Seeluangsawat <[email protected]> + + * configure.in (ALL_LINGUAS): Added "th". + +2003-02-18 Christian Rose <[email protected]> + + * configure.in: Added "ga" to ALL_LINGUAS. + +2003-02-14 Alexander Larsson <[email protected]> + + * eel/eel-glib-extensions.c (eel_unsetenv): + Fix bug. Patch from [email protected]. + +=== eel 2.2.1 === + +2003-02-11 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.2.1 + +2003-02-09 Christian Rose <[email protected]> + + * configure.in: Added "kn" to ALL_LINGUAS. + +2003-02-07 Abel Cheung <[email protected]> + + * configure.in: Removed "ga" from ALL_LINGUAS. Empty translation file. + +2003-02-06 Christian Rose <[email protected]> + + * configure.in: Added "id" to ALL_LINGUAS. + +2003-02-05 James M. Cape <[email protected]> + + * eel/eel-background.c, + eel/eel-canvas-rect-ellipse.c, + eel/eel-canvas.c, + eel/eel-cell-renderer-pixbuf-list.c, + eel/eel-editable-label.c, + eel/eel-gdk-pixbuf-extensions.c, + eel/eel-mate-extensions.c, + eel/eel-stock-dialogs.c, + test/test-eel-image-table.c: + Replace gtk+ functions deprecated in 2.3. + +=== eel 2.2.0.2 === + +2003-01-27 Dave Camp <[email protected]> + + * NEWS: + * configure.in: 2.2.0.2 + +=== eel 2.2.0.1 === + +2003-01-22 Dave Camp <[email protected]> + + * NEWS: + * configure.in: 2.2.0.1 + +2003-01-21 Christian Rose <[email protected]> + + * configure.in: Added "mn" to ALL_LINGUAS. + +=== eel 2.2.0 === + +2003-01-20 Dave Camp <[email protected]> + + * NEWS: + * configure.in: 2.2.0. + +2003-01-17 Alexander Larsson <[email protected]> + + * eel/eel-preferences-glade.c: + Correct previous fix. + +2003-01-17 Alexander Larsson <[email protected]> + + * eel/eel-preferences-glade.c: + Fix a bug in the handling of the hashtable for int enums. + +=== eel 2.1.91 === + +2003-01-13 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.1.91. + +2003-01-13 Alexander Larsson <[email protected]> + + * eel/eel-background.c: + Hack in eel_background_set_up_widget to always get the right size + for desktop window pixmaps. This is needed since matecomponentplug children + gets realized at the wrong size first and then the correct size. + This hack allows us to not load the background image twice and to + not flicker. + Don't draw the background for canvases. This is not needed since + we set up the correct window background. + +2003-01-12 Pablo Saratxaga <[email protected]> + + * configure.in: Added Amharic (am) and Farsi (fa) to ALL_LINGUAS + +=== eel 2.1.6 === + +2003-01-06 Dave Camp <[email protected]> + + * NEWS: + * configure.in: 2.1.6. + +2002-12-17 Alexander Larsson <[email protected]> + + * configure.in: + * eel/Makefile.am: + * test/Makefile.am: + -pthread build fixes + +=== eel 2.1.5 === + +2002-12-16 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump to 2.1.5 + +2002-12-13 Alex Duggan <[email protected]> + + * configure.in: + * eel-2.0.pc.in: + * eel.spec.in: + remove libmatecanvas deps + +=== eel 2.1.4 === + +2002-12-09 Alexander Larsson <[email protected]> + + * configure.in: + * NEWS: + Bump to 2.1.4 + +2002-12-05 Dave Camp <[email protected]> + + * eel/eel-mate-extensions.c: (list_icon_selected_callback): Free + the return value of mate_icon_selection_get_icon(). Patch from + Jörgen Viksell <[email protected]> + +Wed Dec 4 12:50:35 2002 HideToshi Tajima <[email protected]> + + * eel/eel-editable-label.c (eel_editable_label_ensure_layout): + Fix bugzilla.gnome.org #95429 - set input method text to pango layout. + +=== eel 2.1.3 === + +2002-11-25 Alexander Larsson <[email protected]> + + * eel/eel-vfs-extensions.c: + Fix checks so we distcheck. + +2002-11-25 Alexander Larsson <[email protected]> + + * configure.in: + * NEWS: + Bump to 2.1.3. + +2002-11-21 Alexander Larsson <[email protected]> + + * eel/eel-background.[ch]: + (eel_background_set_up_widget): + Set the background pixmap/color on the right window for canvas widgets. + (eel_background_get_suggested_pixmap_size): + New function. + + Based on patch from [email protected] + +2002-11-19 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.[ch]: + Don't use private gtk functions. + +2002-11-05 Dave Camp <[email protected]> + + * test/Makefile.am: + * test/test-eel-widgets.c: (main), + (string_picker_changed_callback): + * test/test.c: + * test/test.h: Took out the tests of removed code. + +2002-11-05 Diego Gonzalez <[email protected]> + + * po/POTFILES.in: remove eel/eel-preferencs-box.c + * eel/Makefile.am: remove eel-font-picker.[c-h], + eel-preferences-box.[c-h], eel-preferences-group.[c-h], + eel-preferences-item.[c-h], eel-preferences-pane.[c-h], + eel-text-caption.[c-h] from the build, these files aren't + used anymore + + * eel/eel.h: remove those headers from here. + +2002-11-04 Diego González <[email protected]> + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: (get_set_value_imethod), + (do_nothing_cb), (eel_matecomponent_pbclient_set_value_async): + remove these functions since they are now in libmatecomponent + +2002-11-04 Alexander Larsson <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: (file_read_callback): + Fix bug with failed reads. + + * eel/eel-wrap-table.c: (eel_wrap_table_class_init), + (eel_wrap_table_init), (eel_wrap_table_realize), + (wrap_table_get_num_fitting), (wrap_table_layout), + (wrap_table_get_max_child_dimensions): + Correct size request. + Patch from Jan Arne Petersen <[email protected]> + +2002-11-03 Dmitry G. Mastrukov <[email protected]> + + * configure.in: Added Belarusian to ALL_LINGUAS + +=== eel 2.1.2 === + +2002-10-31 Dave Camp <[email protected]> + + * MAINTAINERS: Updated. + + * configure.in: + * NEWS: 2.1.2 + +2002-10-31 Dave Camp <[email protected]> + + * eel/eel-background.c: (eel_background_class_init), + (eel_background_set_image_placement), (eel_background_set_color), + (eel_background_set_image_uri_helper), + (set_image_and_color_image_loading_done_callback), + (eel_background_set_image_uri_and_color), + (eel_background_receive_dropped_background_image), + (eel_background_receive_dropped_color): * eel/eel-background.h: + Take a GdkDragAction argument to the receive_dropped_* functions, + and pass it on in the changed signal. + +2002-10-31 Dave Camp <[email protected]> + + * eel/Makefile.am: + * eel/eel-preferences-glade.c: + * eel/eel-preferences-glade.h: New files to connect glade widgets to + preferences. Patch from Jan Arne Petersen <[email protected]>. + +2002-10-25 Dave Camp <[email protected]> + + * eel/Makefile.am: Oops. Removed extra \ at the end of a + commented out line. + +2002-10-19 Dave Camp <[email protected]> + + * eel/Makefile.am: Take out -DMATECOMPONENT_DISABLE_DEPRECATED while the + make_registration_id() api is being worked out. + +=== eel 2.1.1 === + +2002-10-14 Alexander Larsson <[email protected]> + + * NEWS: + Added news items + + * configure.in: + Bump version to 2.1.1 + +2002-10-02 Mark McLoughlin <[email protected]> + + * acconfig.h: define HAVE_GTK_MULTIHEAD + for egg-screen-exec.c. + + * configure.in: require gtk 2.1.0 and remove + HAVE_GTK_MULTIHEAD define. + + * eel/eel-mate-extensions.c, + eel/eel-gtk-extensions.c, + eel/eel-gdk-extensions.c: don't conditionally + build multihead support, gtk HEAD is required. + +2002-10-02 Mark McLoughlin <[email protected]> + + * eel/eel-gdk-extensions.c: + (eel_stipple_bitmap_for_screen): use gdk_screen_get_display + instead of assuming the default display. + + * eel/eel-mate-extensions.c: + (eel_mate_shell_execute_on_screen): use the default screen + if screen == NULL. + +2002-10-02 Mark McLoughlin <[email protected]> + + * eel/eel-mate-extensions.[ch]: + (eel_mate_shell_execute_on_screen): rename from + eel_mate_screen_shell_execute. + (eel_mate_shell_execute): update. + (eel_mate_open_terminal_on_screen): rename from + eel_mate_screen_open_terminal. + (eel_mate_open_terminal): update. + +2002-10-02 Mark McLoughlin <[email protected]> + + * eel/eel-gtk-extensions.c: (eel_gtk_window_set_initial_geometry): + fix build without HAVE_GTK_MULTIHEAD. + + * eel/egg-screen-exec.c: sync with libegg. + +2002-10-02 Mark McLoughlin <[email protected]> + + * configure.in: add check for gtk with multihead support. + + * eel/Makefile.am: add egg-screen-exec.[ch] to the build. + + * eel/eel-gdk-extensions.[ch]: + (eel_stipple_bitmap_for_screen): implement per screen stipple + bitmaps. + (eel_stipple_bitmap): use eel_stipple_bitmap_for_screen. + + * eel/eel-mate-extensions.[ch]: + (eel_mate_screen_shell_execute): implement. + (eel_mate_screen_open_terminal): implement. + (eel_mate_open_terminal): + + * eel/eel-gtk-extensions.c: + (eel_gtk_window_set_initial_geometry): + use gdk_screen_get_(width|height). + +2002-10-01 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.[ch]: + Added eel_editable_label_set_line_wrap_mode. + +2002-09-30 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c: + Implement GtkEditable + +2002-09-30 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c: + Finish cut/paste and other stuff. + +=== eel 2.1.0 === + +2002-09-27 Dave Camp <[email protected]> + + * NEWS: Updated. + +2002-09-27 Alexander Larsson <[email protected]> + + * configure.in: + Bump version to 2.1.0. + +2002-09-26 Alexander Larsson <[email protected]> + + * eel/eel-editable-label.c: + Remove leftover debug spew. + +2002-09-26 Alexander Larsson <[email protected]> + + * test/Makefile.am: + * test/test-eel-canvas-items.c: + Remove canvas item test. + +2002-09-26 Alexander Larsson <[email protected]> + + * eel/Makefile.am: + Add new files, remove old files. + + * eel/README.canvas: + * eel/eel-canvas.[ch]: + * eel/eel-canvas-util.[ch]: + * eel/eel-canvas-rect-ellipse.[ch]: + Import gtk+ only canvas from foocanvas. + + * eel/eel-canvas-rect.[ch]: + Remove old rect object not longer needed. + + * eel/eel-mate-extensions.[ch]: + Remove old canvas extensions no longer needed. + + * eel/eel-background.[ch]: + Update to the new canvas. + + * eel/eel-editable-label.[ch]: + New editable label for rename mode. + + * eel/eel-lib-self-check-functions.h: + Remove old tests. + + * eel/eelmarshal.list: + New marshallers. + + * test/Makefile.am: + * test/test-eel-editable-label.c: + Small test for EelEditableLabel + +2002-09-15 Dave Camp <[email protected]> + + * eel/eel-preferences-item.h: + * eel/eel-preferences-item.c: + (eel_preferences_item_set_description), + (eel_preferences_item_set_accessible_description), + (eel_preferences_item_set_accessible_description_array): Allow users + to set accessible descriptions of preferences items. + * eel/eel-preferences-box.c: (preferences_box_populate_pane): + * eel/eel-preferences-box.h: Allow the user to specify accessible + descriptions for the controls. + * eel/eel-radio-button-group.c: + (eel_radio_button_group_set_entry_accessible_description), + * eel/eel-radio-button-group.h: Allow the user to specify + accessible descriptions for the radio buttons. + +2002-09-10 jacob berkman <[email protected]> + + * eel/eel-types.c: define EEL_COMPILATION + + * eel/Makefile.am (INCLUDES): don't define EEL_COMPILATION + + this fixes actual build problems on OS X, but wasn't correct + anywhere. + +2002-09-10 Dave Camp <[email protected]> + + * eel/eel-background.c: (eel_background_ensure_realized), + (eel_background_set_color_no_emit), (eel_background_set_use_base): + If requested, use base as the fallback color instead of bg. + +2002-09-04 Christian Rose <[email protected]> + + * configure.in: Added "he" to ALL_LINGUAS. + +2002-09-03 Michael Meeks <[email protected]> + + * eel/eel-background.c + (eel_background_load_image_callback): disable, + until the caja side is re-thunk. + +2002-09-03 Michael Meeks <[email protected]> + + * eel/eel-background.c + (set_image_and_color_image_loading_done_callback): + don't double emit apperance_changed occasionaly. + (eel_background_class_init): add determine_image_placement. + (eel_background_load_image_callback): call signal. + [ based on Thomas Meeks' prototype ] + + * eel/eelmarshal.list: add enum:int,int + +2002-08-30 Alexander Larsson <[email protected]> + + branched of mate 2.0.x development to mate-2-0 branch. + +=== eel 2.0.6 === + +2002-08-28 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bumped to 2.0.6. + +=== eel 2.0.5 === + +2002-08-23 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Version bumped to 2.0.5. + +=== eel 2.0.4 === + +2002-08-14 Alexander Larsson <[email protected]> + + * configure.in: + Version bumped to 2.0.4 + +2002-08-12 Dave Camp <[email protected]> + + * eel/eel-string-picker.c: (eel_string_picker_set_string_list): + Use eel_string_list_peek_nth() instead of eel_string_list_nth(). + Fixes a small leak. + +=== eel 2.0.3 === + +2002-08-05 Dave Camp <[email protected]> + + * NEWS: Updated. + * configure.in: 2.0.3. + +2002-07-28 Christian Rose <[email protected]> + + * configure.in: Added "sq" to ALL_LINGUAS. + +2002-07-27 Dave Camp <[email protected]> + + * eel/eel-background.c: (widget_realize_cb), + (eel_get_widget_background): Set up the widget background on + realize. + +2002-07-27 Dave Camp <[email protected]> + + * eel/eel-background.c: (widget_style_set_cb), + (eel_get_widget_background): Put back the style_set handler. + +=== eel 2.0.2 === + +2002-07-25 Dave Camp <[email protected]> + + * NEWS: Add a list of changes. + * configure.in: Bump version to 2.0.2. + +2002-07-25 Pablo Saratxaga <[email protected]> + + * configure.in: Added Bosnian (bs) to ALL_LINGUAS + +2002-07-24 Dave Camp <[email protected]> + + * eel/Makefile.am: Build eel-background-box.[ch], don't build + eel-background-style.[ch]. + * eel/eel-background-style.[ch]: Removed. + * eel/eel-background-box.[ch]: New widget that handles background + drawing itself. + * eel/eel-background.c: (eel_background_init), + (eel_get_widget_background): Removed the style setting and font + updating code. This is now the responsibility of the widget using + the EelBackground. + (eel_background_expose): Helper function for widgets using + EelBackground. + (eel_background_set_up_widget): New function. + (eel_widget_background_changed): Call + eel_background_set_up_widget(). + +=== eel 2.0.1 === + +2002-07-22 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 2.0.01. + Add list of changes. + +2002-07-18 Federico Mena Quintero <[email protected]> + + Fixes the eel part of #46238; see Caja for the rest of the fix. + + * eel/eel-background.c (eel_background_ensure_realized): If we + fail to parse the color spec, don't default to white. Instead use + the background color from the widget's style. + (widget_style_set_cb): New callback for the widget's "style_set" + signal. We regenerate the background and its style when the theme + changes. + (eel_background_set_widget_style): We need a little hack here to + unset the GTK_USER_STYLE flag because otherwise we will not be + notified of theme changes through the "style_set" signal. The + real solution is not to use a style of our own, but rather paint + the widget by hand when needed. + (eel_background_init): Start with is_solid_color = TRUE. + +2002-07-17 Frank Worsley <[email protected]> + + * eel/eel-gtk-extensions.c: + * eel/eel-gtk-extensions.h: + (eel_gtk_window_set_initial_geometry_from_string): + add an ignore_position parameter + +2002-07-12 Damon Chaplin <[email protected]> + + * eel/eel-gtk-extensions.c (eel_gtk_button_new_with_stock_icon): new + function to create a button with a mnemonic label and a stock icon. + GTK+ doesn't make this easy. Needed for bug #85666. + +2002-07-10 Dave Camp <[email protected]> + + * eel/eel-gtk-extensions.c: (tree_view_button_press_callback), + (eel_gtk_tree_view_set_activate_on_single_click): New functions + to make a GtkTreeView activate a row on a single click. + * eel/eel-gtk-extensions.h: Prototype for + eel_gtk_tree_view_set_activate_on_single_click. + * eel/eel-image-chooser.c: (eel_image_chooser_row_activated), + (eel_image_chooser_finalize), (eel_image_chooser_instance_init), + (eel_image_chooser_get_selected_path), + (eel_image_chooser_set_selected_row): Only send a changed event + when the user activates the row. + +2002-07-10 Michael Meeks <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c + (eel_gdk_pixbuf_average_value): unsigned + dividend, width, height. + split out loop invariant and simplify, + killing umpteen multiplies for non-alpha case. + +2002-07-09 Michael Meeks <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c (destroy_global_buffer), + (eel_gdk_pixbuf_get_global_buffer): move these into the only + place that uses them, and hide. + + * test/test-eel-pixbuf-tile.c: here + (pixbuf_drawing_area_expose_event): upd. + +2002-07-09 Damon Chaplin <[email protected]> + + * eel/eel-preferences-box.c (eel_preferences_box_new): added a + 'Cat_egories' label and mnemonic accel above the list. Fixes part + of bug #85673. + + * eel/eel-preferences-group.c (eel_preferences_group_new): set the + border width of the second column of prefs to match the first. + +2002-07-08 Michael Meeks <[email protected]> + + * eel/eel-labeled-image.c + (eel_labeled_image_get_accessible): cope better + with the no a11y scenario. + +2002-07-08 Michael Meeks <[email protected]> + + * eel/eel-labeled-image.c + (eel_labeled_image_radio_button_get_type): impl. + (eel_labeled_image_radio_button_new_from_file_name), + (eel_labeled_image_radio_button_new): impl. + +2002-07-02 Michael Meeks <[email protected]> + + * configure.in: use libglade. + + * eel-2.0.pc.in (Requires): upd. + + * eel/eel-labeled-image.c (eel_labeled_image_set_text): + set text with mnemonic. + (eel_labled_set_mnemonic_widget): impl. + (eel_labeled_*_button_new): set the mnemonic widget. + + * eel/eel-mate-extensions.c (eel_glade_get_file): impl. + +2002-06-28 Marco Pesenti Gritti <[email protected]> + + * eel/eel-gtk-extensions.c (eel_popup_menu_position_func): + Remove context menus custom positioning code to be consistent + with other mate applications. + +2002-06-27 Frank Worsley <[email protected]> + + * eel/eel-vfs-extensions.c: (eel_vfs_has_capability_uri): + * eel/eel-vfs-extensions.h: + implemented EEL_VFS_CAPABILITY_SAFE_TO_EXECUTE + +2002-06-25 Dave Camp <[email protected]> + + * eel/eel-vfs-extensions.c (eel_vfs_has_capability_uri): Moved + here from eel_vfs_test_capabilities(). + (eel_vfs_has_capability): New function, takes a string uri. + * eel/eel-vfs-extensions.h: Changed EelVfsTest to EelVfsCapability, + and EEL_VFS_TEST_* to EEL_VFS_CAPABILITY_*. + +2002-06-25 Frederic Crozat <[email protected]> + + * acconfig.h: + * configure.in: + * eel/Makefile.am: + * eel/check-program.c: (main): + * eel/eel-enumeration.c: + * eel/eel-mateconf-extensions.c: + * eel/eel-glib-extensions.c: + * eel/eel-mate-extensions.c: + * eel/eel-i18n.c: (_eel_gettext): + * eel/eel-i18n.h: + * eel/eel-password-dialog.c: + * eel/eel-preferences-box.c: + * eel/eel-stock-dialogs.c: + * eel/eel-vfs-extensions.c: + * eel/eel-xml-extensions.c: + Use our own _() macro to ensure bind_textdomain_codeset is set + (when available) + + +2002-06-14 Satyajit Kanungo <[email protected]> + + * eel/eel-preferences-box.c : Added a call to get the active pane + for eel preference dialog box. (Applied by Damon Chaplin.) + +2002-06-13 Dave Camp <[email protected]> + + * eel/eel-stock-dialogs.c: (eel_run_simple_dialog): Don't try to + connect to the delete_event signal of the dialog, and handle + gtk_dialog_run() returning GTK_RESPONSE_DELETE_EVENT. Fixes + #78948. + +2002-06-12 Damon Chaplin <[email protected]> + + * eel/eel-mate-extensions.c (icon_selected): hide the dialog at the + start of the function and set the dismissed flag to indicate we're + acting on it, so if we do get called again we just return. + Fixes bug #84134. + +2002-06-10 Alexander Larsson <[email protected]> + + * eel/eel-preferences-box.c: change treeview shadow type + to GTK_SHADOW_IN and add some spacing for consistency with + the rest of mate. + + Patch from Jorn Baayen <[email protected]> + +2002-06-10 Alexander Larsson <[email protected]> + + * NEWS: + Update version nr. + + * configure.in: + Update requirements to latest versions of everything. + +2002-06-10 Naba Kumar <[email protected]> + + * configure.in: Added hi in ALL_LINGUAS. + +2002-06-09 Abel Cheung <[email protected]> + + * eel/eel-glib-extension.c: Clarify the comment about + strftime check. + +2002-06-07 Damon Chaplin <[email protected]> + + * test/Makefile.am (INCLUDES): + * eel/Makefile.am (INCLUDES): use $(prefix)/${DATADIRNAME}/locale + instead of $(datadir)/locale so it works on Solaris. + +2002-06-06 Michael Meeks <[email protected]> + + * eel/eel-vfs-extensions.c + (eel_vfs_test_capabilities): impl. + +2002-06-06 Michael Meeks <[email protected]> + + * Version 2.0.0 + +2002-06-06 Jacob Berkman <[email protected]> + + * eel/eel-gdk-extensions.c: pangoxft.h is not present on all + systems, i think it's safe to just include pango/pango.h + +2002-06-04 Yanko Kaneti <[email protected]> + + * configure.in: (ALL_LINGUAS) Added Bulgarian (bg). + +=== eel 1.1.17 === + +2002-06-03 Alex Larsson <[email protected]> + + * NEWS: + Add some actual changes. + +2002-06-03 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 1.1.17 + +2002-05-31 Alex Larsson <[email protected]> + + * eel/eel-gdk-extensions.[ch] (eel_gdk_draw_layout_with_drop_shadow): + Add new function. + +2002-05-28 Havoc Pennington <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: remove bogus #include <png.h>, + we no longer use libpng + +2002-05-27 Michael Meeks <[email protected]> + + * eel/eel-vfs-extensions.c + (eel_make_valid_utf8): copy from caja + (eel_format_uri_for_display_internal): use it + for awkward (invalid) cases, that we still need to + display in an error dialog. + +=== eel 1.1.16 === + +2002-05-27 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 1.1.16 + +2002-05-23 Michael Meeks <[email protected]> + + * eel/eel-vfs-extensions.c + (eel_format_uri_for_display_internal): move the utf8 + validation assert down to after we've handled 'locale_encoded + filenames' as best we can. + +2002-05-22 Michael Meeks <[email protected]> + + * eel/eel-vfs-extensions.c (eel_is_valid_uri): impl. + +2002-05-21 Damon Chaplin <[email protected]> + + * eel/eel-mate-extensions.c (eel_mate_icon_selector_new): store + the dialog pointer before calling eel_remove_weak_pointer(), as that + will set it to NULL. We want to return it. + + * eel/eel-gdk-pixbuf-extensions.c (eel_gdk_pixbuf_load): close the + pixbuf loader if we get a vfs error. It complains if we unref it + without closing it. + +=== eel 1.1.15 === + +2002-05-20 Alex Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 1.15. + +2002-05-18 Kjartan Maraas <[email protected]> + + * configure.in: Added "mk" to ALL_LINGUAS. + +2002-05-16 Michael Meeks <[email protected]> + + * eel/eel-background-style.c (eel_background_style_draw_flat_box): + unref the pixmap instead of leaking it if not changes_with_size. + +2002-05-16 Mark McLoughlin <[email protected]> + + * eel/eel-pango-extensions.c: (measure_string_width), + (compute_character_widths), (eel_string_ellipsize_start), + (eel_string_ellipsize_end), (eel_string_ellipsize_middle), + (eel_self_check_ellipsize): don't create redundant layouts + when doing calculations. Just use the one we've already + created. + +2002-05-14 Federico Mena Quintero <[email protected]> + + * eel/eel-text-caption.c (entry_key_press_callback): Event + handlers should return a gboolean! Fixes #75229. + +=== eel 1.1.14 === + +2002-05-13 Alex Larsson <[email protected]> + + * NEWS: + * configure.in: + Update to 1.1.14 + +2002-05-12 Anders Carlsson <[email protected]> + + * eel/eel-pango-extensions.c + (eel_pango_layout_fit_to_dimensions): Fix this utterly broken + function by rewriting parts of it. Fixes #81183, reported + by Owen Taylor. + +2002-05-11 Alexander Larsson <[email protected]> + + * eel/eel-background.c: (eel_background_start_loading_image), + (eel_background_set_style_font_from_default), + (eel_background_set_widget_style), (eel_widget_font_changed), + (eel_get_widget_background): + Hacks to update the style when the default font changes. + +2002-05-08 Damon Chaplin <[email protected]> + + * eel/eel-mate-extensions.c (eel_mate_icon_selector_new): connect + the dialog signals up before calling mate_icon_selection_show_icons() + and also add a weak pointer to the dialog. We need to do this as + MateIconSelection reenters the main loop while loading icons, so + it can be closed or a button can be clicked before returning. + Fixes bug #75387. + +=== eel 1.1.13 === + +2002-05-04 David Emory Watson <[email protected]> + + This is needed to fix bug 46582. + + * configure.in: + * NEWS: Bump version to 1.1.13. + + * eel/eel-vfs-extensions.c: + * eel/eel-vfs-extensions.h: + (eel_make_uri_from_input_internal): Optionally strip trailing + whitespace since it could be part of a valid uri. + (eel_make_uri_from_input): Update. + (eel_make_uri_from_input_with_trailing_ws): New. + +2002-04-30 Alexander Larsson <[email protected]> + + * eel/eel-preferences-item.c + (enumeration_menu_changed_callback), + (enumeration_list_changed_callback): + Don't use the translated string when looking up the enumeration position. + Fixes #64696 + +2002-04-29 Pablo Saratxaga <[email protected]> + + * configure.in: Added Vietnamese (vi) to ALL_LINGUAS + * configure.in: Added Walloon (wa) to ALL_LINGUAS + * configure.in: Added Basque (eu) to ALL_LINGUAS + +=== eel 1.1.12 === + +2002-04-28 Alexander Larsson <[email protected]> + + * configure.in: + * NEWS: + Bump version to 1.1.12. + +2002-04-28 Alexander Larsson <[email protected]> + + * configure.in: + Removed -Wcast-align. This broke the build for Alpha on RH 7.1, + even in header files! And it's not that useful. + See bug #79860. + +2002-04-27 Murray Cumming <[email protected]> + + * eel/eel-stock-dialogs.c (eel_show_yes_no_dialog): + Bug #80072: + Use eel_create_question_dialog instead() of show_message_dialog() + so that the custom button titles can be used. + +2002-04-26 Gustavo Giráldez <[email protected]> + + * eel/eel-ellipsizing-label.c (real_finalize): chain call to + parent class' finalize. + +2002-04-22 Anders Carlsson <[email protected]> + + * eel/eel-image-chooser.c: (eel_scrolled_image_chooser_new): + Set shadow type to GTK_SHADOW_IN. Fixes #73389. + +=== eel 1.1.11 === + +2002-04-21 Alexander Larsson <[email protected]> + + * configure.in: + * NEWS: + Bump version to 1.1.11. + +2002-04-21 Alexander Larsson <[email protected]> + + * eel/eel-background.c (eel_background_ensure_image_scaled): + Work around the fact that scaling large pixbufs to 1x1 crashes + while allocating several gigs of memory. + +2002-04-21 Anders Carlsson <[email protected]> + + * eel/eel-gtk-extensions.c: (eel_gtk_label_set_scale), + (get_layout_location), (eel_gtk_label_expose_event), + (eel_gtk_label_size_request), (set_up_label), + (eel_gtk_label_set_drop_shadow_color), + (eel_gtk_label_set_drop_shadow_offset): + * eel/eel-gtk-extensions.h: + Add eel_gtk_label_set_drop_shadow_color and + eel_gtk_label_set_drop_shadow_offset functions. + +2002-04-18 Michael Meeks <[email protected]> + + * eel/eel-mate-extensions.c + (do_nothing_cb, get_set_value_imethod), + (eel_matecomponent_pbclient_set_value_async): impl. + async property setter to cut throbber + latency. + +2002-04-17 Anders Carlsson <[email protected]> + + * eel/eel-background.c: (eel_background_start_loading_image): + If we load the pixbuf sync, unref it so that we won't leak it. + + * eel/eel-image-chooser.c: (eel_image_chooser_cell_data_func): + Free strings. + + * eel/eel-labeled-image.c: (eel_labeled_image_class_init), + (eel_labeled_image_destroy), (eel_labeled_image_forall): + Add a ::destroy handler that destroys the image and label. + + * eel/eel-preferences-box.c: + (preferences_box_category_list_recreate): + Free the GtkTreeIter. + + * eel/eel-preferences-item.c: + (preferences_item_update_editable_integer): + Free the caption. + +2002-04-17 Anders Carlsson <[email protected]> + + * eel/eel-background.c (eel_background_finalize): + Free details after using it, not before. + + * eel/eel-preferences.c: (eel_preferences_get_enum): + Free enums. + + * eel/eel-string-list.c: (eel_string_list_peek_nth): + * eel/eel-string-list.h: + Add eel_string_list_peek_nth which does not strdup the + string returned. + +=== eel 1.1.10 === + +2002-04-14 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version to 1.1.10 + +2002-04-14 Alexander Larsson <[email protected]> + + * eel/eel-mate-extensions.c (eel_mate_canvas_set_scroll_region): + Don't request_update all item unless the top left corner of + the scroll region changed. + +2002-04-13 Alexander Larsson <[email protected]> + + * eel/eel-mate-extensions.c (eel_mate_shell_execute): + Print a warning on failure. For debugging purposes. + +2002-04-12 Jody Goldberg <[email protected]> + + * eel/eel-mate-extensions.c (eel_mate_shell_execute) : no one uses + the return type anyway, remove it and make this a wrapper around + g_spawn_command_line_async. Fixes lots of problems. + +2002-04-12 Padraig O'Briain <[email protected]> + + * configure.in: + Update required GAIL version to 0.13 + + * eel/eel-accessibility.h: + gailtextutil.h has moved from util directory to libgail-util + + * eel/eel-accessibility.c: + Update calls to gail_text_util_get_substring as start_pos and end_pos + arguments have been changed from gint* to gint + +2002-04-07 Alexander Larsson <[email protected]> + + * eel/eel-preferences-item.[ch]: + Add EEL_PREFERENCE_ITEM_ENUMERATION_MENU_INTEGER type that + stores the integer value of the enum. This is needed for + the Caja thumbnail size limit. + +2002-04-04 Dave Camp <[email protected]> + + * eel/eel-preferences-item.c + (eel_preferences_item_set_description): set + text with mnemonics. + + * eel/eel-labeled-image.c + (eel_labeled_image_set_selected), + (eel_labeled_image_get_selected): impl. + + * eel/eel-gtk-extensions.c + (eel_pop_up_context_menu): tolerate a NULL event. + +2002-04-04 Michael Meeks <[email protected]> + + * eel/eel-accessibility.c + (eel_accessibility_set_description), + (eel_accessibility_set_name): impl. + +2002-04-03 Michael Meeks <[email protected]> + + * eel/eel-accessibility.c (get_quark_gobject), + (get_quark_accessible): share quark id's with + gobject-accessible. + (eel_accessibility_set_atk_object_return): only + hook up weak refs etc. for non GObjectAccessible + derived types - otherwise we double unref the + accessible. + +2002-04-02 Michael Meeks <[email protected]> + + * eel/eel-accessibility.c + (eel_accessible_text_get_type): impl. + (eel_accessibility_for_object): impl. + + * eel-2.0.pc.in (Requires): add gail. + +2002-04-01 Michael Meeks <[email protected]> + + * eel/eel-accessibility.c + (eel_accessibility_add_simple_text): impl. + (eel_accessibility_set_text_util): impl. + (get_simple_text): + + * configure.in: require gail >= 0.11 for accessibility. + +2002-03-30 Alexander Larsson <[email protected]> + + * test/test-eel-pixbuf-scale.c: + Don't double define DEST_WIDTH and DEST_HEIGHT. + +2002-03-29 Havoc Pennington <[email protected]> + + * eel/eel-mateconf-extensions.c (eel_mateconf_value_is_equal): don't use + private mateconf fields, and fix a bug in comparison of equality + of list values (if (a != NULL || b != NULL) return FALSE) + +2002-03-28 Michael Meeks <[email protected]> + + * eel/eel-labeled-image.c + (eel_labeled_image_toggle_button_new_from_file_name), + (eel_labeled_image_check_button_new_from_file_name), + (eel_labeled_image_button_new_from_file_name), + (eel_labeled_image_toggle_button_new), + (eel_labeled_image_check_button_new), + (eel_labeled_image_button_new): use the new button types + so we can update accessibility support there. + (eel_labeled_image_button_class_init): use to + override all button's get_accessibles. + (eel_labeled_image_toggle_button_get_type), + (eel_labeled_image_check_button_get_type), + (eel_labeled_image_button_get_type): impl. + (eel_labeled_image_get_accessible): handle all + button and plain label accessibility setup. + (get_image): impl. + (eel_labeled_image_accessible_image_get_size): impl. + (eel_labeled_image_accessible_get_name): impl. + (eel_labeled_image_accessible_image_interface_init), + (eel_labeled_image_accessible_class_init), + (eel_labeled_image_button_class_init), + (eel_labeled_image_get_accessible): impl. etc. + +2002-03-28 Alex Larsson <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.[ch]: + Added new function eel_gdk_pixbuf_scale_down() that does + fast downscaling. Speeds up thumbnailing. + Use it in eel_gdk_pixbuf_scale_down_to_fit(). + + * test/Makefile.am: + * test/test-eel-pixbuf-scale.c: + Tests for pixmap scaling. + +2002-03-28 Michael Meeks <[email protected]> + + * eel/eel-gtk-extensions.c + (eel_gtk_button_set_padding): many buttons (eg. + stock ones) do not have a GTK_MISC as a child, + don't do daft things to them. + + * test/test-eel-labeled-image.c + (labeled_image_button_window_new): add a plain + labeled image. + +2002-03-28 Dave Camp <[email protected]> + + * eel/eel-labeled-image.c + (eel_labeled_image_set_can_focus): impl. + (eel_labeled_image_class_init): add activate + signal & bindings. + (eel_labeled_image_expose_event): render + selection and focus. + +2002-03-28 Michael Meeks <[email protected]> + + * test/test-eel-widgets.c + (create_pixbuf): use DATADIR instead of a hard + coded path. + (test_ok_dialog): impl. + (main): upd. + Add window titles to elucidate function. + + * TODO: clean & add a11y bits. + + * test/test-eel-image-chooser.c: ditto. + + * eel/eel-caption-table.c + (eel_caption_table_set_row_info): set role on + invisible entries' accessibles to 'password'. + +2002-03-27 Michael Meeks <[email protected]> + + * eel/eel-accessibility.h + (EEL_ACCESSIBLE_FACTORY): don't auto-generate the + type name. + + * eel/eel-accessibility.c + (eel_accessibility_weak_unref): notify defunct. + +2002-03-26 Michael Meeks <[email protected]> + + * eel/eel-accessibility.c + [ cut & paste helpers from matecomponent until gail is stable ]: + (eel_accessibility_set_atk_object_return), + (eel_accessibility_get_atk_object): impl. + (eel_a11_weak_unref, get_quark_accessible): impl. + (eel_accessibility_create_derived_type): impl. + (eel_accessibility_get_atk_object): impl. + + * eel/eel-accessibility.h + (EEL_ACCESSIBLE_FACTORY, EEL_WIDGET_SET_FACTORY): + copy from gail - we need them. + +=== eel 1.1.9 === + +2002-03-24 Alexander Larsson <[email protected]> + + * configure.in: Bump version to 1.1.9 + + * NEWS: bump version. + +2002-03-22 Dave Camp <[email protected]> + + * eel/eel-gtk-extensions.c: (eel_gtk_viewport_get_visible_rect), + (eel_gtk_viewport_scroll_to_rect): New functions. + * eel/eel-gtk-extensions.h: Prototypes for the eel_gtk_viewport + functions. + * eel/eel-wrap-table.c: (eel_scrolled_wrap_table_new): New + function to create a wrap table inside of a scrolled window. + (eel_wrap_table_add), (eel_wrap_table_remove): If the wrap table + is scrolled, connect to focus_in_event. + (wrap_table_child_focus_in): New function, scrolls to the focused + item in the viewport. + * eel/eel-wrap-table.h: Prototype for eel_scrolled_wrap_table_new. + +2002-03-18 Anders Carlsson <[email protected]> + + * eel/eel-string.c: + Only include eel-lib-self-check-functions.h if + EEL_OMIT_SELF_CHECK isn't defined. + + * eel/eel-pango-extensions.c: + Only include eel-lib-self-check-functions.h if + EEL_OMIT_SELF_CHECK isn't defined. + + * eel/Makefile.am: + * eel/eel-accessibility.c: + (eel_accessibility_set_up_label_widget_relation): + * eel/eel-accessibility.h: + * eel/eel-caption-table.c: (eel_caption_table_resize): + * eel/eel-caption.c: (eel_caption_set_child): + Add new accessibility utility functions and have our + label-widget composite widgets use them. + + * test/test-eel-widgets.c: (create_pixbuf): + Update path due to e-h changes. + +2002-03-17 Darin Adler <[email protected]> + + * configure.in: Bump required versions. + +=== eel 1.1.8 === + +2002-03-17 Alexander Larsson <[email protected]> + + * configure.in: Bump version to 1.1.8 + + * NEWS: Bump version. + + * eel/eel-vfs-extensions.c: (eel_format_uri_for_display_internal), + (eel_escape_high_chars), (eel_make_uri_from_input_internal), + (eel_format_uri_for_display), (eel_make_uri_from_input), + (eel_self_check_vfs_extensions): + Handle utf8 and G_BORKEN_FILENAMES better. + +2002-03-13 Gregory Leblanc <[email protected]> + + * eel.spec.in: New one, from Chris Chabot + +2002-03-11 Michael Meeks <[email protected]> + + * eel/eel-mate-extensions.c + (eel_matecomponent_make_registration_id): impl. + +2002-03-11 Anders Carlsson <[email protected]> + + * eel/eel-gdk-extensions.c: + * eel/eel-gdk-extensions.h: + Remove the now unneeded eel_set_mini_icon function. + +=== eel 1.1.7 === + +2002-03-10 Darin Adler <[email protected]> + + * NEWS: Bump version. + +2002-03-09 Alexander Larsson <[email protected]> + + * eel/eel-image-table.c: (image_table_emit_signal), + (image_table_handle_motion), (ancestor_button_press_event), + (ancestor_button_release_event): + * eel/eel-image-table.h (EelImageTableEvent): + Add the original GdkEvent to the EelImageTableEvent. You + may need e.g. the time from the event. (Needed to fix + stuck grab in caja.) + +2002-03-08 Darin Adler <[email protected]> + + * eel/eel-preferences.c: + (eel_preferences_set_emergency_fallback_string_list): Add a + g_slist_reverse so that emergency fallback string lists are + in the proper order. + + * eel/eel-background.c: Tweak formatting. + +2002-03-07 Anders Carlsson <[email protected]> + + * configure.in: Bump version to 1.1.7 + + * eel/eel-preferences-item.c: + (preferences_item_update_editable_string), + (preferences_item_create_editable_string), + (eel_preferences_item_new), + (preferences_item_update_displayed_value), + (eel_preferences_item_set_description): + * eel/eel-preferences-item.h: + Add EEL_PREFERENCES_ITEM_EDITABLE_PASSWORD_STRING type. + + * eel/eel-text-caption.c: (eel_text_caption_set_expand_tilde), + (eel_text_caption_set_visibility): + * eel/eel-text-caption.h: + Add eel_text_caption_set_visibility which controls the visibility + of the GtkEntry. + +2002-03-06 Darin Adler <[email protected]> + + * eel/eel-preferences-box.c: (eel_preferences_dialog_new): Make the + button say "Close" instead of "OK". + +2002-03-06 Darin Adler <[email protected]> + + * eel/eel-cell-renderer-pixbuf-list.c: + (eel_cell_renderer_pixbuf_list_class_init): + * eel/eel-labeled-image.c: (eel_labeled_image_class_init): + Remove strings we really don't need; lets not waste time translating + these since no one ever sees them. + + * eel/eel-password-dialog.c: (eel_password_dialog_new): Tweak comment. + + * eel/eel-preferences-box.c: Add mate-i18n.h include. Not sure why + this wasn't needed before. + + * eel/eel-preferences.c: Remove unneeded mate-i18n.h include. + +2002-03-06 Darin Adler <[email protected]> + + * eel/eel-preferences-box.c: (eel_preferences_box_new): + * eel/eel-wrap-table.c: (eel_wrap_table_class_init): + Take out some strings that we don't really need to translate. + +2002-03-06 Michael Meeks <[email protected]> + + * eel/eel-preferences-item.c + (preferences_item_update_enumeration_radio), + (preferences_item_update_enumeration_menu), + (enumeration_radio_changed_callback), + (enumeration_menu_changed_callback): upd. for enums + + * eel/eel-preferences.c + (eel_preferences_add_auto_enum): impl. + (preferences_entry_update_auto_storage): upd. for enums. + +2002-03-05 Michael Meeks <[email protected]> + + * eel/eel-preferences.c + (eel_preferences_get_enum, eel_preferences_set_enum): impl. + + * eel/eel-enumeration.c (eel_enumeration_get_sub_name), + (eel_enumeration_get_sub_value): impl. + +=== eel 1.1.6 === + +2002-03-04 Darin Adler <[email protected]> + + * eel/eel-stock-dialogs.c: (show_message_dialog): Put additional button to + the left of the other buttons. Doing it this way is pretty nasty, but I + don't know any better way to match what the HI folks want. + +2002-03-03 Alexander Larsson <[email protected]> + + * NEWS: + * configure.in: + Bump version. + + * eel/eel-background.h: + Add eel_background_set_is_constant_size() and + eel_background_get_pixmap_and_color() + Remove eel_background_is_too_complex_for_gtk_style(). + + * eel/eel-background.c: (eel_background_init), + (eel_background_finalize), (get_pixmap_size), (eel_background_unrealize), + (eel_background_ensure_realized), (eel_background_get_pixmap_and_color), + (draw_background_callback), (eel_widget_background_changed): + Add bitmap generation and caching capability. + (eel_background_set_is_constant_size): set if windows don't change size, + used by the caja desktop window. + (eel_background_is_too_complex_for_gtk_style); Remve. Not used anymore. + (eel_background_receive_dropped_background_image): Remove old reset.png hack. + + * eel/eel-background-style.c: + (eel_background_style_finalize): unref background + (eel_background_style_draw_flat_box), (eel_background_style_set_background): + Use cached pixmaps from EelBackground. + (eel_background_style_new): Set the background. No need to mess + with the base style. + (eel_background_style_clone): Need to clone the background too. + (eel_background_style_class_init): add clone and set_background virtual + methods + +2002-03-03 Anders Carlsson <[email protected]> + + * eel/eel-preferences-item.c: + (preferences_item_create_enumeration_list), + (preferences_item_create_enumeration_menu): + * eel/eel-string-picker.c: (eel_string_picker_set_string_list), + (eel_string_picker_insert_separator): + * eel/eel-string-picker.h: + Create the string list first and then insert it into the + string picker, instead of rebuilding the option menu + on every insert. + +2002-03-01 Darin Adler <[email protected]> + + * eel/eel-glib-extensions.h: + * eel/eel-glib-extensions.c: (eel_g_object_list_ref), + (eel_g_object_list_unref), (eel_g_object_list_free), + (eel_g_object_list_copy), (eel_add_weak_pointer), + (eel_remove_weak_pointer): New names for old functions + from eel-gtk-extensions.c. + + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: Remove old functions. + +2002-02-28 Darin Adler <[email protected]> + + * eel/eel-image-chooser.c: (eel_image_chooser_set_selected_row): + Handle -1 by deselecting all rows. + +2002-02-28 Darin Adler <[email protected]> + + * eel/eel-mate-extensions.c: (icon_selected): Since this is no longer + a callback, get rid of the widget parameter. + (icon_cancel_pressed): Get rid of the widget parameter. + (entry_activated_callback): Check result of stat. + (eel_mate_icon_selector_new): Store a pointer to the dialog that we + can use later to close it. + +2002-02-27 Anders Carlsson <[email protected]> + + * eel/eel-password-dialog.c: (dialog_show_callback), + (eel_password_dialog_set_readonly_username): + If the username is readonly, focus the password entry. Otherwise + focus the username entry. Fixes #72801. + +2002-02-27 Darin Adler <[email protected]> + + * eel/eel-gdk-extensions.h: + * eel/eel-gdk-extensions.c: (eel_gdk_rectangle_contains_rectangle): New. + + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: + (eel_gtk_tree_view_cell_is_completely_visible): New. + + * eel/eel-gdk-pixbuf-extensions.c: (eel_cancel_gdk_pixbuf_load): + We need to close the loader even if we are just dropping it on the floor. + Not sure that's good design, but I want to make gdk-pixbuf happy. + + * eel/eel-image-chooser.c: (eel_scrolled_image_chooser_show_selected_row): + Only scroll if row isn't already completely visible. + +=== eel 1.1.5 === + +2002-02-25 Anders Carlsson <[email protected]> + + * eel/eel-pango-extensions.c: + (eel_pango_font_description_get_largest_fitting_font_size): + * eel/eel-pango-extensions.h: + Implement eel_pango_font_description_get_largest_fitting_font_size. + +2002-02-22 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel.h: + * eel/eel-generous-bin.c: Re-add. + * eel/eel-generous-bin.h: Re-add. + +2002-02-21 Michael Meeks <[email protected]> + + * eel/eel-pango-extensions.c + (eel_pango_layout_fit_to_dimensions): impl. + + * eel/eel-gdk-pixbuf-extensions.c + (eel_gdk_pixbuf_draw_layout_clipped): document. + +2002-02-22 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel.h: + * eel/eel-generous-bin.c: Remove. + * eel/eel-generous-bin.h: Remove. + * eel/eel-region.c: Remove. + * eel/eel-region.h: Remove. + + * eel/eel-image-table.c: Remove include "eel-region.h". + +2002-02-22 Darin Adler <[email protected]> + + * eel/eel-glib-extensions.h: + * eel/eel-glib-extensions.c: + Remove unused eel_g_ptr_array_* functions. + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: + Remove unused eel_mate_canvas_world_to_window_rectangle. + (eel_mate_canvas_world_to_widget_rectangle), + (eel_mate_canvas_widget_to_world), + (eel_mate_canvas_world_to_widget): + Rename to reflect a clearer conception of these. They map to the + widget coordinate system. Clearer than trying to talk about + widget->window vs. layout->bin_window . + + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: + Remove unused eel_gtk_style_shade, + eel_get_window_list_ordered_front_to_back, + eel_gtk_widget_standard_realize, + eel_gtk_bin_standard_size_allocate, + eel_gtk_bin_standard_size_request. + (eel_gtk_widget_get_button_event_location): New. + (eel_gtk_widget_get_motion_event_location): New. + + * test/Makefile.am: + * test/dumb-box.c: Remove. + * test/dumb-box.h: Remove. + * test/test-eel-gtk-style.c: + Just keep this compiling. Not clear if it still is useful. + + * RENAMING: at_exit -> at_shutdown + +2002-02-21 Darin Adler <[email protected]> + + * AUTHORS: + * MAINTAINERS: + Add some people. + + * eel/eel-gdk-pixbuf-extensions.c: + (eel_gdk_pixbuf_draw_layout_clipped): + Draw nothing if the rectangle is empty or "less than empty" + rather than asserting. + +2002-02-20 David Emory Watson <[email protected]> + + eel/eel-preferences-box.c: + (eel_preferences_box_init): Remove connect. + (user_level_changed_callback): Removed. + +2002-02-20 Michael Meeks <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c + (eel_gdk_pixbuf_draw_layout): split out into + (eel_gdk_pixbuf_draw_layout_clipped): here, new method. + +2002-02-20 Michael Meeks <[email protected]> + + * eel/eel-wrap-table.c (eel_wrap_table_class_init): + do an eel_type_init. + + * eel/eel-types.c (eel_type_init): protect vs. + double init. + +2002-02-19 jacob berkman <[email protected]> + + * eel/eel-mate-extensions.c (get_terminal_command_prefix): + mate-terminal 2 does not accept --login or --start-factory-server + + * eel/eel-gtk-extensions.[ch] (eel_gtk_selection_data_*_deep): + remove as these are fixed in GTK 2.0 (fixes a double free crash) + +2002-02-19 Michael Meeks <[email protected]> + + * eel/eel-preferences-box.c + (category_list_row_activated_callback): rename to + (category_list_selection_changed): this & use the selection's + changed signal instead. + (eel_preferences_box_new): upd. + (preferences_box_category_list_recreate): upd. + +2002-02-18 Gediminas Paulauskas <[email protected]> + + * configure.in: remove MATE_COMMON_INIT, MATE_PLATFORM_MATE_2 + +2002-02-16 Alexander Larsson <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c (eel_gdk_pixbuf_draw_to_pixbuf_alpha): + Add G_OBJECT() casts for g_object_ref/unref so we don't give warnings + due to pixbuf being const. + +2002-02-16 David Emory Watson <[email protected]> + + * NEWS: Bump version. + * configure.in: Bump version. + + * eel/eel-gdk-extensions.h: + * eel/eel-gdk-extensions.c: + (eel_gdk_color_parse): New. + (eel_gdk_color_parse_with_white_default): call eel_gdk_color_parse (). + +2002-02-15 Michael Meeks <[email protected]> + + * eel/Makefile.am: add deprecated flags + permanantly. + + * eel/eel-gdk-extensions.c + (eel_gdk_choose_foreground_color), + (eel_gdk_gc_choose_foreground_color): prune, + unused, and funky color handling. + + * test/test-eel-pixbuf-tile.c: + update image paths to include the prefix. + + * eel/eel-debug-drawing.c + (eel_debug_draw_rectangle_and_cross): make sure + we allocate the color. + +2002-02-13 Michael Meeks <[email protected]> + + * eel/eel-image-table.c + (image_table_peek_clear_gc): upd. color handling. + (eel_image_table_set_smooth_background_color), + (eel_image_table_set_is_smooth): kill, unused. + (eel_image_table_expose_event): kill. + (image_table_foreach_child_subtract_content), + (image_table_peek_clear_gc): remove + + * eel/eel-gdk-pixbuf-extensions.c + (pixbuf_destroy_callback), + (eel_gdk_pixbuf_list_ref, eel_gdk_pixbuf_list_free): + use g_object_ref/unref instead of gdk_pixbuf_~ + + * eel/eel-gdk-extensions.c + (eel_fill_rectangle_with_color): remove, color + handling not pleasant, and not used. + (eel_gdk_gc_choose_foreground_color): upd. + + + * eel/eel-debug-drawing.c + (eel_debug_draw_rectangle_and_cross): upd. color + handling. + +2002-02-12 Michael Meeks <[email protected]> + + * eel/eel-stock-dialogs.h (eel_create_info_dialog): + fix header comment. + +2002-02-12 Darin Adler <[email protected]> + + * eel/eel-wrap-table.c: (eel_wrap_table_class_init): + Register enums in here. This gets rid of the last place + we had MATE2_CONVERSION_COMPLETE. + + * eel/maketypes.awk: Fix to make EEL_TYPE_X instead of + EEL_TYPE_EEL_X. + +2002-02-12 Tõivo Leedjärv <[email protected]> + + * configure.in: Added et to ALL_LINGUAS. + +2002-02-12 Michael Meeks <[email protected]> + + * eel/eel-preferences-box.c + (eel_preferences_box_new): create a tree view & + list model + (category_list_select_row_callback): rename to + (category_list_row_activated_callback): this & re-write.. + (preferences_box_find_row): re-write. + (preferences_model_foreach_find): impl. + (eel_preferences_box_rename_pane): re-write. + (eel_preferences_box_finalize): unref the category model. + (eel_preferences_dialog_new): show after + populating with panes, so we don't get re-sizing jerkiness + on the list. + (preferences_box_select_pane): tolerate setting the name + with the existing string. + + * eel/eel-text-caption.c: remove unused TEXT_CAPTION_INVALID + + * eel/eel-password-dialog.c: remove unused DIALOG_OK_BUTTON + +2002-02-12 Anders Carlsson <[email protected]> + + * eel/eel-canvas-rect.c (eel_canvas_rect_realize): Surround + variable declarations with HAVE_RENDER. + +2002-02-10 Darin Adler <[email protected]> + + * configure.in: Require newer libxml where location of xml memory + calls has moved. + * eel/eel-xml-extensions.c: Remove unneeded include of xmlmemory.h. + +==== eel 1.1.4 ==== + +2002-02-09 Darin Adler <[email protected]> + + * NEWS: Bump version. + * configure.in: Bump version. + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): + Add mate-vfs-modules to list of domains. + +2002-02-08 Anders Carlsson <[email protected]> + + * eel/eel-canvas-rect.c: (eel_canvas_rect_realize), + (eel_canvas_rect_unrealize): + Chain to parent implementations. + +2002-02-06 Darin Adler <[email protected]> + + * eel/Makefile.am: Turn on MATE_DISABLE_DEPRECATED and + EEL_COMPILATION. Get rid of eel-gobject-extensions.[ch]. + + * eel/eel-art-gtk-extensions.h: + * eel/eel-art-gtk-extensions.c: (eel_gdk_window_get_bounds), + (eel_gdk_window_get_screen_relative_bounds), + (eel_gtk_widget_get_bounds), (eel_gtk_widget_get_dimensions), + (eel_gtk_widget_get_preferred_dimensions), + (eel_gdk_window_clip_dirty_area_to_screen), + (eel_gdk_window_get_dimensions), (eel_gdk_get_pointer_position): + Eliminate misguided use of const. Fix a few deprecated things. + + * eel/eel-background-style.c: (eel_gdk_window_update_sizes): + Use gdk_drawable_get_size instead of gdk_window_get_size. + + * eel/eel-background.c: (draw_background_callback): Use g_object_unref + instead of gdk_gc_unref. + (eel_get_widget_background): Use g_signal_connect_object instead + of eel_signal_connect_object_while_alive. + + * eel/eel-debug-drawing.c: (eel_debug_draw_rectangle_and_cross): + Use g_object_unref instead of gdk_gc_unref. + + * eel/eel-debug.c: Turn this back on. + + * eel/eel-mate-extensions.c: (eel_mate_icon_selector_new): Get + rid of a misguided use of eel_signal_connect_while_alive -- plain + old g_signal_connect works fine. + + * eel/eel-gobject-extensions.c: Remove. + * eel/eel-gobject-extensions.h: Remove. + + * eel/eel-image-table.c: (eel_image_table_unrealize): Use g_object_unref + instead of gdk_gc_unref. + + * eel/eel-labeled-image.c: (eel_labeled_image_check_button_new): Get + rid of some misguided use of eel_signal_connect_while alive -- plain + old g_signal_connect works fine. + + * eel/eel-password-dialog.c: (eel_password_dialog_new): Get + rid of some misguided use of eel_signal_connect_while alive -- plain + old g_signal_connect works fine. + + * eel/maketypes.awk: Grab a new copy from gtk+. Is there a way to do + this without copied and pasted code? + * eel/eel-types.c: (eel_type_init): Change name to EEL_TYPE_N_BUILTINS. + + * test/Makefile.am: Turn on G_DISABLE_DEPRECATED, GDK_DISABLE_DEPRECATED, + GTK_DISABLE_DEPRECATED, MATE_DISABLE_DEPRECATED. + + * test/test-eel-background.c: (main): Turn of GtkCTree code that was + already half-disabled. + + * test/test-eel-canvas-items.c: (item_event), (setup_item), + (create_canvas_items), (create_canvas): gtk_signal_connect -> g_signal_connect. + Remove some colormap stuff. gtk_widget_set_usize -> gtk_widget_set_size_request. + gtk_window_set_policy -> gtk_window_set_resizable. + * test/test-eel-gtk-style.c: (color_box_expose_event): gdk_gc_unref -> g_object_unref. + (pixmap_box_expose_event): gdk_window_get_size -> gdk_drawable_get_size. + * test/test.c: (test_window_new): gtk_window_set_policy -> gtk_window_set_resizable + +2002-02-06 Michael Meeks <[email protected]> + + * eel/eel-wrap-table.c + (eel_wrap_table_class_init), + (eel_wrap_table_set_property), + (eel_wrap_table_get_property): ditto + + * eel/makeenums.pl (parse_entries): output + GEnumValue not GtkEnumValue - this should use + glib-mkenums though. + + * eel/eel-gtk-extensions.c + (eel_gtk_signal_connect_full_while_alive), + (eel_gtk_signal_connect_free_data_custom): + port deprecated bits. + (eel_gtk_class_name_make_like_existing_type): + remove - unused & not portable. + + * eel/eel-mate-extensions.c + (eel_mate_icon_selector_new): remove all + deprecated bits. + + * eel/eel-dateedit-extensions.c + (eel_mate_date_edit_get_date_as_string): ditto. + + * eel/eel-labeled-image.c + (eel_labeled_image_class_init), + (eel_labeled_image_set_property), + (eel_labeled_image_get_property), + (eel_labeled_image_check_button_new): ditto. + + * eel/eel-preferences-item.c + (preferences_item_update_displayed_value), + (preferences_item_update_displayed_value): ditto. + + * eel/eel-stock-dialogs.c + (timed_wait_callback): ditto. + +2002-02-05 Michael Meeks <[email protected]> + + * eel/eel-dateedit-extensions.c + (eel_mate_date_edit_get_date_as_string): add + deprecated comment. + + * eel/eel-background.c + (eel_background_reset), + (eel_background_set_color), + (eel_get_widget_background), + (eel_background_set_image_placement), + (eel_background_load_image_callback), + (eel_background_cancel_loading_image), + (eel_background_set_image_uri_helper), + (set_image_and_color_image_loading_done_callback), + (eel_background_class_init): build with deprecated + things disabled. + + * eel/eel-radio-button-group.c + (eel_radio_button_group_class_init): ditto. + + * eel/eel-preferences-item.c + (preferences_item_update_custom), + (eel_preferences_item_set_description): ditto. + + * eel/eel-caption-table.c + (eel_caption_table_class_init, entry_activate), + (eel_caption_table_resize): ditto. + + * eel/eel-password-dialog.c + (eel_password_dialog_new): ditto. + + * eel/eel-gtk-extensions.c + (handle_standard_close_accelerator), + (eel_gtk_menu_set_item_visibility), + (alive_disconnecter), + (eel_gtk_signal_connect_while_realized): ditto. + + * eel/eel-mate-extensions.c + (try_terminal_command), + (eel_mate_icon_selector_new): ditto. + + * eel/eel-ellipsizing-label.c + (eel_ellipsizing_label_new): ditto. + + * eel/eel-text-caption.c + (eel_text_caption_class_init), + (eel_text_caption_set_editable), + (eel_text_caption_init, eel_text_caption_init): ditto. + + * eel/eel-string-picker.c + (eel_string_picker_class_init): ditto. + + * eel/eel-stock-dialogs.c + (timed_wait_delayed_close_timeout_callback), + (eel_show_info_dialog_with_details), + (delete_event_callback): ditto. + +2002-02-05 Darin Adler <[email protected]> + + * eel/eel-clist.c: Remove. + * eel/eel-clist.h: Remove. + * eel/eel-ctree.c: Remove. + * eel/eel-ctree.h: Remove. + * eel/eel-dnd.c: Move back into Caja. + * eel/eel-dnd.h: Move back into Caja. + * eel/eel-list-column-title.c: Remove. + * eel/eel-list-column-title.h: Remove. + * eel/eel-list.c: Remove. + * eel/eel-list.h: Remove. + * eel/eel.h: Housekeeping. + * eel/Makefile.am: Housekeeping. + +==== eel 1.1.3 ==== + +2002-02-04 Darin Adler <[email protected]> + + * NEWS: Update for 1.1.3. + * .cvsignore: Don't ignore the tarballs. + + * eel/eel-pango-extensions.c: (eel_string_ellipsize_middle): + * eel/eel-wrap-table.c: (wrap_table_layout): Fixes to make things + compile with gcc 3.0.2, based on a patch contributed by Anush + <[email protected]>. + +2002-02-04 Laszlo Peter <[email protected]> + + * COPYING: change to LGPL + + * eel/eel-background-style.c eel/eel-background-style.h + eel/eel-background.c eel/eel-background.h + eel/eel-dateedit-extensions.c eel/eel-dateedit-extensions.h + eel/eel-debug-drawing.c eel/eel-debug-drawing.h eel/eel-debug.c + eel/eel-debug.h eel/eel-enumeration.c eel/eel-enumeration.h + eel/eel-graphic-effects.h eel/eel-gtk-macros.h + eel/eel-lib-self-check-functions.c + eel/eel-lib-self-check-functions.h eel/eel-list-column-title.c + eel/eel-list-column-title.h eel/eel-region.c eel/eel-region.h + eel/eel-self-checks.c eel/eel-self-checks.h + eel/eel-string-list.c eel/eel-string-list.h: correct licensing + information in the headers by permission of the Copyright holders. + +Mon Feb 4 11:24:21 2002 Owen Taylor <[email protected]> + + * eel/eel-mate-extensions.c (dialog_response_callback): + Labels need a statement after them. (Fixes -Werror problem + with recent GCC.) + +2002-01-30 Darin Adler <[email protected]> + + * eel/eel-preferences-item.h: + * eel/eel-preferences-item.c: + (preferences_item_update_font), + (font_changed_callback), (preferences_item_create_font), + (eel_preferences_item_new), + (preferences_item_update_displayed_value), + (eel_preferences_item_set_description): + Make EEL_PREFERENCE_ITEM_FONT use the Eel font picker, and get + rid of all support for EEL_PREFERENCE_ITEM_SMOOTH_FONT. + +2002-01-30 Darin Adler <[email protected]> + + * configure.in: Bump to 1.1.3 since we have an API change. + + * eel/eel-dnd.h: start_x and start_y are in window coordinates, + not world coordinates. + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: + (eel_mate_canvas_world_to_canvas_window_rectangle): New. + (eel_mate_canvas_canvas_window_to_world): New. + (eel_mate_canvas_world_to_canvas_window): New. + +==== eel 1.1.2 ==== + +2002-01-29 Darin Adler <[email protected]> + + * eel/eel-pango-extensions.c: (eel_self_check_ellipsize), + (eel_self_check_pango_extensions): Turn off ellipsizing self-checks + because they are failing for me. + +2002-01-29 Darin Adler <[email protected]> + + * NEWS: Update for 1.1.2 release. + +2002-01-28 Gediminas Paulauskas <[email protected]> + + * eel/eel-glib-extensions.c, eel/eel-glib-extensions.h: + (eel_g_list_copy): remove, it was moved into glib. + * eel/eel-gtk-extensions.c, eel/eel-gtk-extensions.h: + (eel_gtk_window_present): remove, it was moved into gtk+. + +2002-01-28 Darin Adler <[email protected]> + + * eel/Makefile.am: Use LC_ALL instead of LC_COLLATE. + * eel/eel-mate-extensions.c: (eel_mate_canvas_item_send_behind): + Oops, it was sending things in front. + +2002-01-27 Anders Carlsson <[email protected]> + + * eel/eel-stock-dialogs.c (eel_run_simple_dialog): Start with + a response id that is 0. + +2002-01-27 Darin Adler <[email protected]> + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: (eel_mate_canvas_item_send_behind): New. + +2002-01-27 Alexander Larsson <[email protected]> + + * acconfig.h: + Add HAVE_RENDER + + * configure.in: + Add checks for Xrender + + * eel/Makefile.am: + Add RENDER_LIBS and eel-canvas-rect.[ch] + + * eel/eel-canvas-rect.[ch]: + New type EelCanvasRect. Implemented for the Caja + selection rectangle. + + * eel/eel-lib-self-check-functions.h: + Add eel_self_check_canvas_rect to list of tests + + * test/test-eel-canvas-items.c: + Add a test of the eel canvas items. + + * test/Makefile.am: + Build test-eel-canvas-items + +2002-01-24 Darin Adler <[email protected]> + + * eel/eel-pango-extensions.h: + * eel/eel-pango-extensions.c: (eel_pango_ft2_get_context): New. + + * eel/eel-gtk-extensions.c: (create_pango_ft2_context): Use + the new eel_pango_ft2_get_context. + +2002-01-23 Peteris Krisjanis <[email protected]> + + * eel/configure.in: added lv to ALL_LINGUAS + +2002-01-22 Darin Adler <[email protected]> + + * eel/eel-font-picker.c: (font_picker_get_index_for_font): + Handle NULL family_name. + +2002-01-21 Darin Adler <[email protected]> + + * eel/eel-font-picker.h: + * eel/eel-font-picker.c: + * test/test-eel-font-picker.c: + Rewrite to use Pango -- first cut, not done yet. + + * eel/eel-preferences-item.c: + (preferences_item_create_smooth_font): Pass NULL for the PangoContext. + +2002-01-19 Gediminas Paulauskas <[email protected]> + + * eel/eel-glib-extensions.c: (eel_strdup_strftime): + Convert format string into locale encoding at start, and convert back + into utf-8 the result. + +2002-01-19 Darin Adler <[email protected]> + + * test/test-eel-gtk-style.c: (style_get_color), (style_get_gc): + Fix mistake in that last change that didn't compile. + +2002-01-19 Darin Adler <[email protected]> + + * test/test-eel-gtk-style.c: (style_get_color), (style_get_gc): + Tweak code so gcc 3.x doesn't give warnings. + +2002-01-18 Darin Adler <[email protected]> + + * TODO: Remove some already-done items. + + * eel/check-program.c: (main): Use the new eel_debug_shut_down. + + * eel/eel-debug.h: + * eel/eel-debug.c: (eel_debug_shut_down), + (eel_debug_call_at_shutdown), + (eel_debug_call_at_shutdown_with_data): New. + + * eel/eel-debug-drawing.c: (eel_debug_show_pixbuf): + * eel/eel-enumeration.c: (enumeration_table_get): + * eel/eel-font-picker.c: (global_font_list_get): + * eel/eel-mateconf-extensions.c: (eel_mateconf_client_get_global): + * eel/eel-gdk-pixbuf-extensions.c: + (eel_gdk_pixbuf_get_global_buffer): + * eel/eel-glib-extensions.c: (eel_g_hash_table_new_free_at_exit): + * eel/eel-preferences.c: (preferences_global_table_get_global): + Switch from g_atexit to eel_debug_call_at_shutdown. + + * eel/eel-image-table.h: + * eel/eel-image-table.c: (eel_image_table_class_init), + (eel_image_table_init), (eel_image_table_new): Get rid of + set_is_smooth signal, eel_image_table_set_is_smooth, and use of + eel_smooth_widget calls. + + * eel/eel-image-with-background.c: Remove. + * eel/eel-image-with-background.h: Remove. + * eel/eel-image.c: Remove. + * eel/eel-image.h: Remove. + * eel/eel-smooth-widget.c: Remove. + * eel/eel-smooth-widget.h: Remove. + * eel/eel-viewport.c: Remove. + * eel/eel-viewport.h: Remove. + + * eel/Makefile.am: Kill eel-image-with-background.[ch], + eel-image.[ch], eel-smooth-widget.[ch], eel-viewport.[ch]. + * eel/eel.h: Ditto. + + * eel/eel-labeled-image.c: (eel_labeled_image_get_arg), + (eel_labeled_image_add), (eel_labeled_image_remove), + (labeled_image_ensure_image), (eel_labeled_image_set_pixbuf), + (eel_labeled_image_set_pixbuf_from_file_name): Port from EelImage + to GtkImage. + + * eel/eel-radio-button-group.c: + (eel_radio_button_group_set_entry_pixbuf): Port from EelImage to + GtkImage. + + * test/test-eel-image-table.c: (image_table_new_scrolled): Port + from EelViewport to GtkViewport. + + * THANKS: Fix typo. + * eel/eel-wrap-table.c: Fix comment format. + + * test/test-eel-image-background.c: Remove. + * test/test-eel-image-simple.c: Remove. + * test/test-eel-viewport-constraint.c: Remove. + + * test/.cvsignore: Remove obsolete tests. + * test/Makefile.am: Remove obsolete tests. + + * test/test-eel-image-chooser.c: (main): Remove eel_smooth_widget + call. + + * test/test.c: Remove EelImage code. + +2002-01-17 Darin Adler <[email protected]> + + * eel/eel-pango-extensions.c: + (eel_pango_layout_set_text_ellipsized): Soften an assert to + a g_return. + +2002-01-17 Darin Adler <[email protected]> + + * eel/Makefile.am: Fix parallel builds by getting rid of an + ill-advised use of a full path to the library. + + * eel/eel-pango-extensions.c: (eel_string_ellipsize_start), + (eel_string_ellipsize_end): These were reversed. + + * test/.cvsignore: test-eel-ellipsizing + +2002-01-17 Anders Carlsson <[email protected]> + + * eel/eel-cell-renderer-pixbuf-list.h: Fix warning. + + * eel/Makefile.am: + Add eel-cell-renderer-pixbuf-list.[ch] + + * eel/eel-background-style.c: (eel_background_style_draw_flat_box): + Special case GtkTreeView. + + * eel/eel-cell-renderer-pixbuf-list.c: + * eel/eel-cell-renderer-pixbuf-list.h: + Add these. + + * eel/eel-stock-dialogs.c: (show_ok_dialog): + Set default response to GTK_RESPONSE_OK. + +2002-01-16 Darin Adler <[email protected]> + + * configure.in: Bump version to 1.1.2. + +2002-01-16 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_draw_layout): + Fix case where clipped height or width turns out to be 0. + * eel/eel-gtk-macros.h: Remove some unused macros, deprecate + others. + * eel/eel-pango-extensions.c: Remove extra include. + * eel/eel-preferences-box.c: (eel_preferences_dialog_new): + Don't try to eel_gtk_window_set_up_close_accelerator, since it's + a dialog that already has a close accelerator. + +2002-01-11 Havoc Pennington <[email protected]> + + * eel/eel.h: add eel-pango-extensions.h + + * eel/eel-pango-extensions.c + (eel_pango_layout_set_text_ellipsized): put ellipsize code back in + here and port to Pango + + * eel/eel-ellipsizing-label.c: re-enable ellipsization in the + widget, change bad hack implementation to different bad hack + implementation to avoid queueing a resize in size_allocate + (real_style_set): remove style_set handler because it results in a + queue_resize anyway + (real_size_allocate): auto-select ellipsize mode based on label + alignment + +==== eel 1.1.1 ==== + +2002-01-15 Darin Adler <[email protected]> + + * NEWS: Get ready for eel 1.1.1 release. + * eel/Makefile.am: Fix makeenums.pl stuff so it works when + srcdir != destdir. + +2002-01-15 Darin Adler <[email protected]> + + * eel/eel-gtk-extensions.c: (create_pango_ft2_context): + Tiny tweak to the code -- makes it more readable, I think. + +2002-01-09 Alexander Larsson <[email protected]> + + * eel/eel-gtk-extensions.c (create_pango_ft2_context): + Copy the font description from the base_context. + +Thu Jan 10 10:53:52 2002 Owen Taylor <[email protected]> + + * eel/eel-mate-extensions.c + (eel_mate_canvas_world_to_window_rectangle): Remove + unused variable so things compile. + +2002-01-09 Darin Adler <[email protected]> + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: + Remove mate_win_hints_*. + + * eel/eel-list.c: (eel_list_destroy): Something I missed in the + last change -- forgot to NULL out details. + +2002-01-09 Darin Adler <[email protected]> + + * eel/eel-list.c: (eel_list_destroy), + (unschedule_keyboard_row_reveal): + Protect against double destroys, but do it in an inelegant way, + which shouldn't matter, since we plan to remove this class. + +2002-01-09 Darin Adler <[email protected]> + + * eel/eel-gdk-font-extensions.c: Remove. + * eel/eel-gdk-font-extensions.h: Remove. + +2002-01-08 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel-ctree.c: + * eel/eel-ellipsizing-label.c: + * eel/eel-lib-self-check-functions.h: + * eel/eel-list.c: + * eel/eel.h: + Remove eel-gdk-font-extensions.[ch] + + * eel/eel-clist.h: Fix some overzealous global replace. + + * eel/eel-gobject-extensions.c: + (eel_signal_connect_object_while_alive), + (eel_signal_connect_while_alive): + Add some more g_return_if_fail. + + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: (eel_gtk_label_set_scale): New. + (eel_gtk_widget_set_foreground_color): Set text color too. + + * eel/eel-image-table.c: + * eel/eel-image.c: + * eel/eel-labeled-image.c: + Add includes needed now that eel-gtk-extensions doesn't include + gtkclist.h or gtkpixmap.h any more. + + * eel/eel-pango-extensions.h: + * eel/eel-pango-extensions.c: (eel_pango_attr_list_copy_or_create), + (eel_pango_attr_list_apply_global_attribute): New helper functions + used by the eel_gtk_label_set_scale and the other code in here. + (apply_global_attribute): New name for an old function. + (eel_pango_layout_set_weight): New. + + * eel/eel-wrap-table.c: (eel_wrap_table_class_init): + Don't add the enums, since we just get lots of complaints and we + don't really use them right now. + +2002-01-05 Christian Rose <[email protected]> + + * configure.in: Added "ms" to ALL_LINGUAS. + +2002-01-04 Havoc Pennington <[email protected]> + + * eel/eel-mateconf-extensions.c (eel_mateconf_monitor_add): don't do the + recursive preload here, too much stuff in /apps/caja it seems + like. Rely on explicit preloads in other code. + + * eel/eel-font-picker.c (font_picker_get_selected_style_entry): + add FIXME and MATE2_CONVERSION_COMPLETE for similar + option_menu->menu_item issue + + * eel/eel-string-picker.c (eel_string_picker_get_selected_string): + use gtk_option_menu_get_history() instead of setting item index + as object data - option_menu->menu_item is no longer non-NULL + apparently, when we want it to be. + + * eel/eel-mateconf-extensions.c + (eel_mateconf_value_get_eel_string_list): add a function to get an + EelStringList + + * eel/eel-preferences-item.c + (preferences_item_create_enumeration_list): use emergency fallback + instead of default for deciding on number of string pickers + + * eel/eel-graphic-effects.c: don't include art_config.h, it + ended up being included twice and has no include guards + + * eel/eel-preferences.c: remove user levels, remove concept of + installing defaults here, never "fix" invalid values in mateconf + database (as we did when a list of enum values was invalid), don't + bother to cache values since MateConfClient does already, remove + callbacks_blocked which incorrectly relied on + synchronicity/non-reentrancy of mateconf, don't store the default + value, remove all suggest_sync + (eel_preferences_set_emergency_fallback): new function to replace + setting defaults + (eel_preferences_get_emergency_fallback): getter + + * eel/eel-mateconf-extensions.c (eel_mateconf_preload_cache): New + function to allow us to get a bunch of MateConf data in a single + round trip + (eel_mateconf_get_default_value): new function to get the default + from the schema + +2002-01-04 Darin Adler <[email protected]> + + * HACKING: Update. + * NEWS: Update. + * README: Update. + * TODO: Update. + * MAINTAINERS: Update. + * Makefile.shared: Remove. + + * configure.in: Clean up. Update requirements. + * eel-2.0.pc.in: Remove bogus matecomponent-activation dependency. + * eel.spec.in: Remove bogus oaf dependency. + * eel/Makefile.am: Do CFLAGS and LIBS a new better way. + * test/Makefile.am: Change name of CFLAGS. + + * eel/eel-graphic-effects.c: Get rid of extra include. + +2002-01-04 Anders Carlsson <[email protected]> + + * eel/eel-gdk-extensions.c (eel_gdk_rgb_to_color): Fix up + color conversion routines, as suggested by Darin. + (eel_self_check_gdk_rgb_to_color): Add debug function. + (eel_gdk_color_as_hex_string): Print all 48 bits of the + color. + (eel_self_check_gdk_extensions): Add some tests for + eel_gdk_rgb_to_color. + +2002-01-03 Darin Adler <[email protected]> + + * test/Makefile.am: + * test/test-eel-font-picker.c: (main): + Loose ends from removing EelFontManager. + +2002-01-03 Darin Adler <[email protected]> + + * eel/eel-mate-extensions.c: (get_terminal_command_prefix): + Port to use libmate to get terminal choice from MateConf. + + * eel/Makefile.am: + * eel/eel-font-manager.c: Remove. + * eel/eel-font-manager.h: Remove. + * eel/eel-font-picker.c: + * eel/eel-lib-self-check-functions.h: + * eel/eel.h: + * test/.cvsignore: + * test/Makefile.am: + * test/test-eel-font-manager.c: Remove. + * test/test-eel-font-picker.c: (main): + Remove EelFontManager. + +2002-01-03 Darin Adler <[email protected]> + + * RENAMING: Lets take those "-extensions" off the names of all + the header files, since "eel" already contains the concept that + it's "extensions". I'll probably do this soon since I have the + access to do the CVS magic now. + + * eel/eel-mate-extensions.c: + (eel_mate_stock_set_icon_or_register): Remove. + + * eel/eel-gtk-extensions.c: + (eel_gtk_window_is_on_current_workspace_and_area) Remove. + + * eel/eel-gdk-font-extensions.c: (xlfd_string_get_nth_as_int): + * eel/eel-preferences-item.c: (update_integer_settings_at_idle): + * eel/eel-string.c: (eel_eat_str_to_int) (eel_self_check_string): + * eel/eel-string.h: + * test/test.c: (test_text_caption_get_text_as_int): + Death to eel_eat_str_to_int. I basically can't face Owen in + public when I know that I have an interface like that in code + that I wrote. + +2002-01-03 Anders Carlsson <[email protected]> + + * eel/eel-pango-extensions.c + * eel/eel-pango-extensions.h + (eel_pango_layout_set_font_desc): Remove this function since + pango_layout_set_font_description does the same thing and + better. + +2002-01-03 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel-canvas-rect.c: Removed. + * eel/eel-canvas-rect.h: Removed. + * eel/eel-lib-self-check-functions.h: + Bye for now to EelCanvasRect. If we do this optimization, it + should be in libmatecanvas itself. + + * eel/eel-font-picker.c: (font_picker_populate), + (global_font_list_free), (global_font_list_get), + (font_picker_find_entries_for_font): + Hack to get rid of asserts about empty font list. This is + a short term solution. Long term we have to decide what + we are going to offer for choosing fonts. + +2002-01-03 Darin Adler <[email protected]> + + * eel/eel-graphic-effects.c: + Fix the include. It's not legal to include art_config.h + directly. I added an art_misc.h include so that things + will work with older libart and people won't get confused. + + * data/.cvsignore: + * data/fonts/.cvsignore: + * data/fonts/urw/.cvsignore: + Re-remove these. Michael added them back in rather than + deleting the obsolete files. + + * test/.cvsignore: + Re-remove the obsolete entries in here. Again, Michael + added these back in rather than deleting the obsolete + files in his directory. + +2002-01-03 Michael Meeks <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c + (eel_gdk_pixbuf_save_to_file): use gdk-pixbuf's save code. + + * eel/eel-graphic-effects.c: add art_config.h include. + + * eel/eel-font-manager.c: use DATADIR not EEL_DATADIR. + +2002-01-03 Anders Carlsson <[email protected]> + + * eel/eel-pango-extensions.h: + * eel/eel-pango-extensions.c: Use the API Darin suggested instead + since that makes more sense. + +2002-01-02 Darin Adler <[email protected]> + + * configure.in: Remove unused libpng code. + * eel.spec.in: Remove libpng, fonts, and librsvg. + +2002-01-02 Darin Adler <[email protected]> + + * Makefile.am: + * configure.in: + * data/: Remove all of the data, since it was fonts that are not + needed any more. + + * configure.in: + * eel-2.0.pc.in: + Remove dependency on librsvg. + + * eel/Makefile.am: + * eel/eel-font-picker.h: + * eel/eel-glyph.c: Removed. + * eel/eel-glyph.h: Removed. + * eel/eel-label.c: Removed. + * eel/eel-label.h: Removed. + * eel/eel-lib-self-check-functions.h: + * eel/eel-scalable-font-private.h: Removed. + * eel/eel-scalable-font.c: Removed. + * eel/eel-scalable-font.h: Removed. + * eel/eel-smooth-text-layout.c: Removed. + * eel/eel-smooth-text-layout.h: Removed. + * eel/eel.h: + * test/test-eel-font-manager.c: + * test/test-eel-font-picker.c: (update_font), + (font_changed_update_label_callback), (use_defalt_font_callback), + (use_defalt_bold_font_callback), (main): + * test/test-eel-gtk-style.c: + * test/test-eel-image-scrolled.c: (toggle_smooth_callback), + (label_window_new), (label_window_new_scrolled): + Remove eel-glyph, eel-label, eel-scalable-font, eel-smooth-text-layout. + + * eel/eel-graphic-effects.c: + Remove incorrect art_config.h include. + + * eel/eel-labeled-image.c: (eel_labeled_image_add), + (eel_labeled_image_remove), (labeled_image_ensure_label), + (eel_labeled_image_set_text), (eel_labeled_image_get_text): + * test/test-eel-viewport-constraint.c: + (summary_view_item_label_new): + Port to GtkLabel from EelLabel. + + * test/.cvsignore: + * test/Makefile.am: + * test/test-eel-font-simple.c: Remove. + * test/test-eel-font.c: Remove. + * test/test-eel-glyph-simple.c: Remove. + * test/test-eel-glyph.c: Remove. + * test/test-eel-label-flavorful.c: Remove. + * test/test-eel-label-offset.c: Remove. + * test/test-eel-label-scrolled.c: Remove. + * test/test-eel-label-simple.c: Remove. + * test/test-eel-label-wrapped.c: Remove. + * test/test-eel-label.c: Remove. + * test/test-eel-smooth-text-layout.c: Remove. + Remove test-eel-font*, test-eel-glyph*, test-eel-label*. + + * test/test.h: + * test/test-eel-pixbuf-tile.c: + Change test includes around a tiny bit. + +2002-01-02 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel-clickable-image.c: + * eel/eel-clickable-image.h: + * eel/eel-label-with-background.c: + * eel/eel-label-with-background.h: + * eel/eel-lib-self-check-functions.h: + * eel/eel-smooth-text-layout-cache.c: + * eel/eel-smooth-text-layout-cache.h: + * eel/eel.h: + * test/test-eel-clickable-image.c: + * test/test-eel-label-background.c: + * test/Makefile.am: + * test/test.c: + Delete some unused classes and files. More to come. + + * eel/eel-ellipsizing-label.c: (real_finalize), + (eel_ellipsizing_label_class_init): + Use finalize instead of destroy. + + * eel/eel-labeled-image.c: + * eel/eel-labeled-image.h: + * test/test-eel-image-table.c: (labeled_image_new): + Remove some unused functions that are hard to implement with + GtkLabel (instead of EelLabel). + +2002-01-02 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_draw_layout): + Clip the ink_rect to what will fit in the buffer. This prevents + problems with gdk_pixbuf_composite, which doesn't help us with + clipping at all. + +2002-01-02 Darin Adler <[email protected]> + + * eel/eel-mate-extensions.c: (eel_mate_canvas_get_pango_context): + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: (create_pango_ft2_context), + (eel_gtk_widget_get_pango_ft2_context): + Add new function to get a freetype2 context for drawing on the + client side. Code moved from the canvas-specific function that + was in here before. + +2002-01-02 Frederic Crozat <[email protected]> + + * eel/eel-background.c: (eel_background_ensure_image_scaled), + (eel_background_start_loading_image), + (eel_background_set_image_uri_helper), + (eel_background_set_image_uri), + (eel_background_set_image_uri_sync), + (eel_background_set_image_uri_and_color): + * eel/eel-background.h: + Add support for synchronous loading of image (needed to fix + flash when starting Caja desktop) + +2002-01-02 Anders Carlsson <[email protected]> + + * eel/eel-image-chooser.c: Use gtk_tree_model_get instead + of gtk_tree_model_get_value; this simplifies a lot since we + don't need to fool around with GValues. + +2002-01-01 Anders Carlsson <[email protected]> + + * test/test-eel-image-chooser.c: Update picture paths. + + * eel/eel-pango-extensions.h: New file. + + * eel/eel-pango-extensions.c: New file. + + * eel/eel-vfs-extensions.c (eel_read_file_async): Fix the argument + order. + + * eel/eel-text-caption.c (eel_text_caption_init): + Call gtk_entry_set_activates_default. + + * eel/eel-radio-button-group.c (eel_radio_button_group_insert): Enable + mnemonic support. + + * eel/eel-image-chooser.c: Rewrite to use GtkTreeView. + + * eel/eel-image-chooser.h: Inherit from GtkTreeView and remove + an unused and unneeded API call. + + * eel/eel-caption.c (eel_caption_set_title_label): Use + gtk_label_set_text_with_mnemonic instead. + (eel_caption_set_child): Use gtk_label_set_mnemonic_widget. + +2001-12-20 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_draw_layout): + Use ink_rect now that the pango bug that was plaguing me is fixed. + + * eel/eel-mate-extensions.c: (create_pango_context_for_aa_canvas): + Remove some unneeded casts. + +2001-12-21 Duarte Loreto <[email protected]> + + * configure.in: Added new pt translation to ALL_LINGUAS + +2001-12-18 Michael Meeks <[email protected]> + + * eel/eel-mateconf-extensions.c (eel_mateconf_monitor_add): + recursively cache the MateConf keys to reduce CORBA traffic. + +2001-12-17 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_draw_layout): + Use the logical_rect to determine the left side. + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): + Add GdkPixbuf. + +2001-12-17 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_draw_layout): + Simplified parameters. + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): Turn this back on. + Michael turned it off by accident. + +2001-12-13 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-gdk-pixbuf-extensions.c: (eel_draw_layout_to_pixbuf): + New function for drawing with Pango. Seems to be agonizingly slow + due to lack of cache, but I'm not sure if that's the problem. + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: (create_pango_context_for_aa_canvas), + (eel_mate_canvas_get_pango_context): Helper function for getting + the appropriate context when drawing to an anti-aliased MateCanvas. + + * eel/eel-gtk-extensions.c: Add an include that's needed now that + I removed excess includes from eel-mate-extensions.h. + +2001-12-12 Michael Meeks <[email protected]> + + * eel/eel-list-column-title.c (eel_list_column_title_paint): + remove erroneous style unref. + +2001-12-11 Laszlo Peter <[email protected]> + + * eel/Makefile.am: add dependencies to fix building with make -j + +2001-12-09 Anders Carlsson <[email protected]> + + * eel/eel-caption-table.c: (eel_caption_table_resize), + (eel_caption_table_set_row_info): Use gtk+ mnemonics. + + * eel/eel-mate-extensions.c: (icon_selected_callback), + (icon_cancel_pressed), (dialog_response_callback), + (entry_activated), (eel_mate_icon_selector_new): + * eel/eel-mate-extensions.h: + Bring back the eel icon selector and remove the + eel_dialog_get_button_by_index function. + + * eel/eel-password-dialog.c: + (caption_table_activate_callback): + Use gtk_window_activate_default instead of calling + gtk_button_clicked on the ok button. + (eel_password_dialog_new): + Use mnemonics in the Username and Password + labels. + +2001-12-08 Michael Meeks <[email protected]> + + * eel/eel-list.c: populate from stable & port + + * eel/eel-list-column-title.c: build it + + * eel/eel-clist.[ch]: cross port changes to Gtk+2.0's + version of GtkCList. + + * eel/eel-ctree.[ch]: cross port changes to Gtk+2.0's + version of GtkCTree. + + * eel/eelmarshal.list: add lots of marshallers. + +2001-12-07 Darin Adler <[email protected]> + + * eel/eel-art-extensions.c: (eel_art_irect_union): Add missing return. + +2001-12-07 Laszlo Peter <[email protected]> + + * eel/eel-art-extensions.c, eel/eel-debug-drawing.c: replace illegal + uses of the ternary operator with if-else. + + * test/test-eel-clickable-image.c, test/test-eel-image-table.c: + s/__FUNCTION__/G_GNUC_FUNCTION/ + +2001-12-06 Darin Adler <[email protected]> + + * lots of files + Get rid of unneeded casts in calls to g_object_ref/unref. + +2001-12-06 Darin Adler <[email protected]> + + * eel/eel-debug.c: (log_handler): Remove the code that adds the + program name and pid to each message. glib now has that built + in if you set the G_MESSAGES_PREFIXED environment variable. + + * eel/eel-debug.h: + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger), + New strategy for the call that makes warnings and criticals + stop in the debugger. We just use a hard-coded list of domains + here in Eel, rather than asking the caller to pass in the list + of domains. Forward looking to the day when we can do this + without explicitly doing it for each domain. + + * eel/check-program.c: (main): + * test/test.c: (test_init): + Fix callers that no longer need to list the domains. + +2001-11-30 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel-background-style.c: + * eel/eel-background-style.h: + Create EelBackgroundStyle subclass for GtkStyle that implements + gradients. This is a better version of a hack we used for Gtk 1.X. + + * eel/eel-background.c: (eel_background_set_widget_style): Use + EelBackgroundStyle. + (eel_self_check_background): Fix an unref/sink thing. + + * eel/eel-background.c: + (eel_background_receive_dropped_color): + * test/test-eel-image-background.c: + (window_new_with_eel_background_gradient), + (window_new_with_gtk_background_hacked): + * test/test-eel-label-background.c: + (window_new_with_eel_background_gradient), + (window_new_with_gtk_background_hacked): + * test/test-eel-label.c: + (red_background_color_value_changed_callback), + (green_background_color_value_changed_callback), + (blue_background_color_value_changed_callback), + (create_background_frame): + * test/test-eel-viewport-constraint.c: (create_row): + Change all rgb:RRRR/GGGG/BBBB to use #RRGGBB format instead. + + * eel/eel-gdk-extensions.h: Fix typo in name of unimplemented + function. I should probably just delete it. + + * eel/eel-gdk-extensions.c: + (eel_gdk_color_parse_with_white_default): Add placeholder for rgb: + code, in case we need it. + (eel_parse_rgb_with_white_default): Call + eel_gdk_color_parse_with_white_default so we share code. + (eel_gdk_rgb_to_color_spec): Create #RRGGBB format. + (eel_gdk_color_as_hex_string): Create #RRGGBB format. + (eel_self_check_gdk_extensions): Use #RRGGBB format. + +Tue Nov 20 20:26:25 2001 Owen Taylor <[email protected]> + + * configure.in: Add [quoting] around AC_CHECK_HEADER + needed by some autoconf versions. + +Mon Nov 19 17:34:16 2001 Jonathan Blandford <[email protected]> + + * eel/eel-stock-dialogs.c (eel_run_simple_dialog): remove uneeded + GTK_OBJECT_DESTROYED check. + + Patch from Gediminas Paulauskas <[email protected]> + + * eel/check-program.c, eel/eel-debug.c, test/test.c: replace + g_log_domain_glib with "Glib" + * eel/eel-gobject-extensions.h: replace #include <gobject/gobject.h> + with glib-object.h + +2001-11-09 Darin Adler <[email protected]> + + * eel/eel-stock-dialogs.c: (show_ok_dialog), + (eel_create_info_dialog), (eel_show_info_dialog), + (details_dialog_response_callback): Destroy dialogs when the + button is pushed. We still need to refine this further. + +2001-11-08 Darin Adler <[email protected]> + + * Tons of files. + Removed many unneeded G_OBJECT casts. + +2001-11-08 Darin Adler <[email protected]> + + * eel/eel-stock-dialogs.h: + * eel/eel-stock-dialogs.c: + A cut at porting this all to GtkDialog. + +2001-11-08 jacob berkman <[email protected]> + + * configure.in: call ourselves eel rather than eel2, and use + eel-2.0 for the gettext package name + + * acconfig.h: add GETTEXT_PACKAGE + +2001-11-06 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel-gobject-extensions.h: + * eel/eel-gobject-extensions.c: + (eel_signal_connect_object_while_alive), + (eel_signal_connect_while_alive): + Add new eel-gobject-extensions.[ch]. + + * Many of files. + More Gtk->G changes. + +2001-11-06 Darin Adler <[email protected]> + + * Lots of files. + More GtkObject -> GObject. + +2001-11-06 Michael Meeks <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c + (free_pixbuf_load_handle): do a g_object_unref not an + unref. + +2001-11-03 Darin Adler <[email protected]> + + * Tons of files: + A bit more GtkObject -> GObject conversion. + +2001-11-03 Darin Adler <[email protected]> + + * eel/eel-gtk-macros.h: Ref the parent class instead of just + peeking at it. + +2001-11-03 Darin Adler <[email protected]> + + * eel/eel-preferences.c: (preferences_while_alive_disconnector), + (eel_preferences_add_callback_while_alive): + * eel/eel-preferences.h: + Change eel_preferences_add_callback_while_alive to work with + any GObject, not just a GtkObject. + + * eel/eel-preferences-box.c: (eel_preferences_box_init): + * eel/eel-preferences-item.c: (preferences_item_set_main_child): + * eel/eel-preferences-pane.c: (eel_preferences_pane_init), + (eel_preferences_pane_add_control_preference): + Update callers. + +2001-11-03 Darin Adler <[email protected]> + + * eel/eel-gtk-macros.h: + Another update to the boilerplate macros. I also decided to + do a name change to take out the word "DEFINE". + + * Many files. + Update for name change. + +2001-11-01 Havoc Pennington <[email protected]> + + * eel/eel-gtk-extensions.c (eel_gtk_window_get_geometry_string): + new function to replace mate_geometry_string + +2001-11-01 Darin Adler <[email protected]> + + * eel/eel-gtk-macros.h: When I fixed the comma in my copy, I + made some formatting changes. + +2001-11-01 Havoc Pennington <[email protected]> + + * eel/eel-gtk-macros.h (EEL_DEFINE_MATECOMPONENT_BOILERPLATE): add + missing comma + + * test/test-eel-label-simple.c (use_system_font_callback): adapt + to not use eel_widget_set_font(), and add note about how the use + of eel_gtk_get_system_font() here is broken and is only for + testing purposes and no one should copy it. + + * eel/eel-gtk-extensions.c (eel_gtk_window_present): that one was + easy + (eel_gtk_widget_set_font_by_name): port to GTK 2 + (eel_gtk_label_make_bold): port to GTK 2 + (eel_gtk_label_make_larger): port and note in docs that it's + broken + (eel_gtk_label_make_smaller): port and note in docs that it's + broken + (eel_gtk_widget_set_background_color): do this properly + (eel_gtk_widget_set_foreground_color): ditto + (eel_get_current_event_time): remove, just use + gtk_get_current_event_time() + (eel_drag_set_icon_pixbuf): remove, just use + gtk_drag_set_icon_pixbuf() + (eel_gtk_widget_standard_draw): delete, there is no draw method + anymore + (eel_gtk_pixmap_new_empty): make this less lame + (eel_nullify_when_destroyed): work on GObject, use + g_object_add_weak_pointer() + (eel_nullify_cancel): corresponding change + (eel_gtk_widget_set_font): remove, just use + gtk_widget_modify_font() + (eel_gtk_style_set_font): delete, this was totally broken; I don't + know what it's for but we have to do it a different way + (eel_gtk_menu_insert_separator): use GtkSeparatorMenuItem! + woo-hoo! also, remove setting it insensitive, this will be fixed + before 2.0 so it isn't required + (EEL_STANDARD_BUTTON_PADDING): remove, should fix in GTK if we are + going to fix it + (eel_gtk_button_auto_click): remove, use gtk_widget_activate() + (eel_gtk_button_set_standard_padding): remove, should not be used + (activate_button_on_double_click): use gtk_widget_activate() + instead of eel_gtk_button_auto_click() + (eel_gtk_window_set_initial_geometry): use gtk_window_move() + instead of gtk_widget_set_uposition() + (eel_gtk_window_set_up_close_accelerator): make it whine if you + use it on GtkDialog, since that breaks the standard GtkDialog + close accelerators + (eel_popup_menu_position_func): remove obsolete FIXME about + GdkPoint using gint16 + + * eel/eel-gdk-extensions.c (eel_gdk_window_set_invisible_cursor): + port to GTK 2 (not sure why it used Xlib before) + + * eel/eel-dnd.c (eel_drag_drop_action_ask): port to GTK 2 + +2001-11-01 Darin Adler <[email protected]> + + * eel/eel-gtk-macros.h: Oops, need to pass init and fini functions + in to matecomponent_type_unique. + +2001-11-01 Darin Adler <[email protected]> + + * configure.in: Remove some unused stuff. + * eel/eel-gtk-macros.h: Fix boilerplate to work with GObject, not + just GtkObject. Share code with the MateComponentObject case too. + +2001-10-29 Darin Adler <[email protected]> + + * eel-2.0.pc.in: Add some Requires. + +2001-10-29 Darin Adler <[email protected]> + + * eel/Makefile.am: Fix typo. + +2001-10-28 Darin Adler <[email protected]> + + * configure.in: Fix comment, remove unnecessary direct pkgconfig + macro since MATE_PLATFORM_MATE_2 takes care of htat. + + * many files: + Since everyone else calls them class_init and init, renamed our + initialize_class and initialize to match existing practice. + + * eel/eel-gtk-macros.h: + Added EEL_DEFINE_MATECOMPONENT_BOILERPLATE. + + * eel/eel-xml-extensions.h: + * eel/eel-xml-extensions.c: (eel_xml_remove_node): Remove this + since xmlUnlinkNode is now implemented. + +2001-10-27 jacob berkman <[email protected]> + + * eel/eel-background.c (eel_background_start_loading_image): + update to new vfs priority macro name + +2001-10-22 Darin Adler <[email protected]> + + * eel/eel-gdk-extensions.c: (eel_gdk_window_set_wm_protocols): + * eel/eel-gdk-font-extensions.c: (eel_gdk_font_get_name): + Fix for GdkAtom/XAtom change in gtk. + +2001-10-20 Anders Carlsson <[email protected]> + + * eel/eel-background.c: (eel_background_start_loading_image): + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_load_async): + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-vfs-extensions.c: (eel_read_file_async), + (eel_read_entire_file_async): + * eel/eel-vfs-extensions.h: Update async eel functions using mate-vfs + to take a priority argument because of the recent priority changes in + mate-vfs. + +2001-10-11 Ramiro Estrugo <[email protected]> + + * eel/eel-clickable-image.c: (eel_clickable_image_new_solid): + * eel/eel-image-chooser.c: (eel_image_chooser_insert_row): + * eel/eel-image.c: (eel_image_initialize_class), + (eel_image_initialize), (eel_image_finalize), (eel_image_set_arg), + (eel_image_get_arg), (eel_image_size_request), + (eel_image_expose_event), (eel_image_new_solid): + * eel/eel-image.h: + * eel/eel-label.c: (eel_label_initialize_class), + (eel_label_initialize), (eel_label_finalize), (eel_label_set_arg), + (eel_label_get_arg), (eel_label_size_request), (label_paint), + (paint_label_smooth), (paint_label_smooth_cached), + (eel_label_expose_event), (label_can_cache_contents), + (eel_label_new_solid): + * eel/eel-label.h: + * eel/eel-labeled-image.c: (eel_labeled_image_make_smaller): + * eel/eel-labeled-image.h: + * eel/eel-smooth-widget.c: (eel_smooth_widget_paint), + (eel_smooth_widget_get_preferred_dimensions): + * eel/eel-smooth-widget.h: + * test/.cvsignore: + * test/Makefile.am: + * test/test-eel-image-background.c: + (window_new_with_eel_background_image), + (window_new_with_eel_background_gradient), + (window_new_with_gtk_background), + (window_new_with_gtk_background_hacked), + (window_new_with_solid_background): + * test/test-eel-image-simple.c: (image_window_new), (main): + * test/test-eel-image-tile.c: + * test/test-eel-image.c: + * test/test-eel-label-background.c: + (window_new_with_eel_background_image), + (window_new_with_eel_background_gradient), + (window_new_with_gtk_background), + (window_new_with_gtk_background_hacked), + (window_new_with_solid_background): + * test/test-eel-label-scrolled.c: (label_window_new), + (label_window_new_scrolled), (label_window_new_table): + * test/test-eel-labeled-image.c: (main): + * test/test-eel-viewport-constraint.c: (create_eel_label): + * test/test.c: (test_image_new), (test_label_new): + * test/test.h: + Lose the "tile" feature of EelImage and EelLabel. The short story + is that this code is unnecessary. Losing it makes the widgets + simpler and should make the transition to using GtkImage from Gtk+ + 2.0 a little easier. Blame 70% Arlo 30% Ramiro for this "feature." + +2001-10-10 Darin Adler <[email protected]> + + * eel/eel-debug-drawing.c: + * eel/eel-label.c: + * eel/eel-smooth-text-layout.c: + Mark functions static for proper namespace hygiene. + +2001-10-02 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (test_diff_rects): Change call to + g_string_printfa to use g_string_append_printf. + +2001-10-02 Darin Adler <[email protected]> + + * .cvsignore: + * Makefile.am: + * configure.in: + Remove use of xml-i18n-tools, since we don't have anything that + we use it to localize. + +2001-10-02 Darin Adler <[email protected]> + + * eel/eel-background.c: (eel_background_is_dark): Remove extra + factor of two that was making every background seem dark. + +2001-10-01 Darin Adler <[email protected]> + + Now that we are setting the translation domain properly to make + _() use eel translations, we must use explicit gettext calls + when we want application translations. + + * eel/eel-dnd.c: (eel_drag_drop_action_ask): Switch into the + eel domain when calling mate_popup_menu_new so we get the + eel translations of the menu items. + + * eel/eel-enumeration.c: + (eel_enumeration_get_nth_description_translated): + * eel/eel-preferences-box.c: (preferences_box_populate_pane), + (eel_preferences_box_populate): + * eel/eel-xml-extensions.c: (eel_xml_get_property_translated): + Use gettext, not _(), to translate strings passed from elsewhere. + + * eel/eel-preferences.c: + (eel_preferences_get_user_level_name_for_display): + Use _(), not gettext, to translate strings in this code. + + * eel/eel-gdk-font-extensions.c: + Remove mate-i18n.h include where it's not used. + + * configure.in: Remove unused @REBUILD@ stuff. + * eel/eel-glib-extensions.c: Whitespace tweaks. + +2001-09-28 Darin Adler <[email protected]> + + * eel/eel-font-manager.c: (eel_self_check_font_manager): + Cleaned up tests a bit. + + * eel/eel-string-list.c: (eel_self_check_string_list): + Changed test results back now that g_strsplit behavior has been + changed in glib. + + * configure.in: Bump required glib version to 1.3.9. + +2001-09-28 Darin Adler <[email protected]> + + Port from destroy to finalize. + + * eel/eel-background.c: (eel_background_initialize_class), + (eel_background_finalize): + * eel/eel-canvas-rect.c: (rect_finalize), + (eel_canvas_rect_initialize_class): + * eel/eel-caption-table.c: (eel_caption_table_initialize_class), + (caption_table_finalize): + * eel/eel-caption.c: (eel_caption_initialize_class), + (eel_caption_finalize): + * eel/eel-clickable-image.c: + (eel_clickable_image_initialize_class), + (eel_clickable_image_finalize): + * eel/eel-debug-drawing.c: (debug_pixbuf_viewer_initialize_class), + (debug_pixbuf_viewer_finalize): + * eel/eel-font-picker.c: (eel_font_picker_initialize_class), + (eel_font_picker_finalize): + * eel/eel-gtk-extensions.c: (eel_gtk_style_set_font), + (eel_gtk_widget_set_font), (eel_gtk_get_system_font): + * eel/eel-gtk-extensions.h: + * eel/eel-image-chooser.c: (eel_image_chooser_initialize_class), + (eel_image_chooser_finalize), (eel_image_chooser_destroy): + * eel/eel-image-table.c: (eel_image_table_initialize_class), + (eel_image_table_finalize): + * eel/eel-image.c: (eel_image_initialize_class), + (eel_image_finalize): + * eel/eel-label.c: (eel_label_initialize_class), + (eel_label_finalize): + * eel/eel-labeled-image.c: (eel_labeled_image_initialize_class), + (eel_labeled_image_finalize): + * eel/eel-list-column-title.c: + (eel_list_column_title_initialize_class), + (eel_list_column_title_finalize): + * eel/eel-password-dialog.c: + (eel_password_dialog_initialize_class), + (eel_password_dialog_initialize), (eel_password_dialog_finalize), + (eel_password_dialog_new): + * eel/eel-preferences-box.c: + (eel_preferences_box_initialize_class), + (eel_preferences_box_finalize): + * eel/eel-preferences-group.c: + (eel_preferences_group_initialize_class), + (eel_preferences_group_finalize): + * eel/eel-preferences-item.c: + (eel_preferences_item_initialize_class), + (preferences_item_finalize): + * eel/eel-preferences-pane.c: + (eel_preferences_pane_initialize_class), + (eel_preferences_pane_finalize): + * eel/eel-radio-button-group.c: + (eel_radio_button_group_initialize_class), + (eel_radio_button_group_finalize): + * eel/eel-scalable-font.c: (eel_scalable_font_initialize_class), + (eel_scalable_font_finalize): + * eel/eel-smooth-text-layout-cache.c: + (eel_smooth_text_layout_cache_initialize_class), + (eel_smooth_text_layout_cache_finalize): + * eel/eel-smooth-text-layout.c: + (eel_smooth_text_layout_initialize_class), + (eel_smooth_text_layout_finalize): + * eel/eel-string-picker.c: (eel_string_picker_initialize_class), + (eel_string_picker_finalize): + * eel/eel-text-caption.c: (eel_text_caption_initialize_class), + (eel_text_caption_finalize): + * eel/eel-viewport.c: (eel_viewport_initialize_class), + (eel_viewport_finalize): + * eel/eel-wrap-table.c: (eel_wrap_table_initialize_class), + (eel_wrap_table_finalize): + Replace destroy default handlers with finalize ones in most cases. + In a few cases, divide an existing destroy handler into two pieces. + + * test/test-eel-label-flavorful.c: (decreasing_label_window_new): + * test/test-eel-label-simple.c: (use_system_font_callback): + Re-enable some test code. + +2001-09-27 Darin Adler <[email protected]> + + * test/test-eel-label-flavorful.c: (label_set_label_to_font_name): + Oops. One more thing to fix in here. Use pango call. + +2001-09-26 Darin Adler <[email protected]> + + * eel/Makefile.am: + Another pass. The last one was too simplistic. + +2001-09-26 Darin Adler <[email protected]> + + * configure.in: + Get the path of glib-genmarshal. + + * eel/.cvsignore: + * eel/Makefile.am: + Fix up generated file build to be simpler. Most importantly, add + the feature where it won't recompile everything every time any + header changes. + + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: (eel_gtk_get_system_font): + Wrote Pango version of this function. + + * test/test-eel-label-flavorful.c: (label_set_label_to_font_name): + Reenabled some ifdef'd out code. + +2001-09-19 Marius Andreiana <[email protected]> + + * configure.in: Added ro (Romanian) to ALL_LINGUAS + +2001-09-18 Darin Adler <[email protected]> + + * eel/eel-gtk-extensions.h: + * eel/eel-ellipsizing-label.c: (recompute_ellipsized_text): + * eel/eel-gdk-pixbuf-extensions.c: (check_average_value): + * eel/eel-gtk-extensions.c: (eel_gtk_widget_set_font_by_name), + (eel_gtk_label_make_bold), (eel_gtk_label_make_larger), + (eel_gtk_label_make_smaller): + * test/test-eel-label-flavorful.c: (label_set_label_to_font_name): + * test/test-eel-label-simple.c: (use_system_font_callback): + + Turned off a lot of GdkFont stuff so we can still compile. + This highlights more of the mate 2 conversion work that will + be needed. + +2001-09-17 Darin Adler <[email protected]> + + * eel/eel-background.c: (eel_background_is_dark): Make this work + with background images that are transparent or partly-transparent. + It turns out this was another part of the problem with the default + Caja theme's text color. + + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_average_value): + Fix bug that caused incorrect average values in pixbufs with more + than about 66000 pixels. Alex Larsson found the problem and + provided a fix that I used as a starting point. Also change + algorithm so that it handles the alpha channel. Also made it use + 64-bit arithmetic for simplicity -- hope that doesn't make it too + slow. Also changed it to use an argb value instead of a GdkColor. + (eel_gdk_pixbuf_intersect): Get rid of special case for + eel_gdk_pixbuf_whole_pixbuf by making just using a wide-open + rectangle instead. + (check_average_value), (eel_self_check_gdk_pixbuf_extensions): + Added some test cases for eel_gdk_pixbuf_average_value. + +2001-09-08 Wang Jian <[email protected]> + + * configure.in(ALL_LINGUAS): Added zh_CN for Simplified Chinese. + +2001-09-07 Darin Adler <[email protected]> + + * eel/eel-gdk-font-extensions.h: + * eel/eel-gdk-font-extensions.c: (eel_gdk_font_get_italic), + (eel_gdk_font_get_bold), (eel_gdk_font_get_larger), + (eel_gdk_font_get_largest_fitting), (font_get_bold), + (font_get_size_in_pixels): Call the new eel_gdk_font_get_name. + (eel_gdk_font_get_name): Public version of font_get_name. Code + stolen from gal used to get name from X. + + * test/test-eel-label-flavorful.c: (label_set_label_to_font_name): + Call eel_gdk_font_get_name, remove font_get_name. + +2001-09-07 Darin Adler <[email protected]> + + * configure.in: Got rid of dependency on libmatesupport. + + * eel/eel-gdk-font-extensions.c: (font_get_name): + * test/test-eel-label-flavorful.c: (font_get_name): + Disabled these until we can figure out what to do about them. + +2001-09-03 Darin Adler <[email protected]> + + * eel/check-program.c: (main): + * test/test-eel-password-dialog.c: (main): + * test/test-eel-widgets.c: (main): + * test/test.c: (test_init): + Use libmateui_module_info_get () instead of + libmateui_module_info. + +2001-09-01 Darin Adler <[email protected]> + + * eel/eel-gtk-extensions.c: Remove include. + +2001-09-01 Darin Adler <[email protected]> + + * eel/eel-dnd.c: + (is_path_that_mate_uri_list_extract_filenames_can_parse): + * eel/eel-font-manager.c: (font_description_table_add), + (next_token): + * eel/eel-glib-extensions.c: (eel_strdup_strftime): + * eel/eel-string.c: (eel_istr_has_prefix), (eel_istr_has_suffix), + (eel_str_to_int), (eel_str_capitalize): + Oops! How did I miss all of these places that needed to use + the new g_ascii_* calls? + +2001-08-31 Darin Adler <[email protected]> + + * eel/eel-background.c: + * eel/eel-dnd.c: + * eel/eel-font-manager.c: + * eel/eel-glib-extensions.c: + * eel/eel-list.c: + * eel/eel-string.c: + * eel/eel-vfs-extensions.c: (is_valid_scheme_character), + (eel_make_uri_canonical): + Get rid of all includes of <ctype.h> and use non-locale-specific + g_ascii_* calls from glib instead. + +2001-08-31 Darin Adler <[email protected]> + + Rolled change from stable eel-1-0 branch: + + * eel/eel-gtk-extensions.c: + (eel_gtk_class_name_make_like_existing_type), + (eel_gtk_get_system_font): Fix storage leaks by using + gtk_object_sink to get rid of temporary widgets that are never + parented instead of using gtk_object_destroy. + +2001-08-31 Darin Adler <[email protected]> + + * eel/eel-gtk-extensions.c: (eel_gtk_window_present): + Get things compiling again by getting rid of code that uses + mate_win_hints (for now). + +2001-08-31 Abel Cheung <[email protected]> + + * configure.in (ALL_LINGUAS): zh_TW.Big5 -> zh_TW + +2001-08-27 Darin Adler <[email protected]> + + Rolled change from stable eel-1-0 branch: + + 2001-08-27 Alex Larsson <[email protected]> + + * eel/eel-list-column-title.c (truncate_string): + Fix elipsis truncation on multibyte locales. + +2001-08-27 Anders Carlsson <[email protected]> + + * eel/eel-font-manager.c (eel_self_check_font_manager): Remove + unused original_current_dir variable. + + * eel/eel-canvas-rect.c (rect_update): Free our fill_svp + if it exists. + + * eel/eel-gdk-font-extensions.c (xlfd_string_get_nth_as_int): + Free strings returned by xlfd_string_get_nth. + +2001-08-24 Darin Adler <[email protected]> + + * configure.in: Require librsvg 1.1, not 1.1.0. + * eel/eel-glyph.c: Use header from libart, not librsvg. + +2001-08-22 Ramiro Estrugo <[email protected]> + + Change from the stable eel-1-0 branch. + + * eel/eel-mateconf-extensions.c: (eel_mateconf_value_set_string_list): + Fix leaks introduced in last checkin. + +2001-08-22 Ramiro Estrugo <[email protected]> + + Change from the stable eel-1-0 branch. + + * eel/eel-mateconf-extensions.h: + * eel/eel-mateconf-extensions.c: (eel_mateconf_is_default): Use value + free cover that does its own not NULL checking. + (eel_mateconf_value_get_string_list), + (eel_mateconf_value_set_string_list): New function to deal with + MateConfValue lists of GNONF_VALUE_STRING type. + + * eel/eel-preferences.c: (preferences_mateconf_value_get_int), + (preferences_mateconf_value_get_bool), + (preferences_mateconf_value_get_string), + (preferences_mateconf_value_get_string_list), (preferences_get_value), + (preferences_preference_is_mateconf_key), (preferences_key_make), + (preferences_find_first_non_null_default_value), + (eel_preferences_get_visible_user_level), + (eel_preferences_set_visible_user_level), + (eel_preferences_set_is_invisible), (eel_preferences_set_boolean), + (eel_preferences_get_boolean), (eel_preferences_set_integer), + (eel_preferences_get_integer), (eel_preferences_set), + (eel_preferences_get), (eel_preferences_set_string_list), + (eel_preferences_get_string_list), + (eel_preferences_default_set_integer), + (eel_preferences_default_get_integer), + (eel_preferences_default_set_boolean), + (eel_preferences_default_get_boolean), + (eel_preferences_default_set_string), + (eel_preferences_default_get_string), + (eel_preferences_default_set_string_list), + (eel_preferences_default_get_string_list), + (preferences_entry_invoke_callbacks_if_needed), + (preferences_entry_update_cached_value), + (preferences_entry_ensure_mateconf_connection), + (preferences_entry_free), (preferences_global_table_free), + (eel_preferences_add_callback), (eel_preferences_add_auto_string), + (eel_preferences_add_auto_string_list), + (eel_preferences_add_auto_integer), + (eel_preferences_add_auto_boolean), + (eel_preferences_remove_auto_string), + (eel_preferences_remove_auto_string_list), + (eel_preferences_remove_auto_integer), + (eel_preferences_remove_auto_boolean), + (preferences_while_alive_disconnector), + (eel_preferences_add_callback_while_alive), + (eel_preferences_remove_callback), + (eel_preferences_set_description), + (eel_preferences_set_enumeration_id), + (eel_preferences_visible_in_current_user_level), + (eel_preferences_initialize): + Cleanup whacky system where preference visibilities and default + values were stored using mateconf. Instead, store the visibilities + and defaults values in the already existing table of preferences. + The changes make this code a bit simpler. In particular, the code + to create the right keys is now gone. Add some covers for getting + values out of MateConfValue safely and with some extra checking the + the types are right. + +2001-08-21 Maciej Stachowiak <[email protected]> + + Merge from stable branch: + + 2001-08-20 Maciej Stachowiak <[email protected]> + + * eel/eel-clist.c: (eel_clist_set_column_justification, + size_allocate_title_buttons): Try to remove some sources of + crashing when EelList is used as a drop-in replacement for + GtkCList. (Using EelCList directly still crashes). + * eel/eel-list-column-title.c: (eel_list_column_title_paint): More + potential crash reduction. + + * test/Makefile.am: Speed up the build a bit by removing some + redundant libraries. + * eel/Makefile.am: Likewise. + +2001-08-21 Maciej Stachowiak <[email protected]> + + * eel/eel-font-manager.c (collect_fonts_from_directory): Adjust to + recent removal of filtering from mate-vfs. + +2001-08-21 Maciej Stachowiak <[email protected]> + + Merge from eel-1-0 branch: + + 2001-07-20 Maciej Stachowiak <[email protected]> + + * eel/eel-ctree.c: (draw_row): Fix bugzilla.eazel.com bug 8387 + (Dragging elements to a folder entry should make it hilighted) by + making the text of the drop target row bold in addition to making + the icon darker. I think this looks a lot better. + +2001-08-17 Darin Adler <[email protected]> + + * eel/eel-gtk-extensions.c: Remove include of obsolete header. + +2001-08-17 Ramiro Estrugo <[email protected]> + + Change from the stable eel-1-0 branch. + + Make these widgets more useful outside Caja by providing + functions to change ui elements (such as titles and descriptions) + as well iterators. + + These changes do not affect either binary or source compatibility + for Caja. + + * eel/eel-preferences-box.h: + * eel/eel-preferences-box.c: + (preferences_box_populate_pane), (eel_preferences_dialog_new), + (eel_preferences_dialog_get_box), Add accessor for the preferences + box of a dialog. + (eel_preferences_dialog_populate), Separate the populate function + out on its own. + (eel_preferences_box_for_each_pane), New function for iterating + panes. + (eel_preferences_box_rename_pane), New function to rename a pane. + (eel_preferences_box_get_pane_name): New function to find the name + of a pane. + + * eel/eel-preferences-group.h: + * eel/eel-preferences-group.c: + (eel_preferences_group_set_title_label), New function for changing + the title label of a group. + (eel_preferences_group_for_each_item): New function for iterating + items. + + * eel/eel-preferences-pane.h: + * eel/eel-preferences-pane.c: (eel_preferences_pane_initialize), + (eel_preferences_pane_destroy), (eel_preferences_pane_new), + (eel_preferences_pane_add_group), + (preferences_pane_get_max_caption_width), + (eel_preferences_pane_update), + (eel_preferences_pane_add_control_preference), Use more consistent + paramter names. + (eel_preferences_pane_for_each_group): New function for iterating + groups. + + * eel/eel-preferences-item.h: + * eel/eel-preferences-item.c: + * eel/eelmarshal.list: + (eel_preferences_item_initialize_class), + (preferences_item_update_custom), + (preferences_item_set_main_child), + (preferences_item_create_enumeration_list), + (preferences_item_create_boolean), + (preferences_item_create_editable_string), + (preferences_item_create_editable_integer), + (preferences_item_create_enumeration_menu), + (preferences_item_create_font), + (preferences_item_create_smooth_font), + (eel_preferences_item_get_name), (update_text_settings_at_idle), + (preferences_item_update_text_settings_at_idle), + (update_integer_settings_at_idle), + (preferences_item_update_editable_integer_settings_at_idle), + (preferences_item_update_description), + (eel_preferences_item_set_control_preference), + (eel_preferences_item_set_control_action), + (preferences_item_get_control_showing), + (eel_preferences_item_enumeration_list_set_unique_exceptions), + (eel_preferences_item_set_description): + Add new functions for changing the descriptions of items. Factor + out the code to set descriptions into its own function and make + that public. Use more consistent parameter names. Add signal for + notifying custom items about description changes. + +2001-08-15 Darin Adler <[email protected]> + + Remove some glib extensions that are obviated by additions to + glib 2.0. + + * eel/eel-glib-extensions.h: Remove EEL_N_ELEMENTS (G_N_ELEMENTS), + eel_g_list_safe_for_each (g_list_foreach), eel_g_list_sort_custom + (g_list_sort_with_data), eel_g_string_append_len (g_string_append_len), + eel_g_hash_table_remove_deep_custom, eel_g_hash_table_remove_deep, + eel_g_hash_table_destroy_deep_custom, eel_g_hash_table_destroy_deep + (use g_hash_table_new_full instead), eel_g_ptr_array_sort + (g_ptr_array_sort_with_data), eel_shell_quote (g_shell_quote). +. + * eel/eel-glib-extensions.c: (eel_strdup_strftime): + Use g_string_append_len instead of eel_g_string_append_len. + (eel_dumb_down_for_multi_byte_locale_hack): Use G_N_ELEMENTS + instead of EEL_N_ELEMENTS. + (eel_self_check_glib_extensions): Test g_shell_quote instead + of eel_shell_quote. + + * eel/eel-mate-extensions.c: (try_terminal_command), + (try_terminal_command_argv), (get_terminal_command_prefix), + (eel_mate_make_terminal_command): + Use g_shell_quote instead of eel_shell_quote. + + * eel/eel-gtk-extensions.c: (eel_gtk_object_list_unref): + Use g_list_foreach instead of eel_g_list_safe_for_each. + + * eel/eel-scalable-font.c: (free_global_font_handle_table), + (initialize_global_stuff_if_needed): + Use g_hash_table_new_full instead of eel_g_hash_table_destroy_deep_custom. + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): + * eel/eel-font-manager.c: (font_directory_is_ignored), + (font_foundry_is_ignored), (font_family_is_ignored), + (eel_font_manager_get_default_font), + (eel_font_manager_get_default_bold_font): + * eel/eel-font-picker.c: (font_make_style_name): + * eel/eel-list.c: (eel_list_initialize_dnd), + (get_data_on_first_target_we_support): + * test/test-eel-gtk-style.c: + * test/test-eel-image-chooser.c: (populate_image_chooser_callback), + (populate_button_group_callback): + * test/test-eel-image-table.c: (labeled_image_new), + (image_table_new_scrolled): + * test/test-eel-image.c: (main): + Use G_N_ELEMENTS instead of EEL_N_ELEMENTS. + +Wed Aug 15 16:32:56 2001 Jonathan Blandford <[email protected]> + + * eel/eel-dnd.c (eel_drag_default_drop_action_for_icons): make the + trash directory. + +2001-08-15 Darin Adler <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: Use a 64K buffer instead of + a 4K one. + +2001-08-14 Darin Adler <[email protected]> + + * eel/eel-font-manager.c: (eel_font_manager_get_bold): + Remove another ill-advised call to + eel_font_manager_file_is_scalable_font. Even if we do want + to test the file's type, we definitely don't want to do it + inside g_return_if_fail. + +2001-08-14 Alex Larsson <[email protected]> + + * eel/eel-scalable-font.c (eel_scalable_font_new): + Don't test eel_font_manager_file_is_scalable_font (), + it does slow I/O. + (eel_scalable_font_get_default_font, + eel_scalable_font_get_default_bold_font): + Don't keep recreating new EelScalableFonts for the + default font. + +2001-08-13 Darin Adler <[email protected]> + + * eel/eel-background.c: (eel_background_load_image_callback), + (draw_background_callback), (render_background_callback), + (eel_background_set_up_canvas): + Replace the old EelBackgroundCanvasGroup hack with code that uses + the new draw_background and render_background signals in + MateCanvas. + + * eel/Makefile.am: + * eel/eel-background-canvas-group.c: + * eel/eel-background-canvas-group.h: + Remove the old EelBackgroundCanvasGroup class. + +2001-08-09 Ramiro Estrugo <[email protected]> + + Change from the eel-1-0 branch. + + * eel/eel-art-extensions.h: + * eel/eel-art-extensions.c: (eel_art_point_assign), + (eel_art_point_clamp), (eel_art_point_offset_by): + Add ArtPoint version of some functions. + +2001-08-08 Darin Adler <[email protected]> + + * autogen.sh: No need for hack-macros any more. + * configure.in: No need to check for freetype, since + we don't depend on it directly. We use it via librsvg. + * eel.spec.in: No need to check for freetype. + +2001-08-06 Darin Adler <[email protected]> + + * autogen.sh: No need to gettextize, xml-i18n-toolize, and + libtoolize twice. + * configure.in: Switch from lots of MATE_PKGCONFIG_CHECK_MODULES + calls to a lot fewer PKG_CHECK_MODULES calls. More oaf -> + matecomponent-activation renaming. No need to build intl directory. + * Makefile.am: No need to build intl directory. + + * test/Makefile.am: No need to use -I to include this directory. + + * eel/check-program.c: + * test/test-eel-password-dialog.c: + * test/test-eel-widgets.c: + <libmateui/mate-init.h> -> <libmateui/mate-ui-init.h>. + +2001-07-26 Darin Adler <[email protected]> + + * configure.in: Fix option checking code. Before it was setting + VFS_CFLAGS, which was wrong. + + * eel/Makefile.am: Add -DG_DISABLE_DEPRECATED. + + * eel/eel-background.c: (eel_widget_background_changed): + Use gtk_widget_queue_draw instead of gtk_widget_queue_clear. + * eel/eel-canvas-rect.c: (test_diff_rects): Use g_string_printfa + instead of g_string_sprintfa. + * eel/eel-caption.c: (eel_caption_get_title_label): Use + gtk_label_get_text instead of gtk_label_get. + * eel/eel-clickable-image.c: + (eel_clickable_image_initialize_class): Use g_signal_new instead + of gtk_signal_new. + (label_enter), (label_leave), (label_handle_button_release): Use + g_signal_emit instead of gtk_signal_emit. + * eel/eel-debug-drawing.c: (eel_debug_show_pixbuf): Use + gtk_window_set_resizable instead of gtk_window_set_policy. + * eel/eel-font-picker.c: (font_picker_populate): Use + gtk_radio_menu_item_get_group instead of gtk_radio_menu_item_group. + * eel/eel-gdk-extensions.c: (eel_fill_rectangle_with_color), + (eel_gdk_gc_choose_foreground_color): Get rid of unneeded calls to + gdk_rgb_init. + * eel/eel-glib-extensions.c: (eel_test_predicate): Use + g_ascii_strcasecmp instead of g_strcasecmp. + * eel/eel-gtk-extensions.h: Add ifdefs so we can compile this + header with GTK_DISABLE_DEPRECATED on -- helps us notice what we + should get rid of. + * eel/eel-image-chooser.c: (eel_image_chooser_initialize_class): + Use G_STRUCT_OFFSET instead of GTK_SIGNAL_OFFSET. + (eel_image_chooser_set_selected_row): Use g_signal_emit instead of + gtk_signal_emit. + * eel/eel-image-table.c: (eel_image_table_initialize_class), + (image_table_emit_signal): Use g_signal_emit instead of + gtk_signal_emit. + * eel/eel-image.c: (eel_image_initialize_class): Use + G_STRUCT_OFFSET instead of GTK_SIGNAL_OFFSET. + * eel/eel-label.c: (eel_label_initialize_class): Use + G_STRUCT_OFFSET instead of GTK_SIGNAL_OFFSET. + * eel/eel-preferences-box.c: (eel_preferences_dialog_new): Use + gtk_window_set_resizable instead of gtk_window_set_policy. + * eel/eel-preferences-item.c: + (preferences_item_create_editable_string): Use g_ascii_strcasecmp + instead of g_strcasecmp. + * eel/eel-radio-button-group.c: (eel_radio_button_group_insert): + Use gtk_radio_button_get_group instead of gtk_radio_button_group. + * eel/eel-stock-dialogs.c: (find_message_label): Use + gtk_label_get_text instead of gtk_label_get. + * eel/eel-string.c: (eel_strcasecmp): Use g_ascii_strcasecmp + instead of g_strcasecmp. + + * eel/eel-gdk-font-extensions.h: Fix typo in comment. + +2001-07-26 Ramiro Estrugo <[email protected]> + + * configure.in: + * eel/.cvsignore: + * eel/Makefile.am: + * eel/eel-features.c: + * eel/eel-features.h.in: + * eel/eel.h: + Add eel-features.[ch] so that the version of the library can be + checked at runtime. + +2001-07-26 Ramiro Estrugo <[email protected]> + + Change from the the eel-1-0 branch: + + * eel/eel-image.h: + * eel/eel-image.c: (eel_image_initialize_class), + (eel_image_initialize), (eel_image_set_arg), (eel_image_get_arg), + (eel_image_expose_event), (eel_image_get_pixbuf_opacity), + (eel_image_set_pixbuf_insensitive_opacity), + (eel_image_get_pixbuf_insensitive_opacity): + Add support for rendering the image pixbuf at a lower opacity when + the widget state is insensitive. + +2001-07-25 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + Add missing eelmarshal.list to EXTRA_DIST and use a sophisticated + alphabetized order on the list. + +2001-07-25 Ramiro Estrugo <[email protected]> + + * eel-2.0.pc.in: + Change link flags to '-leel-2' instead of '-leel' + +2001-07-25 Ramiro Estrugo <[email protected]> + + * configure.in: + Add defines for Eel library major, minor and micro version numbers + so that we can use these to properly set the shared library + version info. + Make the includedir be eel-2/eel' instead of 'eel' so that we can + have MATE1 and MATE2 installations of Eel cohabiting in the + same $prefix. + + Change the PACKAGE name to eel2. + + * data/fonts/urw/Makefile.am: + Data dir is now 'share/eel-2/eel' instead of 'share/eel' + + * eel-2.0.pc.in: + Include dir is now include/eel-2/eel' instead of 'include/eel' + + * eel.spec.in: + Update for includedir and datadir changes. + Add missing .mo file rule. + Cleanup some. + + * eel/Makefile.am: + Set the shared library version info. + Change libary name to libeel-2 so that we can install it in the + same prefix as libeel (MATE1 and MATE2 cohabitation) + Install headers in the new 'eel-2/eel' includedir. + Update EEL_DATADIR for new 'eel-2/eel' data location so that + fallback fonts can be found in the right place. + + * test/Makefile.am: + Update for includedir and datadir changes. + + * test/dumb-box.c: (eel_dumb_box_expose): + More sythetic exposure fixes. + +2001-07-24 Ramiro Estrugo <[email protected]> + + * eel/eel-image-chooser.c: (image_chooser_expose_event): + * eel/eel-viewport.c: (eel_viewport_expose_event): + * eel/eel-wrap-table.c: (eel_wrap_table_expose_event): + More sythetic expose event fixes. + +2001-07-24 Ramiro Estrugo <[email protected]> + + * eel/eel-gtk-container.c: (eel_gtk_container_child_expose_event): + Fix the way that expose events are synthesized for children of + containers. In Gtk+ 2.0 there is a standard and convenient way of + doing this, so we use that instead of doing it "by hand". + +2001-07-24 Ramiro Estrugo <[email protected]> + + * eel/eel-clickable-image.c: + (eel_clickable_image_initialize_class): + * eel/eel-clickable-image.h: + * eel/eel-font-picker.c: (eel_font_picker_initialize_class): + * eel/eel-font-picker.h: + * eel/eel-image-chooser.c: (eel_image_chooser_initialize_class): + * eel/eel-image-chooser.h: + * eel/eel-image-table.c: (eel_image_table_initialize_class): + * eel/eel-image-table.h: + * eel/eel-image.c: (eel_image_initialize_class): + * eel/eel-label.c: (eel_label_initialize_class): + * eel/eel-preferences-item.c: + (eel_preferences_item_initialize_class): + * eel/eel-preferences-item.h: + * eel/eel-radio-button-group.c: + (eel_radio_button_group_initialize_class): + * eel/eel-radio-button-group.h: + * eel/eel-string-picker.c: (eel_string_picker_initialize_class): + * eel/eel-string-picker.h: + * eel/eel-text-caption.c: (eel_text_caption_initialize_class): + * eel/eel-text-caption.h: + Changes to make the GTK+ 2.0 signal system happier. Make sure + that all signals are declared in the class structure and that the + offset argument to gtk_signal_new () points to a valid method + offset. + +2001-07-24 Ramiro Estrugo <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-smooth-widget.c: (smooth_widget_get_gtk_background): + Remove the use of a "safe" (and very hacky) drawable to pixbuf + function, since the problems we were working around have been + fixed in GTK+ 2.0. + With this change, "smooth" widgets work again. + + * test/test.c: (test_init): + Comment out the mate_program_init() thing for now. + Currently the mate_program_init() function makes the test + programs hang for me. Using just the gtk_init () works for + most tests, so I am using just that until the mate_program_init () + function is fixed or we learn how to use it properly. + +2001-07-24 Ramiro Estrugo <[email protected]> + + Change from the the eel-1-0 branch: + + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_prepend): New function + to prepend a string to the collection. + (eel_string_list_append_string_list): Rename from + eel_string_list_append () which was a confusing name. + This API change doesnt affect Caja or Eel since neither used + this function. + +2001-07-18 Darin Adler <[email protected]> + + * acconfig.h: Also need to add MATE_EXPLICIT_TRANSLATION_DOMAIN + here for autoheader. + +2001-07-17 Darin Adler <[email protected]> + + * configure.in: Add MATE_EXPLICIT_TRANSLATION_DOMAIN so messages + withing eel get translated properly. + +2001-07-17 Darin Adler <[email protected]> + + * eel/eel-gdk-font-extensions.c: + (eel_gdk_font_get_largest_fitting): Add FIXME about incorrect + assumption that the longest string is the widest. + (xlfd_string_get_nth): Check for extra characters before the "-", + and don't allow n == 0. + (xlfd_string_replace_nth), Check for extra characters before the + "-", don't allow n == 0, and use return_if_fail to check for bad + values of n rather than just returning NULL. + (xlfd_string_get_nth_as_int): Use return_if_fail to check for bad + values of n rather than just returning XFLD_INVALID_VALUE. Remove + extra check for NULL. + (eel_self_check_gdk_font_extensions): Add lots of new self-checks + and change rule so that we don't allow an extra trailing "-" + character. + + * eel/check-program.c: (main): Use mate_program_init correctly. + * test/test-eel-password-dialog.c: (main): Use mate_program_init + correctly. + * test/test-eel-widgets.c: (main): Use mate_program_init + correctly. + +2001-07-16 Darin Adler <[email protected]> + + * eel/eel-self-checks.c: (eel_check_string_list_result): + Fix place where I called the wrong function. + +2001-07-15 Darin Adler <[email protected]> + + * eel/check-program.c: (main): Fix up init calls. I am still quite + confused about how to use mate_program_init properly. + + * eel/eel-preferences-item.h: + * eel/eel-preferences-item.c: + * eel/eel-self-checks.h: + * eel/eel-string-list.h: + * eel/eel-string.h: + Corrected spelling error: "delimeter" -> "delimiter". + + * eel/eel-self-checks.c: (eel_check_string_list_result): + Changed string list check to be simpler and distinguish lists + with empty strings in them from empty lists. + +2001-07-13 Darin Adler <[email protected]> + + * eel/check-program.c: + * eel/eel-xml-extensions.c: + * eel/eel-xml-extensions.h: + Fix mate-xml includes to use <libxml/*>. Before it was just + picking up the wrong headers on my machine, which is why it worked. + +2001-07-13 Darin Adler <[email protected]> + + Now things link, and the test programs compile too. + + * configure.in: + * eel/check-program.c: (main): + * eel/eel-list-column-title.c: + * eel/eel-list.c: + * eel/eel-smooth-widget.c: (smooth_widget_get_gtk_background): + * test/dumb-box.h: + * test/test-eel-image-chooser.c: (populate_image_chooser_callback): + * test/test-eel-image.c: (pixbuf_new_from_name): + * test/test-eel-label-flavorful.c: (font_get_name): + * test/test-eel-label-offset.c: + * test/test-eel-label.c: (main): + * test/test-eel-password-dialog.c: (main): + * test/test-eel-pixbuf-tile.c: (pixbuf_drawing_area_expose_event), + (drawable_drawing_area_expose_event): + * test/test-eel-viewport-constraint.c: (main): + * test/test-eel-widgets.c: (create_pixbuf), (main): + * test/test.c: (test_pixbuf_new_named), (eel_pixmap_file): + * test/test.h: + +2001-07-13 Darin Adler <[email protected]> + + Enough to make everything compile. + The eel self-check program doesn't link yet. + + * eel/check-program.c: (main): + * eel/eel-password-dialog.c: (caption_table_activate_callback), + (eel_password_dialog_new), (eel_password_dialog_run_and_block): + * eel/eel-preferences-box.c: (eel_preferences_dialog_new): + * eel/eel-stock-dialogs.c: (timed_wait_callback), + (eel_run_simple_dialog), (create_message_dialog), + (show_message_box), (show_ok_box), (eel_create_info_dialog), + (details_dialog_clicked_callback), + (eel_show_info_dialog_with_details), + (eel_show_error_dialog_with_details), (eel_show_yes_no_dialog), + (eel_create_question_dialog): + * eel/eel-types.c: (eel_type_init): + +2001-07-13 Darin Adler <[email protected]> + + A cut at making things compile with MATE 2. + Some things are inside #ifdef MATE2_CONVERSION_COMPLETE. + 90% of the way to compiling everything. + + * eel/.cvsignore: + * eel/Makefile.am: + * eel/check-program.c: (main): + * eel/eel-background-canvas-group.c: + (eel_background_canvas_group_supplant_root_class): + * eel/eel-background.c: (eel_background_initialize_class), + (eel_background_draw), (eel_background_draw_flat_box), + (eel_background_set_widget_style), (eel_get_widget_background), + (eel_background_receive_dropped_color): + * eel/eel-canvas-rect.c: (rect_update): + * eel/eel-canvas-rect.h: + * eel/eel-caption-table.c: (eel_caption_table_initialize_class), + (eel_caption_table_get_entry_text): + * eel/eel-clickable-image.c: + (eel_clickable_image_initialize_class): + * eel/eel-clist.c: + * eel/eel-ctree.c: (eel_ctree_class_init): + * eel/eel-dnd.c: (eel_drag_drop_action_ask): + * eel/eel-enumeration.c: + * eel/eel-font-manager.c: (file_as_string), + (font_description_table_new), (collect_fonts_from_directory), + (directory_contains_file), (try_using_font_server), + (ensure_local_font_table), (eel_font_manager_get_default_font), + (eel_font_manager_get_default_bold_font), + (eel_self_check_font_manager): + * eel/eel-font-picker.c: (eel_font_picker_initialize_class), + (font_picker_add_item), (font_picker_populate): + * eel/eel-gdk-extensions.c: (eel_gdk_window_set_invisible_cursor): + * eel/eel-gdk-font-extensions.c: (font_get_name): + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_load), + (file_read_callback), (load_done), + (eel_gdk_pixbuf_get_from_window_safe): + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-glib-extensions.c: + * eel/eel-mate-extensions.c: (eel_dialog_get_button_by_index), + (get_terminal_command_prefix), (eel_mate_icon_selector_new), + (eel_mate_stock_set_icon_or_register): + * eel/eel-mate-extensions.h: + * eel/eel-gtk-extensions.c: (send_delete_event), + (handle_standard_close_accelerator), + (eel_popup_menu_position_func), (eel_gtk_menu_insert_separator), + (eel_gtk_signal_connect_full_while_alive), + (eel_gtk_signal_connect_while_realized), + (eel_nullify_when_destroyed), (eel_nullify_cancel), + (event_get_time): + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-macros.h: + * eel/eel-image-chooser.c: (eel_image_chooser_initialize_class): + * eel/eel-image-table.c: (eel_image_table_initialize_class): + * eel/eel-image.c: (eel_image_initialize_class), + (eel_image_set_pixbuf_from_file_name), + (eel_image_set_tile_pixbuf_from_file_name): + * eel/eel-label.c: (eel_label_initialize_class), + (eel_label_set_is_smooth), + (eel_label_set_tile_pixbuf_from_file_name), + (eel_label_set_never_smooth): + * eel/eel-list-column-title.c: + (eel_list_column_title_initialize_class), + (eel_list_column_title_destroy), (eel_list_column_title_finalize), + (eel_list_column_title_request), (eel_list_column_title_paint): + * eel/eel-list.c: (eel_list_initialize_class), + (eel_list_initialize), (eel_list_clear_keyboard_focus), + (eel_list_set_keyboard_focus), (eel_list_size_request), + (new_column_width), (draw_rows), (eel_list_draw), + (eel_list_expose), (eel_list_row_at): + * eel/eel-password-dialog.c: (caption_table_activate_callback), + (eel_password_dialog_new), (eel_password_dialog_run_and_block): + * eel/eel-password-dialog.h: + * eel/eel-preferences-box.c: (preferences_box_select_pane), + (eel_preferences_dialog_new): + * eel/eel-preferences-box.h: + * eel/eel-preferences-group.c: + (eel_preferences_group_get_title_label): + * eel/eel-preferences-item.c: + (eel_preferences_item_initialize_class): + * eel/eel-preferences-pane.h: + * eel/eel-preferences.c: + * eel/eel-radio-button-group.c: + (eel_radio_button_group_initialize_class): + * eel/eel-region.c: (gdk_region_new_from_irect), + (eel_region_add_rectangle), (eel_region_subtract_rectangle): + * eel/eel-scalable-font.c: + * eel/eel-smooth-widget.h: + * eel/eel-stock-dialogs.c: (add_label_to_dialog), + (timed_wait_delayed_close_timeout_callback), (timed_wait_free), + (timed_wait_dialog_destroy_callback), (timed_wait_callback), + (delete_event_callback), (eel_run_simple_dialog), + (create_message_dialog), (show_message_box), (show_ok_box), + (eel_create_info_dialog), (eel_show_info_dialog), + (details_dialog_clicked_callback), + (eel_show_info_dialog_with_details), (eel_show_warning_dialog), + (eel_show_error_dialog), (eel_show_error_dialog_with_details), + (eel_show_yes_no_dialog), (eel_create_question_dialog): + * eel/eel-stock-dialogs.h: + * eel/eel-string-picker.c: (eel_string_picker_initialize_class), + (eel_string_picker_set_string_list): + * eel/eel-text-caption.c: (eel_text_caption_initialize_class): + * eel/eel-types.c: (eel_type_init): + * eel/eel-viewport.c: (eel_viewport_initialize_class), + (eel_viewport_draw), (eel_viewport_size_allocate): + * eel/eel-xml-extensions.c: + +2001-07-11 Darin Adler <[email protected]> + + * eel/eel-font-manager.c: (collect_fonts_from_directory): + Fix code that can segfault due to unknown MIME type. + + * eel/eel-scalable-font.c: (initialize_global_stuff_if_needed): + Tell librsvg our datadir so we don't have to be in the same prefix + as librsvg. There's this bad thing where we install fonts that the + librsvg library has to find. Lets hope we can obsolete this + completely soon. + +2001-07-09 Ramiro Estrugo <[email protected]> + + * .cvsignore: + * Makefile.am: + * autogen.sh: + * configure.in: + * eel-2.0.pc.in: + * eel-config.in: + * eel.spec.in: + * eel/eel-art-extensions.h: + * eel/eel-art-gtk-extensions.h: + * eel/eel-background-canvas-group.c: + * eel/eel-background-canvas-group.h: + * eel/eel-background.h: + * eel/eel-canvas-rect.h: + * eel/eel-caption-table.h: + * eel/eel-caption.h: + * eel/eel-clickable-image.h: + * eel/eel-font-manager.h: + * eel/eel-font-picker.h: + * eel/eel-mateconf-extensions.h: + * eel/eel-glyph.h: + * eel/eel-image-chooser.h: + * eel/eel-image-table.h: + * eel/eel-image-with-background.h: + * eel/eel-image.h: + * eel/eel-label-with-background.h: + * eel/eel-label.h: + * eel/eel-labeled-image.h: + * eel/eel-list.h: + * eel/eel-password-dialog.h: + * eel/eel-preferences-box.h: + * eel/eel-preferences-group.h: + * eel/eel-preferences-item.h: + * eel/eel-preferences-pane.h: + * eel/eel-preferences.h: + * eel/eel-radio-button-group.h: + * eel/eel-region.h: + * eel/eel-scalable-font-private.h: + * eel/eel-scalable-font.h: + * eel/eel-smooth-text-layout-cache.h: + * eel/eel-smooth-text-layout.h: + * eel/eel-smooth-widget.h: + * eel/eel-string-picker.h: + * eel/eel-text-caption.h: + * eel/eel-vfs-extensions.h: + * eel/eel-viewport.h: + * eel/eel-wrap-table.h: + * eelConf.sh.in: + Begin port to MATE2, part 1. Make configure work in the MATE2 + universe and also a few simple s/BEGIN_MATE_DECLS/G_BEGIN_DECLS/ + +2001-07-09 Ramiro Estrugo <[email protected]> + + * eel/eel-art-extensions.h: + * eel/eel-art-extensions.c: (eel_art_drect_get_width), + (eel_art_drect_get_height), (eel_art_irect_assign_end_points), + (eel_art_drect_assign_end_points), (eel_art_ipoint_offset_by), + (eel_art_point_equal): + More ArtDRect versions of point/rectangle stuff. + +==== eel 1.0.1 ==== + +2001-07-05 Darin Adler <[email protected]> + + * configure.in: Bumped version to 1.0.1 + * NEWS: Some notes about recent changes. + +2001-06-26 Alexander Larsson <[email protected]> + + * eel/eel-font-manager.c (eel_font_manager_get_default_font, + eel_font_manager_get_default_bold_font): + Don't keep looking for the files after we found them the first + time. + +2001-06-26 Ramiro Estrugo <[email protected]> + + * eel/eel-art-extensions.h: + * eel/eel-art-extensions.c: (eel_art_irect_is_empty): New function. + (eel_art_ipoint_offset_by): New function. + +2001-06-25 Ramiro Estrugo <[email protected]> + + * eel/eel-art-extensions.h: + * eel/eel-art-extensions.c: (eel_dimensions_clamp), + (test_dimensions_clamp), (eel_self_check_art_extensions): + New constant points. New function to clamp dimensions . + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_insert_string_list): + New function to insert a string list into another. + +2001-06-06 Ramiro Estrugo <[email protected]> + + Patch from Frederic Devernay <[email protected]> + (tweaked by me to | bits instead of +) to make the Eel Font Manager + follow links when determining the mime type of fonts. + + * eel/eel-font-manager.c: (collect_fonts_from_directory), + (eel_font_manager_file_is_scalable_font): + +2001-06-06 Darin Adler <[email protected]> + + Integrated a revised version of a patch by Eungkyu Song + <[email protected]> to make the font manager code accept either a + tab or a space as the separator. + + * eel/eel-font-manager.c: (font_description_table_add): Use + strpbrk instead of strstr. + +2001-06-06 Alex Larsson <[email protected]> + + * eel/eel-background.[ch] (eel_background_draw): + This function now takes both the src and dest coordinates. + (eel_background_draw_to_drawable): Update to the new + eel_background_draw API. + * eel/eel-background-canvas-group.c + (eel_background_canvas_group_draw): Update to the new + eel_background_draw API. + +2001-06-05 Ramiro Estrugo <[email protected]> + + * eel/eel-gtk-container.c: (eel_gtk_container_child_size_allocate): + Move the critical after the child check for NULL since we allow + a NULL child to be given. + +2001-06-05 Ramiro Estrugo <[email protected]> + + * eel/eel-art-extensions.c: (eel_art_ipoint_clamp), + (test_irect_intersect), (test_irect_union), (test_ipoint_clamp), + (eel_self_check_art_extensions): + * eel/eel-art-extensions.h: + New function to clamp a point plus checks for that. + +2001-06-04 Ramiro Estrugo <[email protected]> + + * eel/eel-debug-drawing.h: + * eel/eel-debug-drawing.c: + (eel_debug_show_pixbuf_in_external_viewer): + Replace the hard coded eog viewer to one that can accept any + external viewer. I ran into the problem that the Eog binary + changed names from "eog" to "eog-shell" so I decided to make this + debug feature more generic. + + * eel/Makefile.am: + * eel/eel.h: + * eel/eel-gtk-container.h: + * eel/eel-gtk-container.c: (eel_gtk_container_child_expose_event), + (eel_gtk_container_child_map), (eel_gtk_container_child_unmap), + (eel_gtk_container_child_add), (eel_gtk_container_child_remove), + (eel_gtk_container_child_size_allocate): + New files. Functions to simplify the implementations of + GtkContainer widgets. + + * eel/eel-gtk-extensions.c: (eel_gtk_widget_standard_realize): + Dont hardcode the event mask. Use gtk_widget_get_events() + instead. Also document this fact so that users are aware that + they need to set the event mask using gtk_widget_set_events () - + which is the right Gtk+ way anyway. + + * eel/eel-image-chooser.c: (eel_image_chooser_initialize): + Call gtk_widget_set_events() with the right event mask for the + image chooser. + + * eel/eel-labeled-image.c: (eel_labeled_image_size_allocate), + (eel_labeled_image_expose_event), (eel_labeled_image_map), + (eel_labeled_image_unmap), (eel_labeled_image_add), + (eel_labeled_image_remove): + Simplify the implementations of GtkContainer methods by using the + functions in eel-gtk-container.[ch]. Theres probably other + widgets in Eel and Caja that could benefit from this + simplification/code sharing as well. + + * eel/eel-self-checks.c: (eel_check_double_result): + * eel/eel-self-checks.h: + New checks for double values. + + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_new_from_string_array): + New function to allocate a EelStringList from a regular C string + array. + (eel_string_list_assign_from_string_array): New function to assign + a regular C string array to a EelStringList. + (eel_string_list_reverse): New function to reverse a string list. + (test_string_list_reverse), (test_new_from_string_array), + (eel_self_check_string_list): Self checks for the above new + functions. + + * test/dumb-box.c: (eel_dumb_box_initialize_class), + (eel_dumb_box_expose): Some dumb cleanup of old comment cruft. + * test/test-eel-font-simple.c: (main): + * test/test-eel-font.c: (main): + * test/test-eel-glyph-simple.c: (main): + * test/test-eel-glyph.c: (main): + * test/test-eel-smooth-text-layout.c: (main): + Update for changes in debug function to view pixbufs in external + viewers. + +2001-06-04 Darin Adler <[email protected]> + + * eel/eel-font-manager.c: (collect_fonts_from_directory), + (eel_font_manager_file_is_scalable_font): + * test/test-eel-background.c: (main): + * test/test-eel-label.c: (widget_set_eel_background_image): + * test/test.c: (test_gtk_widget_set_background_image): + Fix all code that prepends "file://" to try to make a URI from a + path. Use mate_vfs_get_uri_from_local_path instead. + +2001-06-01 Alex Larsson <[email protected]> + + * eel/eel-background.c (eel_background_draw_flat_box): + Only render area if we get passed an area. + (eel_background_draw): Do correct translation of + coordinates for destination drawable. + +2001-06-01 Darin Adler <[email protected]> + + * configure.in: Bump version number to 1.0.0.1 + * NEWS: Mention the plans to release 1.0.1 + +2001-06-01 Darin Adler <[email protected]> + + * eel/eel-list.c: (eel_list_button_release): Fixed code that was + passing x twice instead of x and y that prevented single-click + from working in the Caja list view. Also did some other + cleanups to behavior when multiple buttons are pressed at once. + +2001-05-22 John Harper <[email protected]> + + Fallout from fixing bug 8220 (Having Ctrl as default "modifier + key used for default WM shortcuts" breaks everything...): + + * eel/eel-list.c (eel_list_keyboard_move_to, + eel_list_keyboard_space): changed to use Control modifier + instead of Alt + +2001-05-20 Darin Adler <[email protected]> + + Checked in change for Miguel Rodríguez Pérez + <[email protected]>. + + * eel/eel-preferences-item.c + (preferences_item_update_editable_string): + (preferences_item_update_editable_integer): Only update + text if it changed. + +2001-05-19 George Lebl <[email protected]> + + * configure.in, po/cs.po: Add czech translations + +2001-05-17 Darin Adler <[email protected]> + + * eel/eel-gtk-extensions.c: + (eel_gtk_signal_connect_full_while_alive): Weakened a + too-strong g_return_if_fail. + +2001-05-09 Ramiro Estrugo <[email protected]> + + * eel/eel-self-checks.h: + * eel/eel-self-checks.c: + Make eel_after_check() and eel_report_check_failure() public so + that third party projects can use them to construct their own + checks and still be able to use the same check failure reporting + machinery. + +2001-05-08 Darin Adler <[email protected]> + + * RENAMING: Refine the renaming ideas. + +==== eel 1.0 ==== + +2001-05-04 Robin * Slomkowski <[email protected]> + + * configure.in: fixed lirsvg test for 1.0.x + +2001-05-04 Robin * Slomkowski <[email protected]> + + * configure.in: upped version to 1.0 and changed upped + dependance too librsvg 1.0.0 + +2001-05-04 Robin * Slomkowski <[email protected]> + + * configure.in: upped version to 0.1 + +2001-05-04 Ramiro Estrugo <[email protected]> + + * eel/eel-preferences-item.c: + (preferences_item_create_editable_string): + Restore a silly hack for the sake of Caja. Id like to + properly fix this, but not so close to a release. + +2001-05-04 Ramiro Estrugo <[email protected]> + + * configure.in: + Add MateConf and OAF dependency. + + * eel.spec.in: + Add MateConf and OAF dependency. Also add missing BuildRequires + entries. + + * eel/Makefile.am: + Need to set librsvg cflags directly here, since librsvg does not + appear in any public eel headers and thus not exported in + eel-config --cflags. + + * eel/eel-dateedit-extensions.c: + * eel/eel-dateedit-extensions.h: + * eel/eel-mateconf-extensions.c: + * eel/eel-mateconf-extensions.h: + * eel/eel-generous-bin.c: + * eel/eel-generous-bin.h: + * eel/eel-lib-self-check-functions.h: + * eel/eel-preferences-box.c: + * eel/eel-preferences-box.h: + * eel/eel-preferences-group.c: + * eel/eel-preferences-group.h: + * eel/eel-preferences-item.c: + * eel/eel-preferences-item.h: + * eel/eel-preferences-pane.c: + * eel/eel-preferences-pane.h: + * eel/eel-preferences.c: + * eel/eel-preferences.h: + * eel/eel.h: + Move over some more stuff over from Caja. + +2001-05-03 Darin Adler <[email protected]> + + * RENAMING: Some renaming ideas. + +2001-05-03 Darin Adler <[email protected]> + + * eel/eel-vfs-extensions.h: + * eel/eel-vfs-extensions.c: (eel_make_uri_from_half_baked_uri), + (eel_self_check_vfs_extensions): Add new call to make a canonical + URI from the kind of half-baked URIs that are used in gmc URL + files and in drag and drop. The definition of a half-baked URI is + that it starts with "file:" and then has a normal path, without + URI escaping. + + * Makefile.am: Fixed a typo. + +2001-05-03 Ramiro Estrugo <[email protected]> + + * eel/eel-gdk-extensions.h: Add an opaque version of the color + packing macro. + * eel/eel-gdk-extensions.c: (eel_self_check_gdk_extensions): Add + checks for color packing macros. + + * eel/eel-art-extensions.h: + * eel/eel-art-extensions.c: (eel_art_irect_intersect), + (eel_art_irect_union), (eel_dimensions_assign), + (eel_dimensions_equal), (eel_art_ipoint_assign), + (eel_art_ipoint_equal), (test_intersect), (test_union), + (eel_self_check_art_extensions): Some more art extensions. + Currently unused in Eel or Caja. + + * eel/eel-self-checks.h: + * eel/eel-self-checks.c: + Add self check machinery for EelArtIPoints. + + * eel/eel-gdk-pixbuf-extensions.h: Dumb spacing tweak. + +2001-05-02 Darin Adler <[email protected]> + + Fixed bug 8219 (crash under libefence): + + * eel/eel-scalable-font.c: (eel_scalable_font_new), + (free_global_font_handle_table): Dup the font names before using + them as keys, since the underlying freetype font can last longer + than the EelScalableFont. + +2001-05-02 Ramiro Estrugo <[email protected]> + + * eel/eel-debug-drawing.c: (eel_debug_show_pixbuf_in_eog): + Update for EOG name change. eog got renamed to eog-shell. + +2001-05-02 Ramiro Estrugo <[email protected]> + + * configure.in: + Lots of improvement. Make dealing with dependency libs/cflags simpler. + + * eel/Makefile.am: + * test/Makefile.am: + Eliminate cut-n-paste disease by using dependency macros defined + in configure.in. + +2001-05-02 Ramiro Estrugo <[email protected]> + + * autogen.sh: + Detect whether the invocation of configure failed and print a + message accordingly. We used to always assume that configure was + successful and print misleading "now type make to build $PROJECT" + messages. + +2001-05-01 Ramiro Estrugo <[email protected]> + + * configure.in: + Simplify the freetype2 detection insanity by using autoconf macro + technology. The new test should work with both FreeType2 RPMS as + well as freetype built from source in any prefix. + +2001-05-01 Ramiro Estrugo <[email protected]> + + * eel/eel-gdk-pixbuf-extensions.c: + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-glyph.c: + * eel/eel-glyph.h: + * eel/eel-label.c: + * eel/eel-scalable-font.c: + * eel/eel-scalable-font.h: + * eel/eel-smooth-text-layout.c: + * eel/eel-smooth-widget.c: + * test/test-eel-font-simple.c: + * test/test-eel-font.c: + * test/test-eel-glyph-simple.c: + * test/test-eel-glyph.c: + * test/test-eel-smooth-text-layout.c: + More work on changing parameters for functions that accept and + return ArtIRect, EelArtIPoint, ArtDRect, EelDimensions to pass by + value instead of by pointer. + +2001-05-01 Ramiro Estrugo <[email protected]> + + * test/Makefile.am: + Add include flag for test directory. + +2001-05-01 Ramiro Estrugo <[email protected]> + + * eel/eel-image-chooser.c: + Respect the GtkStyle. + + * test/.cvsignore: + * test/Makefile.am: + * test/dumb-box.h: + * test/dumb-box.c: + * test-eel-gtk-style.c: + Add a GtkStyle debugging tool + + * test/test-eel-image-chooser.c: + Update for style respect changes. + +2001-04-30 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + Remove some garbage that apparently satan tried to sneak in. + +2001-04-30 Darin Adler <[email protected]> + + reviewed by: John Sullivan <[email protected]> + + Fixed bug 8198 ("New Terminal" does not use MATE default + applications). This involved changing the API, so it requires + changes to Caja too. + + * eel/eel-glib-extensions.c: (eel_shell_quote): Make it smarter so + it doesn't quote simple things with no fancy characters in them. + (eel_self_check_glib_extensions): Update test. + + * eel/eel-mate-extensions.h: + * eel/eel-mate-extensions.c: (try_terminal_command), + (try_terminal_command_argv), (get_terminal_command_prefix): New + functions, used to implement eel_mate_open_terminal. These look + at the mate-config setting that controls which terminal program + is used. + (eel_mate_make_terminal_command): New public function. We've now + eliminated the concept of just getting the name of a terminal + program. + (eel_mate_open_terminal): Use eel_mate_make_terminal_command to + do the hard part. + +2001-04-30 John Sullivan <[email protected]> + + Fixed bug 6234 (Escape should close Properties window) + Fixed bug 6271 (Close dialogs with Escape to match MATE standard) + + * eel/eel-gtk-extensions.c: + (eel_gtk_window_event_is_close_accelerator): Close dialogs with + Escape as well as Control-W. (non-MateDialogs can either call + eel_gtk_window_set_up_close_accelerator to arrange this, or can call + this querying function directly). + +2001-04-30 Ramiro Estrugo <[email protected]> + + * eel/eel-art-extensions.c: + * eel/eel-art-extensions.h: + * eel/eel-art-gtk-extensions.c: + * eel/eel-art-gtk-extensions.h: + * eel/eel-clickable-image.c: + * eel/eel-debug-drawing.c: + * eel/eel-debug-drawing.h: + * eel/eel-gdk-pixbuf-extensions.c: + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-glyph.c: + * eel/eel-glyph.h: + * eel/eel-mate-extensions.c: + * eel/eel-mate-extensions.h: + * eel/eel-image-chooser.c: + * eel/eel-image-table.c: + * eel/eel-image-with-background.c: + * eel/eel-image.c: + * eel/eel-label.c: + * eel/eel-labeled-image.c: + * eel/eel-region.h: + * eel/eel-smooth-text-layout.c: + * eel/eel-smooth-text-layout.h: + * eel/eel-smooth-widget.c: + * eel/eel-smooth-widget.h: + * eel/eel-wrap-table.c: + * test/test-eel-font.c: + * test/test-eel-glyph-simple.c: + * test/test-eel-glyph.c: + * test/test-eel-pixbuf-tile.c: + * test/test-eel-smooth-text-layout.c: + * test/test.c: + Change parameters for functions that accept and return ArtIRect, + EelArtIPoint, ArtDRect, EelDimensions to pass by value instead of + by pointer. + +2001-04-29 Ramiro Estrugo <[email protected]> + + * eel/eel-enumeration.c: (eel_self_check_enumeration): + Add one more check. + + * eel/eel-string-picker.h: + * eel/eel-string-picker.c: (eel_string_picker_set_string_list), + (eel_string_picker_insert_string), + (eel_string_picker_insert_separator): + Add support for separators. + +2001-04-26 Ramiro Estrugo <[email protected]> + + * eel/eel-art-extensions.h: + * eel/eel-art-extensions.c: (eel_art_irect_align), + (eel_dimensions_are_empty), (eel_art_irect_assign_dimensions), + (eel_self_check_art_extensions): Change constants to be lower + case. Also declare them as "extern const" and not just "extern." + + * eel/eel-art-gtk-extensions.c: (eel_gdk_rectangle_to_art_irect), + (eel_gdk_window_get_bounds), + (eel_gdk_window_get_screen_relative_bounds), + (eel_gtk_widget_get_bounds), (eel_gtk_widget_get_dimensions), + (eel_gtk_widget_get_preferred_dimensions), + (eel_gdk_window_clip_dirty_area_to_screen), + (eel_gdk_window_get_dimensions): + * eel/eel-debug-drawing.c: (debug_pixbuf_viewer_size_request): + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_get_dimensions), + (eel_gdk_pixbuf_intersect): + * eel/eel-glyph.c: (eel_glyph_get_dimensions), + (eel_glyph_intersect): + * eel/eel-image-chooser.c: (image_chooser_get_partial_dimensions): + * eel/eel-image.c: (image_get_pixbuf_dimensions), + (image_get_pixbuf_bounds), (image_get_tile_dimensions): + * eel/eel-label.c: (label_composite_text_callback_cached), + (label_get_text_dimensions), (label_get_text_bounds), + (label_get_content_dimensions), (label_get_content_bounds), + (label_get_tile_dimensions): + * eel/eel-labeled-image.c: (labeled_image_get_image_dimensions), + (labeled_image_get_label_dimensions), + (labeled_image_get_image_bounds_fill), + (eel_labeled_image_get_image_bounds), + (labeled_image_get_label_bounds_fill), + (eel_labeled_image_get_label_bounds), + (labeled_image_get_content_dimensions), + (labeled_image_get_content_bounds): + * eel/eel-scalable-font.c: (eel_scalable_font_measure_text): + * eel/eel-smooth-text-layout.c: + (eel_smooth_text_layout_get_dimensions): + * eel/eel-smooth-widget.c: (smooth_widget_get_tile_origin_point), + (eel_smooth_widget_get_tile_bounds), + (eel_smooth_widget_get_preferred_dimensions): + * eel/eel-viewport.c: (eel_viewport_get_scroll_offset): + * eel/eel-wrap-table.c: (wrap_table_art_irect_max_dimensions), + (wrap_table_get_max_child_dimensions), + (wrap_table_get_content_dimensions), + (wrap_table_get_content_bounds), (wrap_table_get_scroll_offset): + Update for art extensions constants renaming. + +2001-04-26 Ramiro Estrugo <[email protected]> + + * eel/eel-image-chooser.c: (image_chooser_motion_notify_event), + (image_chooser_button_press_event), + (image_chooser_button_release_event): + Use pointer grab technology to prevent the list from getting + events from unrelated widgets. + +2001-04-26 John Sullivan <[email protected]> + + * eel/eel-list.c: (eel_list_get_cell_hit_rectangle), (draw_cell): + Made drawing and hit-testing code immune to NULL text. This was + spewing out tons of complaints before in search results view + (from the fancy date-squeezing code). + +2001-04-26 John Sullivan <[email protected]> + + Merged from caja-1 branch: + + 2001-03-30 Ramiro Estrugo <[email protected]> + + reviewed by: John Harper <[email protected]> + + * eel/eel-stock-dialogs.c: (create_message_box): + Make sure the label is not NULL before changing its line wrap. + This works around the crashing problem. Why the label is NULL is + still a mystery. + +2001-04-26 Darin Adler <[email protected]> + + * eel/eel-debug.h: + * eel/eel-debug.c: (call_default_log_handler_with_better_message): + Add comment about handling cases where we're out of + memory. Removed unneeded NULL-handling code. + (eel_assert_computed_str), (eel_str_equal_with_free): Removed an + old unused feature. + + * eel/eel-mate-extensions.c: Formatting tweaks. + +2001-04-26 Ramiro Estrugo <[email protected]> + + * eel/eel-enumeration.h: + * eel/eel-enumeration.c: + (eel_enumeration_get_nth_description_translated), + (eel_enumeration_id_get_nth_description), + (eel_enumeration_id_get_nth_description_translated): + New functions to fetch translated descriptions. + +2001-04-26 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + Build the image chooser widget. + + * eel/eel-art-gtk-extensions.h: + * eel/eel-art-gtk-extensions.c: (eel_gdk_get_pointer_position): + New function to obtain the pointer position as a point. + + * eel/eel-caption.h: + * eel/eel-caption.c: (eel_caption_initialize_class), + (eel_caption_destroy), (caption_show_all), + (eel_caption_set_show_title): + Fix some rotten comments and other minor style tweaks. Remove + unused defines. Fix wrongly named show_all method, a cut-n-paste + mistake. + + * eel/eel-gdk-extensions.h: + * eel/eel-gdk-extensions.c: (eel_gdk_rgb_to_color): + Return the resulting color as a structure instead of a pointer. + + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-extensions.c: (eel_gtk_widget_standard_realize), + (eel_gtk_widget_standard_draw), + (eel_gtk_bin_standard_size_allocate), + (eel_gtk_bin_standard_size_request): + Implementations of some standard gtk widget methods. + + * eel/eel-label.c: + (eel_label_set_solid_background_color), + (eel_label_set_text_color): Fix a bug where the label + wouldnt properly update when some color attributes changed because + of a stale solid pixbuf cache. + + * eel/eel-radio-button-group.h: + * eel/eel-radio-button-group.c: + (eel_radio_button_group_clear): New function to clear out all the + items in the group. + (eel_radio_button_group_initialize_class): + (eel_radio_button_group_initialize), + (eel_radio_button_group_destroy), (button_toggled), + (eel_radio_button_group_insert): + Caja style tweaks. Remove unused constant. Change signal + signature to be simpler. Remove the signal data nastiness and let + the caller find out the active item by using the getter methods + instead. + (eel_radio_button_group_get_active_index), + (eel_radio_button_group_set_active_index): Use signed integers for + the active index. + + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_append): + New function to append one string list to another. + + * eel/eel-viewport.h: + * eel/eel-viewport.c: (eel_gtk_scrolled_window_add_with_viewport): + New convenience function to create scrolled windows with an + EelViewport as the child. + + * eel/eel.h: + Add eel-image-chooser.h + + * test/.cvsignore: + * test/Makefile.am: + Build the image chooser test. + + * test/test.h: + Include eel.h instead of the individual headers. + +2001-04-26 Ramiro Estrugo <[email protected]> + + * eel/eel-image-chooser.h: + * eel/eel-image-chooser.c: + New widget to choose an image from a list. + + * test/test-eel-image-chooser.c: + Test program for the new widget. + +2001-04-24 Darin Adler <[email protected]> + + reviewed by: Ramiro Estrugo <[email protected]> + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): + Add more log domains, most importantly "". + +2001-04-20 John Harper <[email protected]> + + reviewed by: Darin Adler <[email protected]> + + * eel/eel-mate-extensions.h, eel/eel-mate-extensions.c + (eel_mate_win_hints_get_area, + eel_mate_win_hints_get_current_area, + eel_mate_win_hints_set_area, + eel_mate_win_hints_set_current_area): new functions + + * eel/eel-gtk-extensions.c (eel_gtk_window_present): changed to + use the above new functions + + * eel/eel-gtk-extensions.h, eel/eel-gtk-extensions.c + (eel_gtk_window_is_on_current_workspace_and_area): new function + +2001-04-20 jacob berkman <[email protected]> + + * eel/eel-gtk-extensions.c (eel_gtk_window_present): make sure the + window is also on the current viewport/area. sawfish needs to be + updated to listen to _WIN_AREA changes though. + +2001-04-20 Ramiro Estrugo <[email protected]> + + * eel/eel-font-manager.c: (try_using_font_server): + Remove printf left in by accident. + +2001-04-20 Ramiro Estrugo <[email protected]> + + Fix for 8084 - Not all fonts are added to the font list in + preferences dialog. + + * eel/eel-font-manager.c: (try_using_font_server), + (ensure_local_font_table): + Try more than just one know location for the font server + configuation file. If different systems (like different Linux + distributions) put this in other places, then we'll have to update + this code as we know more. Seems lame, but I guess if + distributors and "users" have a choice where to put config files, + then we have no choice but comply. + +2001-04-20 Ramiro Estrugo <[email protected]> + + * eel/eel-glib-extensions.h: + * eel/eel-glib-extensions.c: (eel_get_operating_system_name), + (eel_self_check_glib_extensions): + New function to find out the system name. + +2001-04-20 Ramiro Estrugo <[email protected]> + + * configure.in: + Use /usr/X instead of /usr/openwin which is the new way on + solaris. + +2001-04-20 Ramiro Estrugo <[email protected]> + + Fix for bug 7847 - SOLARIS: When Smoother Graphics turned on - + cannot change Fonts. + + * acconfig.h: + * configure.in: + * eel/eel-font-manager.c: (ensure_local_font_table): + Add support for reaping fonts even when the system is not using + the font server. + + * eel/eel-string-list.c: (eel_self_check_string_list): + Add a few more checks for string tokenizing. + +2001-04-19 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: Add a log domain define for Eel. + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): Remove + G_LOG_DOMAIN item as it will be the same as Eel for this module. + Add Gdk-Pixbuf to the list of standard log domains. + +2001-04-19 Ramiro Estrugo <[email protected]> + + * eel/eel-debug.c: + (eel_make_warnings_and_criticals_stop_in_debugger): + Add a list of "standard" domains for which this debugging feature + is always turned on. + +2001-04-19 Darin Adler <[email protected]> + + reviewed by: Ramiro Estrugo <[email protected]> + + * eel/eel-debug.c: (get_process_name), + (call_default_log_handler_with_better_message), (log_handler), + (set_log_handler), + (eel_make_warnings_and_criticals_stop_in_debugger): + Add the process name and number prefix to all lines. Also fix + the use of getuid where we meant to use getpid. Also tweak + the names of things a bit to make it nicer. + +2001-04-19 Ramiro Estrugo <[email protected]> + + reviewed by: Darin Adler <[email protected]> + + * eel/eel-debug.c: (get_process_command_line): A function to try + and obtain the command line used to invoke the process. + (eel_stop_after_default_log_handler): Print out the process id + and possible command line to make the warning/critical more + useful. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (canvas_item_update_svp_no_repaint), + (canvas_item_update_svp_clip_no_repaint), (rect_update): Renamed + the internal functions to make it more clear what they do. + (eel_canvas_rect_initialize_class): Improved comment. + (rects_intersect): Changed name. + (diff_rects): Update for new name of rects_intersect. + (test_rects_intersect), (eel_self_check_canvas_rect): Added tests + for rects_intersect. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (rect_update): Removed a bunch of code + that's not needed since we decided to optimize only the case + where the canvas is an anti-aliased one. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (rect_update): Fixed backwards logic that + made it never draw the outline. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (make_drect): New function. + (make_empty_drect): New function. + (make_rect_vpath): Changed to take ArtDRect. + (eel_canvas_item_update_svp), (eel_canvas_item_update_svp_clip): + Stole functions from MateCanvas code, because we need versions + that don't do a request_update. + (canvas_request_update_rect): New function. + (rect_update): Changed to do smart calculation about what to + update using the diff_rects function. + (diff_rects_guts), (diff_rects): New implementation that doesn't + use macros. Also changed to leave out empty rectangles. + (eel_self_check_canvas_rect): Updated tests that involve empty + rectangles and added some new ones. + +2001-04-18 Christopher James Lahey <[email protected]> + + * eel/eel-canvas-rect.c (intersect_rectangles): Fixed the + intersect_rectangles function to have rectangles that are tangent + return as not intersecting. + (eel_self_check_canvas_rect): Fixed the tests. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (rect_update): Call diff_rectangles so we + don't get an unused function warning. + (diff_rectangles): Took out of #if 0 and made it compile without + warnings. + (test_diff_rectangles): Test function that uses string for result. + (eel_self_check_canvas_rect): Added two self-tests. The one that + currently fails is commented out. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.h: + * eel/eel-canvas-rect.c: (set_gc_foreground), (set_stipple), + (set_outline_gc_width), (re_update_shared), (re_get_bounds), + (make_rect_vpath), (rect_update): Copied the update function + and everything it needs in here, so we can prepare to modify it. + +2001-04-18 Christopher James Lahey <[email protected]> + + * eel/eel-canvas-rect.c: Added some tests #ifdefed out. Wrote the + diff and intersection functions. + +2001-04-18 Darin Adler <[email protected]> + + * eel/eel-canvas-rect.c: (eel_self_check_canvas_rect): + * eel/eel-lib-self-check-functions.h: + Added a self-check function for EelCanvasRect. + + * eel/eel-self-checks.c: (eel_exit_if_self_checks_failed): + Formatting tweak. + +2001-04-18 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel-canvas-rect.c: + * eel/eel-canvas-rect.h: + Added new class that Chris Lahey and I are working on should make + the selection rectangle in Caja much faster. + +2001-04-18 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: Add the generated files to the CLEANFILES so + that 'make clean' gets rid of them properly. + +2001-04-18 Ramiro Estrugo <[email protected]> + + * eel/eel-enumeration.h: + * eel/eel-enumeration.c: (eel_enumeration_contains_name), + (eel_enumeration_id_contains_name), (eel_self_check_enumeration): + New functions to check whether an enumeration contains a specific + name. + + * eel/eel-string-picker.h: + * eel/eel-string-picker.c: (eel_string_picker_initialize), + (eel_string_picker_destroy), (option_menu_activate_callback), + (menu_item_set_sensitivity_callback), + (menu_item_update_sensitivity), + (string_picker_update_menu_sensitivities), + (eel_string_picker_set_insensitive_list): + Add support for installing a list of insensitive choices. + (eel_string_picker_set_string_list): Make sure the list is + different before actually doing any work. + (eel_string_picker_get_string_list), + (eel_string_picker_get_selected_string), + (eel_string_picker_set_selected_string), + (eel_string_picker_set_selected_string_index), + (eel_string_picker_insert_string), (eel_string_picker_contains), + (eel_string_picker_get_index_for_string), + (eel_string_picker_clear): Some minor tweaking to conform with + Caja style some more. + +2001-04-17 Darin Adler <[email protected]> + + * eel/Makefile.am: + * eel/eel.h: + Take eel-dnd.h out. This should go back to Caja at some + point, I think. + + * eel/eel-dnd.h: + * eel/eel-dnd.c: + (is_path_that_mate_uri_list_extract_filenames_can_parse), + (add_one_compatible_uri), (eel_drag_drag_data_get): Another cut + at making the kind of "URL" that is compatible with bad old + URL-parsing code. + +2001-04-17 Ramiro Estrugo <[email protected]> + + * eel/eel-string-list.h: + * eel/eel-string-list.c: + (eel_string_list_copy): Better name for this function. Dont need + case_sensitive parameter since it can be fetched from the + string_list we are about to copy. + (eel_string_list_as_g_slist): Change list variable name to make + things a tiny bit clearer. + (eel_string_list_as_string): Better name for this function. Add a + num_strings parameter that can be used to limit the number of + strings from the list used to make the new concatenated string. + (eel_self_check_string_list): Update for _as_string changes. + + * eel/eel-enumeration.c: (eel_enumeration_copy), + (eel_enumeration_get_names): Update for _copy changes. + + * eel/eel-gdk-font-extensions.c: (xlfd_string_replace_nth): + Update for _as_string changes. + + * eel/eel-self-checks.c: (eel_check_string_list_result): Update + for _as_string changes. + + * eel/eel-string-picker.c: (eel_string_picker_get_string_list), + (eel_string_picker_insert_string): Update for _copy changes. + +2001-04-17 Darin Adler <[email protected]> + + * eel/eel-dnd.c: (add_one_path_with_file_prefix): Coddle existing + drag and drop recipients who use the mate-libs helper functions. + For them, we must provide a "URL" (quotes intentional) that is + just a full path with "file:" stuck on the beginning. + +2001-04-17 Ramiro Estrugo <[email protected]> + + * eel/eel-string-list.h: + * eel/eel-string-list.c: + (eel_string_list_new_from_g_slist): New function to create string + lists from GLists. + (eel_string_list_new_from_g_list), (eel_string_list_as_g_slist): + Better names for the GLlist and GSList functions. + (eel_string_list_as_concatenated_string): Return an empty string + ("") if the input string list is NULL. + (eel_string_list_for_each): Make the for_each iterator a little + more type safe. + (eel_self_check_string_list): New checks for GSList functions. + New function to create string lists from GLists. Better names for + the GLlist and GSList functions. + +2001-04-17 Ramiro Estrugo <[email protected]> + + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_new_from_slist), + (eel_string_list_as_slist), (eel_self_check_string_list): + New function to create string lists from slists. + +2001-04-17 Ramiro Estrugo <[email protected]> + + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_new), + (eel_string_list_new_from_string), + (eel_string_list_new_from_string_list), + (eel_string_list_new_from_tokens), + (eel_string_list_assign_from_string_list), + (eel_string_list_insert), (eel_string_list_nth), + (eel_string_list_nth_as_integer), (eel_string_list_modify_nth), + (eel_string_list_remove_nth), (eel_string_list_contains), + (eel_string_list_find_by_function), (eel_string_list_get_length), + (eel_string_list_clear), (eel_string_list_equals), + (eel_string_list_as_g_slist), + (eel_string_list_get_index_for_string), + (eel_string_list_as_concatenated_string), (eel_string_list_sort), + (eel_string_list_sort_by_function), + (eel_string_list_remove_duplicates), (eel_string_list_for_each), + (eel_string_list_get_longest_string), + (eel_string_list_get_longest_string_length), (str_is_equal), + (eel_self_check_string_list): + Change implementation of string list to use a GSList instead of a + GList. A few changes to match the caja style more. + +2001-04-16 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + Use RSVG_CFLAGS not RSVG_LIBS. + + * eel/eel-self-checks.c: (eel_check_string_list_result): + * eel/eel-self-checks.h: + Add support for EelStringList checks. + + * eel/eel-string-list.h: + * eel/eel-string-list.c: (eel_string_list_is_case_sensitive): + New function that returns whether the string list is case + sensitive or not. + +2001-04-16 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: Make the self checks header private and dont + install it. Remove some unused include flags and a debug printf. + + * eel/eel.h: Dont include the self checks header since its now + private. + + * test/Makefile.am: Remove some unused include flags. + +2001-04-16 Maciej Stachowiak <[email protected]> + + * eel/Makefile.am: Fix `make distcheck'. + +2001-04-16 Darin Adler <[email protected]> + + * eel/Makefile.am: Remove stray reference to eel-boxed.defs + that was making the Tinderbox unhappy. + +2001-04-16 Maciej Stachowiak <[email protected]> + + * configure.in, eel/.cvsignore, eel/Makefile.am, eel/eel-types.c, + eel/eel-types.h, eel/eel.h, eel/makeenums.pl, eel/maketypes.awk: + Automatically generate GtkTypes for the various enumerations in + eel like gtk+ and mate do. This is needed for language bindings. + +2001-04-13 Pavel Cisler <[email protected]> + + * eel/eel-list.c: (get_cell_text), + (eel_list_get_cell_hit_rectangle), (eel_list_item_hit), + (eel_list_button_press), (eel_list_button_release): + Add proper hit testing to the list view -- items now only get hit when + you click on text or an icon, clicking in empty space deselects. + + * eel/eel-list.c:(eel_list_setup_style_colors): + Tweak divider line colors to match Arlo's original spec. + + * eel/eel-list.c: (draw_cell), + (eel_list_get_initial_drag_offset): + Some small tweaks. + +2001-04-13 Ramiro Estrugo <[email protected]> + + * eel/eel-gdk-font-extensions.c: (eel_gdk_font_get_fixed): + Dont use the translated font anymore, thats the old broken way. + Try to load just a font (not a fontset) if the first try fails. + +2001-04-12 Ramiro Estrugo <[email protected]> + + * eel/check-program.c: (main): + * eel/eel-glib-extensions.c: (eel_g_hash_table_new_free_at_exit): + Use CAJA_DEBUG, not EEL_DEBUG for now. + + * eel/eel-font-manager.c: (ensure_local_font_table): + Use ~/.caja instead of ~/.eel for compatibility. + +2001-04-09 Pavel Cisler <[email protected]> + + reviewed by: Mike Engber <[email protected]> + + * eel/eel-ellipsizing-label.c: (recompute_ellipsized_text): + * eel/eel-gdk-font-extensions.c: (eel_string_ellipsize), + (eel_self_check_ellipsize): + * eel/eel-gdk-font-extensions.h: + Tweak the API of the ellipsizing functions to make it a little + more convenient to use. + +2001-04-09 John Sullivan <[email protected]> + + reviewed by: Pavel Cisler <[email protected]> + + * eel/eel-list-column-title.h: + * eel/eel-list-column-title.c: + (eel_list_column_title_queue_draw): New public function. + + * eel/eel-list.h: + * eel/eel-list.c: + (eel_list_set_sort_column), (eel_list_set_sort_type): New + functions that call eel_clist versions and also make the + column titles redraw. + +2001-04-08 Ramiro Estrugo <[email protected]> + + * eel/eel-enumeration.h: + * eel/eel-enumeration.c: (eel_enumeration_new), + (eel_enumeration_copy), (eel_enumeration_free), + (eel_enumeration_insert), (eel_enumeration_get_id), + (eel_enumeration_get_nth_name), + (eel_enumeration_get_nth_description), + (eel_enumeration_get_nth_value), (eel_enumeration_get_length), + (eel_enumeration_new_from_tokens), + (eel_enumeration_get_name_position), + (eel_enumeration_get_description_position), + (eel_enumeration_get_value_position), (eel_enumeration_get_names), + (eel_enumeration_insert_entries), + (enumeration_table_free_one_node), (enumeration_table_free), + (enumeration_table_get), (enumeration_table_lookup), + (enumeration_register), (eel_enumeration_register), + (eel_enumeration_lookup), (eel_enumeration_id_get_nth_name), + (eel_enumeration_id_get_nth_description), + (eel_enumeration_id_get_nth_value), + (eel_enumeration_id_get_length), + (eel_enumeration_id_get_name_position), + (eel_enumeration_id_get_description_position), + (eel_enumeration_id_get_value_position), + (eel_self_check_enumeration): + Add a way to register and query a global preference table using + string ids. Makes it easier to deal with enumerations. Perhaps + we can even lost the non id based functions. + +2001-04-05 Andy Hertzfeld <[email protected]> + + * eel/eel-gtk-extensions.c: (eel_gtk_marshal_POINTER__POINTER_INT): + * eel/eel-gtk-extensions.h: + added marshalling function needed for my post-1_0 branch + +2001-04-05 Pavel Cisler <[email protected]> + + reviewed by: John Harper <[email protected]> + + Code needed to support nice list view column resizing. + + * eel/eel-gtk-extensions.c: + (eel_gtk_marshal_POINTER__INT_INT_POINTER_POINTER): + * eel/eel-gtk-extensions.h: + Add a marshalling function. + + * eel/eel-list.c: (eel_list_initialize_class), (get_cell_text), + (draw_cell): + * eel/eel-list.h: + Use a signal to get the cell text, formatted for the right width. + +2001-04-05 Pavel Cisler <[email protected]> + + * eel/Makefile.am: + More fixes to not pick up libraries from /usr/lib first. + Checking in for Ramiro. + +2001-04-05 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + Put freettype and png libs at end of link line to prevent /usr/lib conflict. + +2001-04-05 Ramiro Estrugo <[email protected]> + + * eel/eel-dnd.h: + * eel/eel-dnd.c: (eel_drag_init), (eel_drag_selection_item_new), + (drag_selection_item_destroy), (eel_drag_build_selection_list), + (eel_drag_items_local), (eel_drag_items_in_trash), + (eel_drag_default_drop_action_for_icons): + Make some constant private as they were not used anywhere else. + Make sure all public structures have an Eel namespace. + + * eel/eel-clist.c: + * eel/eel-clist.h: + * eel/eel-list.c: + * eel/eel-list.h: + Indentation. + + * Makefile.am: + * eel/eel-string-map.h: + * eel/eel-string-map.c: + * eel/eel-lib-self-check-functions.h: + Retire unused code. + + * eel/eel-vfs-extensions.h: + * eel/eel-vfs-extensions.c: + Fix the authors blurb. + +2001-04-04 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + * eel/eel-clist.c: + * eel/eel-clist.h: + * eel/eel-ctree.c: + * eel/eel-ctree.h: + * eel/eel-dnd.c: + * eel/eel-dnd.h: + * eel/eel-list-column-title.c: + * eel/eel-list-column-title.h: + * eel/eel-list.c: + * eel/eel-list.h: + Move clist, ctree, and list widgets over from Caja. + +2001-04-04 Ramiro Estrugo <[email protected]> + + * eel.spec.in: + Fix a dumb mistake in how the date was specified. + +2001-04-04 Ramiro Estrugo <[email protected]> + + * eel/Makefile.am: + * eel/eel-lib-self-check-functions.h: + * eel/eel-vfs-extensions.h: + * eel/eel-vfs-extensions.c: (eel_read_entire_file), + (read_file_close_callback), (read_file_close), + (read_file_succeeded), (read_file_failed), + (read_file_read_callback), (read_file_read_chunk), + (read_file_open_callback), + (pthread_eel_read_file_callback_idle_binder), + (pthread_eel_read_file_callback_common), + (pthread_eel_read_file_synchronous_callback), + (pthread_eel_read_file_asynchronous_callback), + (pthread_eel_read_file_thread_entry), + (pthread_eel_read_file_async), + (pthread_eel_read_file_async_cancel), (eel_read_file_async), + (eel_read_entire_file_async), (eel_read_file_cancel), + (eel_uri_is_trash), (eel_uri_is_trash_folder), + (eel_uri_is_in_trash), (eel_format_uri_for_display), + (is_valid_scheme_character), (has_valid_scheme), + (eel_make_uri_from_input), (file_uri_from_local_relative_path), + (eel_make_uri_from_shell_arg), (eel_uri_get_basename), + (eel_uri_get_scheme), (is_uri_partial), + (remove_internal_relative_components), + (eel_uri_make_full_from_relative), (eel_uri_is_local_scheme), + (eel_handle_trailing_slashes), (eel_make_uri_canonical), + (eel_make_uri_canonical_strip_fragment), (uris_match), + (eel_uris_match), (eel_uris_match_ignore_fragments), + (eel_is_remote_uri), (eel_make_directory_and_parents), + (eel_copy_uri_simple), (eel_self_check_vfs_extensions): + Move mate-vfs extensions over from + caja/caja-file-utilities.[ch] + +2001-04-04 Ramiro Estrugo <[email protected]> + + * HACKING: + * README: + * RENAMING: + * THANKS: + Updated to be Eel specific. Removed crufy leftover from Caja + move. + + * configure.in: + * eel.spec.in: + Remove unused popt and imlib depenencies. + +2001-04-04 Ramiro Estrugo <[email protected]> + + * eel/check-program.c: (main): + Cleanup a lot of leftover cruft. + + * eel/eel-art-extensions.h: + * eel/eel-art-gtk-extensions.h: + * eel/eel-background-canvas-group.c: + * eel/eel-background.c: + * eel/eel-background.h: + * eel/eel-caption-table.c: + * eel/eel-caption-table.h: + * eel/eel-caption.c: + * eel/eel-caption.h: + * eel/eel-clickable-image.c: + * eel/eel-clickable-image.h: + * eel/eel-debug-drawing.c: + * eel/eel-debug-drawing.h: + * eel/eel-debug.h: + * eel/eel-ellipsizing-label.c: + * eel/eel-ellipsizing-label.h: + * eel/eel-enumeration.h: + * eel/eel-font-manager.c: + * eel/eel-font-manager.h: + * eel/eel-font-picker.c: + * eel/eel-font-picker.h: + * eel/eel-gdk-extensions.h: + * eel/eel-gdk-font-extensions.c: + * eel/eel-gdk-font-extensions.h: + * eel/eel-gdk-pixbuf-extensions.c: + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-glib-extensions.h: + * eel/eel-glyph.c: + * eel/eel-glyph.h: + * eel/eel-mate-extensions.h: + * eel/eel-graphic-effects.h: + * eel/eel-gtk-extensions.h: + * eel/eel-image-table.c: + * eel/eel-image-table.h: + * eel/eel-image.c: + * eel/eel-image.h: + * eel/eel-label.c: + * eel/eel-label.h: + * eel/eel-labeled-image.c: + * eel/eel-labeled-image.h: + * eel/eel-password-dialog.c: + * eel/eel-password-dialog.h: + * eel/eel-radio-button-group.c: + * eel/eel-radio-button-group.h: + * eel/eel-region.h: + * eel/eel-scalable-font.c: + * eel/eel-scalable-font.h: + * eel/eel-self-checks.h: + * eel/eel-smooth-text-layout-cache.c: + * eel/eel-smooth-text-layout-cache.h: + * eel/eel-smooth-text-layout.c: + * eel/eel-smooth-text-layout.h: + * eel/eel-smooth-widget.c: + * eel/eel-smooth-widget.h: + * eel/eel-stock-dialogs.h: + * eel/eel-string-list.c: + * eel/eel-string-list.h: + * eel/eel-string-map.c: + * eel/eel-string-map.h: + * eel/eel-string-picker.c: + * eel/eel-string-picker.h: + * eel/eel-string.h: + * eel/eel-text-caption.c: + * eel/eel-text-caption.h: + * eel/eel-viewport.c: + * eel/eel-viewport.h: + * eel/eel-wrap-table.c: + * eel/eel-wrap-table.h: + * eel/eel-xml-extensions.h: + Many style and indention changes. + +2001-04-03 Darin Adler <[email protected]> + + reviewed by: Ramiro + + * eel/Makefile.am: Make a eel-background-canvas-group.h + private. Remove duplicate FREETYPE2_LIBS. + * eel/eel-glib-extensions.h: Get rid of EEL_MACRO_BEGIN and + EEL_MACRO_END (too close to G_STMT_START/END). + +2001-04-03 Ramiro Estrugo <[email protected]> + + * eel/eel-ellipsizing-label.c: (recompute_ellipsized_text): + Synchronize with Caja (for the last time hopefully). + +2001-04-02 Ramiro Estrugo <[email protected]> + + * test/test-eel-label.c: + * test/test.h: + Remove rogue unused #includes. + +2001-04-02 Ramiro Estrugo <[email protected]> + + * configure.in: + Stuff that goes in eelConf.sh was missing. + +2001-04-02 Ramiro Estrugo <[email protected]> + + * eel-config.in: + * eelConf.sh.in: + Eelify. + +2001-04-02 Ramiro Estrugo <[email protected]> + + * eel/check-eel: + Run checks with --sm-disable so that the session manager will not + hang and show dialogs. + +2001-04-02 Ramiro Estrugo <[email protected]> + + * eel/eel-background-canvas-group.c: + (eel_background_canvas_group_initialize_common): + * eel/eel-font-manager.c: (eel_font_manager_get_default_font): + * eel/eel-gdk-font-extensions.c: + * eel/eel-stock-dialogs.c: + (timed_wait_delayed_close_timeout_callback), (timed_wait_free): + * eel/eel-text-caption.c: + Synchronize with Caja. + +2001-04-02 Ramiro Estrugo <[email protected]> + + * acconfig.h: + * configure.in: + * eel.spec.in: + * eel/Makefile.am: + * eel/eel-art-extensions.h: + * eel/eel-art-gtk-extensions.h: + * eel/eel-background-canvas-group.c: + (eel_background_canvas_group_initialize_common): + * eel/eel-background.c: (eel_background_destroy): + * eel/eel-background.h: + * eel/eel-caption-table.h: + * eel/eel-caption.c: (eel_caption_set_child), + (eel_caption_set_extra_spacing): + * eel/eel-caption.h: + * eel/eel-clickable-image.h: + * eel/eel-debug-drawing.c: (eel_debug_show_pixbuf_in_eog): + * eel/eel-debug-drawing.h: + * eel/eel-debug.h: + * eel/eel-ellipsizing-label.h: + * eel/eel-entry.c: (emacs_shortcuts_preference_changed_callback), + (eel_entry_initialize), (eel_entry_destroy): + * eel/eel-entry.h: + * eel/eel-enumeration.c: (eel_enumeration_new_from_tokens), + (eel_enumeration_get_entry_position), + (eel_enumeration_get_value_position), + (eel_enumeration_get_entries), (eel_self_check_enumeration): + * eel/eel-enumeration.h: + * eel/eel-file-utilities.h: + * eel/eel-font-factory.c: + (eel_font_factory_get_font_from_preferences): + * eel/eel-font-factory.h: + * eel/eel-font-manager.c: (font_description_table_add), + (font_description_table_new), (directory_contains_file), + (ensure_local_font_table), (eel_font_manager_get_default_font), + (eel_font_manager_get_default_bold_font), + (eel_self_check_font_manager): + * eel/eel-font-manager.h: + * eel/eel-font-picker.h: + * eel/eel-gdk-extensions.h: + * eel/eel-gdk-font-extensions.c: (eel_string_ellipsize_start), + (eel_string_ellipsize_end), (eel_string_ellipsize_middle), + (eel_self_check_ellipsize), (eel_self_check_ellipsize_start), + (eel_self_check_ellipsize_middle), (eel_self_check_ellipsize_end), + (eel_self_check_gdk_font_extensions): + * eel/eel-gdk-font-extensions.h: + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-glib-extensions.h: + * eel/eel-glyph.h: + * eel/eel-mate-extensions.h: + * eel/eel-graphic-effects.h: + * eel/eel-gtk-extensions.h: + * eel/eel-image-table.h: + * eel/eel-image.h: + * eel/eel-label.c: (eel_label_set_text): + * eel/eel-label.h: + * eel/eel-labeled-image.h: + * eel/eel-lib-self-check-functions.h: + * eel/eel-password-dialog.h: + * eel/eel-radio-button-group.h: + * eel/eel-region.h: + * eel/eel-scalable-font.h: + * eel/eel-self-checks.h: + * eel/eel-smooth-text-layout-cache.h: + * eel/eel-smooth-text-layout.h: + * eel/eel-smooth-widget.c: + (eel_smooth_widget_global_set_is_smooth), + (eel_smooth_widget_register): + * eel/eel-smooth-widget.h: + * eel/eel-stock-dialogs.h: + * eel/eel-string-list.h: + * eel/eel-string-map.h: + * eel/eel-string-picker.h: + * eel/eel-string.h: + * eel/eel-text-caption.h: + * eel/eel-viewport.h: + * eel/eel-wrap-table.h: + * eel/eel-xml-extensions.h: + * test/Makefile.am: + * test/test.c: (eel_pixmap_file): + * test/test.h: + Synchronize with caja. + +2001-03-28 Ramiro Estrugo <[email protected]> + + * eel.spec.in: + First pass at making the spec file valid. + +2001-03-28 Ramiro Estrugo <[email protected]> + + * Makefile.am: + * acconfig.h: + * configure.in: + Remove more Caja cruft. Make distcheck now passes. + +2001-03-28 Ramiro Estrugo <[email protected]> + + Change 'caja' namespace to 'eel' everywhere. + + * eel/Makefile.am: + * eel/check-program.c: (main): + * eel/eel-art-extensions.c: (eel_art_irect_contains_irect), + (eel_art_irect_contains_point), (eel_art_irect_hits_irect), + (eel_art_irect_equal), (eel_art_drect_equal), + (eel_art_irect_is_valid), (eel_art_irect_assign), + (eel_art_irect_get_width), (eel_art_irect_get_height), + (eel_art_irect_align), (eel_dimensions_empty), + (eel_art_irect_assign_dimensions), (eel_art_irect_offset_by), + (eel_art_irect_offset_to), (eel_art_irect_scale_by), + (eel_art_irect_inset), (eel_art_drect_offset_by), + (eel_art_drect_offset_to), (eel_art_irect_offset_by_point), + (eel_art_irect_offset_to_point), (eel_art_drect_scale_by), + (eel_art_drect_inset), (eel_self_check_art_extensions): + * eel/eel-art-extensions.h: + * eel/eel-art-gtk-extensions.c: (eel_gdk_rectangle_to_art_irect), + (eel_screen_get_dimensions), (eel_gdk_window_get_bounds), + (eel_gdk_window_get_screen_relative_bounds), + (eel_gtk_widget_get_bounds), (eel_gtk_widget_get_dimensions), + (eel_gtk_widget_get_preferred_dimensions), + (eel_gdk_window_clip_dirty_area_to_screen), + (eel_art_irect_to_gdk_rectangle), (eel_gdk_window_get_dimensions): + * eel/eel-art-gtk-extensions.h: + * eel/eel-background-canvas-group.c: + (eel_background_canvas_group_initialize_class), + (eel_background_canvas_group_initialize_common), + (eel_background_canvas_group_initialize), + (eel_background_canvas_group_supplant_root_class), + (eel_background_canvas_group_update), + (eel_background_canvas_group_draw), + (eel_background_canvas_group_render): + * eel/eel-background-canvas-group.h: + * eel/eel-background.c: (eel_background_initialize_class), + (eel_background_initialize), (eel_background_remove_current_image), + (eel_background_destroy), (eel_background_get_combine_mode), + (eel_background_set_combine_mode), + (eel_background_get_image_placement), + (eel_background_set_image_placement_no_emit), + (eel_background_set_image_placement), (eel_background_new), + (reset_cached_color_info), + (eel_background_ensure_gradient_buffered), + (fill_canvas_from_gradient_buffer), + (eel_background_image_totally_obscures), + (eel_background_ensure_image_scaled), (eel_background_pre_draw), + (eel_background_draw), (eel_background_draw_to_drawable), + (eel_background_draw_to_pixbuf), (draw_pixbuf_tiled_aa), + (eel_background_draw_aa), (eel_background_draw_to_canvas), + (eel_background_get_color), (eel_background_get_image_uri), + (eel_background_set_color_no_emit), (eel_background_set_color), + (eel_background_load_image_callback), + (eel_background_is_image_load_in_progress), + (eel_background_cancel_loading_image), + (eel_background_start_loading_image), + (eel_background_set_image_uri_helper), + (eel_background_set_image_uri), + (set_image_and_color_image_loading_done_callback), + (eel_background_set_image_uri_and_color), + (eel_background_receive_dropped_background_image), + (eel_gtk_style_get_default_class), (eel_gdk_window_update_sizes), + (eel_background_draw_flat_box), + (eel_background_get_gtk_style_class), + (eel_background_set_widget_style), (eel_background_is_set), + (eel_background_is_loaded), (eel_background_reset), + (eel_background_set_up_canvas), (eel_widget_background_changed), + (eel_get_widget_background), (eel_widget_has_attached_background), + (eel_gtk_widget_find_background_ancestor), + (eel_background_is_too_complex_for_gtk_style), + (eel_background_is_dark), (eel_background_receive_dropped_color), + (eel_self_check_background): + * eel/eel-background.h: + * eel/eel-caption-table.c: (eel_caption_table_initialize_class), + (eel_caption_table_initialize), (caption_table_destroy), + (eel_caption_table_resize), (caption_table_index_of_entry), + (caption_table_find_next_sensitive_entry), (entry_activate), + (eel_caption_table_new), (eel_caption_table_set_row_info), + (eel_caption_table_set_entry_text), + (eel_caption_table_set_entry_readonly), + (eel_caption_table_entry_grab_focus), + (eel_caption_table_get_entry_text), + (eel_caption_table_get_num_rows): + * eel/eel-caption-table.h: + * eel/eel-caption.c: (eel_caption_initialize_class), + (eel_caption_initialize), (eel_caption_destroy), + (eel_font_picker_show_all), (update_title), (eel_caption_new), + (eel_caption_set_title_label), (eel_caption_set_show_title), + (eel_caption_get_title_label), (eel_caption_get_title_label_width), + (eel_caption_set_child), (eel_caption_set_spacing): + * eel/eel-caption.h: + * eel/eel-clickable-image.c: + (eel_clickable_image_initialize_class), + (eel_clickable_image_initialize), (eel_clickable_image_destroy), + (eel_clickable_image_get_arg), (eel_clickable_image_realize), + (label_enter), (label_leave), (label_handle_motion), + (label_handle_button_press), (label_handle_button_release), + (ancestor_enter_notify_event), (ancestor_leave_notify_event), + (ancestor_motion_notify_event), (ancestor_button_press_event), + (ancestor_button_release_event), + (eel_clickable_image_expose_event), + (eel_clickable_image_set_up_pixbufs), (eel_clickable_image_new), + (eel_clickable_image_new_from_file_name), + (eel_clickable_image_new_solid), + (eel_clickable_image_set_prelight): + * eel/eel-clickable-image.h: + * eel/eel-debug-drawing.c: (debug_pixbuf_viewer_destroy), + (debug_pixbuf_viewer_size_request), + (debug_pixbuf_viewer_expose_event), + (debug_pixbuf_viewer_set_pixbuf), + (eel_debug_draw_rectangle_and_cross), + (eel_debug_show_pixbuf_in_eog), (eel_debug_show_pixbuf), + (eel_debug_pixbuf_draw_point), (eel_debug_pixbuf_draw_rectangle), + (eel_debug_pixbuf_draw_rectangle_inset): + * eel/eel-debug-drawing.h: + * eel/eel-debug.c: (eel_stop_in_debugger), + (eel_stop_after_default_log_handler), + (eel_set_stop_after_default_log_handler), + (eel_make_warnings_and_criticals_stop_in_debugger), + (eel_get_available_file_descriptor_count), + (eel_str_equal_with_free): + * eel/eel-debug.h: + * eel/eel-ellipsizing-label.c: + (eel_ellipsizing_label_initialize_class), + (eel_ellipsizing_label_initialize), (real_destroy), + (eel_ellipsizing_label_new), (recompute_ellipsized_text), + (eel_ellipsizing_label_set_text), (real_size_request), + (real_size_allocate), (real_style_set): + * eel/eel-ellipsizing-label.h: + * eel/eel-entry.c: (eel_entry_initialize), (eel_entry_new), + (eel_entry_new_with_max_length), (eel_entry_destroy), + (obscure_cursor), (eel_entry_key_press), (eel_entry_motion_notify), + (eel_entry_select_all), (select_all_at_idle), + (eel_entry_select_all_at_idle), (eel_entry_set_text), + (eel_entry_set_selection), (eel_entry_button_press), + (eel_entry_button_release), (eel_entry_insert_text), + (eel_entry_delete_text), (eel_entry_selection_clear), + (eel_entry_initialize_class): + * eel/eel-entry.h: + * eel/eel-enumeration.c: (eel_enumeration_new), + (eel_enumeration_free), (eel_enumeration_insert), + (eel_enumeration_get_nth_entry), + (eel_enumeration_get_nth_description), + (eel_enumeration_get_nth_value), (eel_enumeration_get_num_entries), + (eel_self_check_enumeration): + * eel/eel-enumeration.h: + * eel/eel-file-utilities.c: (eel_format_uri_for_display), + (eel_make_uri_from_input), (file_uri_from_local_relative_path), + (eel_make_uri_from_shell_arg), (eel_uri_get_basename), + (eel_uri_get_scheme), (eel_uri_make_full_from_relative), + (eel_uri_is_trash), (eel_uri_is_trash_folder), + (eel_uri_is_in_trash), (eel_uri_is_local_scheme), + (eel_handle_trailing_slashes), (eel_make_uri_canonical), + (eel_make_uri_canonical_strip_fragment), (uris_match), + (eel_uris_match), (eel_uris_match_ignore_fragments), + (eel_file_name_matches_hidden_pattern), + (eel_file_name_matches_backup_pattern), (eel_make_path), + (eel_get_user_directory), (eel_get_desktop_directory), + (eel_user_main_directory_exists), (eel_get_pixmap_directory), + (eel_is_remote_uri), (eel_pixmap_file), (eel_read_entire_file), + (read_file_close), (read_file_succeeded), (read_file_failed), + (read_file_read_callback), (read_file_read_chunk), + (read_file_open_callback), + (pthread_eel_read_file_callback_idle_binder), + (pthread_eel_read_file_callback_common), + (pthread_eel_read_file_synchronous_callback), + (pthread_eel_read_file_asynchronous_callback), + (pthread_eel_read_file_thread_entry), + (pthread_eel_read_file_async), + (pthread_eel_read_file_async_cancel), (eel_read_file_async), + (eel_read_entire_file_async), (eel_read_file_cancel), + (eel_make_directory_and_parents), (eel_copy_uri_simple), + (eel_unique_temporary_file_name), (eel_get_build_time_stamp), + (eel_get_build_message), (eel_self_check_file_utilities): + * eel/eel-file-utilities.h: + * eel/eel-font-factory.c: (eel_get_current_font_factory), + (eel_font_factory_get), (eel_font_factory_initialize), + (eel_font_factory_initialize_class), (destroy), + (font_hash_node_lookup), (font_hash_node_lookup_with_insertion), + (eel_font_factory_get_font_by_family), + (eel_font_factory_get_font_from_preferences): + * eel/eel-font-factory.h: + * eel/eel-font-manager.c: (font_description_new), + (font_description_table_add), (font_get_font_type), + (font_description_table_find), (font_description_table_for_each), + (font_description_table_new), (directory_contains_file), + (font_directory_is_ignored), (font_foundry_is_ignored), + (font_family_is_ignored), (font_manager_collect_font_tables), + (ensure_local_font_table), (eel_font_manager_for_each_font), + (eel_font_manager_get_default_font), + (eel_font_manager_get_default_bold_font), + (eel_font_manager_file_is_scalable_font), + (font_list_find_bold_callback), (eel_font_manager_get_bold), + (eel_font_manager_weight_is_bold), (get_test_font_dir), + (eel_self_check_font_manager): + * eel/eel-font-manager.h: + * eel/eel-font-picker.c: (eel_font_picker_initialize_class), + (option_menu_button_press_event), (menu_deactivate), + (eel_font_picker_initialize), (eel_font_picker_destroy), + (font_list_find), (style_menu_item_activate_callback), + (style_menu_item_button_release_event), (font_picker_add_item), + (font_picker_populate), (font_find_style), (font_make_style_name), + (font_slant_string_to_enum), (font_set_width_string_to_enum), + (font_style_entry_new), (font_list_count_families), + (compare_font_entry), (global_font_list_get), (compare_style), + (global_font_list_populate_callback), + (eel_gtk_menu_shell_get_num_items), + (font_picker_get_selected_style_entry), + (font_picker_find_entries_for_font), + (font_picker_get_index_for_entry), (eel_font_picker_new), + (eel_font_picker_get_selected_font), + (eel_font_picker_set_selected_font): + * eel/eel-font-picker.h: + * eel/eel-gdk-extensions.c: (eel_fill_rectangle), + (eel_fill_rectangle_with_color), (eel_rectangle_contains), + (eel_rectangle_inset), (eel_interpolate_color), (eel_gradient_new), + (eel_gradient_is_gradient), (eel_gradient_is_horizontal), + (eel_gradient_strip_trailing_direction_if_any), + (eel_gradient_parse_one_color_spec), + (eel_gradient_get_start_color_spec), + (eel_gradient_get_end_color_spec), (eel_gradient_set_edge_color), + (eel_gradient_set_left_color_spec), + (eel_gradient_set_top_color_spec), + (eel_gradient_set_right_color_spec), + (eel_gradient_set_bottom_color_spec), + (eel_gdk_color_parse_with_white_default), + (eel_parse_rgb_with_white_default), (eel_rgb16_to_rgb), + (eel_rgb8_to_rgb), (eel_gdk_color_to_rgb), (eel_gdk_rgb_to_color), + (eel_gdk_rgb_to_color_spec), (eel_shift_color_component), + (eel_rgb_shift_color), (eel_gdk_color_is_dark), + (eel_gdk_choose_foreground_color), + (eel_gdk_gc_choose_foreground_color), (eel_stipple_bitmap), + (eel_gdk_window_bring_to_front), (eel_gdk_window_focus), + (eel_gdk_window_set_wm_protocols), (eel_set_mini_icon), + (eel_gdk_window_set_wm_hints_input), + (eel_gdk_window_set_invisible_cursor), (eel_gdk_parse_geometry), + (eel_gdk_color_as_hex_string), (eel_self_check_parse), + (eel_self_check_gdk_extensions): + * eel/eel-gdk-extensions.h: + * eel/eel-gdk-font-extensions.c: (eel_gdk_font_get_italic), + (eel_gdk_font_get_bold), (font_bitmap_get_by_size), + (eel_gdk_font_get_larger), (eel_gdk_font_get_smaller), + (eel_gdk_font_equal), (eel_gdk_font_get_largest_fitting), + (eel_string_ellipsize_start), (font_get_bold), (font_list_fonts), + (font_list_table_free_one_node), (font_list_fonts_cached), + (eel_gdk_font_get_fixed), (xlfd_string_get_nth), + (xlfd_string_replace_nth), (xlfd_string_get_nth_as_int), + (xlfd_string_could_be_scalable_non_bitmap), + (eel_gdk_font_xlfd_string_new), (font_entry_has_bold_weight_test), + (font_entry_has_italic_slant_test), + (font_entry_is_scalable_non_bitmap_test), + (eel_self_check_ellipsize_start), + (eel_self_check_gdk_font_extensions): + * eel/eel-gdk-font-extensions.h: + * eel/eel-gdk-pixbuf-extensions.c: (eel_gdk_pixbuf_list_ref), + (eel_gdk_pixbuf_list_free), (eel_gdk_pixbuf_load), + (eel_gdk_pixbuf_load_async), (file_opened_callback), + (file_read_callback), (free_pixbuf_load_handle), (load_done), + (eel_cancel_gdk_pixbuf_load), (eel_gdk_pixbuf_average_value), + (eel_gdk_scale_to_fit_factor), (eel_gdk_pixbuf_scale_to_fit), + (eel_gdk_pixbuf_scale_down_to_fit), (eel_gdk_pixbuf_is_valid), + (eel_gdk_pixbuf_get_dimensions), + (eel_gdk_pixbuf_fill_rectangle_with_color), + (eel_gdk_pixbuf_save_to_file), (eel_gdk_pixbuf_ref_if_not_null), + (eel_gdk_pixbuf_unref_if_not_null), + (eel_gdk_pixbuf_draw_to_drawable), (eel_gdk_pixbuf_draw_to_pixbuf), + (eel_gdk_pixbuf_draw_to_pixbuf_alpha), + (eel_gdk_pixbuf_new_from_pixbuf_sub_area), + (eel_gdk_pixbuf_new_from_existing_buffer), (pixbuf_draw_tiled), + (draw_tile_to_pixbuf_callback), (draw_tile_to_drawable_callback), + (eel_gdk_pixbuf_draw_to_pixbuf_tiled), + (eel_gdk_pixbuf_draw_to_drawable_tiled), + (eel_gdk_pixbuf_get_global_buffer), + (eel_gdk_pixbuf_get_from_window_safe), (eel_gdk_pixbuf_intersect), + (eel_self_check_gdk_pixbuf_extensions): + * eel/eel-gdk-pixbuf-extensions.h: + * eel/eel-glib-extensions.c: (eel_setenv), (eel_unsetenv), + (eel_g_date_new_tm), (eel_strdup_strftime), + (eel_g_list_exactly_one_item), (eel_g_list_more_than_one_item), + (eel_g_list_equal), (eel_g_list_copy), (eel_g_str_list_equal), + (eel_g_str_list_copy), (eel_g_str_list_alphabetize), + (eel_g_list_free_deep_custom), (eel_g_list_free_deep), + (eel_g_slist_free_deep_custom), (eel_g_slist_free_deep), + (eel_g_strv_find), (eel_g_list_safe_for_each), + (eel_g_list_sort_merge), (eel_g_list_is_already_sorted), + (eel_g_list_sort_custom), + (eel_g_lists_sort_and_check_for_intersection), + (eel_g_list_partition), (eel_g_ptr_array_new_from_list), + (eel_g_ptr_array_sort), (eel_g_ptr_array_search), + (eel_get_system_time), (eel_g_hash_table_new_free_at_exit), + (eel_g_hash_table_safe_for_each), + (eel_g_hash_table_remove_deep_custom), + (eel_g_hash_table_remove_deep), + (eel_g_hash_table_destroy_deep_custom), + (eel_g_hash_table_destroy_deep), (eel_g_string_append_len), + (eel_shell_quote), (eel_round), (eel_g_list_from_g_slist), + (eel_g_slist_from_g_list), + (eel_dumb_down_for_multi_byte_locale_hack), (eel_compare_integer), + (check_tm_to_g_date), (eel_test_predicate), (test_strftime), + (eel_self_check_glib_extensions): + * eel/eel-glib-extensions.h: + * eel/eel-glyph.c: (eel_glyph_new), (eel_glyph_free), + (glyph_get_width_space_safe), (glyph_get_height_space_safe), + (eel_glyph_get_width), (eel_glyph_get_height), + (eel_glyph_get_dimensions), (eel_glyph_get_underline_rectangle), + (glyph_is_valid), (eel_glyph_draw_to_pixbuf), + (eel_glyph_intersect), (eel_glyph_compare): + * eel/eel-glyph.h: + * eel/eel-mate-extensions.c: + (eel_mate_canvas_world_to_window_rectangle), + (eel_mate_canvas_world_to_canvas_rectangle), + (eel_mate_canvas_item_get_current_canvas_bounds), + (eel_mate_canvas_item_request_redraw), + (eel_mate_canvas_request_redraw_rectangle), + (eel_mate_canvas_item_get_world_bounds), + (eel_mate_canvas_item_get_canvas_bounds), + (eel_mate_canvas_draw_pixbuf_helper), + (eel_mate_canvas_draw_pixbuf_helper_alpha), + (eel_mate_canvas_draw_pixbuf), (eel_mate_canvas_fill_rgb), + (eel_mate_dialog_get_button_by_index), + (eel_mate_canvas_item_request_update_deep), + (eel_mate_canvas_request_update_all), + (eel_mate_canvas_set_scroll_region), + (eel_mate_canvas_set_scroll_region_left_justify), + (eel_mate_canvas_set_scroll_region_include_visible_area), + (eel_mate_shell_execute), (eel_mate_get_terminal_path), + (eel_mate_open_terminal), (icon_selected_callback), + (eel_mate_icon_selector_new), + (eel_mate_stock_set_icon_or_register): + * eel/eel-mate-extensions.h: + * eel/eel-graphic-effects.c: (eel_create_spotlight_pixbuf), + (eel_create_darkened_pixbuf), (eel_create_colorized_pixbuf), + (eel_stretch_frame_image), (eel_embed_image_in_frame), + (eel_make_semi_transparent): + * eel/eel-graphic-effects.h: + * eel/eel-gtk-extensions.c: (finish_button_activation), + (eel_gtk_button_auto_click), (eel_gtk_button_set_padding), + (eel_gtk_button_set_standard_padding), + (eel_gtk_clist_get_first_selected_row), + (eel_gtk_clist_get_last_selected_row), + (activate_button_on_double_click), + (eel_gtk_clist_set_double_click_button), + (eel_gtk_signal_connect_free_data_custom), + (eel_gtk_signal_connect_free_data), (eel_gtk_window_present), + (handle_standard_close_accelerator), + (eel_gtk_window_event_is_close_accelerator), + (eel_gtk_window_set_up_close_accelerator), + (eel_gtk_window_set_initial_geometry), + (eel_gtk_window_set_initial_geometry_from_string), + (eel_gtk_selection_data_copy_deep), + (eel_gtk_selection_data_free_deep), (eel_popup_menu_position_func), + (eel_truncate_text_for_menu_item), (eel_pop_up_context_menu), + (eel_gtk_menu_append_separator), (eel_gtk_menu_insert_separator), + (eel_gtk_menu_set_item_visibility), + (eel_gtk_marshal_NONE__POINTER_INT_INT_DOUBLE), + (eel_gtk_marshal_NONE__INT_INT_INT), + (eel_gtk_marshal_NONE__POINTER_INT_INT_INT), + (eel_gtk_marshal_NONE__POINTER_INT_POINTER_POINTER), + (eel_gtk_marshal_NONE__POINTER_POINTER_INT_INT_INT), + (eel_gtk_marshal_BOOL__INT_POINTER_INT_INT_UINT), + (eel_gtk_marshal_NONE__INT_POINTER_INT_INT_UINT), + (eel_gtk_marshal_NONE__POINTER_POINTER_POINTER_INT_INT_INT), + (eel_gtk_marshal_NONE__POINTER_POINTER_POINTER_POINTER_INT_INT_UINT + ), (eel_gtk_marshal_NONE__POINTER_INT_INT_DOUBLE_DOUBLE), + (eel_gtk_marshal_NONE__DOUBLE), + (eel_gtk_marshal_NONE__DOUBLE_DOUBLE_DOUBLE), + (eel_gtk_marshal_POINTER__NONE), (eel_gtk_marshal_INT__NONE), + (eel_gtk_marshal_POINTER__INT), (eel_gtk_marshal_POINTER__POINTER), + (eel_gtk_marshal_INT__POINTER_POINTER), + (eel_gtk_marshal_INT__POINTER_INT), + (eel_gtk_marshal_POINTER__POINTER_POINTER), + (eel_gtk_marshal_POINTER__POINTER_POINTER_POINTER), + (eel_gtk_marshal_NONE__POINTER_POINTER_POINTER_POINTER), + (eel_gtk_marshal_POINTER__POINTER_INT_INT_POINTER_POINTER), + (eel_gtk_marshal_NONE__POINTER_POINTER_POINTER_POINTER_POINTER_POIN + TER), (eel_point_in_allocation), (eel_point_in_widget), + (eel_gtk_object_list_ref), (eel_gtk_object_list_unref), + (eel_gtk_object_list_free), (eel_gtk_object_list_copy), + (eel_gtk_style_set_font), (eel_gtk_widget_set_font), + (eel_gtk_widget_set_shown), (eel_gtk_widget_set_font_by_name), + (eel_gtk_signal_connect_full_while_alive), + (eel_gtk_signal_connect_while_realized), + (eel_nullify_when_destroyed), (eel_nullify_cancel), + (eel_gtk_container_get_first_child), + (eel_gtk_container_foreach_deep), (eel_gtk_pixmap_new_empty), + (eel_gtk_adjustment_set_value), (eel_gtk_adjustment_clamp_value), + (eel_gtk_label_make_bold), (eel_gtk_label_make_larger), + (eel_gtk_label_make_smaller), + (eel_gtk_widget_set_background_color), + (eel_gtk_widget_set_foreground_color), + (eel_gtk_widget_find_windowed_ancestor), (eel_gtk_style_shade), + (eel_gtk_class_name_make_like_existing_type), + (eel_get_window_list_ordered_front_to_back), + (eel_gtk_get_system_font), (eel_get_current_event_time), + (eel_drag_set_icon_pixbuf): + * eel/eel-gtk-extensions.h: + * eel/eel-gtk-macros.h: + * eel/eel-image-table.c: (eel_image_table_initialize_class), + (eel_image_table_initialize), (eel_image_table_destroy), + (eel_image_table_expose_event), (eel_image_table_realize), + (eel_image_table_unrealize), (eel_image_table_remove), + (eel_image_table_child_type), + (eel_image_table_set_is_smooth_signal), + (image_table_foreach_child_subtract_content), + (image_table_clear_dirty_areas), (image_table_peek_clear_gc), + (image_table_emit_signal), (image_table_handle_motion), + (ancestor_enter_notify_event), (ancestor_leave_notify_event), + (ancestor_motion_notify_event), (ancestor_button_press_event), + (ancestor_button_release_event), (eel_image_table_new), + (eel_image_table_set_is_smooth), + (eel_image_table_set_smooth_background_color), + (eel_image_table_add_empty_image): + * eel/eel-image-table.h: + * eel/eel-image-with-background.c: (draw_background_callback), + (eel_image_new_with_background): + * eel/eel-image-with-background.h: + * eel/eel-image.c: (eel_image_initialize_class), + (eel_image_initialize), (eel_image_destroy), (eel_image_set_arg), + (eel_image_get_arg), (eel_image_size_request), + (image_paint_pixbuf_callback), (image_composite_pixbuf_callback), + (eel_image_expose_event), (eel_image_set_is_smooth_signal), + (image_get_pixbuf_dimensions), (image_get_pixbuf_bounds), + (image_get_tile_dimensions), (image_is_smooth), (eel_image_new), + (eel_image_set_is_smooth), (eel_image_get_is_smooth), + (eel_image_set_tile_pixbuf), (eel_image_get_tile_pixbuf), + (eel_image_set_pixbuf), (eel_image_set_pixbuf_from_file_name), + (eel_image_get_pixbuf), (eel_image_set_pixbuf_opacity), + (eel_image_get_pixbuf_opacity), (eel_image_set_tile_opacity), + (eel_image_get_tile_opacity), (eel_image_set_tile_width), + (eel_image_get_tile_width), (eel_image_set_tile_height), + (eel_image_get_tile_height), (eel_image_set_tile_mode_vertical), + (eel_image_get_tile_mode_vertical), + (eel_image_set_tile_mode_horizontal), + (eel_image_get_tile_mode_horizontal), + (eel_image_set_tile_pixbuf_from_file_name), + (eel_image_set_background_mode), (eel_image_get_background_mode), + (eel_image_set_solid_background_color), + (eel_image_get_solid_background_color), (eel_image_new_solid), + (eel_image_set_never_smooth): + * eel/eel-image.h: + * eel/eel-label-with-background.c: (draw_background_callback), + (eel_label_new_with_background): + * eel/eel-label-with-background.h: + * eel/eel-label.c: (eel_label_initialize_class), + (eel_label_initialize), (eel_label_destroy), (eel_label_set_arg), + (eel_label_get_arg), (eel_label_size_request), + (eel_label_size_allocate), (label_paint_pixbuf_callback), + (label_composite_text_callback_cached), + (label_composite_text_callback), + (label_composite_text_and_shadow_callback), (label_paint), + (paint_label_smooth), (paint_label_smooth_cached), + (eel_label_expose_event), (eel_label_set_is_smooth_signal), + (label_get_default_line_wrap_width), (label_get_text_dimensions), + (label_get_text_bounds), (label_get_content_dimensions), + (label_get_content_bounds), (label_get_tile_dimensions), + (label_solid_cache_pixbuf_clear), (label_can_cache_contents), + (label_peek_text), (label_smooth_text_ensure), + (label_smooth_text_clear), (label_is_smooth), (eel_label_new), + (eel_label_set_smooth_font), (eel_label_get_smooth_font), + (eel_label_set_smooth_font_size), (eel_label_get_smooth_font_size), + (label_force_cached_requisition_flush), (eel_label_set_is_smooth), + (eel_label_get_is_smooth), (eel_label_set_tile_pixbuf), + (eel_label_get_tile_pixbuf), (eel_label_set_text_opacity), + (eel_label_get_text_opacity), (eel_label_set_tile_opacity), + (eel_label_get_tile_opacity), (eel_label_set_tile_width), + (eel_label_get_tile_width), (eel_label_set_tile_height), + (eel_label_get_tile_height), (eel_label_set_tile_mode_vertical), + (eel_label_get_tile_mode_vertical), + (eel_label_set_tile_mode_horizontal), + (eel_label_get_tile_mode_horizontal), + (eel_label_set_tile_pixbuf_from_file_name), + (eel_label_set_background_mode), (eel_label_get_background_mode), + (eel_label_set_solid_background_color), + (eel_label_get_solid_background_color), + (eel_label_set_smooth_line_wrap_width), + (eel_label_get_smooth_line_wrap_width), (eel_label_set_text_color), + (eel_label_get_text_color), + (eel_label_set_smooth_drop_shadow_offset), + (eel_label_get_smooth_drop_shadow_offset), + (eel_label_set_smooth_drop_shadow_color), + (eel_label_get_smooth_drop_shadow_color), (eel_label_set_justify), + (eel_label_get_text_justify), (eel_label_set_text), + (eel_label_get_text), (eel_label_set_wrap), (eel_label_get_wrap), + (eel_label_new_solid), (eel_label_make_bold), + (eel_label_make_larger), (eel_label_make_smaller), + (eel_label_set_never_smooth), + (eel_label_set_adjust_wrap_on_resize), + (eel_label_get_adjust_wrap_on_resize): + * eel/eel-label.h: + * eel/eel-labeled-image.c: (eel_labeled_image_initialize_class), + (eel_labeled_image_initialize), (eel_labeled_image_destroy), + (eel_labeled_image_set_arg), (eel_labeled_image_get_arg), + (eel_labeled_image_size_request), + (eel_labeled_image_size_allocate), + (eel_labeled_image_expose_event), (eel_labeled_image_map), + (eel_labeled_image_unmap), (eel_labeled_image_add), + (eel_labeled_image_remove), (eel_labeled_image_forall), + (is_fixed_height), (labeled_image_get_image_dimensions), + (labeled_image_get_label_dimensions), + (labeled_image_get_image_bounds_fill), + (eel_labeled_image_get_image_bounds), + (labeled_image_get_label_bounds_fill), + (eel_labeled_image_get_label_bounds), + (labeled_image_update_alignments), + (labeled_image_get_content_dimensions), + (labeled_image_get_content_bounds), (labeled_image_ensure_label), + (labeled_image_ensure_image), (labeled_image_show_image), + (labeled_image_show_label), (eel_labeled_image_new), + (eel_labeled_image_new_from_file_name), + (eel_labeled_image_set_label_position), + (eel_labeled_image_get_label_position), + (eel_labeled_image_set_show_label), + (eel_labeled_image_get_show_label), + (eel_labeled_image_set_show_image), + (eel_labeled_image_get_show_image), + (eel_labeled_image_set_fixed_image_height), + (eel_labeled_image_set_spacing), (eel_labeled_image_get_spacing), + (eel_labeled_image_set_x_padding), + (eel_labeled_image_get_x_padding), + (eel_labeled_image_set_y_padding), + (eel_labeled_image_get_y_padding), + (eel_labeled_image_set_x_alignment), + (eel_labeled_image_get_x_alignment), + (eel_labeled_image_set_y_alignment), + (eel_labeled_image_get_y_alignment), (eel_labeled_image_set_fill), + (eel_labeled_image_get_fill), (eel_labeled_image_button_new), + (eel_labeled_image_button_new_from_file_name), + (eel_labeled_image_toggle_button_new), + (eel_labeled_image_toggle_button_new_from_file_name), + (button_leave_callback), (eel_labeled_image_check_button_new), + (eel_labeled_image_check_button_new_from_file_name), + (eel_labeled_image_set_pixbuf), + (eel_labeled_image_set_pixbuf_from_file_name), + (eel_labeled_image_set_tile_pixbuf), + (eel_labeled_image_set_tile_pixbuf_from_file_name), + (eel_labeled_image_get_pixbuf), (eel_labeled_image_set_text), + (eel_labeled_image_get_text), (eel_labeled_image_make_bold), + (eel_labeled_image_make_larger), (eel_labeled_image_make_smaller), + (eel_labeled_image_set_tile_width), + (eel_labeled_image_set_tile_height), + (eel_labeled_image_set_background_mode), + (eel_labeled_image_set_solid_background_color), + (eel_labeled_image_set_smooth_drop_shadow_offset), + (eel_labeled_image_set_smooth_drop_shadow_color), + (eel_labeled_image_set_text_color), + (eel_labeled_image_set_label_never_smooth): + * eel/eel-labeled-image.h: + * eel/eel-lib-self-check-functions.c: (eel_run_lib_self_checks): + * eel/eel-lib-self-check-functions.h: + * eel/eel-password-dialog.c: + (eel_password_dialog_initialize_class), + (eel_password_dialog_initialize), (eel_password_dialog_destroy), + (dialog_show_callback), (dialog_close_callback), + (caption_table_activate_callback), (eel_password_dialog_new), + (eel_password_dialog_run_and_block), + (eel_password_dialog_set_username), + (eel_password_dialog_set_password), + (eel_password_dialog_set_readonly_username), + (eel_password_dialog_get_username), + (eel_password_dialog_get_password), + (eel_password_dialog_get_remember), + (eel_password_dialog_set_remember), + (eel_password_dialog_set_remember_label_text): + * eel/eel-password-dialog.h: + * eel/eel-radio-button-group.c: + (eel_radio_button_group_initialize_class), + (eel_radio_button_group_initialize), + (eel_radio_button_group_destroy), + (radio_button_group_emit_changed_signal), + (radio_button_group_free_button_group), (button_toggled), + (eel_radio_button_group_new), (eel_radio_button_group_insert), + (eel_radio_button_group_get_active_index), + (eel_radio_button_group_set_active_index), + (eel_radio_button_group_set_entry_pixbuf), + (eel_radio_button_group_set_entry_description_text): + * eel/eel-radio-button-group.h: + * eel/eel-region.c: (eel_region_new), (eel_region_free), + (gdk_region_new_from_irect), (eel_region_add_rectangle), + (eel_region_subtract_rectangle), (eel_region_set_gc_clip_region): + * eel/eel-region.h: + * eel/eel-scalable-font-private.h: + * eel/eel-scalable-font.c: (eel_scalable_font_initialize_class), + (eel_scalable_font_initialize), (eel_scalable_font_destroy), + (eel_scalable_font_new), (eel_scalable_font_make_bold), + (eel_scalable_font_measure_text), (eel_scalable_font_text_width), + (eel_scalable_font_draw_text), + (eel_scalable_font_largest_fitting_font_size), + (eel_scalable_font_get_default_font), + (eel_scalable_font_get_default_bold_font), + (eel_scalable_font_get_rsvg_handle), + (eel_scalable_font_get_rsvg_context), + (eel_self_check_scalable_font): + * eel/eel-scalable-font.h: + * eel/eel-self-checks.c: (eel_exit_if_self_checks_failed), + (eel_report_check_failure), (eel_strdup_boolean), + (eel_before_check), (eel_after_check), (eel_check_boolean_result), + (eel_check_rectangle_result), (eel_check_dimensions_result), + (eel_check_integer_result), (eel_check_string_result), + (eel_before_check_function), (eel_after_check_function): + * eel/eel-self-checks.h: + * eel/eel-smooth-text-layout-cache.c: (cache_index_new), + (cache_insert), (cache_remove), (cache_enter), (cache_evict), + (cache_lookup), (cache_trim), + (eel_smooth_text_layout_cache_render), + (eel_smooth_text_layout_cache_new), + (eel_smooth_text_layout_cache_initialize_class), + (eel_smooth_text_layout_cache_initialize), (free_one_cache_entry), + (eel_smooth_text_layout_cache_destroy), (check_one), + (eel_self_check_smooth_text_layout_cache): + * eel/eel-smooth-text-layout-cache.h: + * eel/eel-smooth-text-layout.c: + (eel_smooth_text_layout_initialize_class), + (eel_smooth_text_layout_initialize), + (eel_smooth_text_layout_destroy), (smooth_text_layout_clear_lines), + (smooth_text_layout_ensure_lines), + (smooth_text_layout_line_list_new), + (smooth_text_layout_line_list_free), + (smooth_text_layout_line_list_draw_to_pixbuf), + (smooth_text_layout_line_list_new_wrapped), + (smooth_text_layout_get_empty_line_height), + (smooth_text_layout_get_num_empty_lines), + (smooth_text_layout_get_max_line_width), + (smooth_text_layout_get_total_line_height), + (smooth_text_layout_get_line_wrap_width), + (eel_smooth_text_layout_new), + (eel_smooth_text_layout_draw_to_pixbuf), + (eel_smooth_text_layout_draw_to_pixbuf_shadow), + (eel_smooth_text_layout_get_dimensions), + (eel_smooth_text_layout_get_width), + (eel_smooth_text_layout_get_height), + (eel_smooth_text_layout_set_wrap), + (eel_smooth_text_layout_get_wrap), + (eel_smooth_text_layout_set_font), + (eel_smooth_text_layout_get_font), + (eel_smooth_text_layout_set_font_size), + (eel_smooth_text_layout_get_font_size), + (eel_smooth_text_layout_set_line_spacing), + (eel_smooth_text_layout_get_line_spacing), + (eel_smooth_text_layout_set_empty_line_height), + (eel_smooth_text_layout_get_empty_line_height), + (smooth_text_layout_set_text), + (eel_smooth_text_layout_set_line_break_characters), + (eel_smooth_text_layout_get_line_break_characters), + (eel_smooth_text_layout_set_line_wrap_width), + (text_layout_free_row), (eel_text_layout_free), + (eel_text_layout_new), (eel_smooth_text_layout_compare): + * eel/eel-smooth-text-layout.h: + * eel/eel-smooth-widget.c: (preferences_get_is_smooth), + (eel_smooth_widget_register), + (smooth_widget_get_tile_origin_point), + (smooth_widget_get_gtk_background), (smooth_widget_get_background), + (smooth_widget_paint_tile_opaque), + (smooth_widget_paint_tile_transparent), + (smooth_widget_paint_content_opaque), + (smooth_widget_paint_content_transparent), + (smooth_widget_paint_tile_and_content_transparent), + (eel_smooth_widget_paint), (eel_smooth_widget_get_tile_bounds), + (eel_smooth_widget_get_preferred_dimensions), + (eel_smooth_widget_register_type): + * eel/eel-smooth-widget.h: + * eel/eel-stock-dialogs.c: (timed_wait_free), + (timed_wait_dialog_destroy_callback), (timed_wait_callback), + (eel_timed_wait_start_with_duration), (eel_timed_wait_start), + (eel_timed_wait_stop), (eel_run_simple_dialog), + (find_message_label), (create_message_box), + (eel_create_info_dialog), (eel_show_info_dialog), + (details_dialog_clicked_callback), + (eel_show_info_dialog_with_details), (eel_show_warning_dialog), + (eel_show_error_dialog), (eel_show_error_dialog_with_details), + (eel_show_yes_no_dialog), (eel_create_question_dialog): + * eel/eel-stock-dialogs.h: + * eel/eel-string-list.c: (eel_string_list_new), + (eel_string_list_new_from_string), + (eel_string_list_new_from_string_list), + (eel_string_list_new_from_tokens), + (eel_string_list_assign_from_string_list), (eel_string_list_free), + (eel_string_list_insert), (eel_string_list_nth), + (eel_string_list_nth_as_integer), (eel_string_list_modify_nth), + (eel_string_list_remove_nth), (eel_string_list_contains), + (eel_string_list_find_by_function), (eel_string_list_get_length), + (eel_string_list_clear), (eel_string_list_equals), + (eel_string_list_as_g_list), + (eel_string_list_get_index_for_string), + (eel_string_list_as_concatenated_string), (eel_string_list_sort), + (eel_string_list_sort_by_function), + (eel_string_list_remove_duplicates), (eel_string_list_for_each), + (eel_string_list_get_longest_string), + (eel_string_list_get_longest_string_length), (str_is_equal), + (test_dog), (test_data), (test_true), (test_false), + (compare_number), (eel_self_check_string_list): + * eel/eel-string-list.h: + * eel/eel-string-map.c: (eel_string_map_new), + (eel_string_map_free), (eel_string_map_clear), + (eel_string_map_lookup), (eel_string_map_add), (map_entry_new), + (map_entry_free), (map_entry_list_lookup), (str_is_equal), + (eel_self_check_string_map): + * eel/eel-string-map.h: + * eel/eel-string-picker.c: (eel_string_picker_initialize_class), + (eel_string_picker_initialize), (eel_string_picker_destroy), + (option_menu_activate_callback), (eel_string_picker_new), + (eel_string_picker_set_string_list), + (eel_string_picker_get_string_list), + (eel_string_picker_get_selected_string), + (eel_string_picker_set_selected_string), + (eel_string_picker_set_selected_string_index), + (eel_string_picker_insert_string), (eel_string_picker_contains), + (eel_string_picker_get_index_for_string), + (eel_string_picker_clear): + * eel/eel-string-picker.h: + * eel/eel-string.c: (eel_strlen), (eel_strchr), (eel_strcmp), + (eel_strcasecmp), (eel_strcmp_case_breaks_ties), (eel_strcoll), + (eel_str_is_empty), (eel_str_is_equal), (eel_istr_is_equal), + (eel_strcmp_compare_func), (eel_strcoll_compare_func), + (eel_strcasecmp_compare_func), (eel_str_has_prefix), + (eel_str_has_suffix), (eel_istr_has_prefix), (eel_istr_has_suffix), + (eel_str_get_prefix), (eel_str_get_after_prefix), (eel_str_to_int), + (eel_str_strip_chr), (eel_str_strip_trailing_chr), + (eel_str_strip_trailing_str), (eel_eat_str_to_int), + (eel_str_double_underscores), (eel_str_capitalize), + (eel_str_middle_truncate), (eel_str_count_characters), + (eel_str_strip_substring_and_after), (eel_str_replace_substring), + (eel_str_remove_bracketed_text), (call_str_to_int), + (call_eat_str_to_int), (eel_self_check_string): + * eel/eel-string.h: + * eel/eel-text-caption.c: (eel_text_caption_initialize_class), + (eel_text_caption_initialize), (eel_text_caption_destroy), + (entry_changed_callback), (entry_key_press_callback), + (eel_text_caption_new), (eel_text_caption_get_text), + (eel_text_caption_set_text), (eel_text_caption_set_editable), + (eel_text_caption_set_expand_tilde): + * eel/eel-text-caption.h: + * eel/eel-viewport.c: (eel_viewport_initialize_class), + (eel_viewport_initialize), (eel_viewport_destroy), + (eel_viewport_draw), (eel_viewport_size_allocate), + (eel_viewport_expose_event), (eel_viewport_realize), + (eel_viewport_paint), (eel_viewport_set_is_smooth_signal), + (eel_viewport_new), (eel_viewport_set_is_smooth), + (eel_viewport_get_is_smooth), (eel_viewport_set_constrain_width), + (eel_viewport_get_constrain_width), + (eel_viewport_set_constrain_height), + (eel_viewport_get_constrain_height), + (eel_viewport_set_never_smooth), (eel_viewport_get_scroll_offset): + * eel/eel-viewport.h: + * eel/eel-wrap-table.c: (eel_wrap_table_initialize_class), + (eel_wrap_table_initialize), (eel_wrap_table_destroy), + (eel_wrap_table_set_arg), (eel_wrap_table_get_arg), + (eel_wrap_table_size_request), (eel_wrap_table_size_allocate), + (eel_wrap_table_expose_event), (eel_wrap_table_map), + (eel_wrap_table_unmap), (eel_wrap_table_add), + (eel_wrap_table_remove), (eel_wrap_table_forall), + (eel_wrap_table_child_type), (wrap_table_layout), + (wrap_table_art_irect_max_dimensions), + (wrap_table_get_max_child_dimensions), + (wrap_table_get_content_dimensions), + (wrap_table_get_content_bounds), (wrap_table_get_scroll_offset), + (wrap_table_find_child_at_point), (eel_wrap_table_new), + (eel_wrap_table_set_x_spacing), (eel_wrap_table_get_x_spacing), + (eel_wrap_table_set_y_spacing), (eel_wrap_table_get_y_spacing), + (eel_wrap_table_find_child_at_event_point), + (eel_wrap_table_set_x_justification), + (eel_wrap_table_get_x_justification), + (eel_wrap_table_set_y_justification), + (eel_wrap_table_get_y_justification), + (eel_wrap_table_set_homogeneous), (eel_wrap_table_get_homogeneous), + (eel_wrap_table_reorder_child), (eel_wrap_table_get_num_children): + * eel/eel-wrap-table.h: + * eel/eel-xml-extensions.c: (eel_xml_get_children), + (eel_xml_get_root_children), + (eel_xml_get_child_by_name_and_property), + (eel_xml_get_child_by_name), + (eel_xml_get_root_child_by_name_and_property), + (eel_xml_get_property_for_children), + (eel_xml_get_property_translated), (eel_xml_remove_node): + * eel/eel-xml-extensions.h: + * test/Makefile.am: + * test/test-eel-background.c: (main): + * test/test-eel-clickable-image.c: (clicked_callback), + (enter_callback), (leave_callback), (clickable_image_new): + * test/test-eel-font-manager.c: (font_type_to_string), + (font_iterator_callback), (main): + * test/test-eel-font-picker.c: (update_font), + (font_changed_update_label_callback), + (font_changed_update_file_name_callback), + (use_defalt_font_callback), (use_defalt_bold_font_callback), + (use_defalt_font_update_picker_callback), + (use_defalt_bold_font_update_picker_callback), + (print_selected_font_callback), (main): + * test/test-eel-font-simple.c: (main): + * test/test-eel-font.c: (main): + * test/test-eel-glyph-simple.c: (glyph_new), (main): + * test/test-eel-glyph.c: (glyph_new), (main): + * test/test-eel-image-background.c: + (window_new_with_eel_background_image), + (window_new_with_eel_background_gradient), + (window_new_with_solid_background), (main): + * test/test-eel-image-scrolled.c: (toggle_smooth_callback), + (label_window_new), (label_window_new_scrolled): + * test/test-eel-image-simple.c: (toggle_smooth_callback), + (image_window_new), (main): + * test/test-eel-image-table.c: (labeled_image_new), + (image_table_child_enter_callback), + (image_table_child_leave_callback), + (image_table_child_pressed_callback), + (image_table_child_released_callback), + (image_table_child_clicked_callback), (image_table_size_allocate), + (image_table_new_scrolled): + * test/test-eel-image-tile.c: + (window_new_with_eel_background_image), + (window_new_with_eel_background_gradient), (window_four_new), + (main): + * test/test-eel-image.c: (icon_get_path), (label_new), + (label_enter_event), (label_leave_event), (label_free_data), + (image_new), (image_new_from_name), (label_add_prelighting), + (header_new), (main): + * test/test-eel-label-background.c: + (window_new_with_eel_background_image), + (window_new_with_eel_background_gradient), + (window_new_with_solid_background), (main): + * test/test-eel-label-flavorful.c: (increasing_label_window_new), + (decreasing_label_window_new), (main): + * test/test-eel-label-offset.c: (main): + * test/test-eel-label-scrolled.c: (label_window_new), + (label_window_new_scrolled), (label_window_new_table): + * test/test-eel-label-simple.c: (use_system_font_callback), + (use_system_font_bold_callback), (main): + * test/test-eel-label-wrapped.c: (create_eel_label), + (create_gtk_label_window), (create_eel_label_window), (main): + * test/test-eel-label.c: (red_label_color_value_changed_callback), + (green_label_color_value_changed_callback), + (blue_label_color_value_changed_callback), + (alpha_label_color_value_changed_callback), + (red_background_color_value_changed_callback), + (green_background_color_value_changed_callback), + (blue_background_color_value_changed_callback), + (alpha_background_color_value_changed_callback), + (text_caption_changed_callback), (create_value_scale), + (create_color_picker_frame), (create_text_caption_frame), + (widget_set_eel_background_image), + (widget_set_eel_background_color), + (widget_get_eel_background_color), (widget_set_background_reset), + (background_changed_callback), (justification_changed_callback), + (drop_shadow_offset_changed_callback), (create_background_frame), + (create_justification_frame), (create_drop_shadow_offset_frame), + (main): + * test/test-eel-labeled-image.c: (labeled_image_new), + (labeled_image_window_new), (labeled_image_button_window_new), + (main): + * test/test-eel-password-dialog.c: (authenticate_boink_callback): + * test/test-eel-pixbuf-tile.c: (pixbuf_drawing_area_expose_event), + (drawable_drawing_area_expose_event): + * test/test-eel-smooth-text-layout.c: (main): + * test/test-eel-viewport-constraint.c: + (widget_set_eel_background_color), (create_eel_label), + (summary_view_item_label_new), (create_row), (main): + * test/test-eel-widgets.c: (create_pixbuf), + (radio_group_load_it_up), (test_radio_group), + (test_radio_group_horizontal), (test_caption_table), + (test_string_picker), (test_text_caption), + (string_picker_changed_callback), (text_caption_changed_callback), + (test_radio_changed_callback): + * test/test.c: (test_init), (test_gtk_widget_set_background_image), + (test_gtk_widget_set_background_color), (test_pixbuf_new_named), + (test_image_new), (test_label_new), + (test_text_caption_get_text_as_int), + (test_pixbuf_draw_rectangle_tiled): + * test/test.h: + +2001-03-28 Ramiro Estrugo <[email protected]> + + Started ChangeLog + +# Local Variables: +# coding: utf-8 +# End: diff --git a/eel/Makefile.am b/eel/Makefile.am new file mode 100644 index 00000000..d690eba2 --- /dev/null +++ b/eel/Makefile.am @@ -0,0 +1,186 @@ +NULL= + +noinst_LTLIBRARIES=libeel-2.la + +INCLUDES = \ + -DG_LOG_DOMAIN=\"Eel\" \ + -I$(top_srcdir) \ + $(CORE_CFLAGS) \ + $(WARNING_CFLAGS) \ + -DDATADIR=\""$(datadir)"\" \ + -DSOURCE_DATADIR=\""$(top_srcdir)/data"\" \ + -DMATELOCALEDIR=\""$(prefix)/${DATADIRNAME}/locale"\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DMATEMENU_I_KNOW_THIS_IS_UNSTABLE \ + $(NULL) + +libeel_2_la_LDFLAGS = \ + -no-undefined \ + $(CORE_CFLAGS) \ + $(NULL) + +libeel_2_la_LIBADD = \ + $(CORE_LIBS) \ + $(RENDER_LIBS) \ + $(X_LIBS) \ + $(NULL) + +libeel_2_la_SOURCES = \ + eel-accessibility.c \ + eel-alert-dialog.c \ + eel-art-extensions.c \ + eel-art-gtk-extensions.c \ + eel-background.c \ + eel-background-box.c \ + eel-canvas.c \ + eel-canvas-util.c \ + eel-canvas-rect-ellipse.c \ + eel-debug-drawing.c \ + eel-debug.c \ + eel-editable-label.c \ + eel-enumeration.c \ + eel-mateconf-extensions.c \ + eel-gdk-extensions.c \ + eel-gdk-pixbuf-extensions.c \ + eel-glib-extensions.c \ + eel-mate-extensions.c \ + eel-graphic-effects.c \ + eel-gtk-container.c \ + eel-gtk-extensions.c \ + eel-i18n.c \ + eel-image-table.c \ + eel-labeled-image.c \ + eel-lib-self-check-functions.c \ + eel-pango-extensions.c \ + eel-preferences-builder.c \ + eel-preferences.c \ + eel-self-checks.c \ + eel-stock-dialogs.c \ + eel-string.c \ + eel-types.c \ + eel-vfs-extensions.c \ + eel-wrap-table.c \ + eel-xml-extensions.c \ + eel-lib-self-check-functions.h \ + $(NULL) + +eel_headers = \ + eel-accessibility.h \ + eel-alert-dialog.h \ + eel-art-extensions.h \ + eel-art-gtk-extensions.h \ + eel-background.h \ + eel-background-box.h \ + eel-canvas.h \ + eel-canvas-util.h \ + eel-canvas-rect-ellipse.h \ + eel-debug-drawing.h \ + eel-debug.h \ + eel-editable-label.h \ + eel-enumeration.h \ + eel-mateconf-extensions.h \ + eel-gdk-extensions.h \ + eel-gdk-pixbuf-extensions.h \ + eel-glib-extensions.h \ + eel-mate-extensions.h \ + eel-graphic-effects.h \ + eel-gtk-container.h \ + eel-gtk-extensions.h \ + eel-gtk-macros.h \ + eel-i18n.h \ + eel-image-table.h \ + eel-labeled-image.h \ + eel-pango-extensions.h \ + eel-preferences.h \ + eel-self-checks.h \ + eel-stock-dialogs.h \ + eel-string.h \ + eel-types.h \ + eel-vfs-extensions.h \ + eel-wrap-table.h \ + eel-xml-extensions.h \ + eel.h \ + $(NULL) + +marshal_sources = \ + eel-marshal.h \ + eel-marshal.c \ + $(NULL) + +eel-marshal.h: eelmarshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --header --prefix=eel_marshal > $@ +eel-marshal.c: eelmarshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --body --prefix=eel_marshal > $@ + +stamp_sources = \ + eel-enums.defs \ + eel-type-builtins-evals.c \ + $(NULL) + +stamps = \ + eel-makeenums-stamp \ + eel-stamp \ + $(NULL) + +eel-makeenums-stamp: makeenums.pl $(eel_headers) + $(AM_V_GEN)$(PERL) $< defs $(filter-out $<,$^) > xgen-eed \ + && (cmp -s xgen-eed eel-enums.defs || mv -f xgen-eed eel-enums.defs) \ + && rm -f xgen-eed \ + && $(PERL) $< arrays $(filter-out $<,$^) > xgen-etbe \ + && (cmp -s xgen-etbe eel-type-builtins-evals.c || mv -f xgen-etbe eel-type-builtins-evals.c) \ + && rm -f xgen-etbe \ + && echo timestamp > $@ + +maketypes_sources = \ + eel-type-builtins.h \ + eel-type-builtins-ids.c \ + eel-type-builtins-vars.c \ + $(NULL) + +eel-stamp: eel-makeenums-stamp $(maketypes_sources) + echo timestamp > $@ + +eel-type-builtins.h: eel-enums.defs maketypes.awk eel-makeenums-stamp + LC_ALL=C $(AWK) -f $(srcdir)/maketypes.awk $< macros > $@ +eel-type-builtins-vars.c: eel-enums.defs maketypes.awk eel-makeenums-stamp + LC_ALL=C $(AWK) -f $(srcdir)/maketypes.awk $< variables > $@ +eel-type-builtins-ids.c: eel-enums.defs maketypes.awk eel-makeenums-stamp + LC_ALL=C $(AWK) -f $(srcdir)/maketypes.awk $< entries > $@ + +noinst_PROGRAMS = check-program + +check_program_SOURCES = check-program.c +check_program_DEPENDENCIES = libeel-2.la +check_program_LDADD = $(EEL_LIBS) +check_program_LDFLAGS = $(check_program_DEPENDENCIES) -lm + +TESTS = check-eel + +EXTRA_DIST = \ + $(eel_headers) \ + eel-type-builtins.h \ + eel-marshal.h \ + check-eel \ + eelmarshal.list \ + makeenums.pl \ + maketypes.awk \ + $(NULL) + +$(libeel_2_la_OBJECTS): $(marshal_sources) + +# This trick causes the stamp file to be built first. +Makefile: eel-stamp + +# This trick causes the generated files to be built the first time. +$(stamp_sources): # never add any dependencies + test -f $@ || touch $@ + +built_sources = $(stamps) $(stamp_sources) $(maketypes_sources) $(marshal_sources) +CLEANFILES = $(built_sources) +DONT_DIST_FILES = $(built_sources) + +dist-hook: + for file in $(DONT_DIST_FILES) ; do \ + rm -f $(distdir)/$$file ; \ + done diff --git a/eel/README b/eel/README new file mode 100644 index 00000000..15d86bba --- /dev/null +++ b/eel/README @@ -0,0 +1,4 @@ +README for eel/eel + +Writeme + diff --git a/eel/check-eel b/eel/check-eel new file mode 100755 index 00000000..d1c67b62 --- /dev/null +++ b/eel/check-eel @@ -0,0 +1,3 @@ +#!/bin/sh +./check-program --g-fatal-warnings --sm-disable + diff --git a/eel/check-program.c b/eel/check-program.c new file mode 100644 index 00000000..b1e0a3c7 --- /dev/null +++ b/eel/check-program.c @@ -0,0 +1,60 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* check-program.c: A simple driver for eel self checks. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> + +#include <eel/eel-debug.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-lib-self-check-functions.h> +#include <eel/eel-self-checks.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> +#include <libxml/parser.h> +#include <stdlib.h> + +int +main (int argc, char *argv[]) +{ +#if !defined (EEL_OMIT_SELF_CHECK) + + eel_make_warnings_and_criticals_stop_in_debugger (); + + + LIBXML_TEST_VERSION + gtk_init (&argc, &argv); + + /* Run the checks for eel twice. */ + + eel_run_lib_self_checks (); + eel_exit_if_self_checks_failed (); + + eel_run_lib_self_checks (); + eel_exit_if_self_checks_failed (); + + eel_debug_shut_down (); + +#endif /* !EEL_OMIT_SELF_CHECK */ + + return EXIT_SUCCESS; +} diff --git a/eel/eel-accessibility.c b/eel/eel-accessibility.c new file mode 100644 index 00000000..1a8a8037 --- /dev/null +++ b/eel/eel-accessibility.c @@ -0,0 +1,432 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* eel-accessibility.h - Utility functions for accessibility + + Copyright (C) 2002 Anders Carlsson, Sun Microsystems, Inc. + + The Eel Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Eel Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Eel Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: + Anders Carlsson <[email protected]> + Michael Meeks <[email protected]> +*/ +#include <config.h> +#include <gtk/gtk.h> +#include <atk/atkrelationset.h> +#include <eel/eel-accessibility.h> + +void +eel_accessibility_set_up_label_widget_relation (GtkWidget *label, GtkWidget *widget) +{ + AtkObject *atk_widget, *atk_label; + + atk_label = gtk_widget_get_accessible (label); + atk_widget = gtk_widget_get_accessible (widget); + + /* Create the label -> widget relation */ + atk_object_add_relationship (atk_label, ATK_RELATION_LABEL_FOR, atk_widget); + + /* Create the widget -> label relation */ + atk_object_add_relationship (atk_widget, ATK_RELATION_LABELLED_BY, atk_label); +} + +/* + * Hacks to make re-using gail somewhat easier. + */ + +/** + * eel_accessibility_create_derived_type: + * @type_name: the name for the new accessible type eg. CajaIconCanvasItemAccessible + * @existing_gobject_with_proxy: the GType of an object that has a registered factory that + * manufactures the type we want to inherit from. ie. to inherit from a GailCanvasItem + * we need to pass MATE_TYPE_CANVAS_ITEM - since GailCanvasItem is registered against + * that type. + * @opt_gail_parent_class: the name of the Gail class to derive from eg. GailCanvasItem + * @class_init: the init function to run for this class + * + * This should be run to register the type, it can subsequently be run with + * the same name and will not re-register it, but simply return it. + * + * NB. to do instance init, you prolly want to override AtkObject::initialize + * + * Return value: the registered type, or 0 on failure. + **/ +GType +eel_accessibility_create_derived_type (const char *type_name, + GType existing_gobject_with_proxy, + EelAccessibilityClassInitFn class_init) +{ + GType type; + GType parent_atk_type; + GTypeInfo tinfo = { 0 }; + GTypeQuery query; + AtkObjectFactory *factory; + + if ((type = g_type_from_name (type_name))) + { + return type; + } + + factory = atk_registry_get_factory + (atk_get_default_registry (), + existing_gobject_with_proxy); + if (!factory) + { + return G_TYPE_INVALID; + } + + parent_atk_type = atk_object_factory_get_accessible_type (factory); + if (!parent_atk_type) + { + return G_TYPE_INVALID; + } + + /* + * Figure out the size of the class and instance + * we are deriving from + */ + g_type_query (parent_atk_type, &query); + + if (class_init) + { + tinfo.class_init = (GClassInitFunc) class_init; + } + + tinfo.class_size = query.class_size; + tinfo.instance_size = query.instance_size; + + /* Register the type */ + type = g_type_register_static ( + parent_atk_type, type_name, &tinfo, 0); + + return type; +} + + +static GQuark +get_quark_accessible (void) +{ + static GQuark quark_accessible_object = 0; + + if (!quark_accessible_object) + { + quark_accessible_object = g_quark_from_static_string + ("accessible-object"); + } + + return quark_accessible_object; +} + +static GQuark +get_quark_gobject (void) +{ + static GQuark quark_accessible_gobject = 0; + + if (!quark_accessible_gobject) + { + quark_accessible_gobject = g_quark_from_static_string + ("object-for-accessible"); + } + + return quark_accessible_gobject; +} + +/** + * eel_accessibility_get_atk_object: + * @object: a GObject of some sort + * + * gets an AtkObject associated with a GObject + * + * Return value: the associated accessible if one exists or NULL + **/ +AtkObject * +eel_accessibility_get_atk_object (gpointer object) +{ + return g_object_get_qdata (object, get_quark_accessible ()); +} + +/** + * eel_accessibilty_for_object: + * @object: a GObject of some sort + * + * gets an AtkObject associated with a GObject and if it doesn't + * exist creates a suitable accessible object. + * + * Return value: an associated accessible. + **/ +AtkObject * +eel_accessibility_for_object (gpointer object) +{ + if (GTK_IS_WIDGET (object)) + return gtk_widget_get_accessible (object); + + return atk_gobject_accessible_for_object (object); +} + +/** + * eel_accessibility_get_gobject: + * @object: an AtkObject + * + * gets the GObject associated with the AtkObject, for which + * @object provides accessibility support. + * + * Return value: the accessible's associated GObject + **/ +gpointer +eel_accessibility_get_gobject (AtkObject *object) +{ + return g_object_get_qdata (G_OBJECT (object), get_quark_gobject ()); +} + +static void +eel_accessibility_destroy (gpointer data, + GObject *where_the_object_was) +{ + atk_object_notify_state_change + (ATK_OBJECT (data), ATK_STATE_DEFUNCT, TRUE); +} + +/** + * eel_accessibility_set_atk_object_return: + * @object: a GObject + * @atk_object: it's AtkObject + * + * used to register and return a new accessible object for something + * + * Return value: @atk_object. + **/ +AtkObject * +eel_accessibility_set_atk_object_return (gpointer object, + AtkObject *atk_object) +{ + atk_object_initialize (atk_object, object); + + if (!ATK_IS_GOBJECT_ACCESSIBLE (atk_object)) + { + g_object_set_qdata_full + (object, get_quark_accessible (), atk_object, + (GDestroyNotify)eel_accessibility_destroy); + g_object_set_qdata + (G_OBJECT (atk_object), get_quark_gobject (), object); + } + + return atk_object; +} + +static GailTextUtil * +get_simple_text (gpointer object) +{ + GObject *gobject; + EelAccessibleTextIface *aif; + + if (GTK_IS_ACCESSIBLE (object)) + { + gobject = G_OBJECT (gtk_accessible_get_widget (GTK_ACCESSIBLE (object))); + } + else + { + gobject = eel_accessibility_get_gobject (object); + } + + if (!gobject) + { + return NULL; + } + + aif = EEL_ACCESSIBLE_TEXT_GET_IFACE (gobject); + if (!aif) + { + g_warning ("No accessible text inferface on '%s'", + g_type_name_from_instance ((gpointer) gobject)); + + } + else if (aif->get_text) + { + return aif->get_text (gobject); + } + + return NULL; +} + +char * +eel_accessibility_text_get_text (AtkText *text, + gint start_pos, + gint end_pos) +{ + GailTextUtil *util = get_simple_text (text); + g_return_val_if_fail (util != NULL, NULL); + + return gail_text_util_get_substring (util, start_pos, end_pos); +} + +gunichar +eel_accessibility_text_get_character_at_offset (AtkText *text, + gint offset) +{ + char *txt, *index; + gint sucks1 = 0, sucks2 = -1; + gunichar c; + GailTextUtil *util = get_simple_text (text); + g_return_val_if_fail (util != NULL, 0); + + txt = gail_text_util_get_substring (util, sucks1, sucks2); + + index = g_utf8_offset_to_pointer (txt, offset); + c = g_utf8_get_char (index); + g_free (txt); + + return c; +} + +char * +eel_accessibility_text_get_text_before_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + GailTextUtil *util = get_simple_text (text); + g_return_val_if_fail (util != NULL, NULL); + + return gail_text_util_get_text ( + util, NULL, GAIL_BEFORE_OFFSET, + boundary_type, offset, start_offset, end_offset); +} + +char * +eel_accessibility_text_get_text_at_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + GailTextUtil *util = get_simple_text (text); + g_return_val_if_fail (util != NULL, NULL); + + return gail_text_util_get_text ( + util, NULL, GAIL_AT_OFFSET, + boundary_type, offset, start_offset, end_offset); +} + +gchar* +eel_accessibility_text_get_text_after_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + GailTextUtil *util = get_simple_text (text); + g_return_val_if_fail (util != NULL, NULL); + + return gail_text_util_get_text ( + util, NULL, GAIL_AFTER_OFFSET, + boundary_type, offset, start_offset, end_offset); +} + +gint +eel_accessibility_text_get_character_count (AtkText *text) +{ + GailTextUtil *util = get_simple_text (text); + g_return_val_if_fail (util != NULL, -1); + + return gtk_text_buffer_get_char_count (util->buffer); +} + +static void +eel_accessibility_simple_text_interface_init (AtkTextIface *iface) +{ + iface->get_text = eel_accessibility_text_get_text; + iface->get_character_at_offset = eel_accessibility_text_get_character_at_offset; + iface->get_text_before_offset = eel_accessibility_text_get_text_before_offset; + iface->get_text_at_offset = eel_accessibility_text_get_text_at_offset; + iface->get_text_after_offset = eel_accessibility_text_get_text_after_offset; + iface->get_character_count = eel_accessibility_text_get_character_count; + + /* iface->get_caret_offset = eel_accessibility_text_get_caret_offset; + iface->set_caret_offset = eel_accessibility_text_set_caret_offset; + iface->get_selection = eel_accessibility_text_get_selection; + iface->get_n_selections = eel_accessibility_text_get_n_selections; + iface->add_selection = eel_accessibility_text_add_selection; + iface->remove_selection = eel_accessibility_text_remove_selection; + iface->set_selection = eel_accessibility_text_set_selection; + iface->get_run_attributes = eel_accessibility_text_get_run_attributes; + iface->get_default_attributes = eel_accessibility_text_get_default_attributes; + iface->get_character_extents = eel_accessibility_text_get_character_extents; + iface->get_offset_at_point = eel_accessibility_text_get_offset_at_point; */ +} + +void +eel_accessibility_add_simple_text (GType type) +{ + const GInterfaceInfo simple_text_info = + { + (GInterfaceInitFunc) + eel_accessibility_simple_text_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + g_return_if_fail (type != G_TYPE_INVALID); + + g_type_add_interface_static ( + type, ATK_TYPE_TEXT, &simple_text_info); +} + +GType +eel_accessible_text_get_type (void) +{ + static GType type = 0; + + if (!type) + { + const GTypeInfo tinfo = + { + sizeof (AtkTextIface), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) NULL, + (GClassFinalizeFunc) NULL + }; + + type = g_type_register_static ( + G_TYPE_INTERFACE, "EelAccessibleText", &tinfo, 0); + } + + return type; +} + +void +eel_accessibility_set_name (gpointer object, + const char *name) +{ + AtkObject *atk_object = eel_accessibility_for_object (object); + + if (atk_object) + { + atk_object_set_name (atk_object, name); + } +} + +void +eel_accessibility_set_description (gpointer object, + const char *description) +{ + AtkObject *atk_object = eel_accessibility_for_object (object); + + if (atk_object) + { + atk_object_set_description (atk_object, description); + } +} diff --git a/eel/eel-accessibility.h b/eel/eel-accessibility.h new file mode 100644 index 00000000..3ca24a0f --- /dev/null +++ b/eel/eel-accessibility.h @@ -0,0 +1,153 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* eel-accessibility.h - Utility functions for accessibility + + Copyright (C) 2002 Anders Carlsson + + The Eel Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Eel Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Eel Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Anders Carlsson <[email protected]> +*/ + +#ifndef EEL_ACCESSIBILITY_H +#define EEL_ACCESSIBILITY_H + +#include <glib-object.h> +#include <atk/atkobject.h> +#include <atk/atkregistry.h> +#include <atk/atkobjectfactory.h> +#include <gtk/gtk.h> +#include <libgail-util/gailtextutil.h> + +void eel_accessibility_set_up_label_widget_relation (GtkWidget *label, GtkWidget *widget); + +typedef void (*EelAccessibilityClassInitFn) (AtkObjectClass *klass); + +AtkObject *eel_accessibility_get_atk_object (gpointer object); +AtkObject *eel_accessibility_for_object (gpointer object); +gpointer eel_accessibility_get_gobject (AtkObject *object); +AtkObject *eel_accessibility_set_atk_object_return (gpointer object, + AtkObject *atk_object); +GType eel_accessibility_create_derived_type (const char *type_name, + GType existing_gobject_with_proxy, + EelAccessibilityClassInitFn class_init); +void eel_accessibility_set_name (gpointer object, + const char *name); +void eel_accessibility_set_description (gpointer object, + const char *description); + +char* eel_accessibility_text_get_text (AtkText *text, + gint start_pos, + gint end_pos); +gunichar eel_accessibility_text_get_character_at_offset +(AtkText *text, + gint offset); +char* eel_accessibility_text_get_text_before_offset +(AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset); +char* eel_accessibility_text_get_text_at_offset +(AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset); +char* eel_accessibility_text_get_text_after_offset +(AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset); +gint eel_accessibility_text_get_character_count +(AtkText *text); + + +#define EEL_TYPE_ACCESSIBLE_TEXT (eel_accessible_text_get_type ()) +#define EEL_IS_ACCESSIBLE_TEXT(obj) G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_ACCESSIBLE_TEXT) +#define EEL_ACCESSIBLE_TEXT(obj) G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_ACCESSIBLE_TEXT, EelAccessibleText) +#define EEL_ACCESSIBLE_TEXT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EEL_TYPE_ACCESSIBLE_TEXT, EelAccessibleTextIface)) + +/* Instead of implementing the AtkText interface, implement this */ +typedef struct _EelAccessibleText EelAccessibleText; + +typedef struct +{ + GTypeInterface parent; + + GailTextUtil *(*get_text) (GObject *text); + PangoLayout *(*get_layout) (GObject *text); +} EelAccessibleTextIface; + +GType eel_accessible_text_get_type (void); +void eel_accessibility_add_simple_text (GType type); + +/* From gail - should be unneccessary when AtkObjectFactory is fixed */ +#define EEL_ACCESSIBLE_FACTORY(type, factory_name, type_as_function, opt_create_accessible) \ + \ +static GType \ +type_as_function ## _factory_get_accessible_type (void) \ +{ \ + return type; \ +} \ + \ +static AtkObject* \ +type_as_function ## _factory_create_accessible (GObject *obj) \ +{ \ + AtkObject *accessible; \ + \ + g_assert (G_IS_OBJECT (obj)); \ + \ + accessible = opt_create_accessible (obj); \ + \ + return accessible; \ +} \ + \ +static void \ +type_as_function ## _factory_class_init (AtkObjectFactoryClass *klass) \ +{ \ + klass->create_accessible = type_as_function ## _factory_create_accessible; \ + klass->get_accessible_type = type_as_function ## _factory_get_accessible_type;\ +} \ + \ +static GType \ +type_as_function ## _factory_get_type (void) \ +{ \ + static GType t = 0; \ + \ + if (!t) \ + { \ + static const GTypeInfo tinfo = \ + { \ + sizeof (AtkObjectFactoryClass), \ + NULL, NULL, (GClassInitFunc) type_as_function ## _factory_class_init, \ + NULL, NULL, sizeof (AtkObjectFactory), 0, NULL, NULL \ + }; \ + \ + t = g_type_register_static ( \ + ATK_TYPE_OBJECT_FACTORY, factory_name, &tinfo, 0); \ + } \ + \ + return t; \ +} + +#define EEL_OBJECT_SET_FACTORY(object_type, type_as_function) \ + atk_registry_set_factory_type (atk_get_default_registry (), \ + object_type, \ + type_as_function ## _factory_get_type ()) + + +#endif /* EEL_ACCESSIBILITY_H */ diff --git a/eel/eel-alert-dialog.c b/eel/eel-alert-dialog.c new file mode 100644 index 00000000..976c1227 --- /dev/null +++ b/eel/eel-alert-dialog.c @@ -0,0 +1,490 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-alert-dialog.c: An HIG compliant alert dialog. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#include <config.h> + +#include "eel-alert-dialog.h" +#include "eel-i18n.h" +#include "eel-gtk-macros.h" +#include <gtk/gtk.h> +#include <string.h> + +enum +{ + PROP_0, + PROP_ALERT_TYPE, + PROP_BUTTONS +}; + +struct _EelAlertDialogDetails +{ + GtkWidget *image; + GtkWidget *primary_label; + GtkWidget *secondary_label; + GtkWidget *details_expander; + GtkWidget *details_label; + GtkMessageType type; +}; + + +static gpointer parent_class; + +static void eel_alert_dialog_finalize (GObject *object); +static void eel_alert_dialog_class_init (EelAlertDialogClass *klass); +static void eel_alert_dialog_init (EelAlertDialog *dialog); +static void eel_alert_dialog_style_set (GtkWidget *widget, + GtkStyle *prev_style); +static void eel_alert_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void eel_alert_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void eel_alert_dialog_add_buttons (EelAlertDialog *alert_dialog, + GtkButtonsType buttons); + +GType +eel_alert_dialog_get_type (void) +{ + static GType dialog_type = 0; + + if (!dialog_type) + { + + const GTypeInfo dialog_info = + { + sizeof (EelAlertDialogClass), + NULL, + NULL, + (GClassInitFunc) eel_alert_dialog_class_init, + NULL, + NULL, + sizeof (EelAlertDialog), + 0, + (GInstanceInitFunc) eel_alert_dialog_init, + }; + + dialog_type = g_type_register_static (GTK_TYPE_DIALOG, "EelAlertDialog", + &dialog_info, 0); + } + return dialog_type; +} + +static void +eel_alert_dialog_class_init (EelAlertDialogClass *class) +{ + GtkWidgetClass *widget_class; + GObjectClass *gobject_class; + + widget_class = GTK_WIDGET_CLASS (class); + gobject_class = G_OBJECT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + + G_OBJECT_CLASS (class)->finalize = eel_alert_dialog_finalize; + + widget_class->style_set = eel_alert_dialog_style_set; + + gobject_class->set_property = eel_alert_dialog_set_property; + gobject_class->get_property = eel_alert_dialog_get_property; + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("alert_border", + _("Image/label border"), + _("Width of border around the label and image in the alert dialog"), + 0, + G_MAXINT, + 5, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_ALERT_TYPE, + g_param_spec_enum ("alert_type", + _("Alert Type"), + _("The type of alert"), + GTK_TYPE_MESSAGE_TYPE, + GTK_MESSAGE_INFO, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (gobject_class, + PROP_BUTTONS, + g_param_spec_enum ("buttons", + _("Alert Buttons"), + _("The buttons shown in the alert dialog"), + GTK_TYPE_BUTTONS_TYPE, + GTK_BUTTONS_NONE, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +eel_alert_dialog_finalize (GObject *object) +{ + EelAlertDialog *dialog; + + dialog = EEL_ALERT_DIALOG (object); + + g_free (dialog->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + + +static void +eel_alert_dialog_init (EelAlertDialog *dialog) +{ + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *expander; + + dialog->details = g_new0 (EelAlertDialogDetails, 1); + + dialog->details->primary_label = gtk_label_new (NULL); + dialog->details->secondary_label = gtk_label_new (NULL); + dialog->details->details_label = gtk_label_new (NULL); + dialog->details->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (dialog->details->image), 0.5, 0.0); + + gtk_label_set_line_wrap (GTK_LABEL (dialog->details->primary_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (dialog->details->primary_label), TRUE); + gtk_label_set_use_markup (GTK_LABEL (dialog->details->primary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (dialog->details->primary_label), 0.0, 0.5); + + gtk_label_set_line_wrap (GTK_LABEL (dialog->details->secondary_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (dialog->details->secondary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (dialog->details->secondary_label), 0.0, 0.5); + + gtk_label_set_line_wrap (GTK_LABEL (dialog->details->details_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (dialog->details->details_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (dialog->details->details_label), 0.0, 0.5); + + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + gtk_box_pack_start (GTK_BOX (hbox), dialog->details->image, + FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 12); + + gtk_box_pack_start (GTK_BOX (hbox), vbox, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), dialog->details->primary_label, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), dialog->details->secondary_label, + FALSE, FALSE, 0); + + expander = gtk_expander_new_with_mnemonic (_("Show more _details")); + dialog->details->details_expander = expander; + gtk_expander_set_spacing (GTK_EXPANDER (expander), 6); + gtk_container_add (GTK_CONTAINER (expander), dialog->details->details_label); + + gtk_box_pack_start (GTK_BOX (vbox), expander, + FALSE, FALSE, 0); + + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, + FALSE, FALSE, 0); + + gtk_widget_show_all (hbox); + gtk_widget_hide (expander); + +} + +static void +setup_type (EelAlertDialog *dialog, + GtkMessageType type) +{ + const gchar *stock_id = NULL; + GtkStockItem item; + + switch (type) + { + case GTK_MESSAGE_INFO: + stock_id = GTK_STOCK_DIALOG_INFO; + break; + case GTK_MESSAGE_QUESTION: + stock_id = GTK_STOCK_DIALOG_QUESTION; + break; + case GTK_MESSAGE_WARNING: + stock_id = GTK_STOCK_DIALOG_WARNING; + break; + case GTK_MESSAGE_ERROR: + stock_id = GTK_STOCK_DIALOG_ERROR; + break; + default: + g_warning ("Unknown GtkMessageType %d", type); + break; + } + + if (stock_id == NULL) + { + stock_id = GTK_STOCK_DIALOG_INFO; + } + + if (gtk_stock_lookup (stock_id, &item)) + { + gtk_image_set_from_stock (GTK_IMAGE (dialog->details->image), stock_id, + GTK_ICON_SIZE_DIALOG); + } + else + { + g_warning ("Stock dialog ID doesn't exist?"); + } +} + +static void +eel_alert_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EelAlertDialog *dialog; + + dialog = EEL_ALERT_DIALOG (object); + + switch (prop_id) + { + case PROP_ALERT_TYPE: + dialog->details->type = g_value_get_enum (value); + setup_type (dialog, dialog->details->type); + break; + case PROP_BUTTONS: + eel_alert_dialog_add_buttons (dialog, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eel_alert_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EelAlertDialog *dialog; + + dialog = EEL_ALERT_DIALOG (object); + + switch (prop_id) + { + case PROP_ALERT_TYPE: + g_value_set_enum (value, dialog->details->type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +void +eel_alert_dialog_set_primary_label (EelAlertDialog *dialog, + const gchar *message) +{ + gchar *markup_str; + char *escaped_message; + + if (message != NULL) + { + escaped_message = g_markup_escape_text (message, -1); + markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", escaped_message, "</span>", NULL); + gtk_label_set_markup (GTK_LABEL (EEL_ALERT_DIALOG (dialog)->details->primary_label), + markup_str); + g_free (markup_str); + g_free (escaped_message); + } +} + +void +eel_alert_dialog_set_secondary_label (EelAlertDialog *dialog, + const gchar *message) +{ + if (message != NULL) + { + gtk_label_set_text (GTK_LABEL (EEL_ALERT_DIALOG (dialog)->details->secondary_label), + message); + } + else + { + gtk_widget_hide (EEL_ALERT_DIALOG (dialog)->details->secondary_label); + } +} + +void +eel_alert_dialog_set_details_label (EelAlertDialog *dialog, + const gchar *message) +{ + if (message != NULL) + { + gtk_widget_show (dialog->details->details_expander); + gtk_label_set_text (GTK_LABEL (dialog->details->details_label), message); + } + else + { + gtk_widget_hide (dialog->details->details_expander); + } +} + + +GtkWidget* +eel_alert_dialog_new (GtkWindow *parent, + GtkDialogFlags flags, + GtkMessageType type, + GtkButtonsType buttons, + const gchar *primary_message, + const gchar *secondary_message) +{ + GtkWidget *widget; + GtkDialog *dialog; + + g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); + + widget = g_object_new (EEL_TYPE_ALERT_DIALOG, + "alert_type", type, + "buttons", buttons, + NULL); + atk_object_set_role (gtk_widget_get_accessible (widget), ATK_ROLE_ALERT); + + dialog = GTK_DIALOG (widget); + + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_dialog_set_has_separator (dialog, FALSE); + + /* Make sure we don't get a window title. + * HIG says that alert dialogs should not have window title + */ + gtk_window_set_title (GTK_WINDOW (dialog), ""); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); + + eel_alert_dialog_set_primary_label (EEL_ALERT_DIALOG (dialog), + primary_message); + + eel_alert_dialog_set_secondary_label (EEL_ALERT_DIALOG (dialog), + secondary_message); + + if (parent != NULL) + { + gtk_window_set_transient_for (GTK_WINDOW (widget), + GTK_WINDOW (parent)); + } + + if (flags & GTK_DIALOG_MODAL) + { + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + } + + if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) + { + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + } + return widget; +} + +static void +eel_alert_dialog_add_buttons (EelAlertDialog* alert_dialog, + GtkButtonsType buttons) +{ + GtkDialog* dialog; + + dialog = GTK_DIALOG (alert_dialog); + + switch (buttons) + { + case GTK_BUTTONS_NONE: + break; + case GTK_BUTTONS_OK: + gtk_dialog_add_button (dialog, + GTK_STOCK_OK, + GTK_RESPONSE_OK); + gtk_dialog_set_default_response (dialog, + GTK_RESPONSE_OK); + break; + case GTK_BUTTONS_CLOSE: + gtk_dialog_add_button (dialog, + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE); + gtk_dialog_set_default_response (dialog, + GTK_RESPONSE_CLOSE); + break; + case GTK_BUTTONS_CANCEL: + gtk_dialog_add_button (dialog, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + gtk_dialog_set_default_response (dialog, + GTK_RESPONSE_CANCEL); + break; + case GTK_BUTTONS_YES_NO: + gtk_dialog_add_button (dialog, + GTK_STOCK_NO, + GTK_RESPONSE_NO); + gtk_dialog_add_button (dialog, + GTK_STOCK_YES, + GTK_RESPONSE_YES); + gtk_dialog_set_default_response (dialog, + GTK_RESPONSE_YES); + break; + case GTK_BUTTONS_OK_CANCEL: + gtk_dialog_add_button (dialog, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (dialog, + GTK_STOCK_OK, + GTK_RESPONSE_OK); + gtk_dialog_set_default_response (dialog, + GTK_RESPONSE_OK); + break; + default: + g_warning ("Unknown GtkButtonsType"); + break; + } + g_object_notify (G_OBJECT (alert_dialog), "buttons"); +} + +static void +eel_alert_dialog_style_set (GtkWidget *widget, + GtkStyle *prev_style) +{ + GtkWidget *parent; + gint border_width; + + border_width = 0; + + parent = GTK_WIDGET (gtk_widget_get_parent (EEL_ALERT_DIALOG (widget)->details->image)); + + if (parent != NULL) + { + gtk_widget_style_get (widget, "alert_border", + &border_width, NULL); + + gtk_container_set_border_width (GTK_CONTAINER (parent), + border_width); + } + + if (GTK_WIDGET_CLASS (parent_class)->style_set) + { + (GTK_WIDGET_CLASS (parent_class)->style_set) (widget, prev_style); + } +} diff --git a/eel/eel-alert-dialog.h b/eel/eel-alert-dialog.h new file mode 100644 index 00000000..62d86a27 --- /dev/null +++ b/eel/eel-alert-dialog.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-alert-dialog.h: An HIG compliant alert dialog. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef EEL_ALERT_DIALOG_H +#define EEL_ALERT_DIALOG_H + +#include <gtk/gtk.h> + +#define EEL_TYPE_ALERT_DIALOG (eel_alert_dialog_get_type ()) +#define EEL_ALERT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_ALERT_DIALOG, EelAlertDialog)) + +typedef struct _EelAlertDialog EelAlertDialog; +typedef struct _EelAlertDialogClass EelAlertDialogClass; +typedef struct _EelAlertDialogDetails EelAlertDialogDetails; + +struct _EelAlertDialog +{ + GtkDialog parent_instance; + EelAlertDialogDetails *details; +}; + +struct _EelAlertDialogClass +{ + GtkDialogClass parent_class; +}; + +GType eel_alert_dialog_get_type (void); + +GtkWidget* eel_alert_dialog_new (GtkWindow *parent, + GtkDialogFlags flags, + GtkMessageType type, + GtkButtonsType buttons, + const gchar *primary_message, + const gchar *secondary_message); +void eel_alert_dialog_set_primary_label (EelAlertDialog *dialog, + const gchar *message); +void eel_alert_dialog_set_secondary_label (EelAlertDialog *dialog, + const gchar *message); +void eel_alert_dialog_set_details_label (EelAlertDialog *dialog, + const gchar *message); + +#endif /* EEL_ALERT_DIALOG_H */ diff --git a/eel/eel-art-extensions.c b/eel/eel-art-extensions.c new file mode 100644 index 00000000..c245101b --- /dev/null +++ b/eel/eel-art-extensions.c @@ -0,0 +1,321 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-art-extensions.c - implementation of libart extension functions. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> + +#include "eel-art-extensions.h" +#include "eel-lib-self-check-functions.h" +#include <math.h> + +const EelDRect eel_drect_empty = { 0.0, 0.0, 0.0, 0.0 }; +const EelIRect eel_irect_empty = { 0, 0, 0, 0 }; +const EelIPoint eel_ipoint_max = { G_MAXINT, G_MAXINT }; +const EelIPoint eel_ipoint_min = { G_MININT, G_MININT }; +const EelIPoint eel_ipoint_zero = { 0, 0 }; +const EelDimensions eel_dimensions_empty = { 0, 0 }; + +void +eel_irect_copy (EelIRect *dest, const EelIRect *src) +{ + dest->x0 = src->x0; + dest->y0 = src->y0; + dest->x1 = src->x1; + dest->y1 = src->y1; +} + +void +eel_irect_union (EelIRect *dest, + const EelIRect *src1, + const EelIRect *src2) +{ + if (eel_irect_is_empty (src1)) + { + eel_irect_copy (dest, src2); + } + else if (eel_irect_is_empty (src2)) + { + eel_irect_copy (dest, src1); + } + else + { + dest->x0 = MIN (src1->x0, src2->x0); + dest->y0 = MIN (src1->y0, src2->y0); + dest->x1 = MAX (src1->x1, src2->x1); + dest->y1 = MAX (src1->y1, src2->y1); + } +} + +void +eel_irect_intersect (EelIRect *dest, + const EelIRect *src1, + const EelIRect *src2) +{ + dest->x0 = MAX (src1->x0, src2->x0); + dest->y0 = MAX (src1->y0, src2->y0); + dest->x1 = MIN (src1->x1, src2->x1); + dest->y1 = MIN (src1->y1, src2->y1); +} + +gboolean +eel_irect_is_empty (const EelIRect *src) +{ + return (src->x1 <= src->x0 || + src->y1 <= src->y0); +} + +EelIRect +eel_irect_assign (int x, + int y, + int width, + int height) +{ + EelIRect rectangle; + + rectangle.x0 = x; + rectangle.y0 = y; + rectangle.x1 = rectangle.x0 + width; + rectangle.y1 = rectangle.y0 + height; + + return rectangle; +} + +/** + * eel_irect_assign_dimensions: + * + * @x: X coodinate for resulting rectangle. + * @y: Y coodinate for resulting rectangle. + * @dimensions: A EelDimensions structure for the rect's width and height. + * + * Returns: An EelIRect with the given coordinates and dimensions. + */ +EelIRect +eel_irect_assign_dimensions (int x, + int y, + EelDimensions dimensions) +{ + EelIRect rectangle; + + rectangle.x0 = x; + rectangle.y0 = y; + rectangle.x1 = rectangle.x0 + dimensions.width; + rectangle.y1 = rectangle.y0 + dimensions.height; + + return rectangle; +} + +/** + * eel_irect_get_width: + * + * @rectangle: An EelIRect. + * + * Returns: The width of the rectangle. + * + */ +int +eel_irect_get_width (EelIRect rectangle) +{ + return rectangle.x1 - rectangle.x0; +} + +/** + * eel_irect_get_height: + * + * @rectangle: An EelIRect. + * + * Returns: The height of the rectangle. + * + */ +int +eel_irect_get_height (EelIRect rectangle) +{ + return rectangle.y1 - rectangle.y0; +} + + +static void +eel_drect_copy (EelDRect *dest, + const EelDRect *src) +{ + dest->x0 = src->x0; + dest->y0 = src->y0; + dest->x1 = src->x1; + dest->y1 = src->y1; +} + +static gboolean +eel_drect_is_empty (const EelDRect *src) +{ + return (src->x1 <= src->x0 || src->y1 <= src->y0); +} + +void +eel_drect_union (EelDRect *dest, + const EelDRect *src1, + const EelDRect *src2) +{ + if (eel_drect_is_empty (src1)) + { + eel_drect_copy (dest, src2); + } + else if (eel_drect_is_empty (src2)) + { + eel_drect_copy (dest, src1); + } + else + { + dest->x0 = MIN (src1->x0, src2->x0); + dest->y0 = MIN (src1->y0, src2->y0); + dest->x1 = MAX (src1->x1, src2->x1); + dest->y1 = MAX (src1->y1, src2->y1); + } +} + + +/** + * eel_irect_contains_point: + * + * @rectangle: An EelIRect. + * @x: X coordinate to test. + * @y: Y coordinate to test. + * + * Returns: A boolean value indicating whether the rectangle + * contains the x,y coordinate. + * + */ +gboolean +eel_irect_contains_point (EelIRect rectangle, + int x, + int y) +{ + return x >= rectangle.x0 + && x <= rectangle.x1 + && y >= rectangle.y0 + && y <= rectangle.y1; +} + +gboolean +eel_irect_hits_irect (EelIRect rectangle_a, + EelIRect rectangle_b) +{ + EelIRect intersection; + eel_irect_intersect (&intersection, &rectangle_a, &rectangle_b); + return !eel_irect_is_empty (&intersection); +} + +gboolean +eel_irect_equal (EelIRect rectangle_a, + EelIRect rectangle_b) +{ + return rectangle_a.x0 == rectangle_b.x0 + && rectangle_a.y0 == rectangle_b.y0 + && rectangle_a.x1 == rectangle_b.x1 + && rectangle_a.y1 == rectangle_b.y1; +} + +/** + * eel_irect_align: + * + * @container: The rectangle that is to contain the aligned rectangle. + * @aligned_width: Width of rectangle being algined. + * @aligned_height: Height of rectangle being algined. + * @x_alignment: X alignment. + * @y_alignment: Y alignment. + * + * Returns: A rectangle aligned within a container rectangle + * using the given alignment parameters. + */ +EelIRect +eel_irect_align (EelIRect container, + int aligned_width, + int aligned_height, + float x_alignment, + float y_alignment) +{ + EelIRect aligned; + int available_width; + int available_height; + + if (eel_irect_is_empty (&container)) + { + return eel_irect_empty; + } + + if (aligned_width == 0 || aligned_height == 0) + { + return eel_irect_empty; + } + + /* Make sure the aligment parameters are within range */ + x_alignment = MAX (0, x_alignment); + x_alignment = MIN (1.0, x_alignment); + y_alignment = MAX (0, y_alignment); + y_alignment = MIN (1.0, y_alignment); + + available_width = eel_irect_get_width (container) - aligned_width; + available_height = eel_irect_get_height (container) - aligned_height; + + aligned.x0 = floor (container.x0 + (available_width * x_alignment) + 0.5); + aligned.y0 = floor (container.y0 + (available_height * y_alignment) + 0.5); + aligned.x1 = aligned.x0 + aligned_width; + aligned.y1 = aligned.y0 + aligned_height; + + return aligned; +} + + +/** + * eel_dimensions_are_empty: + * + * @dimensions: A EelDimensions structure. + * + * Returns: Whether the dimensions are empty. + */ +gboolean +eel_dimensions_are_empty (EelDimensions dimensions) +{ + return dimensions.width <= 0 || dimensions.height <= 0; +} + +EelIRect +eel_irect_offset_by (EelIRect rectangle, int x, int y) +{ + rectangle.x0 += x; + rectangle.x1 += x; + rectangle.y0 += y; + rectangle.y1 += y; + + return rectangle; +} + +EelIRect +eel_irect_scale_by (EelIRect rectangle, double scale) +{ + rectangle.x0 *= scale; + rectangle.x1 *= scale; + rectangle.y0 *= scale; + rectangle.y1 *= scale; + + return rectangle; +} diff --git a/eel/eel-art-extensions.h b/eel/eel-art-extensions.h new file mode 100644 index 00000000..67f5aa04 --- /dev/null +++ b/eel/eel-art-extensions.h @@ -0,0 +1,120 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-art-extensions.h - interface of libart extension functions. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_ART_EXTENSIONS_H +#define EEL_ART_EXTENSIONS_H + +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct + { + double x, y; + } EelDPoint; + + typedef struct + { + int x; + int y; + } EelIPoint; + + typedef struct + { + double x0, y0, x1, y1; + } EelDRect; + + typedef struct + { + /*< public >*/ + int x0, y0, x1, y1; + } EelIRect; + + typedef struct + { + int width; + int height; + } EelDimensions; + + extern const EelDRect eel_drect_empty; + extern const EelIRect eel_irect_empty; + extern const EelIPoint eel_ipoint_max; + extern const EelIPoint eel_ipoint_min; + extern const EelIPoint eel_ipoint_zero; + extern const EelDimensions eel_dimensions_empty; + + void eel_irect_copy (EelIRect *dest, + const EelIRect *src); + void eel_irect_union (EelIRect *dest, + const EelIRect *src1, + const EelIRect *src2); + void eel_irect_intersect (EelIRect *dest, + const EelIRect *src1, + const EelIRect *src2); + gboolean eel_irect_equal (EelIRect rectangle_a, + EelIRect rectangle_b); + gboolean eel_irect_hits_irect (EelIRect rectangle_a, + EelIRect rectangle_b); + EelIRect eel_irect_offset_by (EelIRect rectangle, + int x, + int y); + EelIRect eel_irect_scale_by (EelIRect rectangle, + double scale); + gboolean eel_irect_is_empty (const EelIRect *rectangle); + gboolean eel_irect_contains_point (EelIRect outer_rectangle, + int x, + int y); + EelIRect eel_irect_assign (int x, + int y, + int width, + int height); + EelIRect eel_irect_assign_dimensions (int x, + int y, + EelDimensions dimensions); + int eel_irect_get_width (EelIRect rectangle); + int eel_irect_get_height (EelIRect rectangle); + EelIRect eel_irect_align (EelIRect container, + int aligned_width, + int aligned_height, + float x_alignment, + float y_alignment); + + + void eel_drect_union (EelDRect *dest, + const EelDRect *src1, + const EelDRect *src2); + + + /* EelDimensions functions. */ + gboolean eel_dimensions_are_empty (EelDimensions dimensions); + + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_ART_EXTENSIONS_H */ diff --git a/eel/eel-art-gtk-extensions.c b/eel/eel-art-gtk-extensions.c new file mode 100644 index 00000000..f3ccef3c --- /dev/null +++ b/eel/eel-art-gtk-extensions.c @@ -0,0 +1,346 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-eel-gtk-extensions.c - Access gtk/gdk attributes as libeel rectangles. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PEELICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> + +#include "eel-art-gtk-extensions.h" +#include <gdk/gdkx.h> + +/** + * eel_gdk_rectangle_to_eel_irect: + * @gdk_rectangle: The source GdkRectangle. + * + * Return value: An EelIRect representation of the GdkRectangle. + * + * This is a very simple conversion of rectangles from the Gdk to the Libeel + * universe. This is useful in code that does clipping (or other operations) + * using libeel and has a GdkRectangle to work with - for example expose_event() + * in GtkWidget's. + */ +EelIRect +eel_gdk_rectangle_to_eel_irect (GdkRectangle gdk_rectangle) +{ + EelIRect rectangle; + + rectangle.x0 = gdk_rectangle.x; + rectangle.y0 = gdk_rectangle.y; + rectangle.x1 = rectangle.x0 + (int) gdk_rectangle.width; + rectangle.y1 = rectangle.y0 + (int) gdk_rectangle.height; + + return rectangle; +} + +/** + * eel_screen_get_dimensions: + * + * Return value: The screen dimensions. + * + */ +EelDimensions +eel_screen_get_dimensions (void) +{ + EelDimensions screen_dimensions; + + screen_dimensions.width = gdk_screen_width (); + screen_dimensions.height = gdk_screen_height (); + + g_assert (screen_dimensions.width > 0); + g_assert (screen_dimensions.height > 0); + + return screen_dimensions; +} + +/** + * eel_gdk_window_get_bounds: + * @gdk_window: The source GdkWindow. + * + * Return value: An EelIRect representation of the given GdkWindow's geometry + * relative to its parent in the Gdk window hierarchy. + * + */ +EelIRect +eel_gdk_window_get_bounds (GdkWindow *gdk_window) +{ + EelIRect bounds; + int width; + int height; + + g_return_val_if_fail (gdk_window != NULL, eel_irect_empty); + + gdk_window_get_position (gdk_window, &bounds.x0, &bounds.y0); + +#if GTK_CHECK_VERSION(3, 0, 0) + width = gdk_window_get_width(gdk_window); + height = gdk_window_get_height(gdk_window); +#else + gdk_drawable_get_size (gdk_window, &width, &height); +#endif + + + bounds.x1 = bounds.x0 + width; + bounds.y1 = bounds.y0 + height; + + return bounds; +} + +/** + * eel_gdk_window_get_bounds: + * @gdk_window: The source GdkWindow. + * + * Return value: An EelIRect representation of the given GdkWindow's geometry + * relative to the screen. + * + */ +EelIRect +eel_gdk_window_get_screen_relative_bounds (GdkWindow *gdk_window) +{ + EelIRect screen_bounds; + int width; + int height; + + g_return_val_if_fail (gdk_window != NULL, eel_irect_empty); + + if (!gdk_window_get_origin (gdk_window, + &screen_bounds.x0, + &screen_bounds.y0)) + { + return eel_irect_empty; + } + +#if GTK_CHECK_VERSION(3, 0, 0) + width = gdk_window_get_width(gdk_window); + height = gdk_window_get_height(gdk_window); +#else + gdk_drawable_get_size(gdk_window, &width, &height); +#endif + + screen_bounds.x1 = screen_bounds.x0 + width; + screen_bounds.y1 = screen_bounds.y0 + height; + + return screen_bounds; +} + +/** + * eel_gtk_widget_get_bounds: + * @gtk_widget: The source GtkWidget. + * + * Return value: An EelIRect representation of the given GtkWidget's geometry + * relative to its parent. In the Gtk universe this is known as "allocation." + * + */ +EelIRect +eel_gtk_widget_get_bounds (GtkWidget *gtk_widget) +{ + GtkAllocation allocation; + g_return_val_if_fail (GTK_IS_WIDGET (gtk_widget), eel_irect_empty); + + gtk_widget_get_allocation (gtk_widget, &allocation); + return eel_irect_assign (allocation.x, + allocation.y, + (int) allocation.width, + (int) allocation.height); +} + +/** + * eel_gtk_widget_get_dimensions: + * @gtk_widget: The source GtkWidget. + * + * Return value: The widget's dimensions. The returned dimensions are only valid + * after the widget's geometry has been "allocated" by its container. + */ +EelDimensions +eel_gtk_widget_get_dimensions (GtkWidget *gtk_widget) +{ + EelDimensions dimensions; + GtkAllocation allocation; + + g_return_val_if_fail (GTK_IS_WIDGET (gtk_widget), eel_dimensions_empty); + + gtk_widget_get_allocation (gtk_widget, &allocation); + dimensions.width = (int) allocation.width; + dimensions.height = (int) allocation.height; + + return dimensions; +} + +/** + * eel_gtk_widget_get_preferred_dimensions: + * @gtk_widget: The source GtkWidget. + * + * Return value: The widget's preferred dimensions. The preferred dimensions are + * computed by calling the widget's 'size_request' method and thus + * could potentially be expensive for complicated widgets. + */ +EelDimensions +eel_gtk_widget_get_preferred_dimensions (GtkWidget *gtk_widget) +{ + GtkRequisition requisition; + EelDimensions preferred_dimensions; + + g_return_val_if_fail (GTK_IS_WIDGET (gtk_widget), eel_dimensions_empty); + + gtk_widget_size_request (gtk_widget, &requisition); + + preferred_dimensions.width = (int) requisition.width; + preferred_dimensions.height = (int) requisition.height; + + return preferred_dimensions; +} + +/** + * eel_gdk_window_clip_dirty_area_to_screen: + * @gdk_window: The GdkWindow that the damage occured on. + * @dirty_area: The dirty area as an EelIRect. + * + * Return value: An EelIRect of the dirty area clipped to the screen. + * + * This function is useful to do less work in expose_event() GtkWidget methods. + * It also ensures that any drawing that the widget does is actually onscreen. + */ +EelIRect +eel_gdk_window_clip_dirty_area_to_screen (GdkWindow *gdk_window, + EelIRect dirty_area) +{ + EelIRect clipped; + EelDimensions screen_dimensions; + EelIRect screen_relative_bounds; + int dirty_width; + int dirty_height; + + g_return_val_if_fail (gdk_window != NULL, eel_irect_empty); + + dirty_width = dirty_area.x1 - dirty_area.x0; + dirty_height = dirty_area.y1 - dirty_area.y0; + + g_return_val_if_fail (dirty_width > 0, eel_irect_empty); + g_return_val_if_fail (dirty_height > 0, eel_irect_empty); + + screen_dimensions = eel_screen_get_dimensions (); + screen_relative_bounds = eel_gdk_window_get_screen_relative_bounds (gdk_window); + + /* Window is obscured by left edge of screen */ + if ((screen_relative_bounds.x0 + dirty_area.x0) < 0) + { + int clipped_width = screen_relative_bounds.x0 + dirty_area.x0 + dirty_width; + clipped.x0 = dirty_area.x0 + dirty_width - clipped_width; + clipped.x1 = clipped.x0 + clipped_width; + } + else + { + clipped.x0 = dirty_area.x0; + clipped.x1 = clipped.x0 + dirty_width; + } + + /* Window is obscured by right edge of screen */ + if (screen_relative_bounds.x1 > screen_dimensions.width) + { + int obscured_width; + + obscured_width = + screen_relative_bounds.x0 + dirty_area.x0 + dirty_width - screen_dimensions.width; + + if (obscured_width > 0) + { + clipped.x1 -= obscured_width; + } + } + + /* Window is obscured by top edge of screen */ + if ((screen_relative_bounds.y0 + dirty_area.y0) < 0) + { + int clipped_height = screen_relative_bounds.y0 + dirty_area.y0 + dirty_height; + clipped.y0 = dirty_area.y0 + dirty_height - clipped_height; + clipped.y1 = clipped.y0 + clipped_height; + } + else + { + clipped.y0 = dirty_area.y0; + clipped.y1 = clipped.y0 + dirty_height; + } + + /* Window is obscured by bottom edge of screen */ + if (screen_relative_bounds.y1 > screen_dimensions.height) + { + int obscured_height; + + obscured_height = + screen_relative_bounds.y0 + dirty_area.y0 + dirty_height - screen_dimensions.height; + + if (obscured_height > 0) + { + clipped.y1 -= obscured_height; + } + } + + if (eel_irect_is_empty (&clipped)) + { + clipped = eel_irect_empty; + } + + return clipped; +} + +GdkRectangle +eel_irect_to_gdk_rectangle (EelIRect rectangle) +{ + GdkRectangle gdk_rect; + + gdk_rect.x = rectangle.x0; + gdk_rect.y = rectangle.y0; + gdk_rect.width = eel_irect_get_width (rectangle); + gdk_rect.height = eel_irect_get_height (rectangle); + + return gdk_rect; +} + +EelDimensions +eel_gdk_window_get_dimensions (GdkWindow *gdk_window) +{ + EelDimensions dimensions; + + g_return_val_if_fail (gdk_window != NULL, eel_dimensions_empty); + +#if GTK_CHECK_VERSION(3, 0, 0) + dimensions.width = gdk_window_get_width(gdk_window); + dimensions.height = gdk_window_get_height(gdk_window); +#else + gdk_drawable_get_size (gdk_window, &dimensions.width, &dimensions.height); +#endif + + return dimensions; +} + +EelIPoint +eel_gdk_get_pointer_position (void) +{ + + EelIPoint position; + + gdk_window_get_pointer (gdk_get_default_root_window (), + &position.x, + &position.y, + NULL); + + return position; +} diff --git a/eel/eel-art-gtk-extensions.h b/eel/eel-art-gtk-extensions.h new file mode 100644 index 00000000..3ad24f2d --- /dev/null +++ b/eel/eel-art-gtk-extensions.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-art-gtk-extensions.h - Access gtk/gdk attributes as libart rectangles. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +/* The following functions accept gtk/gdk structures and + * return their bounds and dimensions, where: + * + * bounds: The (x,y) and (width, height) of something. + * dimensions: The (width, height) of something. + * + * These are very useful in code that uses libart functions + * to do operations on ArtIRects (such as intersection) + */ + +#ifndef EEL_ART_GTK_EXTENSIONS_H +#define EEL_ART_GTK_EXTENSIONS_H + +#include <eel/eel-gdk-extensions.h> +#include <eel/eel-gtk-extensions.h> +#include <eel/eel-art-extensions.h> + +#ifdef __cplusplus +extern "C" { +#endif + + /* Convert between GdkRectangle and EelIRect and back */ + GdkRectangle eel_irect_to_gdk_rectangle (EelIRect rectangle); + EelIRect eel_gdk_rectangle_to_eel_irect (GdkRectangle gdk_rectangle); + EelDimensions eel_screen_get_dimensions (void); + + /* GdkWindow parent-relative bounds */ + EelIRect eel_gdk_window_get_bounds (GdkWindow *window); + + /* GdkWindow dimensions */ + EelDimensions eel_gdk_window_get_dimensions (GdkWindow *window); + + /* GdkWindow screen parent-relative bounds */ + EelIRect eel_gdk_window_get_screen_relative_bounds (GdkWindow *window); + + /* Clip a dirty area (from exposures) to the on screen parts of a GdkWindow */ + EelIRect eel_gdk_window_clip_dirty_area_to_screen (GdkWindow *window, + EelIRect dirty_area); + + /* GtkWidget bounds and dimensions */ + EelIRect eel_gtk_widget_get_bounds (GtkWidget *widget); + EelDimensions eel_gtk_widget_get_dimensions (GtkWidget *widget); + EelDimensions eel_gtk_widget_get_preferred_dimensions (GtkWidget *widget); + EelIPoint eel_gdk_get_pointer_position (void); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_ART_GTK_EXTENSIONS_H */ diff --git a/eel/eel-background-box.c b/eel/eel-background-box.c new file mode 100644 index 00000000..614d89ab --- /dev/null +++ b/eel/eel-background-box.c @@ -0,0 +1,70 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-background-box.c - an event box that renders an eel background + + Copyright (C) 2002 Sun Microsystems, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Dave Camp <[email protected]> +*/ + +#include <config.h> +#include "eel-background-box.h" + +#include "eel-gtk-macros.h" +#include "eel-background.h" + +static void eel_background_box_class_init (EelBackgroundBoxClass *background_box_class); +static void eel_background_box_init (EelBackgroundBox *background); + +EEL_CLASS_BOILERPLATE (EelBackgroundBox, eel_background_box, GTK_TYPE_EVENT_BOX) + +static gboolean +eel_background_box_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + eel_background_expose (widget, event); + + gtk_container_propagate_expose (GTK_CONTAINER (widget), + gtk_bin_get_child (GTK_BIN (widget)), + event); + + return TRUE; +} + +static void +eel_background_box_class_init (EelBackgroundBoxClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->expose_event = eel_background_box_expose_event; +} + +static void +eel_background_box_init (EelBackgroundBox *box) +{ +} + +GtkWidget* +eel_background_box_new (void) +{ + EelBackgroundBox *background_box; + + background_box = EEL_BACKGROUND_BOX (gtk_widget_new (eel_background_box_get_type (), NULL)); + + return GTK_WIDGET (background_box); +} diff --git a/eel/eel-background-box.h b/eel/eel-background-box.h new file mode 100644 index 00000000..849f5ebf --- /dev/null +++ b/eel/eel-background-box.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-background-box.c - an event box that renders an eel background + + Copyright (C) 2002 Sun Microsystems, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Dave Camp <[email protected]> +*/ + +#ifndef EEL_BACKGROUND_BOX_H +#define EEL_BACKGROUND_BOX_H + +#include <glib.h> +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_TYPE_BACKGROUND_BOX eel_background_box_get_type() +#define EEL_BACKGROUND_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_BACKGROUND_BOX, EelBackgroundBox)) +#define EEL_BACKGROUND_BOX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_BACKGROUND_BOX, EelBackgroundBoxClass)) +#define EEL_IS_BACKGROUND_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_BACKGROUND_BOX)) +#define EEL_IS_BACKGROUND_BOX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_BACKGROUND_BOX)) +#define EEL_BACKGROUND_BOX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_BACKGROUND_BOX, EelBackgroundBoxClass)) + + typedef struct EelBackgroundBox EelBackgroundBox; + typedef struct EelBackgroundBoxClass EelBackgroundBoxClass; + typedef struct EelBackgroundBoxDetails EelBackgroundBoxDetails; + + struct EelBackgroundBox + { + /* Superclass */ + GtkEventBox event_box; + }; + + struct EelBackgroundBoxClass + { + GtkEventBoxClass parent_class; + }; + + GType eel_background_box_get_type (void); + GtkWidget *eel_background_box_new (void); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_BACKGROUND_TABLE_H */ + + diff --git a/eel/eel-background.c b/eel/eel-background.c new file mode 100644 index 00000000..4d12b37f --- /dev/null +++ b/eel/eel-background.c @@ -0,0 +1,1273 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-background.c: Object for the background of a widget. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-background.h" +#include "eel-gdk-extensions.h" +#include "eel-gdk-pixbuf-extensions.h" +#include "eel-glib-extensions.h" +#include "eel-mate-extensions.h" +#include "eel-gtk-macros.h" +#include "eel-lib-self-check-functions.h" +#include "eel-string.h" +#include "eel-marshal.h" +#include "eel-types.h" +#include "eel-type-builtins.h" +#include <gtk/gtk.h> +#include <eel/eel-canvas.h> +#include <eel/eel-canvas-util.h> +#include <gdk/gdkx.h> +#include <gio/gio.h> +#include <math.h> +#include <stdio.h> +#define MATE_DESKTOP_USE_UNSTABLE_API +#include <libmateui/mate-bg.h> + +static void eel_background_class_init (gpointer klass); +static void eel_background_init (gpointer object, + gpointer klass); +static void eel_background_finalize (GObject *object); +static GdkPixmap *eel_background_get_pixmap_and_color (EelBackground *background, + GdkWindow *window, + GdkColor *color); + +static void set_image_properties (EelBackground *background); + +static void init_fade (EelBackground *background, GtkWidget *widget); +static void free_fade (EelBackground *background); + +EEL_CLASS_BOILERPLATE (EelBackground, eel_background, GTK_TYPE_OBJECT) + +enum +{ + APPEARANCE_CHANGED, + SETTINGS_CHANGED, + RESET, + LAST_SIGNAL +}; + +/* This is the size of the GdkRGB dither matrix, in order to avoid + * bad dithering when tiling the gradient + */ +#define GRADIENT_PIXMAP_TILE_SIZE 128 + +static guint signals[LAST_SIGNAL]; + +struct EelBackgroundDetails +{ + char *color; + + MateBG *bg; + GtkWidget *widget; + + /* Realized data: */ + GdkPixmap *background_pixmap; + gboolean background_pixmap_is_unset_root_pixmap; + MateBGCrossfade *fade; + int background_entire_width; + int background_entire_height; + GdkColor default_color; + + gboolean use_base; + + /* Is this background attached to desktop window */ + gboolean is_desktop; + /* Desktop screen size watcher */ + gulong screen_size_handler; + /* Desktop monitors configuration watcher */ + gulong screen_monitors_handler; + /* Can we use common pixmap for root window and desktop window */ + gboolean use_common_pixmap; + guint change_idle_id; + + /* activity status */ + gboolean is_active; +}; + +static void +eel_background_class_init (gpointer klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + eel_type_init (); + + signals[APPEARANCE_CHANGED] = + g_signal_new ("appearance_changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EelBackgroundClass, + appearance_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[SETTINGS_CHANGED] = + g_signal_new ("settings_changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EelBackgroundClass, + settings_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, G_TYPE_INT); + signals[RESET] = + g_signal_new ("reset", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EelBackgroundClass, + reset), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + object_class->finalize = eel_background_finalize; +} + +static void +on_bg_changed (MateBG *bg, EelBackground *background) +{ + init_fade (background, background->details->widget); + g_signal_emit (G_OBJECT (background), + signals[APPEARANCE_CHANGED], 0); +} + +static void +on_bg_transitioned (MateBG *bg, EelBackground *background) +{ + free_fade (background); + g_signal_emit (G_OBJECT (background), + signals[APPEARANCE_CHANGED], 0); +} + +static void +eel_background_init (gpointer object, gpointer klass) +{ + EelBackground *background; + + background = EEL_BACKGROUND (object); + + background->details = g_new0 (EelBackgroundDetails, 1); + background->details->default_color.red = 0xffff; + background->details->default_color.green = 0xffff; + background->details->default_color.blue = 0xffff; + background->details->bg = mate_bg_new (); + background->details->is_active = TRUE; + + g_signal_connect (background->details->bg, "changed", + G_CALLBACK (on_bg_changed), background); + g_signal_connect (background->details->bg, "transitioned", + G_CALLBACK (on_bg_transitioned), background); + +} + +/* The safe way to clear an image from a background is: + * eel_background_set_image_uri (NULL); + * This fn is a private utility - it does NOT clear + * the details->bg_uri setting. + */ +static void +eel_background_remove_current_image (EelBackground *background) +{ + if (background->details->bg != NULL) + { + g_object_unref (G_OBJECT (background->details->bg)); + background->details->bg = NULL; + } +} + +static void +free_fade (EelBackground *background) +{ + if (background->details->fade != NULL) + { + g_object_unref (background->details->fade); + background->details->fade = NULL; + } +} + +static void +free_background_pixmap (EelBackground *background) +{ + GdkDisplay *display; + GdkPixmap *pixmap; + + pixmap = background->details->background_pixmap; + if (pixmap != NULL) + { + /* If we created a root pixmap and didn't set it as background + it will live forever, so we need to kill it manually. + If set as root background it will be killed next time the + background is changed. */ + if (background->details->background_pixmap_is_unset_root_pixmap) + { + display = gdk_drawable_get_display (GDK_DRAWABLE (pixmap)); + XKillClient (GDK_DISPLAY_XDISPLAY (display), + GDK_PIXMAP_XID (pixmap)); + } + g_object_unref (pixmap); + background->details->background_pixmap = NULL; + } +} + + +static void +eel_background_finalize (GObject *object) +{ + EelBackground *background; + + background = EEL_BACKGROUND (object); + + g_free (background->details->color); + eel_background_remove_current_image (background); + + free_background_pixmap (background); + + free_fade (background); + + g_free (background->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static EelBackgroundImagePlacement +placement_mate_to_eel (MateBGPlacement p) +{ + switch (p) + { + case MATE_BG_PLACEMENT_CENTERED: + return EEL_BACKGROUND_CENTERED; + case MATE_BG_PLACEMENT_FILL_SCREEN: + return EEL_BACKGROUND_SCALED; + case MATE_BG_PLACEMENT_SCALED: + return EEL_BACKGROUND_SCALED_ASPECT; + case MATE_BG_PLACEMENT_ZOOMED: + return EEL_BACKGROUND_ZOOM; + case MATE_BG_PLACEMENT_TILED: + return EEL_BACKGROUND_TILED; + case MATE_BG_PLACEMENT_SPANNED: + return EEL_BACKGROUND_SPANNED; + } + + return EEL_BACKGROUND_TILED; +} + +static MateBGPlacement +placement_eel_to_mate (EelBackgroundImagePlacement p) +{ + switch (p) + { + case EEL_BACKGROUND_CENTERED: + return MATE_BG_PLACEMENT_CENTERED; + case EEL_BACKGROUND_SCALED: + return MATE_BG_PLACEMENT_FILL_SCREEN; + case EEL_BACKGROUND_SCALED_ASPECT: + return MATE_BG_PLACEMENT_SCALED; + case EEL_BACKGROUND_ZOOM: + return MATE_BG_PLACEMENT_ZOOMED; + case EEL_BACKGROUND_TILED: + return MATE_BG_PLACEMENT_TILED; + case EEL_BACKGROUND_SPANNED: + return MATE_BG_PLACEMENT_SPANNED; + } + + return MATE_BG_PLACEMENT_TILED; +} + +EelBackgroundImagePlacement +eel_background_get_image_placement (EelBackground *background) +{ + g_return_val_if_fail (EEL_IS_BACKGROUND (background), EEL_BACKGROUND_TILED); + + return placement_mate_to_eel (mate_bg_get_placement (background->details->bg)); +} + +void +eel_background_set_image_placement (EelBackground *background, + EelBackgroundImagePlacement new_placement) +{ + g_return_if_fail (EEL_IS_BACKGROUND (background)); + + mate_bg_set_placement (background->details->bg, + placement_eel_to_mate (new_placement)); +} + +EelBackground * +eel_background_new (void) +{ + return EEL_BACKGROUND (g_object_new (EEL_TYPE_BACKGROUND, NULL)); +} + +static void +eel_background_unrealize (EelBackground *background) +{ + free_background_pixmap (background); + + background->details->background_entire_width = 0; + background->details->background_entire_height = 0; + background->details->default_color.red = 0xffff; + background->details->default_color.green = 0xffff; + background->details->default_color.blue = 0xffff; +} + +static void +drawable_get_adjusted_size (EelBackground *background, + GdkDrawable *drawable, + int *width, + int *height) +{ + GdkScreen *screen; + + /* + * Screen resolution change makes root drawable have incorrect size. + */ +#if GTK_CHECK_VERSION(3, 0, 0) + width = gdk_window_get_width(GDK_WINDOW(drawable)); + height = gdk_window_get_height(GDK_WINDOW(drawable)); +#else + gdk_drawable_get_size(drawable, width, height); // FIXME: this is right? +#endif + + + if (background->details->is_desktop) + { + screen = gdk_drawable_get_screen (drawable); + *width = gdk_screen_get_width (screen); + *height = gdk_screen_get_height (screen); + } +} + +static gboolean +eel_background_ensure_realized (EelBackground *background, GdkWindow *window) +{ + gpointer data; + GtkWidget *widget; + GtkStyle *style; + gboolean changed; + int entire_width; + int entire_height; + + drawable_get_adjusted_size (background, window, &entire_width, &entire_height); + + /* Set the default color */ + + /* Get the widget to which the window belongs and its style as well */ + gdk_window_get_user_data (window, &data); + widget = GTK_WIDGET (data); + if (widget != NULL) + { + style = gtk_widget_get_style (widget); + if (background->details->use_base) + { + background->details->default_color = style->base[GTK_STATE_NORMAL]; + } + else + { + background->details->default_color = style->bg[GTK_STATE_NORMAL]; + } + + gdk_rgb_find_color (style->colormap, &(background->details->default_color)); + } + + /* If the window size is the same as last time, don't update */ + if (entire_width == background->details->background_entire_width && + entire_height == background->details->background_entire_height) + { + return FALSE; + } + + free_background_pixmap (background); + + changed = FALSE; + + set_image_properties (background); + + background->details->background_pixmap = mate_bg_create_pixmap (background->details->bg, + window, + entire_width, entire_height, + background->details->is_desktop); + background->details->background_pixmap_is_unset_root_pixmap = background->details->is_desktop; + + /* We got the pixmap and everything, so we don't care about a change + that is pending (unless things actually change after this time) */ + g_object_set_data (G_OBJECT (background->details->bg), + "ignore-pending-change", GINT_TO_POINTER (TRUE)); + changed = TRUE; + + + background->details->background_entire_width = entire_width; + background->details->background_entire_height = entire_height; + + return changed; +} + +#define CLAMP_COLOR(v) (t = (v), CLAMP (t, 0, G_MAXUSHORT)) +#define SATURATE(v) ((1.0 - saturation) * intensity + saturation * (v)) + +static void +make_color_inactive (EelBackground *background, GdkColor *color) +{ + double intensity, saturation; + gushort t; + + if (!background->details->is_active) + { + saturation = 0.7; + intensity = color->red * 0.30 + color->green * 0.59 + color->blue * 0.11; + color->red = SATURATE (color->red); + color->green = SATURATE (color->green); + color->blue = SATURATE (color->blue); + + if (intensity > G_MAXUSHORT / 2) + { + color->red *= 0.9; + color->green *= 0.9; + color->blue *= 0.9; + } + else + { + color->red *= 1.25; + color->green *= 1.25; + color->blue *= 1.25; + } + + color->red = CLAMP_COLOR (color->red); + color->green = CLAMP_COLOR (color->green); + color->blue = CLAMP_COLOR (color->blue); + } +} + +static GdkPixmap * +eel_background_get_pixmap_and_color (EelBackground *background, + GdkWindow *window, + GdkColor *color) +{ + int entire_width; + int entire_height; + + drawable_get_adjusted_size (background, window, &entire_width, &entire_height); + + eel_background_ensure_realized (background, window); + + *color = background->details->default_color; + make_color_inactive (background, color); + + if (background->details->background_pixmap != NULL) + { + return g_object_ref (background->details->background_pixmap); + } + return NULL; +} + +void +eel_background_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GdkColor color; + int window_width; + int window_height; + GdkPixmap *pixmap; + GdkGC *gc; + GdkGCValues gc_values; + GdkGCValuesMask value_mask; + GdkWindow *widget_window; + + EelBackground *background; + + widget_window = gtk_widget_get_window (widget); + if (event->window != widget_window) + { + return; + } + + background = eel_get_widget_background (widget); + + drawable_get_adjusted_size (background, widget_window, &window_width, &window_height); + + pixmap = eel_background_get_pixmap_and_color (background, + widget_window, + &color); + + if (pixmap) + { + gc_values.tile = pixmap; + gc_values.ts_x_origin = 0; + gc_values.ts_y_origin = 0; + gc_values.fill = GDK_TILED; + value_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN; + } + else + { + gdk_rgb_find_color (gtk_widget_get_colormap (widget), &color); + gc_values.foreground = color; + gc_values.fill = GDK_SOLID; + value_mask = GDK_GC_FILL | GDK_GC_FOREGROUND; + } + + gc = gdk_gc_new_with_values (widget_window, &gc_values, value_mask); + + gdk_gc_set_clip_rectangle (gc, &event->area); + + gdk_draw_rectangle (widget_window, gc, TRUE, 0, 0, window_width, window_height); + + g_object_unref (gc); + + if (pixmap) + { + g_object_unref (pixmap); + } +} + +static void +set_image_properties (EelBackground *background) +{ + GdkColor c; + if (!background->details->color) + { + c = background->details->default_color; + make_color_inactive (background, &c); + mate_bg_set_color (background->details->bg, MATE_BG_COLOR_SOLID, + &c, NULL); + } + else if (!eel_gradient_is_gradient (background->details->color)) + { + eel_gdk_color_parse_with_white_default (background->details->color, &c); + make_color_inactive (background, &c); + mate_bg_set_color (background->details->bg, MATE_BG_COLOR_SOLID, &c, NULL); + } + else + { + GdkColor c1; + GdkColor c2; + char *spec; + + spec = eel_gradient_get_start_color_spec (background->details->color); + eel_gdk_color_parse_with_white_default (spec, &c1); + make_color_inactive (background, &c1); + g_free (spec); + + spec = eel_gradient_get_end_color_spec (background->details->color); + eel_gdk_color_parse_with_white_default (spec, &c2); + make_color_inactive (background, &c2); + g_free (spec); + + if (eel_gradient_is_horizontal (background->details->color)) + mate_bg_set_color (background->details->bg, MATE_BG_COLOR_H_GRADIENT, &c1, &c2); + else + mate_bg_set_color (background->details->bg, MATE_BG_COLOR_V_GRADIENT, &c1, &c2); + + } +} + +char * +eel_background_get_color (EelBackground *background) +{ + g_return_val_if_fail (EEL_IS_BACKGROUND (background), NULL); + + return g_strdup (background->details->color); +} + +char * +eel_background_get_image_uri (EelBackground *background) +{ + const char *filename; + + g_return_val_if_fail (EEL_IS_BACKGROUND (background), NULL); + + filename = mate_bg_get_filename (background->details->bg); + if (filename) + { + return g_filename_to_uri (filename, NULL, NULL); + } + return NULL; +} + +/* Use style->base as the default color instead of bg */ +void +eel_background_set_use_base (EelBackground *background, + gboolean use_base) +{ + background->details->use_base = use_base; +} + +void +eel_background_set_color (EelBackground *background, + const char *color) +{ + if (eel_strcmp (background->details->color, color) != 0) + { + g_free (background->details->color); + background->details->color = g_strdup (color); + + set_image_properties (background); + } +} + +static gboolean +eel_background_set_image_uri_helper (EelBackground *background, + const char *image_uri, + gboolean emit_signal) +{ + char *filename; + + if (image_uri != NULL) + { + filename = g_filename_from_uri (image_uri, NULL, NULL); + } + else + { + filename = NULL; + } + + mate_bg_set_filename (background->details->bg, filename); + + if (emit_signal) + { + g_signal_emit (GTK_OBJECT (background), signals[SETTINGS_CHANGED], 0, GDK_ACTION_COPY); + } + + set_image_properties (background); + + g_free (filename); + + return TRUE; +} + +void +eel_background_set_image_uri (EelBackground *background, const char *image_uri) +{ + + + eel_background_set_image_uri_helper (background, image_uri, TRUE); +} + +/* Use this fn to set both the image and color and avoid flash. The color isn't + * changed till after the image is done loading, that way if an update occurs + * before then, it will use the old color and image. + */ +static void +eel_background_set_image_uri_and_color (EelBackground *background, GdkDragAction action, + const char *image_uri, const char *color) +{ + eel_background_set_image_uri_helper (background, image_uri, FALSE); + eel_background_set_color (background, color); + + /* We always emit, even if the color didn't change, because the image change + * relies on us doing it here. + */ + + g_signal_emit (background, signals[SETTINGS_CHANGED], 0, action); +} + +void +eel_background_receive_dropped_background_image (EelBackground *background, + GdkDragAction action, + const char *image_uri) +{ + /* Currently, we only support tiled images. So we set the placement. + * We rely on eel_background_set_image_uri_and_color to emit + * the SETTINGS_CHANGED & APPEARANCE_CHANGE signals. + */ + eel_background_set_image_placement (background, EEL_BACKGROUND_TILED); + + eel_background_set_image_uri_and_color (background, action, image_uri, NULL); +} + +/** + * eel_background_is_set: + * + * Check whether the background's color or image has been set. + */ +gboolean +eel_background_is_set (EelBackground *background) +{ + g_assert (EEL_IS_BACKGROUND (background)); + + return background->details->color != NULL + || mate_bg_get_filename (background->details->bg) != NULL; +} + +/** + * eel_background_reset: + * + * Emit the reset signal to forget any color or image that has been + * set previously. + */ +void +eel_background_reset (EelBackground *background) +{ + g_return_if_fail (EEL_IS_BACKGROUND (background)); + + g_signal_emit (GTK_OBJECT (background), signals[RESET], 0); +} + +static void +set_root_pixmap (EelBackground *background, + GdkWindow *window) +{ + GdkPixmap *pixmap, *root_pixmap; + GdkScreen *screen; + GdkColor color; + + pixmap = eel_background_get_pixmap_and_color (background, + window, + &color); + screen = gdk_drawable_get_screen (window); + + if (background->details->use_common_pixmap) + { + background->details->background_pixmap_is_unset_root_pixmap = FALSE; + root_pixmap = g_object_ref (pixmap); + } + else + { + root_pixmap = mate_bg_create_pixmap (background->details->bg, window, + gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE); + } + + mate_bg_set_pixmap_as_root (screen, pixmap); + + g_object_unref (pixmap); + g_object_unref (root_pixmap); +} + +static gboolean +fade_to_pixmap (EelBackground *background, + GdkWindow *window, + GdkPixmap *pixmap) +{ + if (background->details->fade == NULL) + { + return FALSE; + } + + if (!mate_bg_crossfade_set_end_pixmap (background->details->fade, + pixmap)) + { + return FALSE; + } + + if (!mate_bg_crossfade_is_started (background->details->fade)) + { + mate_bg_crossfade_start (background->details->fade, window); + if (background->details->is_desktop) + { + g_signal_connect_swapped (background->details->fade, + "finished", + G_CALLBACK (set_root_pixmap), background); + } + } + + return mate_bg_crossfade_is_started (background->details->fade); +} + + +static void +eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) +{ + GtkStyle *style; + GdkPixmap *pixmap; + GdkColor color; + + int window_width; + int window_height; + + GdkWindow *window; + GdkWindow *widget_window; + gboolean in_fade; + + if (!gtk_widget_get_realized (widget)) + { + return; + } + + widget_window = gtk_widget_get_window (widget); + drawable_get_adjusted_size (background, widget_window, &window_width, &window_height); + + pixmap = eel_background_get_pixmap_and_color (background, + widget_window, + &color); + + style = gtk_widget_get_style (widget); + + gdk_rgb_find_color (style->colormap, &color); + + if (EEL_IS_CANVAS (widget)) + { + window = gtk_layout_get_bin_window (GTK_LAYOUT (widget)); + } + else + { + window = widget_window; + } + + if (background->details->fade != NULL) + { + in_fade = fade_to_pixmap (background, window, pixmap); + } + else + { + in_fade = FALSE; + } + + if (!in_fade) + { + if (background->details->is_desktop) + { + gdk_window_set_back_pixmap (window, pixmap, FALSE); + } + else + { + gdk_window_set_background (window, &color); + gdk_window_set_back_pixmap (window, pixmap, FALSE); + } + } + + if (background->details->is_desktop && !in_fade) + { + set_root_pixmap (background, window); + } + + if (pixmap) + { + g_object_unref (pixmap); + } +} + +static gboolean +on_background_changed (EelBackground *background) +{ + if (background->details->change_idle_id == 0) + { + return FALSE; + } + + background->details->change_idle_id = 0; + + eel_background_unrealize (background); + eel_background_set_up_widget (background, background->details->widget); + + gtk_widget_queue_draw (background->details->widget); + + return FALSE; +} + +static void +init_fade (EelBackground *background, GtkWidget *widget) +{ + if (widget == NULL || !gtk_widget_get_realized (widget)) + return; + + if (!background->details->is_desktop) + { + return; + } + + if (background->details->fade == NULL) + { + GdkWindow *window; + int old_width, old_height, width, height; + + /* If this was the result of a screen size change, + * we don't want to crossfade + */ + window = gtk_widget_get_window (widget); + +#if GTK_CHECK_VERSION(3, 0, 0) + old_width = gdk_window_get_width(GDK_WINDOW(window)); + old_height = gdk_window_get_height(GDK_WINDOW(window)); +#else + gdk_drawable_get_size(window, &old_width, &old_height); +#endif + + drawable_get_adjusted_size (background, window, + &width, &height); + if (old_width == width && old_height == height) + { + background->details->fade = mate_bg_crossfade_new (width, height); + g_signal_connect_swapped (background->details->fade, + "finished", + G_CALLBACK (free_fade), + background); + } + } + + if (background->details->fade != NULL && !mate_bg_crossfade_is_started (background->details->fade)) + { + GdkPixmap *start_pixmap; + + if (background->details->background_pixmap == NULL) + { + start_pixmap = mate_bg_get_pixmap_from_root (gtk_widget_get_screen (widget)); + } + else + { + start_pixmap = g_object_ref (background->details->background_pixmap); + } + mate_bg_crossfade_set_start_pixmap (background->details->fade, + start_pixmap); + g_object_unref (start_pixmap); + } +} + +static void +eel_widget_queue_background_change (GtkWidget *widget) +{ + EelBackground *background; + + background = eel_get_widget_background (widget); + + if (background->details->change_idle_id > 0) + { + return; + } + + background->details->change_idle_id = g_idle_add ((GSourceFunc) on_background_changed, background); +} + +/* Callback used when the style of a widget changes. We have to regenerate its + * EelBackgroundStyle so that it will match the chosen GTK+ theme. + */ +static void +widget_style_set_cb (GtkWidget *widget, GtkStyle *previous_style, gpointer data) +{ + EelBackground *background; + + background = EEL_BACKGROUND (data); + + if (previous_style != NULL) + { + eel_widget_queue_background_change (widget); + } +} + +static void +screen_size_changed (GdkScreen *screen, EelBackground *background) +{ + g_signal_emit (background, signals[APPEARANCE_CHANGED], 0); +} + +static void +widget_realized_setup (GtkWidget *widget, gpointer data) +{ + EelBackground *background; + + background = EEL_BACKGROUND (data); + + if (background->details->is_desktop) + { + GdkWindow *root_window; + GdkScreen *screen; + + screen = gtk_widget_get_screen (widget); + + if (background->details->screen_size_handler > 0) + { + g_signal_handler_disconnect (screen, + background->details->screen_size_handler); + } + + background->details->screen_size_handler = + g_signal_connect (screen, "size_changed", + G_CALLBACK (screen_size_changed), background); + if (background->details->screen_monitors_handler > 0) + { + g_signal_handler_disconnect (screen, + background->details->screen_monitors_handler); + } + background->details->screen_monitors_handler = + g_signal_connect (screen, "monitors-changed", + G_CALLBACK (screen_size_changed), background); + + root_window = gdk_screen_get_root_window(screen); + +#if GTK_CHECK_VERSION(3, 0, 0) + if (gdk_window_get_visual(root_window) == gtk_widget_get_visual(widget)) +#else + if (gdk_drawable_get_visual(root_window) == gtk_widget_get_visual(widget)) +#endif + { + background->details->use_common_pixmap = TRUE; + } + else + { + background->details->use_common_pixmap = FALSE; + } + + init_fade (background, widget); + } +} + +static void +widget_realize_cb (GtkWidget *widget, gpointer data) +{ + EelBackground *background; + + background = EEL_BACKGROUND (data); + + widget_realized_setup (widget, data); + + eel_background_set_up_widget (background, widget); +} + +static void +widget_unrealize_cb (GtkWidget *widget, gpointer data) +{ + EelBackground *background; + + background = EEL_BACKGROUND (data); + + if (background->details->screen_size_handler > 0) + { + g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (widget)), + background->details->screen_size_handler); + background->details->screen_size_handler = 0; + } + if (background->details->screen_monitors_handler > 0) + { + g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (widget)), + background->details->screen_monitors_handler); + background->details->screen_monitors_handler = 0; + } + background->details->use_common_pixmap = FALSE; +} + +void +eel_background_set_desktop (EelBackground *background, GtkWidget *widget, gboolean is_desktop) +{ + background->details->is_desktop = is_desktop; + + if (gtk_widget_get_realized (widget) && background->details->is_desktop) + { + widget_realized_setup (widget, background); + } + +} + +gboolean +eel_background_is_desktop (EelBackground *background) +{ + return background->details->is_desktop; +} + +static void +on_widget_destroyed (GtkWidget *widget, EelBackground *background) +{ + if (background->details->change_idle_id != 0) + { + g_source_remove (background->details->change_idle_id); + background->details->change_idle_id = 0; + } + + background->details->widget = NULL; +} + +/* Gets the background attached to a widget. + + If the widget doesn't already have a EelBackground object, + this will create one. To change the widget's background, you can + just call eel_background methods on the widget. + + If the widget is a canvas, nothing more needs to be done. For + normal widgets, you need to call eel_background_expose() from your + expose handler to draw the background. + + Later, we might want a call to find out if we already have a background, + or a way to share the same background among multiple widgets; both would + be straightforward. +*/ +EelBackground * +eel_get_widget_background (GtkWidget *widget) +{ + gpointer data; + EelBackground *background; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + /* Check for an existing background. */ + data = g_object_get_data (G_OBJECT (widget), "eel_background"); + if (data != NULL) + { + g_assert (EEL_IS_BACKGROUND (data)); + return data; + } + + /* Store the background in the widget's data. */ + background = eel_background_new (); + g_object_ref_sink (background); + g_object_set_data_full (G_OBJECT (widget), "eel_background", + background, g_object_unref); + background->details->widget = widget; + g_signal_connect_object (widget, "destroy", G_CALLBACK (on_widget_destroyed), background, 0); + + /* Arrange to get the signal whenever the background changes. */ + g_signal_connect_object (background, "appearance_changed", + G_CALLBACK (eel_widget_queue_background_change), widget, G_CONNECT_SWAPPED); + eel_widget_queue_background_change (widget); + + g_signal_connect_object (widget, "style_set", + G_CALLBACK (widget_style_set_cb), + background, + 0); + g_signal_connect_object (widget, "realize", + G_CALLBACK (widget_realize_cb), + background, + 0); + g_signal_connect_object (widget, "unrealize", + G_CALLBACK (widget_unrealize_cb), + background, + 0); + + return background; +} + +/* determine if a background is darker or lighter than average, to help clients know what + colors to draw on top with */ +gboolean +eel_background_is_dark (EelBackground *background) +{ + GdkScreen *screen; + GdkRectangle rect; + + /* only check for the background on the 0th monitor */ + screen = gdk_screen_get_default (); + gdk_screen_get_monitor_geometry (screen, 0, &rect); + + return mate_bg_is_dark (background->details->bg, rect.width, rect.height); +} + +/* handle dropped colors */ +void +eel_background_receive_dropped_color (EelBackground *background, + GtkWidget *widget, + GdkDragAction action, + int drop_location_x, + int drop_location_y, + const GtkSelectionData *selection_data) +{ + guint16 *channels; + char *color_spec; + char *new_gradient_spec; + int left_border, right_border, top_border, bottom_border; + GtkAllocation allocation; + + g_return_if_fail (EEL_IS_BACKGROUND (background)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (selection_data != NULL); + + /* Convert the selection data into a color spec. */ + if (gtk_selection_data_get_length ((GtkSelectionData *) selection_data) != 8 || + gtk_selection_data_get_format ((GtkSelectionData *) selection_data) != 16) + { + g_warning ("received invalid color data"); + return; + } + channels = (guint16 *) gtk_selection_data_get_data ((GtkSelectionData *) selection_data); + color_spec = g_strdup_printf ("#%02X%02X%02X", + channels[0] >> 8, + channels[1] >> 8, + channels[2] >> 8); + + /* Figure out if the color was dropped close enough to an edge to create a gradient. + For the moment, this is hard-wired, but later the widget will have to have some + say in where the borders are. + */ + gtk_widget_get_allocation (widget, &allocation); + left_border = 32; + right_border = allocation.width - 32; + top_border = 32; + bottom_border = allocation.height - 32; + if (drop_location_x < left_border && drop_location_x <= right_border) + { + new_gradient_spec = eel_gradient_set_left_color_spec (background->details->color, color_spec); + } + else if (drop_location_x >= left_border && drop_location_x > right_border) + { + new_gradient_spec = eel_gradient_set_right_color_spec (background->details->color, color_spec); + } + else if (drop_location_y < top_border && drop_location_y <= bottom_border) + { + new_gradient_spec = eel_gradient_set_top_color_spec (background->details->color, color_spec); + } + else if (drop_location_y >= top_border && drop_location_y > bottom_border) + { + new_gradient_spec = eel_gradient_set_bottom_color_spec (background->details->color, color_spec); + } + else + { + new_gradient_spec = g_strdup (color_spec); + } + + g_free (color_spec); + + eel_background_set_image_uri_and_color (background, action, NULL, new_gradient_spec); + + g_free (new_gradient_spec); +} + +void +eel_background_save_to_mateconf (EelBackground *background) +{ + MateConfClient *client = mateconf_client_get_default (); + + if (background->details->bg) + mate_bg_save_to_preferences (background->details->bg, client); +} + +void +eel_background_set_active (EelBackground *background, + gboolean is_active) +{ + if (background->details->is_active != is_active) + { + background->details->is_active = is_active; + set_image_properties (background); + } +} + +/* self check code */ + +#if !defined (EEL_OMIT_SELF_CHECK) + +void +eel_self_check_background (void) +{ + EelBackground *background; + + background = eel_background_new (); + + eel_background_set_color (background, NULL); + eel_background_set_color (background, ""); + eel_background_set_color (background, "red"); + eel_background_set_color (background, "red-blue"); + eel_background_set_color (background, "red-blue:h"); + + g_object_ref_sink (background); + g_object_unref (background); +} + +#endif diff --git a/eel/eel-background.h b/eel/eel-background.h new file mode 100644 index 00000000..36a6c3f5 --- /dev/null +++ b/eel/eel-background.h @@ -0,0 +1,162 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-background.h: Object for the background of a widget. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#ifndef EEL_BACKGROUND_H +#define EEL_BACKGROUND_H + +/* Windows for Eel can contain backgrounds that are either tiled + with an image, a solid color, or a color gradient. This class manages + the process of loading the image if necessary and parsing the string + that specifies either a color or color gradient. + + The color or gradient is always present, even if there's a tiled image + on top of it. This is used when the tiled image can't be loaded for + some reason (or just has not been loaded yet). + + The EelBackground object is easier to modify than a GtkStyle. + You can just call eel_get_window_background and modify the + returned background directly, unlike a style, which must be copied, + modified and then set. +*/ + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> + +typedef struct EelBackground EelBackground; +typedef struct EelBackgroundClass EelBackgroundClass; + +#define EEL_TYPE_BACKGROUND eel_background_get_type() +#define EEL_BACKGROUND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_BACKGROUND, EelBackground)) +#define EEL_BACKGROUND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_BACKGROUND, EelBackgroundClass)) +#define EEL_IS_BACKGROUND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_BACKGROUND)) +#define EEL_IS_BACKGROUND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_BACKGROUND)) +#define EEL_BACKGROUND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_BACKGROUND, EelBackgroundClass)) + +typedef enum +{ + EEL_BACKGROUND_TILED = 0, /* zero makes this the default placement */ + EEL_BACKGROUND_CENTERED, + EEL_BACKGROUND_SCALED, + EEL_BACKGROUND_SCALED_ASPECT, + EEL_BACKGROUND_ZOOM, + EEL_BACKGROUND_SPANNED +} EelBackgroundImagePlacement; + +GType eel_background_get_type (void); +EelBackground * eel_background_new (void); + + +/* Calls to change a background. */ +void eel_background_set_use_base (EelBackground *background, + gboolean use_base); +void eel_background_set_color (EelBackground *background, + const char *color_or_gradient); +void eel_background_set_image_uri (EelBackground *background, + const char *image_uri); + +void eel_background_reset (EelBackground *background); +void eel_background_set_image_placement (EelBackground *background, + EelBackgroundImagePlacement placement); + +/* Should be TRUE for desktop background */ +void eel_background_set_desktop (EelBackground *background, + GtkWidget *widget, + gboolean is_desktop); +gboolean eel_background_is_desktop (EelBackground *background); + +/* Calls to interrogate the current state of a background. */ +char * eel_background_get_color (EelBackground *background); +char * eel_background_get_image_uri (EelBackground *background); +EelBackgroundImagePlacement eel_background_get_image_placement (EelBackground *background); +gboolean eel_background_is_dark (EelBackground *background); +gboolean eel_background_is_set (EelBackground *background); + +/* Helper function for widgets using EelBackground */ +void eel_background_expose (GtkWidget *widget, + GdkEventExpose *event); + +/* Handles a dragged color being dropped on a widget to change the background color. */ +void eel_background_receive_dropped_color (EelBackground *background, + GtkWidget *widget, + GdkDragAction action, + int drop_location_x, + int drop_location_y, + const GtkSelectionData *dropped_color); + +/* Handles a special-case image name that means "reset to default background" too. */ +void eel_background_receive_dropped_background_image (EelBackground *background, + GdkDragAction action, + const char *image_uri); + +/* Gets or creates a background so that it's attached to a widget. */ +EelBackground * eel_get_widget_background (GtkWidget *widget); +void eel_background_save_to_mateconf (EelBackground *background); + +/* Set activity status of background. Inactive backgrounds are drawn in the theme's INSENSITIVE color. */ +void eel_background_set_active (EelBackground *background, + gboolean is_active); + +typedef struct EelBackgroundDetails EelBackgroundDetails; + +struct EelBackground +{ + GtkObject object; + EelBackgroundDetails *details; +}; + +struct EelBackgroundClass +{ + GtkObjectClass parent_class; + + /* This signal is emitted whenever the background settings are + * changed. + */ + void (* settings_changed) (EelBackground *); + + /* This signal is emitted whenever the appearance of the + * background has changed, like when the background settings are + * altered or when an image is loaded. + */ + void (* appearance_changed) (EelBackground *); + + /* This signal is emitted when image loading is over - whether it + * was successfully loaded or not. + */ + void (* image_loading_done) (EelBackground *background, gboolean successful_load); + + /* This signal is emitted when the background is reset by receiving + the reset property from a drag + */ + void (* reset) (EelBackground *); + +}; + +#endif /* EEL_BACKGROUND_H */ diff --git a/eel/eel-canvas-rect-ellipse.c b/eel/eel-canvas-rect-ellipse.c new file mode 100644 index 00000000..9481a7fd --- /dev/null +++ b/eel/eel-canvas-rect-ellipse.c @@ -0,0 +1,1550 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + @NOTATION@ + */ +/* Rectangle and ellipse item types for EelCanvas widget + * + * EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is + * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. + * + * + * Author: Federico Mena <[email protected]> + */ + +#include <config.h> +#include <math.h> +#include "eel-canvas-rect-ellipse.h" +#include "eel-canvas-util.h" +#include <string.h> + +#ifdef HAVE_RENDER +#include <gdk/gdkx.h> +#include <X11/extensions/Xrender.h> +#endif + +/* Base class for rectangle and ellipse item types */ + +#define noVERBOSE + +enum +{ + PROP_0, + PROP_X1, + PROP_Y1, + PROP_X2, + PROP_Y2, + PROP_FILL_COLOR, + PROP_FILL_COLOR_GDK, + PROP_FILL_COLOR_RGBA, + PROP_OUTLINE_COLOR, + PROP_OUTLINE_COLOR_GDK, + PROP_OUTLINE_COLOR_RGBA, + PROP_FILL_STIPPLE, + PROP_OUTLINE_STIPPLE, + PROP_WIDTH_PIXELS, + PROP_WIDTH_UNITS +}; + + +static void eel_canvas_re_class_init (EelCanvasREClass *klass); +static void eel_canvas_re_init (EelCanvasRE *re); +static void eel_canvas_re_destroy (GtkObject *object); +static void eel_canvas_re_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void eel_canvas_re_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void eel_canvas_re_update_shared (EelCanvasItem *item, + double i2w_dx, double i2w_dy, int flags); +static void eel_canvas_re_realize (EelCanvasItem *item); +static void eel_canvas_re_unrealize (EelCanvasItem *item); +static void eel_canvas_re_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2); +static void eel_canvas_re_translate (EelCanvasItem *item, double dx, double dy); +static void eel_canvas_rect_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags); +static void eel_canvas_ellipse_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags); + +typedef struct +{ + /*< public >*/ + int x0, y0, x1, y1; +} Rect; + +static Rect make_rect (int x0, int y0, int x1, int y1); +static void diff_rects (Rect r1, Rect r2, int *count, Rect result[4]); + +static EelCanvasItemClass *re_parent_class; +static EelCanvasREClass *rect_parent_class; + + +GType +eel_canvas_re_get_type (void) +{ + static GType re_type = 0; + + if (!re_type) + { + GTypeInfo re_info = + { + sizeof (EelCanvasREClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_re_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EelCanvasRE), + 0, /* n_preallocs */ + (GInstanceInitFunc) eel_canvas_re_init + }; + + re_type = g_type_register_static (eel_canvas_item_get_type (), + "EelCanvasRE", + &re_info, + 0); + } + + return re_type; +} + +static void +eel_canvas_re_class_init (EelCanvasREClass *klass) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + EelCanvasItemClass *item_class; + + gobject_class = (GObjectClass *) klass; + object_class = (GtkObjectClass *) klass; + item_class = (EelCanvasItemClass *) klass; + + re_parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = eel_canvas_re_set_property; + gobject_class->get_property = eel_canvas_re_get_property; + + g_object_class_install_property + (gobject_class, + PROP_X1, + g_param_spec_double ("x1", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_Y1, + g_param_spec_double ("y1", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_X2, + g_param_spec_double ("x2", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_Y2, + g_param_spec_double ("y2", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_FILL_COLOR, + g_param_spec_string ("fill-color", NULL, NULL, + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_FILL_COLOR_GDK, + g_param_spec_boxed ("fill-color-gdk", NULL, NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_FILL_COLOR_RGBA, + g_param_spec_uint ("fill-color-rgba", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_FILL_STIPPLE, + g_param_spec_object ("fill-stipple", NULL, NULL, + GDK_TYPE_DRAWABLE, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_OUTLINE_COLOR, + g_param_spec_string ("outline-color", NULL, NULL, + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_OUTLINE_COLOR_GDK, + g_param_spec_boxed ("outline-color-gdk", NULL, NULL, + GDK_TYPE_COLOR, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_OUTLINE_COLOR_RGBA, + g_param_spec_uint ("outline-color-rgba", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_OUTLINE_STIPPLE, + g_param_spec_object ("outline-stipple", NULL, NULL, + GDK_TYPE_DRAWABLE, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_WIDTH_PIXELS, + g_param_spec_uint ("width-pixels", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, + PROP_WIDTH_UNITS, + g_param_spec_double ("width-units", NULL, NULL, + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE)); + + object_class->destroy = eel_canvas_re_destroy; + + item_class->realize = eel_canvas_re_realize; + item_class->unrealize = eel_canvas_re_unrealize; + item_class->translate = eel_canvas_re_translate; + item_class->bounds = eel_canvas_re_bounds; +} + +static void +eel_canvas_re_init (EelCanvasRE *re) +{ + re->x1 = 0.0; + re->y1 = 0.0; + re->x2 = 0.0; + re->y2 = 0.0; + re->width = 0.0; +} + +static void +eel_canvas_re_destroy (GtkObject *object) +{ + EelCanvasRE *re; + + g_return_if_fail (object != NULL); + g_return_if_fail (EEL_IS_CANVAS_RE (object)); + + re = EEL_CANVAS_RE (object); + + /* remember, destroy can be run multiple times! */ + + if (re->fill_stipple) + g_object_unref (re->fill_stipple); + re->fill_stipple = NULL; + + if (re->outline_stipple) + g_object_unref (re->outline_stipple); + re->outline_stipple = NULL; + + if (GTK_OBJECT_CLASS (re_parent_class)->destroy) + (* GTK_OBJECT_CLASS (re_parent_class)->destroy) (object); +} + +static void get_bounds (EelCanvasRE *re, double *px1, double *py1, double *px2, double *py2) +{ + EelCanvasItem *item; + double x1, y1, x2, y2; + int cx1, cy1, cx2, cy2; + double hwidth; + +#ifdef VERBOSE + g_print ("re get_bounds\n"); +#endif + item = EEL_CANVAS_ITEM (re); + + if (re->width_pixels) + hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0; + else + hwidth = re->width / 2.0; + + x1 = re->x1; + y1 = re->y1; + x2 = re->x2; + y2 = re->y2; + + eel_canvas_item_i2w (item, &x1, &y1); + eel_canvas_item_i2w (item, &x2, &y2); + eel_canvas_w2c (item->canvas, x1 - hwidth, y1 - hwidth, &cx1, &cy1); + eel_canvas_w2c (item->canvas, x2 + hwidth, y2 + hwidth, &cx2, &cy2); + *px1 = cx1; + *py1 = cy1; + *px2 = cx2; + *py2 = cy2; + + /* Some safety fudging */ + + *px1 -= 2; + *py1 -= 2; + *px2 += 2; + *py2 += 2; +} + +/* Convenience function to set a GC's foreground color to the specified pixel value */ +static void +set_gc_foreground (GdkGC *gc, gulong pixel) +{ + GdkColor c; + + if (!gc) + return; + + c.pixel = pixel; + gdk_gc_set_foreground (gc, &c); +} + +/* Sets the stipple pattern for the specified gc */ +static void +set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure) +{ + if (*internal_stipple && !reconfigure) + g_object_unref (*internal_stipple); + + *internal_stipple = stipple; + if (stipple && !reconfigure) + g_object_ref (stipple); + + if (gc) + { + if (stipple) + { + gdk_gc_set_stipple (gc, stipple); + gdk_gc_set_fill (gc, GDK_STIPPLED); + } + else + gdk_gc_set_fill (gc, GDK_SOLID); + } +} + +/* Recalculate the outline width of the rectangle/ellipse and set it in its GC */ +static void +set_outline_gc_width (EelCanvasRE *re) +{ + int width; + + if (!re->outline_gc) + return; + + if (re->width_pixels) + width = (int) re->width; + else + width = (int) (re->width * re->item.canvas->pixels_per_unit + 0.5); + + gdk_gc_set_line_attributes (re->outline_gc, width, + GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER); +} + +static void +eel_canvas_re_set_fill (EelCanvasRE *re, gboolean fill_set) +{ + if (re->fill_set != fill_set) + { + re->fill_set = fill_set; + eel_canvas_item_request_update (EEL_CANVAS_ITEM (re)); + } +} + +static void +eel_canvas_re_set_outline (EelCanvasRE *re, gboolean outline_set) +{ + if (re->outline_set != outline_set) + { + re->outline_set = outline_set; + eel_canvas_item_request_update (EEL_CANVAS_ITEM (re)); + } +} + +static void +eel_canvas_re_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EelCanvasItem *item; + EelCanvasRE *re; + GdkColor color = { 0, 0, 0, 0, }; + GdkColor *pcolor; + int have_pixel; + + g_return_if_fail (object != NULL); + g_return_if_fail (EEL_IS_CANVAS_RE (object)); + + item = EEL_CANVAS_ITEM (object); + re = EEL_CANVAS_RE (object); + have_pixel = FALSE; + + switch (param_id) + { + case PROP_X1: + re->x1 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_Y1: + re->y1 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_X2: + re->x2 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_Y2: + re->y2 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_FILL_COLOR: + case PROP_FILL_COLOR_GDK: + case PROP_FILL_COLOR_RGBA: + switch (param_id) + { + case PROP_FILL_COLOR: + if (g_value_get_string (value) && + gdk_color_parse (g_value_get_string (value), &color)) + eel_canvas_re_set_fill (re, TRUE); + else + eel_canvas_re_set_fill (re, FALSE); + + re->fill_color = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + break; + + case PROP_FILL_COLOR_GDK: + pcolor = g_value_get_boxed (value); + eel_canvas_re_set_fill (re, pcolor != NULL); + + if (pcolor) + { + GdkColormap *colormap; + + color = *pcolor; + colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas)); + gdk_rgb_find_color (colormap, &color); + have_pixel = TRUE; + } + + re->fill_color = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + break; + + case PROP_FILL_COLOR_RGBA: + eel_canvas_re_set_fill (re, TRUE); + re->fill_color = g_value_get_uint (value); + break; + } +#ifdef VERBOSE + g_print ("re fill color = %08x\n", re->fill_color); +#endif + if (have_pixel) + re->fill_pixel = color.pixel; + else + re->fill_pixel = eel_canvas_get_color_pixel (item->canvas, re->fill_color); + + set_gc_foreground (re->fill_gc, re->fill_pixel); + + eel_canvas_item_request_redraw (item); + break; + + case PROP_OUTLINE_COLOR: + case PROP_OUTLINE_COLOR_GDK: + case PROP_OUTLINE_COLOR_RGBA: + switch (param_id) + { + case PROP_OUTLINE_COLOR: + if (g_value_get_string (value) && + gdk_color_parse (g_value_get_string (value), &color)) + eel_canvas_re_set_outline (re, TRUE); + else + eel_canvas_re_set_outline (re, FALSE); + + re->outline_color = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + break; + + case PROP_OUTLINE_COLOR_GDK: + pcolor = g_value_get_boxed (value); + eel_canvas_re_set_outline (re, pcolor != NULL); + + if (pcolor) + { + GdkColormap *colormap; + + color = *pcolor; + colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas)); + gdk_rgb_find_color (colormap, &color); + + have_pixel = TRUE; + } + + re->outline_color = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + break; + + case PROP_OUTLINE_COLOR_RGBA: + eel_canvas_re_set_outline (re, TRUE); + re->outline_color = g_value_get_uint (value); + break; + } +#ifdef VERBOSE + g_print ("re outline color %x %x %x\n", color.red, color.green, color.blue); +#endif + if (have_pixel) + re->outline_pixel = color.pixel; + else + re->outline_pixel = eel_canvas_get_color_pixel (item->canvas, + re->outline_color); + + set_gc_foreground (re->outline_gc, re->outline_pixel); + + eel_canvas_item_request_redraw (item); + break; + + case PROP_FILL_STIPPLE: + set_stipple (re->fill_gc, &re->fill_stipple, (GdkBitmap *) g_value_get_object (value), FALSE); + + break; + + case PROP_OUTLINE_STIPPLE: + set_stipple (re->outline_gc, &re->outline_stipple, (GdkBitmap *) g_value_get_object (value), FALSE); + break; + + case PROP_WIDTH_PIXELS: + re->width = g_value_get_uint (value); + re->width_pixels = TRUE; + set_outline_gc_width (re); + + eel_canvas_item_request_update (item); + break; + + case PROP_WIDTH_UNITS: + re->width = fabs (g_value_get_double (value)); + re->width_pixels = FALSE; + set_outline_gc_width (re); + + eel_canvas_item_request_update (item); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/* Allocates a GdkColor structure filled with the specified pixel, and puts it into the specified + * value for returning it in the get_property method. + */ +static void +get_color_value (EelCanvasRE *re, gulong pixel, GValue *value) +{ + GdkColor color; + EelCanvasItem *item = (EelCanvasItem *) re; + GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas)); + + gdk_colormap_query_color (colormap, pixel, &color); + g_value_set_boxed (value, &color); +} + +static void +eel_canvas_re_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EelCanvasRE *re; + + g_return_if_fail (object != NULL); + g_return_if_fail (EEL_IS_CANVAS_RE (object)); + + re = EEL_CANVAS_RE (object); + + switch (param_id) + { + case PROP_X1: + g_value_set_double (value, re->x1); + break; + + case PROP_Y1: + g_value_set_double (value, re->y1); + break; + + case PROP_X2: + g_value_set_double (value, re->x2); + break; + + case PROP_Y2: + g_value_set_double (value, re->y2); + break; + + case PROP_FILL_COLOR_GDK: + get_color_value (re, re->fill_pixel, value); + break; + + case PROP_OUTLINE_COLOR_GDK: + get_color_value (re, re->outline_pixel, value); + break; + + case PROP_FILL_COLOR_RGBA: + g_value_set_uint (value, re->fill_color); + break; + + case PROP_OUTLINE_COLOR_RGBA: + g_value_set_uint (value, re->outline_color); + break; + + case PROP_FILL_STIPPLE: + g_value_set_object (value, (GObject *) re->fill_stipple); + break; + + case PROP_OUTLINE_STIPPLE: + g_value_set_object (value, (GObject *) re->outline_stipple); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +set_colors_and_stipples (EelCanvasRE *re) +{ + set_gc_foreground (re->fill_gc, re->fill_pixel); + set_gc_foreground (re->outline_gc, re->outline_pixel); + set_stipple (re->fill_gc, &re->fill_stipple, re->fill_stipple, TRUE); + set_stipple (re->outline_gc, &re->outline_stipple, re->outline_stipple, TRUE); + set_outline_gc_width (re); +} + +static void +eel_canvas_re_update_shared (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags) +{ + EelCanvasRE *re; + +#ifdef VERBOSE + g_print ("eel_canvas_re_update_shared\n"); +#endif + re = EEL_CANVAS_RE (item); + + if (re_parent_class->update) + (* re_parent_class->update) (item, i2w_dx, i2w_dy, flags); + + set_colors_and_stipples (re); + +#ifdef OLD_XFORM + recalc_bounds (re); +#endif +} + +static void +eel_canvas_re_realize (EelCanvasItem *item) +{ + EelCanvasRE *re; + +#ifdef VERBOSE + g_print ("eel_canvas_re_realize\n"); +#endif + re = EEL_CANVAS_RE (item); + + if (re_parent_class->realize) + (* re_parent_class->realize) (item); + + re->fill_gc = gdk_gc_new (gtk_layout_get_bin_window (&item->canvas->layout)); + re->fill_pixel = eel_canvas_get_color_pixel (item->canvas, re->fill_color); + re->outline_gc = gdk_gc_new (gtk_layout_get_bin_window (&item->canvas->layout)); + re->outline_pixel = eel_canvas_get_color_pixel (item->canvas, re->outline_color); + set_colors_and_stipples (re); + +#ifdef OLD_XFORM + (* EEL_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0); +#endif +} + +static void +eel_canvas_re_unrealize (EelCanvasItem *item) +{ + EelCanvasRE *re; + + re = EEL_CANVAS_RE (item); + + g_object_unref (re->fill_gc); + re->fill_gc = NULL; + g_object_unref (re->outline_gc); + re->outline_gc = NULL; + + if (re_parent_class->unrealize) + (* re_parent_class->unrealize) (item); +} + +static void +eel_canvas_re_translate (EelCanvasItem *item, double dx, double dy) +{ + EelCanvasRE *re; + +#ifdef VERBOSE + g_print ("eel_canvas_re_translate\n"); +#endif + re = EEL_CANVAS_RE (item); + + re->x1 += dx; + re->y1 += dy; + re->x2 += dx; + re->y2 += dy; +} + + +static void +eel_canvas_re_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + EelCanvasRE *re; + double hwidth; + +#ifdef VERBOSE + g_print ("eel_canvas_re_bounds\n"); +#endif + re = EEL_CANVAS_RE (item); + + if (re->width_pixels) + hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0; + else + hwidth = re->width / 2.0; + + *x1 = re->x1 - hwidth; + *y1 = re->y1 - hwidth; + *x2 = re->x2 + hwidth; + *y2 = re->y2 + hwidth; +} + +/* Rectangle item */ + + +static void eel_canvas_rect_class_init (EelCanvasRectClass *klass); +static void eel_canvas_rect_init (EelCanvasRect *rect); +static void eel_canvas_rect_finalize (GObject *object); +static void eel_canvas_rect_realize (EelCanvasItem *item); + +static void eel_canvas_rect_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose); +static double eel_canvas_rect_point (EelCanvasItem *item, double x, double y, int cx, int cy, + EelCanvasItem **actual_item); + +struct _EelCanvasRectPrivate +{ + Rect last_update_rect; + Rect last_outline_update_rect; + int last_outline_update_width; + +#ifdef HAVE_RENDER + gboolean use_render; + XRenderPictFormat *format; +#endif +}; + +GType +eel_canvas_rect_get_type (void) +{ + static GType rect_type = 0; + + if (!rect_type) + { + GTypeInfo rect_info = + { + sizeof (EelCanvasRectClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_rect_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EelCanvasRect), + 0, /* n_preallocs */ + (GInstanceInitFunc) eel_canvas_rect_init + }; + + rect_type = g_type_register_static (eel_canvas_re_get_type (), + "EelCanvasRect", + &rect_info, + 0); + } + + return rect_type; +} + +static void +eel_canvas_rect_class_init (EelCanvasRectClass *klass) +{ + EelCanvasItemClass *item_class; + + rect_parent_class = g_type_class_peek_parent (klass); + + item_class = (EelCanvasItemClass *) klass; + + item_class->draw = eel_canvas_rect_draw; + item_class->point = eel_canvas_rect_point; + item_class->update = eel_canvas_rect_update; + item_class->realize = eel_canvas_rect_realize; + + G_OBJECT_CLASS (klass)->finalize = eel_canvas_rect_finalize; + +} + +static void +eel_canvas_rect_init (EelCanvasRect *rect) +{ + rect->priv = g_new0 (EelCanvasRectPrivate, 1); +} + +static void +eel_canvas_rect_finalize (GObject *object) +{ + EelCanvasRect *rect = EEL_CANVAS_RECT (object); + + if (rect->priv) + { + g_free (rect->priv); + } + + G_OBJECT_CLASS (rect_parent_class)->finalize (object); +} + +static void +eel_canvas_rect_realize (EelCanvasItem *item) +{ +#ifdef HAVE_RENDER + EelCanvasRectPrivate *priv; + int event_base, error_base; + Display *dpy; + + priv = EEL_CANVAS_RECT (item)->priv; + + dpy = gdk_x11_drawable_get_xdisplay (gtk_widget_get_window (GTK_WIDGET (item->canvas))); + priv->use_render = XRenderQueryExtension (dpy, &event_base, &error_base); + + if (priv->use_render) + { + GdkVisual *gdk_visual; + Visual *visual; + + gdk_visual = gtk_widget_get_visual (GTK_WIDGET (item->canvas)); + visual = gdk_x11_visual_get_xvisual (gdk_visual); + + priv->format = XRenderFindVisualFormat (dpy, visual); + } +#endif + + if (EEL_CANVAS_ITEM_CLASS (rect_parent_class)->realize) + { + (* EEL_CANVAS_ITEM_CLASS (rect_parent_class)->realize) (item); + } +} + + +static void +render_rect_alpha (EelCanvasRect *rect, + GdkDrawable *drawable, + int x, int y, + int width, int height, + guint32 rgba) +{ + GdkPixbuf *pixbuf; + guchar *data; + int rowstride, i; + guchar r, g, b, a; + EelCanvasRectPrivate *priv; + + if (width <= 0 || height <= 0 ) + { + return; + } + + priv = rect->priv; + + r = (rgba >> 24) & 0xff; + g = (rgba >> 16) & 0xff; + b = (rgba >> 8) & 0xff; + a = (rgba >> 0) & 0xff; + +#ifdef HAVE_RENDER + /* Every visual is not guaranteed to have a matching + * XRenderPictFormat. So make sure that format is not null before + * trying to render using Xrender calls. + */ + if (priv->use_render && (priv->format != NULL)) + { + GdkDrawable *real_drawable; + int x_offset, y_offset; + + Display *dpy; + Picture pict; + XRenderPictureAttributes attributes; + XRenderColor color; + + gdk_window_get_internal_paint_info (drawable, &real_drawable, + &x_offset, &y_offset); + + dpy = gdk_x11_drawable_get_xdisplay (real_drawable); + + pict = XRenderCreatePicture (dpy, + gdk_x11_drawable_get_xid (real_drawable), + priv->format, + 0, + &attributes); + + + /* Convert to premultiplied alpha: */ + r = r * a / 255; + g = g * a / 255; + b = b * a / 255; + + color.red = (r << 8) + r; + color.green = (g << 8) + g; + color.blue = (b << 8) + b; + color.alpha = (a << 8) + a; + + XRenderFillRectangle (dpy, + PictOpOver, + pict, + &color, + x - x_offset, y - y_offset, + width, height); + + XRenderFreePicture (dpy, pict); + + return; + } +#endif + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + data = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + + r = (rgba >> 24) & 0xff; + g = (rgba >> 16) & 0xff; + b = (rgba >> 8) & 0xff; + a = (rgba >> 0) & 0xff; + + for (i = 0; i < width*4; ) + { + data[i++] = r; + data[i++] = g; + data[i++] = b; + data[i++] = a; + } + + for (i = 1; i < height; i++) + { + memcpy (data + i*rowstride, data, width*4); + } + + gdk_draw_pixbuf (drawable, NULL, pixbuf, + 0, 0, x, y, width, height, + GDK_RGB_DITHER_NONE, 0, 0); + g_object_unref (pixbuf); +} + + +static void +eel_canvas_rect_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose) +{ + EelCanvasRE *re; + double x1, y1, x2, y2; + int cx1, cy1, cx2, cy2; + double i2w_dx, i2w_dy; + + re = EEL_CANVAS_RE (item); + + /* Get canvas pixel coordinates */ + i2w_dx = 0.0; + i2w_dy = 0.0; + eel_canvas_item_i2w (item, &i2w_dx, &i2w_dy); + + x1 = re->x1 + i2w_dx; + y1 = re->y1 + i2w_dy; + x2 = re->x2 + i2w_dx; + y2 = re->y2 + i2w_dy; + + eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1); + eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2); + + if (re->fill_set) + { + if ((re->fill_color & 0xff) != 255) + { + GdkRectangle *rectangles; + gint i, n_rectangles; + GdkRectangle draw_rect; + GdkRectangle part; + + draw_rect.x = cx1; + draw_rect.y = cy1; + draw_rect.width = cx2 - cx1 + 1; + draw_rect.height = cy2 - cy1 + 1; + + /* For alpha mode, only render the parts of the region + that are actually exposed */ + gdk_region_get_rectangles (expose->region, + &rectangles, + &n_rectangles); + + for (i = 0; i < n_rectangles; i++) + { + if (gdk_rectangle_intersect (&rectangles[i], + &draw_rect, + &part)) + { + render_rect_alpha (EEL_CANVAS_RECT (item), + drawable, + part.x, part.y, + part.width, part.height, + re->fill_color); + } + } + + g_free (rectangles); + } + else + { + if (re->fill_stipple) + eel_canvas_set_stipple_origin (item->canvas, re->fill_gc); + + gdk_draw_rectangle (drawable, + re->fill_gc, + TRUE, + cx1, cy1, + cx2 - cx1 + 1, + cy2 - cy1 + 1); + } + } + + if (re->outline_set) + { + if (re->outline_stipple) + eel_canvas_set_stipple_origin (item->canvas, re->outline_gc); + + gdk_draw_rectangle (drawable, + re->outline_gc, + FALSE, + cx1, + cy1, + cx2 - cx1, + cy2 - cy1); + } +} + +static double +eel_canvas_rect_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) +{ + EelCanvasRE *re; + double x1, y1, x2, y2; + double hwidth; + double dx, dy; + double tmp; + +#ifdef VERBOSE + g_print ("eel_canvas_rect_point\n"); +#endif + re = EEL_CANVAS_RE (item); + + *actual_item = item; + + /* Find the bounds for the rectangle plus its outline width */ + + x1 = re->x1; + y1 = re->y1; + x2 = re->x2; + y2 = re->y2; + + if (re->outline_set) + { + if (re->width_pixels) + hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0; + else + hwidth = re->width / 2.0; + + x1 -= hwidth; + y1 -= hwidth; + x2 += hwidth; + y2 += hwidth; + } + else + hwidth = 0.0; + + /* Is point inside rectangle (which can be hollow if it has no fill set)? */ + + if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) + { + if (re->fill_set || !re->outline_set) + return 0.0; + + dx = x - x1; + tmp = x2 - x; + if (tmp < dx) + dx = tmp; + + dy = y - y1; + tmp = y2 - y; + if (tmp < dy) + dy = tmp; + + if (dy < dx) + dx = dy; + + dx -= 2.0 * hwidth; + + if (dx < 0.0) + return 0.0; + else + return dx; + } + + /* Point is outside rectangle */ + + if (x < x1) + dx = x1 - x; + else if (x > x2) + dx = x - x2; + else + dx = 0.0; + + if (y < y1) + dy = y1 - y; + else if (y > y2) + dy = y - y2; + else + dy = 0.0; + + return sqrt (dx * dx + dy * dy); +} + +static void +request_redraw_borders (EelCanvas *canvas, + Rect *update_rect, + int width) +{ + eel_canvas_request_redraw (canvas, + update_rect->x0, update_rect->y0, + update_rect->x1, update_rect->y0 + width); + eel_canvas_request_redraw (canvas, + update_rect->x0, update_rect->y1-width, + update_rect->x1, update_rect->y1); + eel_canvas_request_redraw (canvas, + update_rect->x0, update_rect->y0, + update_rect->x0+width, update_rect->y1); + eel_canvas_request_redraw (canvas, + update_rect->x1-width, update_rect->y0, + update_rect->x1, update_rect->y1); +} + + +static void +eel_canvas_rect_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, gint flags) +{ + EelCanvasRE *re; + double x1, y1, x2, y2; + int cx1, cy1, cx2, cy2; + int repaint_rects_count, i; + int width_pixels; + int width_lt, width_rb; + Rect update_rect, repaint_rects[4]; + EelCanvasRectPrivate *priv; + + eel_canvas_re_update_shared (item, i2w_dx, i2w_dy, flags); + + re = EEL_CANVAS_RE (item); + priv = EEL_CANVAS_RECT (item)->priv; + + x1 = re->x1 + i2w_dx; + y1 = re->y1 + i2w_dy; + x2 = re->x2 + i2w_dx; + y2 = re->y2 + i2w_dy; + + eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1); + eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2); + + update_rect = make_rect (cx1, cy1, cx2+1, cy2+1); +#if 0 + eel_canvas_request_redraw (item->canvas, + update_rect.x0, update_rect.y0, + update_rect.x1, update_rect.y1); + eel_canvas_request_redraw (item->canvas, + priv->last_update_rect.x0, priv->last_update_rect.y0, + priv->last_update_rect.x1, priv->last_update_rect.y1); +#else + diff_rects (update_rect, priv->last_update_rect, + &repaint_rects_count, repaint_rects); + for (i = 0; i < repaint_rects_count; i++) + { + eel_canvas_request_redraw (item->canvas, + repaint_rects[i].x0, repaint_rects[i].y0, + repaint_rects[i].x1, repaint_rects[i].y1); + } +#endif + priv->last_update_rect = update_rect; + + if (re->outline_set) + { + /* Outline and bounding box */ + if (re->width_pixels) + width_pixels = (int) re->width; + else + width_pixels = (int) floor (re->width * re->item.canvas->pixels_per_unit + 0.5); + + width_lt = width_pixels / 2; + width_rb = (width_pixels + 1) / 2; + + cx1 -= width_lt; + cy1 -= width_lt; + cx2 += width_rb; + cy2 += width_rb; + + update_rect = make_rect (cx1, cy1, cx2, cy2); + request_redraw_borders (item->canvas, &update_rect, + (width_lt + width_rb)); + request_redraw_borders (item->canvas, &priv->last_outline_update_rect, + priv->last_outline_update_width); + priv->last_outline_update_rect = update_rect; + priv->last_outline_update_width = width_lt + width_rb; + + item->x1 = cx1; + item->y1 = cy1; + item->x2 = cx2+1; + item->y2 = cy2+1; + } + else + { + item->x1 = cx1; + item->y1 = cy1; + item->x2 = cx2+1; + item->y2 = cy2+1; + } +} + +/* Ellipse item */ + + +static void eel_canvas_ellipse_class_init (EelCanvasEllipseClass *klass); + +static void eel_canvas_ellipse_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose); +static double eel_canvas_ellipse_point (EelCanvasItem *item, double x, double y, int cx, int cy, + EelCanvasItem **actual_item); + + +GType +eel_canvas_ellipse_get_type (void) +{ + static GType ellipse_type = 0; + + if (!ellipse_type) + { + GTypeInfo ellipse_info = + { + sizeof (EelCanvasEllipseClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_ellipse_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EelCanvasEllipse), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL + + }; + + ellipse_type = g_type_register_static (eel_canvas_re_get_type (), + "EelCanvasEllipse", + &ellipse_info, + 0); + } + + return ellipse_type; +} + +static void +eel_canvas_ellipse_class_init (EelCanvasEllipseClass *klass) +{ + EelCanvasItemClass *item_class; + + item_class = (EelCanvasItemClass *) klass; + + item_class->draw = eel_canvas_ellipse_draw; + item_class->point = eel_canvas_ellipse_point; + item_class->update = eel_canvas_ellipse_update; +} + +static void +eel_canvas_ellipse_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose) +{ + EelCanvasRE *re; + int x1, y1, x2, y2; + double i2w_dx, i2w_dy; + + re = EEL_CANVAS_RE (item); + + /* Get canvas pixel coordinates */ + + i2w_dx = 0.0; + i2w_dy = 0.0; + eel_canvas_item_i2w (item, &i2w_dx, &i2w_dy); + + eel_canvas_w2c (item->canvas, + re->x1 + i2w_dx, + re->y1 + i2w_dy, + &x1, &y1); + eel_canvas_w2c (item->canvas, + re->x2 + i2w_dx, + re->y2 + i2w_dy, + &x2, &y2); + + if (re->fill_set) + { + if (re->fill_stipple) + eel_canvas_set_stipple_origin (item->canvas, re->fill_gc); + + gdk_draw_arc (drawable, + re->fill_gc, + TRUE, + x1, + y1, + x2 - x1, + y2 - y1, + 0 * 64, + 360 * 64); + } + + if (re->outline_set) + { + if (re->outline_stipple) + eel_canvas_set_stipple_origin (item->canvas, re->outline_gc); + + gdk_draw_arc (drawable, + re->outline_gc, + FALSE, + x1, + y1, + x2 - x1, + y2 - y1, + 0 * 64, + 360 * 64); + } +} + +static double +eel_canvas_ellipse_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) +{ + EelCanvasRE *re; + double dx, dy; + double scaled_dist; + double outline_dist; + double center_dist; + double width; + double a, b; + double diamx, diamy; + + re = EEL_CANVAS_RE (item); + + *actual_item = item; + + if (re->outline_set) + { + if (re->width_pixels) + width = re->width / item->canvas->pixels_per_unit; + else + width = re->width; + } + else + width = 0.0; + + /* Compute the distance between the center of the ellipse and the point, with the ellipse + * considered as being scaled to a circle. + */ + + dx = x - (re->x1 + re->x2) / 2.0; + dy = y - (re->y1 + re->y2) / 2.0; + center_dist = sqrt (dx * dx + dy * dy); + + a = dx / ((re->x2 + width - re->x1) / 2.0); + b = dy / ((re->y2 + width - re->y1) / 2.0); + scaled_dist = sqrt (a * a + b * b); + + /* If the scaled distance is greater than 1, then we are outside. Compute the distance from + * the point to the edge of the circle, then scale back to the original un-scaled coordinate + * system. + */ + + if (scaled_dist > 1.0) + return (center_dist / scaled_dist) * (scaled_dist - 1.0); + + /* We are inside the outer edge of the ellipse. If it is filled, then we are "inside". + * Otherwise, do the same computation as above, but also check whether we are inside the + * outline. + */ + + if (re->fill_set) + return 0.0; + + if (scaled_dist > EEL_CANVAS_EPSILON) + outline_dist = (center_dist / scaled_dist) * (1.0 - scaled_dist) - width; + else + { + /* Handle very small distance */ + + diamx = re->x2 - re->x1; + diamy = re->y2 - re->y1; + + if (diamx < diamy) + outline_dist = (diamx - width) / 2.0; + else + outline_dist = (diamy - width) / 2.0; + } + + if (outline_dist < 0.0) + return 0.0; + + return outline_dist; +} + +static void +eel_canvas_ellipse_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, gint flags) +{ + EelCanvasRE *re; + double x0, y0, x1, y1; + +#ifdef VERBOSE + g_print ("eel_canvas_sllipse_update item %x\n", item); +#endif + + eel_canvas_re_update_shared (item, i2w_dx, i2w_dy, flags); + re = EEL_CANVAS_RE (item); + + get_bounds (re, &x0, &y0, &x1, &y1); + eel_canvas_update_bbox (item, x0, y0, x1, y1); +} + +static int +rect_empty (const Rect *src) +{ + return (src->x1 <= src->x0 || src->y1 <= src->y0); +} + +static Rect +make_rect (int x0, int y0, int x1, int y1) +{ + Rect r; + + r.x0 = x0; + r.y0 = y0; + r.x1 = x1; + r.y1 = y1; + return r; +} + +static gboolean +rects_intersect (Rect r1, Rect r2) +{ + if (r1.x0 >= r2.x1) + { + return FALSE; + } + if (r2.x0 >= r1.x1) + { + return FALSE; + } + if (r1.y0 >= r2.y1) + { + return FALSE; + } + if (r2.y0 >= r1.y1) + { + return FALSE; + } + return TRUE; +} + +static void +diff_rects_guts (Rect ra, Rect rb, int *count, Rect result[4]) +{ + if (ra.x0 < rb.x0) + { + result[(*count)++] = make_rect (ra.x0, ra.y0, rb.x0, ra.y1); + } + if (ra.y0 < rb.y0) + { + result[(*count)++] = make_rect (ra.x0, ra.y0, ra.x1, rb.y0); + } + if (ra.x1 < rb.x1) + { + result[(*count)++] = make_rect (ra.x1, rb.y0, rb.x1, rb.y1); + } + if (ra.y1 < rb.y1) + { + result[(*count)++] = make_rect (rb.x0, ra.y1, rb.x1, rb.y1); + } +} + +static void +diff_rects (Rect r1, Rect r2, int *count, Rect result[4]) +{ + g_assert (count != NULL); + g_assert (result != NULL); + + *count = 0; + + if (rects_intersect (r1, r2)) + { + diff_rects_guts (r1, r2, count, result); + diff_rects_guts (r2, r1, count, result); + } + else + { + if (!rect_empty (&r1)) + { + result[(*count)++] = r1; + } + if (!rect_empty (&r2)) + { + result[(*count)++] = r2; + } + } +} diff --git a/eel/eel-canvas-rect-ellipse.h b/eel/eel-canvas-rect-ellipse.h new file mode 100644 index 00000000..06f1eeab --- /dev/null +++ b/eel/eel-canvas-rect-ellipse.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + @NOTATION@ + */ +/* Rectangle and ellipse item types for EelCanvas widget + * + * EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is + * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. + * + * + * Author: Federico Mena <[email protected]> + */ + +#ifndef EEL_CANVAS_RECT_ELLIPSE_H +#define EEL_CANVAS_RECT_ELLIPSE_H + + +#include <eel/eel-canvas.h> + +#ifdef __cplusplus +extern "C" { +#endif + + + /* Base class for rectangle and ellipse item types. These are defined by their top-left and + * bottom-right corners. Rectangles and ellipses share the following arguments: + * + * name type read/write description + * ------------------------------------------------------------------------------------------ + * x1 double RW Leftmost coordinate of rectangle or ellipse + * y1 double RW Topmost coordinate of rectangle or ellipse + * x2 double RW Rightmost coordinate of rectangle or ellipse + * y2 double RW Bottommost coordinate of rectangle or ellipse + * fill_color string W X color specification for fill color, + * or NULL pointer for no color (transparent) + * fill_color_gdk GdkColor* RW Allocated GdkColor for fill + * outline_color string W X color specification for outline color, + * or NULL pointer for no color (transparent) + * outline_color_gdk GdkColor* RW Allocated GdkColor for outline + * fill_stipple GdkBitmap* RW Stipple pattern for fill + * outline_stipple GdkBitmap* RW Stipple pattern for outline + * width_pixels uint RW Width of the outline in pixels. The outline will + * not be scaled when the canvas zoom factor is changed. + * width_units double RW Width of the outline in canvas units. The outline + * will be scaled when the canvas zoom factor is changed. + */ + + +#define EEL_TYPE_CANVAS_RE (eel_canvas_re_get_type ()) +#define EEL_CANVAS_RE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_RE, EelCanvasRE)) +#define EEL_CANVAS_RE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_RE, EelCanvasREClass)) +#define EEL_IS_CANVAS_RE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_RE)) +#define EEL_IS_CANVAS_RE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_RE)) +#define EEL_CANVAS_RE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_RE, EelCanvasREClass)) + + + typedef struct _EelCanvasRE EelCanvasRE; + typedef struct _EelCanvasREClass EelCanvasREClass; + + struct _EelCanvasRE + { + EelCanvasItem item; + + GdkBitmap *fill_stipple; /* Stipple for fill */ + GdkBitmap *outline_stipple; /* Stipple for outline */ + + GdkGC *fill_gc; /* GC for filling */ + GdkGC *outline_gc; /* GC for outline */ + + gulong fill_pixel; /* Fill color */ + gulong outline_pixel; /* Outline color */ + + double x1, y1, x2, y2; /* Corners of item */ + double width; /* Outline width */ + + guint fill_color; /* Fill color, RGBA */ + guint outline_color; /* Outline color, RGBA */ + + /* Configuration flags */ + + unsigned int fill_set : 1; /* Is fill color set? */ + unsigned int outline_set : 1; /* Is outline color set? */ + unsigned int width_pixels : 1; /* Is outline width specified in pixels or units? */ + }; + + struct _EelCanvasREClass + { + EelCanvasItemClass parent_class; + }; + + + /* Standard Gtk function */ + GType eel_canvas_re_get_type (void) G_GNUC_CONST; + + + /* Rectangle item. No configurable or queryable arguments are available (use those in + * EelCanvasRE). + */ + + +#define EEL_TYPE_CANVAS_RECT (eel_canvas_rect_get_type ()) +#define EEL_CANVAS_RECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_RECT, EelCanvasRect)) +#define EEL_CANVAS_RECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_RECT, EelCanvasRectClass)) +#define EEL_IS_CANVAS_RECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_RECT)) +#define EEL_IS_CANVAS_RECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_RECT)) +#define EEL_CANVAS_RECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_RECT, EelCanvasRectClass)) + + + typedef struct _EelCanvasRect EelCanvasRect; + typedef struct _EelCanvasRectPrivate EelCanvasRectPrivate; + typedef struct _EelCanvasRectClass EelCanvasRectClass; + + struct _EelCanvasRect + { + EelCanvasRE re; + EelCanvasRectPrivate *priv; + }; + + struct _EelCanvasRectClass + { + EelCanvasREClass parent_class; + }; + + + /* Standard Gtk function */ + GType eel_canvas_rect_get_type (void) G_GNUC_CONST; + + + /* Ellipse item. No configurable or queryable arguments are available (use those in + * EelCanvasRE). + */ + + +#define EEL_TYPE_CANVAS_ELLIPSE (eel_canvas_ellipse_get_type ()) +#define EEL_CANVAS_ELLIPSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_ELLIPSE, EelCanvasEllipse)) +#define EEL_CANVAS_ELLIPSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_ELLIPSE, EelCanvasEllipseClass)) +#define EEL_IS_CANVAS_ELLIPSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_ELLIPSE)) +#define EEL_IS_CANVAS_ELLIPSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_ELLIPSE)) +#define EEL_CANVAS_ELLIPSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_ELLIPSE, EelCanvasEllipseClass)) + + + typedef struct _EelCanvasEllipse EelCanvasEllipse; + typedef struct _EelCanvasEllipseClass EelCanvasEllipseClass; + + struct _EelCanvasEllipse + { + EelCanvasRE re; + }; + + struct _EelCanvasEllipseClass + { + EelCanvasREClass parent_class; + }; + + + /* Standard Gtk function */ + GType eel_canvas_ellipse_get_type (void) G_GNUC_CONST; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eel/eel-canvas-util.c b/eel/eel-canvas-util.c new file mode 100644 index 00000000..ac90177f --- /dev/null +++ b/eel/eel-canvas-util.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + @NOTATION@ + */ +/* Miscellaneous utility functions for the EelCanvas widget + * + * EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is + * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. + * + * + * Author: Federico Mena <[email protected]> + */ + +#include <config.h> + +#include <sys/types.h> +#include <glib.h> +#include <math.h> + +#include "eel-canvas.h" +#include "eel-canvas-util.h" + +/* + * Ok, so some systems require magic incantations for M_PI to be defined. + * It's not important enough to worry about. + */ +#ifndef M_PI +#define M_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117 +#endif + +/** + * eel_canvas_points_new: + * @num_points: The number of points to allocate space for in the array. + * + * Creates a structure that should be used to pass an array of points to + * items. + * + * Return value: A newly-created array of points. It should be filled in + * by the user. + **/ +EelCanvasPoints * +eel_canvas_points_new (int num_points) +{ + EelCanvasPoints *points; + + g_return_val_if_fail (num_points > 1, NULL); + + points = g_new (EelCanvasPoints, 1); + points->num_points = num_points; + points->coords = g_new (double, 2 * num_points); + points->ref_count = 1; + + return points; +} + +/** + * eel_canvas_points_ref: + * @points: A canvas points structure. + * + * Increases the reference count of the specified points structure. + * + * Return value: The canvas points structure itself. + **/ +EelCanvasPoints * +eel_canvas_points_ref (EelCanvasPoints *points) +{ + g_return_val_if_fail (points != NULL, NULL); + + points->ref_count += 1; + return points; +} + +/** + * eel_canvas_points_free: + * @points: A canvas points structure. + * + * Decreases the reference count of the specified points structure. If it + * reaches zero, then the structure is freed. + **/ +void +eel_canvas_points_free (EelCanvasPoints *points) +{ + g_return_if_fail (points != NULL); + + points->ref_count -= 1; + if (points->ref_count == 0) + { + g_free (points->coords); + g_free (points); + } +} + +/** + * eel_canvas_get_miter_points: + * @x1: X coordinate of the first point + * @y1: Y coordinate of the first point + * @x2: X coordinate of the second (angle) point + * @y2: Y coordinate of the second (angle) point + * @x3: X coordinate of the third point + * @y3: Y coordinate of the third point + * @width: Width of the line + * @mx1: The X coordinate of the first miter point is returned here. + * @my1: The Y coordinate of the first miter point is returned here. + * @mx2: The X coordinate of the second miter point is returned here. + * @my2: The Y coordinate of the second miter point is returned here. + * + * Given three points forming an angle, computes the coordinates of the inside + * and outside points of the mitered corner formed by a line of a given width at + * that angle. + * + * Return value: FALSE if the angle is less than 11 degrees (this is the same + * threshold as X uses. If this occurs, the return points are not modified. + * Otherwise, returns TRUE. + **/ +int +eel_canvas_get_miter_points (double x1, double y1, double x2, double y2, double x3, double y3, + double width, + double *mx1, double *my1, double *mx2, double *my2) +{ + double theta1; /* angle of segment p2-p1 */ + double theta2; /* angle of segment p2-p3 */ + double theta; /* angle between line segments */ + double theta3; /* angle that bisects theta1 and theta2 and points to p1 */ + double dist; /* distance of miter points from p2 */ + double dx, dy; /* x and y offsets corresponding to dist */ + + double ELEVEN_DEGREES = 11.0 * M_PI / 180.0; + + /* Degenerate cases. */ + if ((x1 == x2 && y1 == y2) || (x2 == x3 && y2 == y3)) + return FALSE; + + theta1 = atan2 (y1 - y2, x1 - x2); + theta2 = atan2 (y3 - y2, x3 - x2); + theta = theta1 - theta2; + + /* Normalize to (-pi; pi]. */ + if (theta > M_PI) + theta -= 2.0 * M_PI; + else if (theta <= -M_PI) + theta += 2.0 * M_PI; + + if (fabs (theta) < ELEVEN_DEGREES) + return FALSE; + + dist = fabs (0.5 * width / sin (0.5 * theta)); + + theta3 = (theta1 + theta2) / 2.0; + if (sin (theta3 - theta1) > 0.0) + theta3 += M_PI; + + dx = dist * cos (theta3); + dy = dist * sin (theta3); + + *mx1 = x2 + dx; + *mx2 = x2 - dx; + *my1 = y2 + dy; + *my2 = y2 - dy; + + return TRUE; +} + +/** + * eel_canvas_get_butt_points: + * @x1: X coordinate of first point in the line + * @y1: Y cooordinate of first point in the line + * @x2: X coordinate of second point (endpoint) of the line + * @y2: Y coordinate of second point (endpoint) of the line + * @width: Width of the line + * @project: Whether the butt points should project out by width/2 distance + * @bx1: X coordinate of first butt point is returned here + * @by1: Y coordinate of first butt point is returned here + * @bx2: X coordinate of second butt point is returned here + * @by2: Y coordinate of second butt point is returned here + * + * Computes the butt points of a line segment. + **/ +void +eel_canvas_get_butt_points (double x1, double y1, double x2, double y2, + double width, int project, + double *bx1, double *by1, double *bx2, double *by2) +{ + double length; + double dx, dy; + + width *= 0.5; + dx = x2 - x1; + dy = y2 - y1; + length = sqrt (dx * dx + dy * dy); + + if (length < EEL_CANVAS_EPSILON) + { + *bx1 = *bx2 = x2; + *by1 = *by2 = y2; + } + else + { + dx = -width * (y2 - y1) / length; + dy = width * (x2 - x1) / length; + + *bx1 = x2 + dx; + *bx2 = x2 - dx; + *by1 = y2 + dy; + *by2 = y2 - dy; + + if (project) + { + *bx1 += dy; + *bx2 += dy; + *by1 -= dx; + *by2 -= dx; + } + } +} + +/** + * eel_canvas_polygon_to_point: + * @poly: Vertices of the polygon. X coordinates are in the even indices, and Y + * coordinates are in the odd indices + * @num_points: Number of points in the polygon + * @x: X coordinate of the point + * @y: Y coordinate of the point + * + * Computes the distance between a point and a polygon. + * + * Return value: The distance from the point to the polygon, or zero if the + * point is inside the polygon. + **/ +double +eel_canvas_polygon_to_point (double *poly, int num_points, double x, double y) +{ + double best; + int intersections; + int i; + double *p; + double dx, dy; + + /* Iterate through all the edges in the polygon, updating best and intersections. + * + * When computing intersections, include left X coordinate of line within its range, but not + * Y coordinate. Otherwise if the point lies exactly below a vertex we'll count it as two + * intersections. + */ + + best = 1.0e36; + if (poly == NULL) + return best; + + intersections = 0; + + for (i = num_points, p = poly; i > 1; i--, p += 2) + { + double px, py, dist; + + /* Compute the point on the current edge closest to the point and update the + * intersection count. This must be done separately for vertical edges, horizontal + * edges, and others. + */ + + if (p[2] == p[0]) + { + /* Vertical edge */ + + px = p[0]; + + if (p[1] >= p[3]) + { + py = MIN (p[1], y); + py = MAX (py, p[3]); + } + else + { + py = MIN (p[3], y); + py = MAX (py, p[1]); + } + } + else if (p[3] == p[1]) + { + /* Horizontal edge */ + + py = p[1]; + + if (p[0] >= p[2]) + { + px = MIN (p[0], x); + px = MAX (px, p[2]); + + if ((y < py) && (x < p[0]) && (x >= p[2])) + intersections++; + } + else + { + px = MIN (p[2], x); + px = MAX (px, p[0]); + + if ((y < py) && (x < p[2]) && (x >= p[0])) + intersections++; + } + } + else + { + double m1, b1, m2, b2; + int lower; + + /* Diagonal edge. Convert the edge to a line equation (y = m1*x + b1), then + * compute a line perpendicular to this edge but passing through the point, + * (y = m2*x + b2). + */ + + m1 = (p[3] - p[1]) / (p[2] - p[0]); + b1 = p[1] - m1 * p[0]; + + m2 = -1.0 / m1; + b2 = y - m2 * x; + + px = (b2 - b1) / (m1 - m2); + py = m1 * px + b1; + + if (p[0] > p[2]) + { + if (px > p[0]) + { + px = p[0]; + py = p[1]; + } + else if (px < p[2]) + { + px = p[2]; + py = p[3]; + } + } + else + { + if (px > p[2]) + { + px = p[2]; + py = p[3]; + } + else if (px < p[0]) + { + px = p[0]; + py = p[1]; + } + } + + lower = (m1 * x + b1) > y; + + if (lower && (x >= MIN (p[0], p[2])) && (x < MAX (p[0], p[2]))) + intersections++; + } + + /* Compute the distance to the closest point, and see if that is the best so far */ + + dx = x - px; + dy = y - py; + dist = sqrt (dx * dx + dy * dy); + if (dist < best) + best = dist; + } + + /* We've processed all the points. If the number of intersections is odd, the point is + * inside the polygon. + */ + + if (intersections & 0x1) + return 0.0; + else + return best; +} + +/** + * eel_canvas_item_reset_bounds: + * @item: A canvas item + * + * Resets the bounding box of a canvas item to an empty rectangle. + **/ +void +eel_canvas_item_reset_bounds (EelCanvasItem *item) +{ + item->x1 = 0.0; + item->y1 = 0.0; + item->x2 = 0.0; + item->y2 = 0.0; +} + +/** + * eel_canvas_update_bbox: + * @canvas: the canvas needing update + * @x1: Left coordinate of the new bounding box + * @y1: Top coordinate of the new bounding box + * @x2: Right coordinate of the new bounding box + * @y2: Bottom coordinate of the new bounding box + * + * Sets the bbox to the new value, requesting full repaint. + **/ +void +eel_canvas_update_bbox (EelCanvasItem *item, int x1, int y1, int x2, int y2) +{ + eel_canvas_item_request_redraw (item); + item->x1 = x1; + item->y1 = y1; + item->x2 = x2; + item->y2 = y2; + eel_canvas_item_request_redraw (item); +} + diff --git a/eel/eel-canvas-util.h b/eel/eel-canvas-util.h new file mode 100644 index 00000000..e4484cde --- /dev/null +++ b/eel/eel-canvas-util.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + @NOTATION@ + */ +/* Miscellaneous utility functions for the EelCanvas widget + * + * EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is + * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. + * + * Author: Federico Mena <[email protected]> + */ + +#ifndef EEL_CANVAS_UTIL_H +#define EEL_CANVAS_UTIL_H + + +#ifdef __cplusplus +extern "C" { +#endif + + + /* This structure defines an array of points. X coordinates are stored in the even-numbered + * indices, and Y coordinates are stored in the odd-numbered indices. num_points indicates the + * number of points, so the array is 2*num_points elements big. + */ + typedef struct + { + double *coords; + int num_points; + int ref_count; + } EelCanvasPoints; + + + /* Allocate a new EelCanvasPoints structure with enough space for the specified number of points */ + EelCanvasPoints *eel_canvas_points_new (int num_points); + + /* Increate ref count */ + EelCanvasPoints *eel_canvas_points_ref (EelCanvasPoints *points); +#define eel_canvas_points_unref eel_canvas_points_free + + /* Decrease ref count and free structure if it has reached zero */ + void eel_canvas_points_free (EelCanvasPoints *points); + + /* Given three points forming an angle, compute the coordinates of the inside and outside points of + * the mitered corner formed by a line of a given width at that angle. + * + * If the angle is less than 11 degrees, then FALSE is returned and the return points are not + * modified. Otherwise, TRUE is returned. + */ + int eel_canvas_get_miter_points (double x1, double y1, double x2, double y2, double x3, double y3, + double width, + double *mx1, double *my1, double *mx2, double *my2); + + /* Compute the butt points of a line segment. If project is FALSE, then the results are as follows: + * + * -------------------* (bx1, by1) + * | + * (x1, y1) *------------------* (x2, y2) + * | + * -------------------* (bx2, by2) + * + * that is, the line is not projected beyond (x2, y2). If project is TRUE, then the results are as + * follows: + * + * -------------------* (bx1, by1) + * (x2, y2) | + * (x1, y1) *-------------* | + * | + * -------------------* (bx2, by2) + */ + void eel_canvas_get_butt_points (double x1, double y1, double x2, double y2, + double width, int project, + double *bx1, double *by1, double *bx2, double *by2); + + /* Calculate the distance from a polygon to a point. The polygon's X coordinates are in the even + * indices of the poly array, and the Y coordinates are in the odd indices. + */ + double eel_canvas_polygon_to_point (double *poly, int num_points, double x, double y); + + + void eel_canvas_item_reset_bounds (EelCanvasItem *item); + + /* Sets the bbox to the new value, requesting full repaint. */ + void eel_canvas_update_bbox (EelCanvasItem *item, int x1, int y1, int x2, int y2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eel/eel-canvas.c b/eel/eel-canvas.c new file mode 100644 index 00000000..afa038f0 --- /dev/null +++ b/eel/eel-canvas.c @@ -0,0 +1,4213 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + @NOTATION@ + */ +/* + * EelCanvas widget - Tk-like canvas widget for Mate + * + * EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is + * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties. + * + * + * Authors: Federico Mena <[email protected]> + * Raph Levien <[email protected]> + */ + +/* + * TO-DO list for the canvas: + * + * - Allow to specify whether EelCanvasImage sizes are in units or pixels (scale or don't scale). + * + * - Implement a flag for eel_canvas_item_reparent() that tells the function to keep the item + * visually in the same place, that is, to keep it in the same place with respect to the canvas + * origin. + * + * - GC put functions for items. + * + * - Widget item (finish it). + * + * - GList *eel_canvas_gimme_all_items_contained_in_this_area (EelCanvas *canvas, Rectangle area); + * + * - Retrofit all the primitive items with microtile support. + * + * - Curve support for line item. + * + * - Arc item (Havoc has it; to be integrated in EelCanvasEllipse). + * + * - Sane font handling API. + * + * - Get_arg methods for items: + * - How to fetch the outline width and know whether it is in pixels or units? + */ + +#include <config.h> + +#include <math.h> +#include <string.h> +#include <stdio.h> +#include <gdk/gdkprivate.h> +#include <gtk/gtk.h> +#include "eel-canvas.h" +#include "eel-i18n.h" + +#include "eel-marshal.h" + +static void eel_canvas_request_update (EelCanvas *canvas); +static void group_add (EelCanvasGroup *group, + EelCanvasItem *item); +static void group_remove (EelCanvasGroup *group, + EelCanvasItem *item); +static void redraw_and_repick_if_mapped (EelCanvasItem *item); + +/*** EelCanvasItem ***/ + +/* Some convenience stuff */ +#define GCI_UPDATE_MASK (EEL_CANVAS_UPDATE_REQUESTED | EEL_CANVAS_UPDATE_DEEP) +#define GCI_EPSILON 1e-18 + +enum +{ + ITEM_PROP_0, + ITEM_PROP_PARENT, + ITEM_PROP_VISIBLE +}; + +enum +{ + ITEM_EVENT, + ITEM_LAST_SIGNAL +}; + +static void eel_canvas_item_class_init (EelCanvasItemClass *klass); +static void eel_canvas_item_init (EelCanvasItem *item); +static int emit_event (EelCanvas *canvas, GdkEvent *event); + +static guint item_signals[ITEM_LAST_SIGNAL]; + +static GtkObjectClass *item_parent_class; + +static gpointer accessible_item_parent_class; +static gpointer accessible_parent_class; + + +/** + * eel_canvas_item_get_type: + * + * Registers the &EelCanvasItem class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &EelCanvasItem class. + **/ +GType +eel_canvas_item_get_type (void) +{ + static GType canvas_item_type = 0; + + if (!canvas_item_type) + { + static const GTypeInfo canvas_item_info = + { + sizeof (EelCanvasItemClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_item_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EelCanvasItem), + 0, /* n_preallocs */ + (GInstanceInitFunc) eel_canvas_item_init + }; + + canvas_item_type = g_type_register_static (gtk_object_get_type (), + "EelCanvasItem", + &canvas_item_info, + 0); + } + + return canvas_item_type; +} + +/* Object initialization function for EelCanvasItem */ +static void +eel_canvas_item_init (EelCanvasItem *item) +{ + item->flags |= EEL_CANVAS_ITEM_VISIBLE; +} + +/** + * eel_canvas_item_new: + * @parent: The parent group for the new item. + * @type: The object type of the item. + * @first_arg_name: A list of object argument name/value pairs, NULL-terminated, + * used to configure the item. For example, "fill_color", "black", + * "width_units", 5.0, NULL. + * @Varargs: + * + * Creates a new canvas item with @parent as its parent group. The item is + * created at the top of its parent's stack, and starts up as visible. The item + * is of the specified @type, for example, it can be + * eel_canvas_rect_get_type(). The list of object arguments/value pairs is + * used to configure the item. + * + * Return value: The newly-created item. + **/ +EelCanvasItem * +eel_canvas_item_new (EelCanvasGroup *parent, GType type, const gchar *first_arg_name, ...) +{ + EelCanvasItem *item; + va_list args; + + g_return_val_if_fail (EEL_IS_CANVAS_GROUP (parent), NULL); + g_return_val_if_fail (g_type_is_a (type, eel_canvas_item_get_type ()), NULL); + + item = EEL_CANVAS_ITEM (g_object_new (type, NULL)); + + va_start (args, first_arg_name); + eel_canvas_item_construct (item, parent, first_arg_name, args); + va_end (args); + + return item; +} + + +/* Performs post-creation operations on a canvas item (adding it to its parent + * group, etc.) + */ +static void +item_post_create_setup (EelCanvasItem *item) +{ + group_add (EEL_CANVAS_GROUP (item->parent), item); + + redraw_and_repick_if_mapped (item); +} + +/* Set_property handler for canvas items */ +static void +eel_canvas_item_set_property (GObject *gobject, guint param_id, + const GValue *value, GParamSpec *pspec) +{ + EelCanvasItem *item; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject)); + + item = EEL_CANVAS_ITEM (gobject); + + switch (param_id) + { + case ITEM_PROP_PARENT: + if (item->parent != NULL) + { + g_warning ("Cannot set `parent' argument after item has " + "already been constructed."); + } + else if (g_value_get_object (value)) + { + item->parent = EEL_CANVAS_ITEM (g_value_get_object (value)); + item->canvas = item->parent->canvas; + item_post_create_setup (item); + } + break; + case ITEM_PROP_VISIBLE: + if (g_value_get_boolean (value)) + { + eel_canvas_item_show (item); + } + else + { + eel_canvas_item_hide (item); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); + break; + } +} + +/* Get_property handler for canvas items */ +static void +eel_canvas_item_get_property (GObject *gobject, guint param_id, + GValue *value, GParamSpec *pspec) +{ + EelCanvasItem *item; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject)); + + item = EEL_CANVAS_ITEM (gobject); + + switch (param_id) + { + case ITEM_PROP_VISIBLE: + g_value_set_boolean (value, item->flags & EEL_CANVAS_ITEM_VISIBLE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); + break; + } +} + +/** + * eel_canvas_item_construct: + * @item: An unconstructed canvas item. + * @parent: The parent group for the item. + * @first_arg_name: The name of the first argument for configuring the item. + * @args: The list of arguments used to configure the item. + * + * Constructs a canvas item; meant for use only by item implementations. + **/ +void +eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent, + const gchar *first_arg_name, va_list args) +{ + g_return_if_fail (EEL_IS_CANVAS_GROUP (parent)); + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + item->parent = EEL_CANVAS_ITEM (parent); + item->canvas = item->parent->canvas; + + g_object_set_valist (G_OBJECT (item), first_arg_name, args); + + item_post_create_setup (item); +} + + +static void +redraw_and_repick_if_mapped (EelCanvasItem *item) +{ + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + { + eel_canvas_item_request_redraw (item); + item->canvas->need_repick = TRUE; + } +} + +/* Dispose handler for canvas items */ +static void +eel_canvas_item_dispose (GObject *object) +{ + EelCanvasItem *item; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (object)); + + item = EEL_CANVAS_ITEM (object); + + if (item->canvas) + { + eel_canvas_item_request_redraw (item); + + /* Make the canvas forget about us */ + + if (item == item->canvas->current_item) + { + item->canvas->current_item = NULL; + item->canvas->need_repick = TRUE; + } + + if (item == item->canvas->new_current_item) + { + item->canvas->new_current_item = NULL; + item->canvas->need_repick = TRUE; + } + + if (item == item->canvas->grabbed_item) + { + GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (item->canvas)); + item->canvas->grabbed_item = NULL; + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + } + + if (item == item->canvas->focused_item) + item->canvas->focused_item = NULL; + + /* Normal destroy stuff */ + + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); + + if (item->flags & EEL_CANVAS_ITEM_REALIZED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item); + + if (item->parent) + group_remove (EEL_CANVAS_GROUP (item->parent), item); + + item->canvas = NULL; + } + + G_OBJECT_CLASS (item_parent_class)->dispose (object); +} + + +/* Realize handler for canvas items */ +static void +eel_canvas_item_realize (EelCanvasItem *item) +{ + if (item->parent && !(item->parent->flags & EEL_CANVAS_ITEM_REALIZED)) + (* EEL_CANVAS_ITEM_GET_CLASS (item->parent)->realize) (item->parent); + + if (item->parent == NULL && !gtk_widget_get_realized (GTK_WIDGET (item->canvas))) + gtk_widget_realize (GTK_WIDGET (item->canvas)); + + item->flags |= EEL_CANVAS_ITEM_REALIZED; + + eel_canvas_item_request_update (item); +} + +/* Unrealize handler for canvas items */ +static void +eel_canvas_item_unrealize (EelCanvasItem *item) +{ + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); + + item->flags &= ~(EEL_CANVAS_ITEM_REALIZED); +} + +/* Map handler for canvas items */ +static void +eel_canvas_item_map (EelCanvasItem *item) +{ + item->flags |= EEL_CANVAS_ITEM_MAPPED; +} + +/* Unmap handler for canvas items */ +static void +eel_canvas_item_unmap (EelCanvasItem *item) +{ + item->flags &= ~(EEL_CANVAS_ITEM_MAPPED); +} + +/* Update handler for canvas items */ +static void +eel_canvas_item_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags) +{ + item->flags &= ~(EEL_CANVAS_ITEM_NEED_UPDATE); + item->flags &= ~(EEL_CANVAS_ITEM_NEED_DEEP_UPDATE); +} + +/* + * This routine invokes the update method of the item + * Please notice, that we take parent to canvas pixel matrix as argument + * unlike virtual method ::update, whose argument is item 2 canvas pixel + * matrix + * + * I will try to force somewhat meaningful naming for affines (Lauris) + * General naming rule is FROM2TO, where FROM and TO are abbreviations + * So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel + * I hope that this helps to keep track of what really happens + * + */ + +static void +eel_canvas_item_invoke_update (EelCanvasItem *item, + double i2w_dx, + double i2w_dy, + int flags) +{ + int child_flags; + + child_flags = flags; + + /* apply object flags to child flags */ + child_flags &= ~EEL_CANVAS_UPDATE_REQUESTED; + + if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE) + child_flags |= EEL_CANVAS_UPDATE_REQUESTED; + + if (item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE) + child_flags |= EEL_CANVAS_UPDATE_DEEP; + + if (child_flags & GCI_UPDATE_MASK) + { + if (EEL_CANVAS_ITEM_GET_CLASS (item)->update) + EEL_CANVAS_ITEM_GET_CLASS (item)->update (item, i2w_dx, i2w_dy, child_flags); + } + + /* If this fail you probably forgot to chain up to + * EelCanvasItem::update from a derived class */ + g_return_if_fail (!(item->flags & EEL_CANVAS_ITEM_NEED_UPDATE)); +} + +/* + * This routine invokes the point method of the item. + * The arguments x, y should be in the parent item local coordinates. + */ + +static double +eel_canvas_item_invoke_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item) +{ + /* Calculate x & y in item local coordinates */ + + if (EEL_CANVAS_ITEM_GET_CLASS (item)->point) + return EEL_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item); + + return 1e18; +} + +/** + * eel_canvas_item_set: + * @item: A canvas item. + * @first_arg_name: The list of object argument name/value pairs used to configure the item. + * @Varargs: + * + * Configures a canvas item. The arguments in the item are set to the specified + * values, and the item is repainted as appropriate. + **/ +void +eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...) +{ + va_list args; + + va_start (args, first_arg_name); + eel_canvas_item_set_valist (item, first_arg_name, args); + va_end (args); +} + + +/** + * eel_canvas_item_set_valist: + * @item: A canvas item. + * @first_arg_name: The name of the first argument used to configure the item. + * @args: The list of object argument name/value pairs used to configure the item. + * + * Configures a canvas item. The arguments in the item are set to the specified + * values, and the item is repainted as appropriate. + **/ +void +eel_canvas_item_set_valist (EelCanvasItem *item, const gchar *first_arg_name, va_list args) +{ + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + g_object_set_valist (G_OBJECT (item), first_arg_name, args); + +#if 0 + /* I commented this out, because item implementations have to schedule update/redraw */ + eel_canvas_item_request_redraw (item); +#endif + + item->canvas->need_repick = TRUE; +} + + +/** + * eel_canvas_item_move: + * @item: A canvas item. + * @dx: Horizontal offset. + * @dy: Vertical offset. + * + * Moves a canvas item by creating an affine transformation matrix for + * translation by using the specified values. This happens in item + * local coordinate system, so if you have nontrivial transform, it + * most probably does not do, what you want. + **/ +void +eel_canvas_item_move (EelCanvasItem *item, double dx, double dy) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (!EEL_CANVAS_ITEM_GET_CLASS (item)->translate) + { + g_warning ("Item type %s does not implement translate method.\n", + g_type_name (G_OBJECT_TYPE (item))); + return; + } + + (* EEL_CANVAS_ITEM_GET_CLASS (item)->translate) (item, dx, dy); + + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + item->canvas->need_repick = TRUE; + + if (!(item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) + { + item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; + if (item->parent != NULL) + eel_canvas_item_request_update (item->parent); + else + eel_canvas_request_update (item->canvas); + } + +} + +/* Convenience function to reorder items in a group's child list. This puts the + * specified link after the "before" link. Returns TRUE if the list was changed. + */ +static gboolean +put_item_after (GList *link, GList *before) +{ + EelCanvasGroup *parent; + + if (link == before) + return FALSE; + + parent = EEL_CANVAS_GROUP (EEL_CANVAS_ITEM (link->data)->parent); + + if (before == NULL) + { + if (link == parent->item_list) + return FALSE; + + link->prev->next = link->next; + + if (link->next) + link->next->prev = link->prev; + else + parent->item_list_end = link->prev; + + link->prev = before; + link->next = parent->item_list; + link->next->prev = link; + parent->item_list = link; + } + else + { + if ((link == parent->item_list_end) && (before == parent->item_list_end->prev)) + return FALSE; + + if (link->next) + link->next->prev = link->prev; + + if (link->prev) + link->prev->next = link->next; + else + { + parent->item_list = link->next; + parent->item_list->prev = NULL; + } + + link->prev = before; + link->next = before->next; + + link->prev->next = link; + + if (link->next) + link->next->prev = link; + else + parent->item_list_end = link; + } + return TRUE; +} + + +/** + * eel_canvas_item_raise: + * @item: A canvas item. + * @positions: Number of steps to raise the item. + * + * Raises the item in its parent's stack by the specified number of positions. + * If the number of positions is greater than the distance to the top of the + * stack, then the item is put at the top. + **/ +void +eel_canvas_item_raise (EelCanvasItem *item, int positions) +{ + GList *link, *before; + EelCanvasGroup *parent; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + g_return_if_fail (positions >= 0); + + if (!item->parent || positions == 0) + return; + + parent = EEL_CANVAS_GROUP (item->parent); + link = g_list_find (parent->item_list, item); + g_assert (link != NULL); + + for (before = link; positions && before; positions--) + before = before->next; + + if (!before) + before = parent->item_list_end; + + if (put_item_after (link, before)) + { + redraw_and_repick_if_mapped (item); + } +} + + +/** + * eel_canvas_item_lower: + * @item: A canvas item. + * @positions: Number of steps to lower the item. + * + * Lowers the item in its parent's stack by the specified number of positions. + * If the number of positions is greater than the distance to the bottom of the + * stack, then the item is put at the bottom. + **/ +void +eel_canvas_item_lower (EelCanvasItem *item, int positions) +{ + GList *link, *before; + EelCanvasGroup *parent; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + g_return_if_fail (positions >= 1); + + if (!item->parent || positions == 0) + return; + + parent = EEL_CANVAS_GROUP (item->parent); + link = g_list_find (parent->item_list, item); + g_assert (link != NULL); + + if (link->prev) + for (before = link->prev; positions && before; positions--) + before = before->prev; + else + before = NULL; + + if (put_item_after (link, before)) + { + redraw_and_repick_if_mapped (item); + } +} + + +/** + * eel_canvas_item_raise_to_top: + * @item: A canvas item. + * + * Raises an item to the top of its parent's stack. + **/ +void +eel_canvas_item_raise_to_top (EelCanvasItem *item) +{ + GList *link; + EelCanvasGroup *parent; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (!item->parent) + return; + + parent = EEL_CANVAS_GROUP (item->parent); + link = g_list_find (parent->item_list, item); + g_assert (link != NULL); + + if (put_item_after (link, parent->item_list_end)) + { + redraw_and_repick_if_mapped (item); + } +} + + +/** + * eel_canvas_item_lower_to_bottom: + * @item: A canvas item. + * + * Lowers an item to the bottom of its parent's stack. + **/ +void +eel_canvas_item_lower_to_bottom (EelCanvasItem *item) +{ + GList *link; + EelCanvasGroup *parent; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (!item->parent) + return; + + parent = EEL_CANVAS_GROUP (item->parent); + link = g_list_find (parent->item_list, item); + g_assert (link != NULL); + + if (put_item_after (link, NULL)) + { + redraw_and_repick_if_mapped (item); + } +} + +/** + * eel_canvas_item_send_behind: + * @item: A canvas item. + * @behind_item: The canvas item to put item behind, or NULL + * + * Moves item to a in the position in the stacking order so that + * it is placed immediately below behind_item, or at the top if + * behind_item is NULL. + **/ +void +eel_canvas_item_send_behind (EelCanvasItem *item, + EelCanvasItem *behind_item) +{ + GList *item_list; + int item_position, behind_position; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (behind_item == NULL) + { + eel_canvas_item_raise_to_top (item); + return; + } + + g_return_if_fail (EEL_IS_CANVAS_ITEM (behind_item)); + g_return_if_fail (item->parent == behind_item->parent); + + item_list = EEL_CANVAS_GROUP (item->parent)->item_list; + + item_position = g_list_index (item_list, item); + g_assert (item_position != -1); + behind_position = g_list_index (item_list, behind_item); + g_assert (behind_position != -1); + g_assert (item_position != behind_position); + + if (item_position == behind_position - 1) + { + return; + } + + if (item_position < behind_position) + { + eel_canvas_item_raise (item, (behind_position - 1) - item_position); + } + else + { + eel_canvas_item_lower (item, item_position - behind_position); + } +} + +/** + * eel_canvas_item_show: + * @item: A canvas item. + * + * Shows a canvas item. If the item was already shown, then no action is taken. + **/ +void +eel_canvas_item_show (EelCanvasItem *item) +{ + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (!(item->flags & EEL_CANVAS_ITEM_VISIBLE)) + { + item->flags |= EEL_CANVAS_ITEM_VISIBLE; + + if (!(item->flags & EEL_CANVAS_ITEM_REALIZED)) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item); + + if (item->parent != NULL) + { + if (!(item->flags & EEL_CANVAS_ITEM_MAPPED) && + item->parent->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item); + } + else + { + if (!(item->flags & EEL_CANVAS_ITEM_MAPPED) && + gtk_widget_get_mapped (GTK_WIDGET (item->canvas))) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item); + } + + redraw_and_repick_if_mapped (item); + } +} + + +/** + * eel_canvas_item_hide: + * @item: A canvas item. + * + * Hides a canvas item. If the item was already hidden, then no action is + * taken. + **/ +void +eel_canvas_item_hide (EelCanvasItem *item) +{ + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (item->flags & EEL_CANVAS_ITEM_VISIBLE) + { + item->flags &= ~EEL_CANVAS_ITEM_VISIBLE; + + redraw_and_repick_if_mapped (item); + + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); + + /* No need to unrealize when we just want to hide */ + } +} + + +/** + * eel_canvas_item_grab: + * @item: A canvas item. + * @event_mask: Mask of events that will be sent to this item. + * @cursor: If non-NULL, the cursor that will be used while the grab is active. + * @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME. + * + * Specifies that all events that match the specified event mask should be sent + * to the specified item, and also grabs the mouse by calling + * gdk_pointer_grab(). The event mask is also used when grabbing the pointer. + * If @cursor is not NULL, then that cursor is used while the grab is active. + * The @etime parameter is the timestamp required for grabbing the mouse. + * + * Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED. If + * the specified item was hidden by calling eel_canvas_item_hide(), then it + * returns %GDK_GRAB_NOT_VIEWABLE. Else, it returns the result of calling + * gdk_pointer_grab(). + **/ +int +eel_canvas_item_grab (EelCanvasItem *item, guint event_mask, GdkCursor *cursor, guint32 etime) +{ + int retval; + + g_return_val_if_fail (EEL_IS_CANVAS_ITEM (item), GDK_GRAB_NOT_VIEWABLE); + g_return_val_if_fail (gtk_widget_get_mapped (GTK_WIDGET (item->canvas)), + GDK_GRAB_NOT_VIEWABLE); + + if (item->canvas->grabbed_item) + return GDK_GRAB_ALREADY_GRABBED; + + if (!(item->flags & EEL_CANVAS_ITEM_MAPPED)) + return GDK_GRAB_NOT_VIEWABLE; + + retval = gdk_pointer_grab (gtk_layout_get_bin_window (&item->canvas->layout), + FALSE, + event_mask, + NULL, + cursor, + etime); + + if (retval != GDK_GRAB_SUCCESS) + return retval; + + item->canvas->grabbed_item = item; + item->canvas->grabbed_event_mask = event_mask; + item->canvas->current_item = item; /* So that events go to the grabbed item */ + + return retval; +} + + +/** + * eel_canvas_item_ungrab: + * @item: A canvas item that holds a grab. + * @etime: The timestamp for ungrabbing the mouse. + * + * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the + * mouse. + **/ +void +eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime) +{ + GdkDisplay *display; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + if (item->canvas->grabbed_item != item) + return; + + display = gtk_widget_get_display (GTK_WIDGET (item->canvas)); + item->canvas->grabbed_item = NULL; + gdk_display_pointer_ungrab (display, etime); +} + + +/** + * eel_canvas_item_w2i: + * @item: A canvas item. + * @x: X coordinate to convert (input/output value). + * @y: Y coordinate to convert (input/output value). + * + * Converts a coordinate pair from world coordinates to item-relative + * coordinates. + **/ +void +eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y) +{ + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + g_return_if_fail (x != NULL); + g_return_if_fail (y != NULL); + + item = item->parent; + while (item) + { + if (EEL_IS_CANVAS_GROUP (item)) + { + *x -= EEL_CANVAS_GROUP (item)->xpos; + *y -= EEL_CANVAS_GROUP (item)->ypos; + } + + item = item->parent; + } +} + + +/** + * eel_canvas_item_i2w: + * @item: A canvas item. + * @x: X coordinate to convert (input/output value). + * @y: Y coordinate to convert (input/output value). + * + * Converts a coordinate pair from item-relative coordinates to world + * coordinates. + **/ +void +eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y) +{ + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + g_return_if_fail (x != NULL); + g_return_if_fail (y != NULL); + + item = item->parent; + while (item) + { + if (EEL_IS_CANVAS_GROUP (item)) + { + *x += EEL_CANVAS_GROUP (item)->xpos; + *y += EEL_CANVAS_GROUP (item)->ypos; + } + + item = item->parent; + } +} + +/* Returns whether the item is an inferior of or is equal to the parent. */ +static int +is_descendant (EelCanvasItem *item, EelCanvasItem *parent) +{ + for (; item; item = item->parent) + if (item == parent) + return TRUE; + + return FALSE; +} + +/** + * eel_canvas_item_reparent: + * @item: A canvas item. + * @new_group: A canvas group. + * + * Changes the parent of the specified item to be the new group. The item keeps + * its group-relative coordinates as for its old parent, so the item may change + * its absolute position within the canvas. + **/ +void +eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group) +{ + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + g_return_if_fail (EEL_IS_CANVAS_GROUP (new_group)); + + /* Both items need to be in the same canvas */ + g_return_if_fail (item->canvas == EEL_CANVAS_ITEM (new_group)->canvas); + + /* The group cannot be an inferior of the item or be the item itself -- + * this also takes care of the case where the item is the root item of + * the canvas. */ + g_return_if_fail (!is_descendant (EEL_CANVAS_ITEM (new_group), item)); + + /* Everything is ok, now actually reparent the item */ + + g_object_ref (G_OBJECT (item)); /* protect it from the unref in group_remove */ + + eel_canvas_item_request_redraw (item); + + group_remove (EEL_CANVAS_GROUP (item->parent), item); + item->parent = EEL_CANVAS_ITEM (new_group); + /* item->canvas is unchanged. */ + group_add (new_group, item); + + /* Redraw and repick */ + + redraw_and_repick_if_mapped (item); + + g_object_unref (G_OBJECT (item)); +} + +/** + * eel_canvas_item_grab_focus: + * @item: A canvas item. + * + * Makes the specified item take the keyboard focus, so all keyboard events will + * be sent to it. If the canvas widget itself did not have the focus, it grabs + * it as well. + **/ +void +eel_canvas_item_grab_focus (EelCanvasItem *item) +{ + EelCanvasItem *focused_item; + GdkEvent ev; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))); + + focused_item = item->canvas->focused_item; + + if (focused_item) + { + ev.focus_change.type = GDK_FOCUS_CHANGE; + ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)); + ev.focus_change.send_event = FALSE; + ev.focus_change.in = FALSE; + + emit_event (item->canvas, &ev); + } + + item->canvas->focused_item = item; + gtk_widget_grab_focus (GTK_WIDGET (item->canvas)); + + if (focused_item) + { + ev.focus_change.type = GDK_FOCUS_CHANGE; + ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)); + ev.focus_change.send_event = FALSE; + ev.focus_change.in = TRUE; + + emit_event (item->canvas, &ev); + } +} + + +/** + * eel_canvas_item_get_bounds: + * @item: A canvas item. + * @x1: Leftmost edge of the bounding box (return value). + * @y1: Upper edge of the bounding box (return value). + * @x2: Rightmost edge of the bounding box (return value). + * @y2: Lower edge of the bounding box (return value). + * + * Queries the bounding box of a canvas item. The bounds are returned in the + * coordinate system of the item's parent. + **/ +void +eel_canvas_item_get_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + double tx1, ty1, tx2, ty2; + + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + tx1 = ty1 = tx2 = ty2 = 0.0; + + /* Get the item's bounds in its coordinate system */ + + if (EEL_CANVAS_ITEM_GET_CLASS (item)->bounds) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->bounds) (item, &tx1, &ty1, &tx2, &ty2); + + /* Return the values */ + + if (x1) + *x1 = tx1; + + if (y1) + *y1 = ty1; + + if (x2) + *x2 = tx2; + + if (y2) + *y2 = ty2; +} + + +/** + * eel_canvas_item_request_update + * @item: A canvas item. + * + * To be used only by item implementations. Requests that the canvas queue an + * update for the specified item. + **/ +void +eel_canvas_item_request_update (EelCanvasItem *item) +{ + if (NULL == item->canvas) + return; + + g_return_if_fail (!item->canvas->doing_update); + + if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE) + return; + + item->flags |= EEL_CANVAS_ITEM_NEED_UPDATE; + + if (item->parent != NULL) + { + /* Recurse up the tree */ + eel_canvas_item_request_update (item->parent); + } + else + { + /* Have reached the top of the tree, make sure the update call gets scheduled. */ + eel_canvas_request_update (item->canvas); + } +} + +/** + * eel_canvas_item_request_update + * @item: A canvas item. + * + * Convenience function that informs a canvas that the specified item needs + * to be repainted. To be used by item implementations + **/ +void +eel_canvas_item_request_redraw (EelCanvasItem *item) +{ + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + eel_canvas_request_redraw (item->canvas, + item->x1, item->y1, + item->x2 + 1, item->y2 + 1); +} + + + +/*** EelCanvasGroup ***/ + + +enum +{ + GROUP_PROP_0, + GROUP_PROP_X, + GROUP_PROP_Y +}; + + +static void eel_canvas_group_class_init (EelCanvasGroupClass *klass); +static void eel_canvas_group_init (EelCanvasGroup *group); +static void eel_canvas_group_set_property(GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void eel_canvas_group_get_property(GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void eel_canvas_group_destroy (GtkObject *object); + +static void eel_canvas_group_update (EelCanvasItem *item, + double i2w_dx, + double i2w_dy, + int flags); +static void eel_canvas_group_unrealize (EelCanvasItem *item); +static void eel_canvas_group_map (EelCanvasItem *item); +static void eel_canvas_group_unmap (EelCanvasItem *item); +static void eel_canvas_group_draw (EelCanvasItem *item, GdkDrawable *drawable, + GdkEventExpose *expose); +static double eel_canvas_group_point (EelCanvasItem *item, double x, double y, + int cx, int cy, + EelCanvasItem **actual_item); +static void eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy); +static void eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1, + double *x2, double *y2); + + +static EelCanvasItemClass *group_parent_class; + + +/** + * eel_canvas_group_get_type: + * + * Registers the &EelCanvasGroup class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &EelCanvasGroup class. + **/ +GType +eel_canvas_group_get_type (void) +{ + static GType group_type = 0; + + if (!group_type) + { + static const GTypeInfo group_info = + { + sizeof (EelCanvasGroupClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_group_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EelCanvasGroup), + 0, /* n_preallocs */ + (GInstanceInitFunc) eel_canvas_group_init + + + }; + + group_type = g_type_register_static (eel_canvas_item_get_type (), + "EelCanvasGroup", + &group_info, + 0); + } + + return group_type; +} + +/* Class initialization function for EelCanvasGroupClass */ +static void +eel_canvas_group_class_init (EelCanvasGroupClass *klass) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + EelCanvasItemClass *item_class; + + gobject_class = (GObjectClass *) klass; + object_class = (GtkObjectClass *) klass; + item_class = (EelCanvasItemClass *) klass; + + group_parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = eel_canvas_group_set_property; + gobject_class->get_property = eel_canvas_group_get_property; + + g_object_class_install_property + (gobject_class, GROUP_PROP_X, + g_param_spec_double ("x", + _("X"), + _("X"), + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, GROUP_PROP_Y, + g_param_spec_double ("y", + _("Y"), + _("Y"), + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE)); + + object_class->destroy = eel_canvas_group_destroy; + + item_class->update = eel_canvas_group_update; + item_class->unrealize = eel_canvas_group_unrealize; + item_class->map = eel_canvas_group_map; + item_class->unmap = eel_canvas_group_unmap; + item_class->draw = eel_canvas_group_draw; + item_class->point = eel_canvas_group_point; + item_class->translate = eel_canvas_group_translate; + item_class->bounds = eel_canvas_group_bounds; +} + +/* Object initialization function for EelCanvasGroup */ +static void +eel_canvas_group_init (EelCanvasGroup *group) +{ + group->xpos = 0.0; + group->ypos = 0.0; +} + +/* Set_property handler for canvas groups */ +static void +eel_canvas_group_set_property (GObject *gobject, guint param_id, + const GValue *value, GParamSpec *pspec) +{ + EelCanvasItem *item; + EelCanvasGroup *group; + double old; + gboolean moved; + + g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject)); + + item = EEL_CANVAS_ITEM (gobject); + group = EEL_CANVAS_GROUP (gobject); + + moved = FALSE; + switch (param_id) + { + case GROUP_PROP_X: + old = group->xpos; + group->xpos = g_value_get_double (value); + if (old != group->xpos) + moved = TRUE; + break; + + case GROUP_PROP_Y: + old = group->ypos; + group->ypos = g_value_get_double (value); + if (old != group->ypos) + moved = TRUE; + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); + break; + } + + if (moved) + { + item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; + if (item->parent != NULL) + eel_canvas_item_request_update (item->parent); + else + eel_canvas_request_update (item->canvas); + } +} + +/* Get_property handler for canvas groups */ +static void +eel_canvas_group_get_property (GObject *gobject, guint param_id, + GValue *value, GParamSpec *pspec) +{ + EelCanvasItem *item; + EelCanvasGroup *group; + + g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject)); + + item = EEL_CANVAS_ITEM (gobject); + group = EEL_CANVAS_GROUP (gobject); + + switch (param_id) + { + case GROUP_PROP_X: + g_value_set_double (value, group->xpos); + break; + + case GROUP_PROP_Y: + g_value_set_double (value, group->ypos); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec); + break; + } +} + +/* Destroy handler for canvas groups */ +static void +eel_canvas_group_destroy (GtkObject *object) +{ + EelCanvasGroup *group; + EelCanvasItem *child; + GList *list; + + g_return_if_fail (EEL_IS_CANVAS_GROUP (object)); + + group = EEL_CANVAS_GROUP (object); + + list = group->item_list; + while (list) + { + child = list->data; + list = list->next; + + gtk_object_destroy (GTK_OBJECT (child)); + } + + if (GTK_OBJECT_CLASS (group_parent_class)->destroy) + (* GTK_OBJECT_CLASS (group_parent_class)->destroy) (object); +} + +/* Update handler for canvas groups */ +static void +eel_canvas_group_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags) +{ + EelCanvasGroup *group; + GList *list; + EelCanvasItem *i; + double bbox_x0, bbox_y0, bbox_x1, bbox_y1; + gboolean first = TRUE; + + group = EEL_CANVAS_GROUP (item); + + (* group_parent_class->update) (item, i2w_dx, i2w_dy, flags); + + bbox_x0 = 0; + bbox_y0 = 0; + bbox_x1 = 0; + bbox_y1 = 0; + + for (list = group->item_list; list; list = list->next) + { + i = list->data; + + eel_canvas_item_invoke_update (i, i2w_dx + group->xpos, i2w_dy + group->ypos, flags); + + if (first) + { + first = FALSE; + bbox_x0 = i->x1; + bbox_y0 = i->y1; + bbox_x1 = i->x2; + bbox_y1 = i->y2; + } + else + { + bbox_x0 = MIN (bbox_x0, i->x1); + bbox_y0 = MIN (bbox_y0, i->y1); + bbox_x1 = MAX (bbox_x1, i->x2); + bbox_y1 = MAX (bbox_y1, i->y2); + } + } + item->x1 = bbox_x0; + item->y1 = bbox_y0; + item->x2 = bbox_x1; + item->y2 = bbox_y1; +} + +/* Unrealize handler for canvas groups */ +static void +eel_canvas_group_unrealize (EelCanvasItem *item) +{ + EelCanvasGroup *group; + GList *list; + EelCanvasItem *i; + + group = EEL_CANVAS_GROUP (item); + + /* Unmap group before children to avoid flash */ + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); + + for (list = group->item_list; list; list = list->next) + { + i = list->data; + + if (i->flags & EEL_CANVAS_ITEM_REALIZED) + (* EEL_CANVAS_ITEM_GET_CLASS (i)->unrealize) (i); + } + + (* group_parent_class->unrealize) (item); +} + +/* Map handler for canvas groups */ +static void +eel_canvas_group_map (EelCanvasItem *item) +{ + EelCanvasGroup *group; + GList *list; + EelCanvasItem *i; + + group = EEL_CANVAS_GROUP (item); + + for (list = group->item_list; list; list = list->next) + { + i = list->data; + + if (i->flags & EEL_CANVAS_ITEM_VISIBLE && + !(i->flags & EEL_CANVAS_ITEM_MAPPED)) + { + if (!(i->flags & EEL_CANVAS_ITEM_REALIZED)) + (* EEL_CANVAS_ITEM_GET_CLASS (i)->realize) (i); + + (* EEL_CANVAS_ITEM_GET_CLASS (i)->map) (i); + } + } + + (* group_parent_class->map) (item); +} + +/* Unmap handler for canvas groups */ +static void +eel_canvas_group_unmap (EelCanvasItem *item) +{ + EelCanvasGroup *group; + GList *list; + EelCanvasItem *i; + + group = EEL_CANVAS_GROUP (item); + + for (list = group->item_list; list; list = list->next) + { + i = list->data; + + if (i->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (i)->unmap) (i); + } + + (* group_parent_class->unmap) (item); +} + +/* Draw handler for canvas groups */ +static void +eel_canvas_group_draw (EelCanvasItem *item, GdkDrawable *drawable, + GdkEventExpose *expose) +{ + EelCanvasGroup *group; + GList *list; + EelCanvasItem *child = NULL; + + group = EEL_CANVAS_GROUP (item); + + for (list = group->item_list; list; list = list->next) + { + child = list->data; + + if ((child->flags & EEL_CANVAS_ITEM_MAPPED) && + (EEL_CANVAS_ITEM_GET_CLASS (child)->draw)) + { + GdkRectangle child_rect; + + child_rect.x = child->x1; + child_rect.y = child->y1; + child_rect.width = child->x2 - child->x1 + 1; + child_rect.height = child->y2 - child->y1 + 1; + + if (gdk_region_rect_in (expose->region, &child_rect) != GDK_OVERLAP_RECTANGLE_OUT) + (* EEL_CANVAS_ITEM_GET_CLASS (child)->draw) (child, drawable, expose); + } + } +} + +/* Point handler for canvas groups */ +static double +eel_canvas_group_point (EelCanvasItem *item, double x, double y, int cx, int cy, + EelCanvasItem **actual_item) +{ + EelCanvasGroup *group; + GList *list; + EelCanvasItem *child, *point_item; + int x1, y1, x2, y2; + double gx, gy; + double dist, best; + int has_point; + + group = EEL_CANVAS_GROUP (item); + + x1 = cx - item->canvas->close_enough; + y1 = cy - item->canvas->close_enough; + x2 = cx + item->canvas->close_enough; + y2 = cy + item->canvas->close_enough; + + best = 0.0; + *actual_item = NULL; + + gx = x - group->xpos; + gy = y - group->ypos; + + dist = 0.0; /* keep gcc happy */ + + for (list = group->item_list; list; list = list->next) + { + child = list->data; + + if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1)) + continue; + + point_item = NULL; /* cater for incomplete item implementations */ + + if ((child->flags & EEL_CANVAS_ITEM_MAPPED) + && EEL_CANVAS_ITEM_GET_CLASS (child)->point) + { + dist = eel_canvas_item_invoke_point (child, gx, gy, cx, cy, &point_item); + has_point = TRUE; + } + else + has_point = FALSE; + + if (has_point + && point_item + && ((int) (dist * item->canvas->pixels_per_unit + 0.5) + <= item->canvas->close_enough)) + { + best = dist; + *actual_item = point_item; + } + } + + return best; +} + +void +eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy) +{ + EelCanvasGroup *group; + + group = EEL_CANVAS_GROUP (item); + + group->xpos += dx; + group->ypos += dy; +} + +/* Bounds handler for canvas groups */ +static void +eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + EelCanvasGroup *group; + EelCanvasItem *child; + GList *list; + double tx1, ty1, tx2, ty2; + double minx, miny, maxx, maxy; + int set; + + group = EEL_CANVAS_GROUP (item); + + /* Get the bounds of the first visible item */ + + child = NULL; /* Unnecessary but eliminates a warning. */ + + set = FALSE; + + for (list = group->item_list; list; list = list->next) + { + child = list->data; + + if (child->flags & EEL_CANVAS_ITEM_MAPPED) + { + set = TRUE; + eel_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy); + break; + } + } + + /* If there were no visible items, return an empty bounding box */ + + if (!set) + { + *x1 = *y1 = *x2 = *y2 = 0.0; + return; + } + + /* Now we can grow the bounds using the rest of the items */ + + list = list->next; + + for (; list; list = list->next) + { + child = list->data; + + if (!(child->flags & EEL_CANVAS_ITEM_MAPPED)) + continue; + + eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2); + + if (tx1 < minx) + minx = tx1; + + if (ty1 < miny) + miny = ty1; + + if (tx2 > maxx) + maxx = tx2; + + if (ty2 > maxy) + maxy = ty2; + } + + /* Make the bounds be relative to our parent's coordinate system */ + + if (item->parent) + { + minx += group->xpos; + miny += group->ypos; + maxx += group->xpos; + maxy += group->ypos; + } + + *x1 = minx; + *y1 = miny; + *x2 = maxx; + *y2 = maxy; +} + +/* Adds an item to a group */ +static void +group_add (EelCanvasGroup *group, EelCanvasItem *item) +{ +#if GLIB_CHECK_VERSION(2,10,0) && GTK_CHECK_VERSION(2,8,14) + g_object_ref_sink (item); +#else + g_object_ref (item); + gtk_object_sink (GTK_OBJECT (item)); +#endif + + if (!group->item_list) + { + group->item_list = g_list_append (group->item_list, item); + group->item_list_end = group->item_list; + } + else + group->item_list_end = g_list_append (group->item_list_end, item)->next; + + if (item->flags & EEL_CANVAS_ITEM_VISIBLE && + group->item.flags & EEL_CANVAS_ITEM_MAPPED) + { + if (!(item->flags & EEL_CANVAS_ITEM_REALIZED)) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item); + + if (!(item->flags & EEL_CANVAS_ITEM_MAPPED)) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item); + } +} + +/* Removes an item from a group */ +static void +group_remove (EelCanvasGroup *group, EelCanvasItem *item) +{ + GList *children; + + g_return_if_fail (EEL_IS_CANVAS_GROUP (group)); + g_return_if_fail (EEL_IS_CANVAS_ITEM (item)); + + for (children = group->item_list; children; children = children->next) + if (children->data == item) + { + if (item->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item); + + if (item->flags & EEL_CANVAS_ITEM_REALIZED) + (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item); + + /* Unparent the child */ + + item->parent = NULL; + /* item->canvas = NULL; */ + g_object_unref (G_OBJECT (item)); + + /* Remove it from the list */ + + if (children == group->item_list_end) + group->item_list_end = children->prev; + + group->item_list = g_list_remove_link (group->item_list, children); + g_list_free (children); + break; + } +} + + +/*** EelCanvas ***/ + + +enum +{ + DRAW_BACKGROUND, + LAST_SIGNAL +}; + +static void eel_canvas_class_init (EelCanvasClass *klass); +static void eel_canvas_init (EelCanvas *canvas); +static void eel_canvas_destroy (GtkObject *object); +static void eel_canvas_map (GtkWidget *widget); +static void eel_canvas_unmap (GtkWidget *widget); +static void eel_canvas_realize (GtkWidget *widget); +static void eel_canvas_unrealize (GtkWidget *widget); +static void eel_canvas_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint eel_canvas_button (GtkWidget *widget, + GdkEventButton *event); +static gint eel_canvas_motion (GtkWidget *widget, + GdkEventMotion *event); +static gint eel_canvas_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint eel_canvas_key (GtkWidget *widget, + GdkEventKey *event); +static gint eel_canvas_crossing (GtkWidget *widget, + GdkEventCrossing *event); +static gint eel_canvas_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint eel_canvas_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void eel_canvas_request_update_real (EelCanvas *canvas); +static void eel_canvas_draw_background (EelCanvas *canvas, + int x, + int y, + int width, + int height); + + +static GtkLayoutClass *canvas_parent_class; + +static guint canvas_signals[LAST_SIGNAL]; + +/** + * eel_canvas_get_type: + * + * Registers the &EelCanvas class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &EelCanvas class. + **/ +GType +eel_canvas_get_type (void) +{ + static GType canvas_type = 0; + + if (!canvas_type) + { + static const GTypeInfo canvas_info = + { + sizeof (EelCanvasClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EelCanvas), + 0, /* n_preallocs */ + (GInstanceInitFunc) eel_canvas_init + }; + + canvas_type = g_type_register_static (gtk_layout_get_type (), + "EelCanvas", + &canvas_info, + 0); + } + + return canvas_type; +} + +static void +eel_canvas_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eel_canvas_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eel_canvas_accessible_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + AtkObject *atk_obj; + + /* The scrollbars have changed */ + atk_obj = ATK_OBJECT (data); + + g_signal_emit_by_name (atk_obj, "visible_data_changed"); +} + +static void +eel_canvas_accessible_initialize (AtkObject *obj, + gpointer data) +{ + EelCanvas *canvas; + + if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize != NULL) + ATK_OBJECT_CLASS (accessible_parent_class)->initialize (obj, data); + + canvas = EEL_CANVAS (data); + g_signal_connect (gtk_layout_get_hadjustment (&canvas->layout), + "value_changed", + G_CALLBACK (eel_canvas_accessible_adjustment_changed), + obj); + g_signal_connect (gtk_layout_get_vadjustment (&canvas->layout), + "value_changed", + G_CALLBACK (eel_canvas_accessible_adjustment_changed), + obj); + + obj->role = ATK_ROLE_LAYERED_PANE; +} + +static gint +eel_canvas_accessible_get_n_children (AtkObject* obj) +{ + GtkAccessible *accessible; + GtkWidget *widget; + EelCanvas *canvas; + EelCanvasGroup *root_group; + + accessible = GTK_ACCESSIBLE (obj); + widget = gtk_accessible_get_widget (accessible); + if (widget == NULL) + { + /* State is defunct */ + return 0; + } + + g_return_val_if_fail (EEL_IS_CANVAS (widget), 0); + + canvas = EEL_CANVAS (widget); + root_group = eel_canvas_root (canvas); + g_return_val_if_fail (root_group, 0); + return 1; +} + +static AtkObject* +eel_canvas_accessible_ref_child (AtkObject *obj, + gint i) +{ + GtkAccessible *accessible; + GtkWidget *widget; + EelCanvas *canvas; + EelCanvasGroup *root_group; + AtkObject *atk_object; + + /* Canvas only has one child, so return NULL if index is non zero */ + if (i != 0) + { + return NULL; + } + + accessible = GTK_ACCESSIBLE (obj); + widget = gtk_accessible_get_widget (accessible); + if (widget == NULL) + { + /* State is defunct */ + return NULL; + } + + canvas = EEL_CANVAS (widget); + root_group = eel_canvas_root (canvas); + g_return_val_if_fail (root_group, NULL); + atk_object = atk_gobject_accessible_for_object (G_OBJECT (root_group)); + g_object_ref (atk_object); + + g_warning ("Accessible support for FooGroup needs to be implemented"); + + return atk_object; +} + +static void +eel_canvas_accessible_class_init (AtkObjectClass *klass) +{ + accessible_parent_class = g_type_class_peek_parent (klass); + + klass->initialize = eel_canvas_accessible_initialize; + klass->get_n_children = eel_canvas_accessible_get_n_children; + klass->ref_child = eel_canvas_accessible_ref_child; +} + +static GType +eel_canvas_accessible_get_type (void) +{ + static GType type = 0; + + if (!type) + { + AtkObjectFactory *factory; + GType parent_atk_type; + GTypeQuery query; + GTypeInfo tinfo = { 0 }; + + factory = atk_registry_get_factory (atk_get_default_registry(), + GTK_TYPE_WIDGET); + if (!factory) + { + return G_TYPE_INVALID; + } + parent_atk_type = atk_object_factory_get_accessible_type (factory); + if (!parent_atk_type) + { + return G_TYPE_INVALID; + } + g_type_query (parent_atk_type, &query); + tinfo.class_init = (GClassInitFunc) eel_canvas_accessible_class_init; + tinfo.class_size = query.class_size; + tinfo.instance_size = query.instance_size; + type = g_type_register_static (parent_atk_type, + "EelCanvasAccessibility", + &tinfo, 0); + } + return type; +} + +static AtkObject * +eel_canvas_accessible_create (GObject *for_object) +{ + GType type; + AtkObject *accessible; + EelCanvas *canvas; + + canvas = EEL_CANVAS (for_object); + g_return_val_if_fail (canvas != NULL, NULL); + + type = eel_canvas_accessible_get_type (); + + if (type == G_TYPE_INVALID) + { + return atk_no_op_object_new (for_object); + } + + accessible = g_object_new (type, NULL); + atk_object_initialize (accessible, for_object); + return accessible; +} + +static GType +eel_canvas_accessible_factory_get_accessible_type (void) +{ + return eel_canvas_accessible_get_type (); +} + +static AtkObject* +eel_canvas_accessible_factory_create_accessible (GObject *obj) +{ + AtkObject *accessible; + + g_return_val_if_fail (G_IS_OBJECT (obj), NULL); + + accessible = eel_canvas_accessible_create (obj); + + return accessible; +} + +static void +eel_canvas_accessible_factory_class_init (AtkObjectFactoryClass *klass) +{ + klass->create_accessible = eel_canvas_accessible_factory_create_accessible; + klass->get_accessible_type = eel_canvas_accessible_factory_get_accessible_type; +} + +static GType +eel_canvas_accessible_factory_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo tinfo = + { + sizeof (AtkObjectFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_accessible_factory_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (AtkObjectFactory), + 0, /* n_preallocs */ + NULL + }; + type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, + "EelCanvasAccessibilityFactory", + &tinfo, 0); + } + + return type; +} + + +/* Class initialization function for EelCanvasClass */ +static void +eel_canvas_class_init (EelCanvasClass *klass) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + gobject_class = (GObjectClass *)klass; + object_class = (GtkObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + + canvas_parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = eel_canvas_set_property; + gobject_class->get_property = eel_canvas_get_property; + + object_class->destroy = eel_canvas_destroy; + + widget_class->map = eel_canvas_map; + widget_class->unmap = eel_canvas_unmap; + widget_class->realize = eel_canvas_realize; + widget_class->unrealize = eel_canvas_unrealize; + widget_class->size_allocate = eel_canvas_size_allocate; + widget_class->button_press_event = eel_canvas_button; + widget_class->button_release_event = eel_canvas_button; + widget_class->motion_notify_event = eel_canvas_motion; + widget_class->expose_event = eel_canvas_expose; + widget_class->key_press_event = eel_canvas_key; + widget_class->key_release_event = eel_canvas_key; + widget_class->enter_notify_event = eel_canvas_crossing; + widget_class->leave_notify_event = eel_canvas_crossing; + widget_class->focus_in_event = eel_canvas_focus_in; + widget_class->focus_out_event = eel_canvas_focus_out; + + klass->draw_background = eel_canvas_draw_background; + klass->request_update = eel_canvas_request_update_real; + + canvas_signals[DRAW_BACKGROUND] = + g_signal_new ("draw_background", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelCanvasClass, draw_background), + NULL, NULL, + eel_marshal_VOID__INT_INT_INT_INT, + G_TYPE_NONE, 4, + G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + + atk_registry_set_factory_type (atk_get_default_registry (), + EEL_TYPE_CANVAS, + eel_canvas_accessible_factory_get_type ()); +} + +/* Callback used when the root item of a canvas is destroyed. The user should + * never ever do this, so we panic if this happens. + */ +static void +panic_root_destroyed (GtkObject *object, gpointer data) +{ + g_error ("Eeeek, root item %p of canvas %p was destroyed!", object, data); +} + +/* Object initialization function for EelCanvas */ +static void +eel_canvas_init (EelCanvas *canvas) +{ + guint width, height; + gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE); + + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas), FALSE); + + canvas->scroll_x1 = 0.0; + canvas->scroll_y1 = 0.0; + gtk_layout_get_size (&canvas->layout, + &width, &height); + canvas->scroll_x2 = width; + canvas->scroll_y2 = height; + + canvas->pixels_per_unit = 1.0; + + canvas->pick_event.type = GDK_LEAVE_NOTIFY; + canvas->pick_event.crossing.x = 0; + canvas->pick_event.crossing.y = 0; + + gtk_layout_set_hadjustment (GTK_LAYOUT (canvas), NULL); + gtk_layout_set_vadjustment (GTK_LAYOUT (canvas), NULL); + + /* Create the root item as a special case */ + + canvas->root = EEL_CANVAS_ITEM (g_object_new (eel_canvas_group_get_type (), NULL)); + canvas->root->canvas = canvas; + +#if GLIB_CHECK_VERSION(2,10,0) && GTK_CHECK_VERSION(2,8,14) + g_object_ref_sink (canvas->root); +#else + g_object_ref (canvas->root); + gtk_object_sink (GTK_OBJECT (canvas->root)); +#endif + + canvas->root_destroy_id = g_signal_connect (G_OBJECT (canvas->root), + "destroy", G_CALLBACK (panic_root_destroyed), canvas); + + canvas->need_repick = TRUE; + canvas->doing_update = FALSE; +} + +/* Convenience function to remove the idle handler of a canvas */ +static void +remove_idle (EelCanvas *canvas) +{ + if (canvas->idle_id == 0) + return; + + g_source_remove (canvas->idle_id); + canvas->idle_id = 0; +} + +/* Removes the transient state of the canvas (idle handler, grabs). */ +static void +shutdown_transients (EelCanvas *canvas) +{ + /* We turn off the need_redraw flag, since if the canvas is mapped again + * it will request a redraw anyways. We do not turn off the need_update + * flag, though, because updates are not queued when the canvas remaps + * itself. + */ + if (canvas->need_redraw) + { + canvas->need_redraw = FALSE; + } + + if (canvas->grabbed_item) + { + GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (canvas)); + canvas->grabbed_item = NULL; + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + } + + remove_idle (canvas); +} + +/* Destroy handler for EelCanvas */ +static void +eel_canvas_destroy (GtkObject *object) +{ + EelCanvas *canvas; + + g_return_if_fail (EEL_IS_CANVAS (object)); + + /* remember, destroy can be run multiple times! */ + + canvas = EEL_CANVAS (object); + + if (canvas->root_destroy_id) + { + g_signal_handler_disconnect (G_OBJECT (canvas->root), canvas->root_destroy_id); + canvas->root_destroy_id = 0; + } + if (canvas->root) + { + EelCanvasItem *root = canvas->root; + canvas->root = NULL; + gtk_object_destroy (GTK_OBJECT (root)); + g_object_unref (root); + } + + shutdown_transients (canvas); + + if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy) + (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object); +} + +/** + * eel_canvas_new: + * @void: + * + * Creates a new empty canvas. If you wish to use the + * &EelCanvasImage item inside this canvas, then you must push the gdk_imlib + * visual and colormap before calling this function, and they can be popped + * afterwards. + * + * Return value: A newly-created canvas. + **/ +GtkWidget * +eel_canvas_new (void) +{ + return GTK_WIDGET (g_object_new (eel_canvas_get_type (), NULL)); +} + +/* Map handler for the canvas */ +static void +eel_canvas_map (GtkWidget *widget) +{ + EelCanvas *canvas; + + g_return_if_fail (EEL_IS_CANVAS (widget)); + + /* Normal widget mapping stuff */ + + if (GTK_WIDGET_CLASS (canvas_parent_class)->map) + (* GTK_WIDGET_CLASS (canvas_parent_class)->map) (widget); + + canvas = EEL_CANVAS (widget); + + /* Map items */ + + if (canvas->root->flags & EEL_CANVAS_ITEM_VISIBLE && + !(canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) && + EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->map) + (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->map) (canvas->root); +} + +/* Unmap handler for the canvas */ +static void +eel_canvas_unmap (GtkWidget *widget) +{ + EelCanvas *canvas; + + g_return_if_fail (EEL_IS_CANVAS (widget)); + + canvas = EEL_CANVAS (widget); + + shutdown_transients (canvas); + + /* Unmap items */ + + if (EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) + (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (canvas->root); + + /* Normal widget unmapping stuff */ + + if (GTK_WIDGET_CLASS (canvas_parent_class)->unmap) + (* GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (widget); +} + +/* Realize handler for the canvas */ +static void +eel_canvas_realize (GtkWidget *widget) +{ + EelCanvas *canvas; + + g_return_if_fail (EEL_IS_CANVAS (widget)); + + /* Normal widget realization stuff */ + + if (GTK_WIDGET_CLASS (canvas_parent_class)->realize) + (* GTK_WIDGET_CLASS (canvas_parent_class)->realize) (widget); + + canvas = EEL_CANVAS (widget); + + gdk_window_set_events (gtk_layout_get_bin_window (&canvas->layout), + (gdk_window_get_events (gtk_layout_get_bin_window (&canvas->layout)) + | GDK_EXPOSURE_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_KEY_PRESS_MASK + | GDK_KEY_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_FOCUS_CHANGE_MASK)); + + /* Create our own temporary pixmap gc and realize all the items */ + + canvas->pixmap_gc = gdk_gc_new (gtk_layout_get_bin_window (&canvas->layout)); + + (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->realize) (canvas->root); +} + +/* Unrealize handler for the canvas */ +static void +eel_canvas_unrealize (GtkWidget *widget) +{ + EelCanvas *canvas; + + g_return_if_fail (EEL_IS_CANVAS (widget)); + + canvas = EEL_CANVAS (widget); + + shutdown_transients (canvas); + + /* Unrealize items and parent widget */ + + (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unrealize) (canvas->root); + + g_object_unref (canvas->pixmap_gc); + canvas->pixmap_gc = NULL; + + if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) + (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget); +} + +/* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to + * keep as much as possible of the canvas scrolling region in view. + */ +static void +scroll_to (EelCanvas *canvas, int cx, int cy) +{ + int scroll_width, scroll_height; + int right_limit, bottom_limit; + int old_zoom_xofs, old_zoom_yofs; + int changed_x = FALSE, changed_y = FALSE; + int canvas_width, canvas_height; + GtkAllocation allocation; + GtkAdjustment *vadjustment, *hadjustment; + guint width, height; + + gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation); + canvas_width = allocation.width; + canvas_height = allocation.height; + + scroll_width = floor ((canvas->scroll_x2 - canvas->scroll_x1) * canvas->pixels_per_unit + 0.5); + scroll_height = floor ((canvas->scroll_y2 - canvas->scroll_y1) * canvas->pixels_per_unit + 0.5); + + right_limit = scroll_width - canvas_width; + bottom_limit = scroll_height - canvas_height; + + old_zoom_xofs = canvas->zoom_xofs; + old_zoom_yofs = canvas->zoom_yofs; + + if (right_limit < 0) + { + cx = 0; + if (canvas->center_scroll_region) + { + canvas->zoom_xofs = (canvas_width - scroll_width) / 2; + scroll_width = canvas_width; + } + else + { + canvas->zoom_xofs = 0; + } + } + else if (cx < 0) + { + cx = 0; + canvas->zoom_xofs = 0; + } + else if (cx > right_limit) + { + cx = right_limit; + canvas->zoom_xofs = 0; + } + else + canvas->zoom_xofs = 0; + + if (bottom_limit < 0) + { + cy = 0; + if (canvas->center_scroll_region) + { + canvas->zoom_yofs = (canvas_height - scroll_height) / 2; + scroll_height = canvas_height; + } + else + { + canvas->zoom_yofs = 0; + } + } + else if (cy < 0) + { + cy = 0; + canvas->zoom_yofs = 0; + } + else if (cy > bottom_limit) + { + cy = bottom_limit; + canvas->zoom_yofs = 0; + } + else + canvas->zoom_yofs = 0; + + if ((canvas->zoom_xofs != old_zoom_xofs) || (canvas->zoom_yofs != old_zoom_yofs)) + { + /* This can only occur, if either canvas size or widget size changes */ + /* So I think we can request full redraw here */ + /* More stuff - we have to mark root as needing fresh affine (Lauris) */ + if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) + { + canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; + eel_canvas_request_update (canvas); + } + gtk_widget_queue_draw (GTK_WIDGET (canvas)); + } + + hadjustment = gtk_layout_get_hadjustment (&canvas->layout); + vadjustment = gtk_layout_get_vadjustment (&canvas->layout); + + if (((int) gtk_adjustment_get_value (hadjustment)) != cx) + { + gtk_adjustment_set_value (hadjustment, cx); + changed_x = TRUE; + } + + if (((int) gtk_adjustment_get_value (vadjustment)) != cy) + { + gtk_adjustment_set_value (vadjustment, cy); + changed_y = TRUE; + } + + gtk_layout_get_size (&canvas->layout, &width, &height); + if ((scroll_width != (int) width )|| (scroll_height != (int) height)) + { + gtk_layout_set_size (GTK_LAYOUT (canvas), scroll_width, scroll_height); + } + + /* Signal GtkLayout that it should do a redraw. */ + if (changed_x) + g_signal_emit_by_name (hadjustment, "value_changed"); + if (changed_y) + g_signal_emit_by_name (vadjustment, "value_changed"); +} + +/* Size allocation handler for the canvas */ +static void +eel_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + EelCanvas *canvas; + GtkAdjustment *vadjustment, *hadjustment; + + g_return_if_fail (EEL_IS_CANVAS (widget)); + g_return_if_fail (allocation != NULL); + + if (GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) + (* GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (widget, allocation); + + canvas = EEL_CANVAS (widget); + + /* Recenter the view, if appropriate */ + + hadjustment = gtk_layout_get_hadjustment (&canvas->layout); + vadjustment = gtk_layout_get_vadjustment (&canvas->layout); + + gtk_adjustment_set_page_size (hadjustment, allocation->width); + gtk_adjustment_set_page_increment (hadjustment, allocation->width / 2); + + gtk_adjustment_set_page_size (vadjustment, allocation->height); + gtk_adjustment_set_page_increment (vadjustment, allocation->height / 2); + + scroll_to (canvas, + gtk_adjustment_get_value (hadjustment), + gtk_adjustment_get_value (vadjustment)); + + g_signal_emit_by_name (hadjustment, "changed"); + g_signal_emit_by_name (vadjustment, "changed"); +} + +/* Emits an event for an item in the canvas, be it the current item, grabbed + * item, or focused item, as appropriate. + */ + +static int +emit_event (EelCanvas *canvas, GdkEvent *event) +{ + GdkEvent ev; + gint finished; + EelCanvasItem *item; + EelCanvasItem *parent; + guint mask; + + /* Could be an old pick event */ + if (!gtk_widget_get_realized (GTK_WIDGET (canvas))) + { + return FALSE; + } + + /* Perform checks for grabbed items */ + + if (canvas->grabbed_item && + !is_descendant (canvas->current_item, canvas->grabbed_item)) + { + return FALSE; + } + + if (canvas->grabbed_item) + { + switch (event->type) + { + case GDK_ENTER_NOTIFY: + mask = GDK_ENTER_NOTIFY_MASK; + break; + + case GDK_LEAVE_NOTIFY: + mask = GDK_LEAVE_NOTIFY_MASK; + break; + + case GDK_MOTION_NOTIFY: + mask = GDK_POINTER_MOTION_MASK; + break; + + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + mask = GDK_BUTTON_PRESS_MASK; + break; + + case GDK_BUTTON_RELEASE: + mask = GDK_BUTTON_RELEASE_MASK; + break; + + case GDK_KEY_PRESS: + mask = GDK_KEY_PRESS_MASK; + break; + + case GDK_KEY_RELEASE: + mask = GDK_KEY_RELEASE_MASK; + break; + + default: + mask = 0; + break; + } + + if (!(mask & canvas->grabbed_event_mask)) + return FALSE; + } + + /* Convert to world coordinates -- we have two cases because of diferent + * offsets of the fields in the event structures. + */ + + ev = *event; + + switch (ev.type) + { + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + eel_canvas_window_to_world (canvas, + ev.crossing.x, ev.crossing.y, + &ev.crossing.x, &ev.crossing.y); + break; + + case GDK_MOTION_NOTIFY: + eel_canvas_window_to_world (canvas, + ev.motion.x, ev.motion.y, + &ev.motion.x, &ev.motion.y); + break; + + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + eel_canvas_window_to_world (canvas, + ev.motion.x, ev.motion.y, + &ev.motion.x, &ev.motion.y); + break; + + case GDK_BUTTON_RELEASE: + eel_canvas_window_to_world (canvas, + ev.motion.x, ev.motion.y, + &ev.motion.x, &ev.motion.y); + break; + + default: + break; + } + + /* Choose where we send the event */ + + item = canvas->current_item; + + if (canvas->focused_item + && ((event->type == GDK_KEY_PRESS) || + (event->type == GDK_KEY_RELEASE) || + (event->type == GDK_FOCUS_CHANGE))) + item = canvas->focused_item; + + /* The event is propagated up the hierarchy (for if someone connected to + * a group instead of a leaf event), and emission is stopped if a + * handler returns TRUE, just like for GtkWidget events. + */ + + finished = FALSE; + + while (item && !finished) + { + g_object_ref (GTK_OBJECT (item)); + + g_signal_emit ( + G_OBJECT (item), item_signals[ITEM_EVENT], 0, + &ev, &finished); + + parent = item->parent; + g_object_unref (GTK_OBJECT (item)); + + item = parent; + } + + return finished; +} + +/* Re-picks the current item in the canvas, based on the event's coordinates. + * Also emits enter/leave events for items as appropriate. + */ +static int +pick_current_item (EelCanvas *canvas, GdkEvent *event) +{ + int button_down; + double x, y; + int cx, cy; + int retval; + + retval = FALSE; + + /* If a button is down, we'll perform enter and leave events on the + * current item, but not enter on any other item. This is more or less + * like X pointer grabbing for canvas items. + */ + button_down = canvas->state & (GDK_BUTTON1_MASK + | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK + | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK); + if (!button_down) + canvas->left_grabbed_item = FALSE; + + /* Save the event in the canvas. This is used to synthesize enter and + * leave events in case the current item changes. It is also used to + * re-pick the current item if the current one gets deleted. Also, + * synthesize an enter event. + */ + if (event != &canvas->pick_event) + { + if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) + { + /* these fields have the same offsets in both types of events */ + + canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY; + canvas->pick_event.crossing.window = event->motion.window; + canvas->pick_event.crossing.send_event = event->motion.send_event; + canvas->pick_event.crossing.subwindow = NULL; + canvas->pick_event.crossing.x = event->motion.x; + canvas->pick_event.crossing.y = event->motion.y; + canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL; + canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR; + canvas->pick_event.crossing.focus = FALSE; + canvas->pick_event.crossing.state = event->motion.state; + + /* these fields don't have the same offsets in both types of events */ + + if (event->type == GDK_MOTION_NOTIFY) + { + canvas->pick_event.crossing.x_root = event->motion.x_root; + canvas->pick_event.crossing.y_root = event->motion.y_root; + } + else + { + canvas->pick_event.crossing.x_root = event->button.x_root; + canvas->pick_event.crossing.y_root = event->button.y_root; + } + } + else + canvas->pick_event = *event; + } + + /* Don't do anything else if this is a recursive call */ + + if (canvas->in_repick) + return retval; + + /* LeaveNotify means that there is no current item, so we don't look for one */ + + if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) + { + /* these fields don't have the same offsets in both types of events */ + + if (canvas->pick_event.type == GDK_ENTER_NOTIFY) + { + x = canvas->pick_event.crossing.x; + y = canvas->pick_event.crossing.y; + } + else + { + x = canvas->pick_event.motion.x; + y = canvas->pick_event.motion.y; + } + + /* canvas pixel coords */ + + cx = (int) (x + 0.5); + cy = (int) (y + 0.5); + + /* world coords */ + eel_canvas_c2w (canvas, cx, cy, &x, &y); + + /* find the closest item */ + if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) + eel_canvas_item_invoke_point (canvas->root, x, y, cx, cy, + &canvas->new_current_item); + else + canvas->new_current_item = NULL; + } + else + canvas->new_current_item = NULL; + + if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item) + return retval; /* current item did not change */ + + /* Synthesize events for old and new current items */ + + if ((canvas->new_current_item != canvas->current_item) + && (canvas->current_item != NULL) + && !canvas->left_grabbed_item) + { + GdkEvent new_event; + EelCanvasItem *item; + + item = canvas->current_item; + + new_event = canvas->pick_event; + new_event.type = GDK_LEAVE_NOTIFY; + + new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; + new_event.crossing.subwindow = NULL; + canvas->in_repick = TRUE; + retval = emit_event (canvas, &new_event); + canvas->in_repick = FALSE; + } + + /* new_current_item may have been set to NULL during the call to emit_event() above */ + + if ((canvas->new_current_item != canvas->current_item) && button_down) + { + canvas->left_grabbed_item = TRUE; + return retval; + } + + /* Handle the rest of cases */ + + canvas->left_grabbed_item = FALSE; + canvas->current_item = canvas->new_current_item; + + if (canvas->current_item != NULL) + { + GdkEvent new_event; + + new_event = canvas->pick_event; + new_event.type = GDK_ENTER_NOTIFY; + new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; + new_event.crossing.subwindow = NULL; + retval = emit_event (canvas, &new_event); + } + + return retval; +} + +/* Button event handler for the canvas */ +static gint +eel_canvas_button (GtkWidget *widget, GdkEventButton *event) +{ + EelCanvas *canvas; + int mask; + int retval; + + g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + retval = FALSE; + + canvas = EEL_CANVAS (widget); + + /* + * dispatch normally regardless of the event's window if an item has + * has a pointer grab in effect + */ + if (!canvas->grabbed_item && event->window != gtk_layout_get_bin_window (&canvas->layout)) + return retval; + + switch (event->button) + { + case 1: + mask = GDK_BUTTON1_MASK; + break; + case 2: + mask = GDK_BUTTON2_MASK; + break; + case 3: + mask = GDK_BUTTON3_MASK; + break; + case 4: + mask = GDK_BUTTON4_MASK; + break; + case 5: + mask = GDK_BUTTON5_MASK; + break; + default: + mask = 0; + } + + switch (event->type) + { + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + /* Pick the current item as if the button were not pressed, and + * then process the event. + */ + canvas->state = event->state; + pick_current_item (canvas, (GdkEvent *) event); + canvas->state ^= mask; + retval = emit_event (canvas, (GdkEvent *) event); + break; + + case GDK_BUTTON_RELEASE: + /* Process the event as if the button were pressed, then repick + * after the button has been released + */ + canvas->state = event->state; + retval = emit_event (canvas, (GdkEvent *) event); + event->state ^= mask; + canvas->state = event->state; + pick_current_item (canvas, (GdkEvent *) event); + event->state ^= mask; + break; + + default: + g_assert_not_reached (); + } + + return retval; +} + +/* Motion event handler for the canvas */ +static gint +eel_canvas_motion (GtkWidget *widget, GdkEventMotion *event) +{ + EelCanvas *canvas; + + g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + canvas = EEL_CANVAS (widget); + + if (event->window != gtk_layout_get_bin_window (&canvas->layout)) + return FALSE; + + canvas->state = event->state; + pick_current_item (canvas, (GdkEvent *) event); + return emit_event (canvas, (GdkEvent *) event); +} + +/* Key event handler for the canvas */ +static gint +eel_canvas_key (GtkWidget *widget, GdkEventKey *event) +{ + EelCanvas *canvas; + + g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + canvas = EEL_CANVAS (widget); + + if (emit_event (canvas, (GdkEvent *) event)) + return TRUE; + if (event->type == GDK_KEY_RELEASE) + return GTK_WIDGET_CLASS (canvas_parent_class)->key_release_event (widget, event); + else + return GTK_WIDGET_CLASS (canvas_parent_class)->key_press_event (widget, event); +} + + +/* Crossing event handler for the canvas */ +static gint +eel_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event) +{ + EelCanvas *canvas; + + g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + canvas = EEL_CANVAS (widget); + + if (event->window != gtk_layout_get_bin_window (&canvas->layout)) + return FALSE; + + canvas->state = event->state; + return pick_current_item (canvas, (GdkEvent *) event); +} + +/* Focus in handler for the canvas */ +static gint +eel_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event) +{ + EelCanvas *canvas; + + canvas = EEL_CANVAS (widget); + + if (canvas->focused_item) + return emit_event (canvas, (GdkEvent *) event); + else + return FALSE; +} + +/* Focus out handler for the canvas */ +static gint +eel_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event) +{ + EelCanvas *canvas; + + canvas = EEL_CANVAS (widget); + + if (canvas->focused_item) + return emit_event (canvas, (GdkEvent *) event); + else + return FALSE; +} + +/* Expose handler for the canvas */ +static gint +eel_canvas_expose (GtkWidget *widget, GdkEventExpose *event) +{ + EelCanvas *canvas; + + canvas = EEL_CANVAS (widget); + + if (!gtk_widget_is_drawable (widget) || (event->window != gtk_layout_get_bin_window (&canvas->layout))) return FALSE; + +#ifdef VERBOSE + g_print ("Expose\n"); +#endif + /* If there are any outstanding items that need updating, do them now */ + if (canvas->idle_id) + { + g_source_remove (canvas->idle_id); + canvas->idle_id = 0; + } + if (canvas->need_update) + { + g_return_val_if_fail (!canvas->doing_update, FALSE); + + canvas->doing_update = TRUE; + eel_canvas_item_invoke_update (canvas->root, 0, 0, 0); + + g_return_val_if_fail (canvas->doing_update, FALSE); + + canvas->doing_update = FALSE; + + canvas->need_update = FALSE; + } + + /* Hmmm. Would like to queue antiexposes if the update marked + anything that is gonna get redrawn as invalid */ + + + g_signal_emit (G_OBJECT (canvas), canvas_signals[DRAW_BACKGROUND], 0, + event->area.x, event->area.y, + event->area.width, event->area.height); + + if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) + (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->draw) (canvas->root, + gtk_layout_get_bin_window (&canvas->layout), + event); + + + + /* Chain up to get exposes on child widgets */ + GTK_WIDGET_CLASS (canvas_parent_class)->expose_event (widget, event); + + return FALSE; +} + +static void +eel_canvas_draw_background (EelCanvas *canvas, + int x, int y, int width, int height) +{ + /* By default, we use the style background. */ + gdk_gc_set_foreground (canvas->pixmap_gc, + >k_widget_get_style (GTK_WIDGET (canvas))->bg[GTK_STATE_NORMAL]); + gdk_draw_rectangle (gtk_layout_get_bin_window (&canvas->layout), + canvas->pixmap_gc, + TRUE, + x, y, + width, height); +} + +static void +do_update (EelCanvas *canvas) +{ + /* Cause the update if necessary */ + +update_again: + if (canvas->need_update) + { + g_return_if_fail (!canvas->doing_update); + + canvas->doing_update = TRUE; + eel_canvas_item_invoke_update (canvas->root, 0, 0, 0); + + g_return_if_fail (canvas->doing_update); + + canvas->doing_update = FALSE; + + canvas->need_update = FALSE; + } + + /* Pick new current item */ + + while (canvas->need_repick) + { + canvas->need_repick = FALSE; + pick_current_item (canvas, &canvas->pick_event); + } + + /* it is possible that during picking we emitted an event in which + the user then called some function which then requested update + of something. Without this we'd be left in a state where + need_update would have been left TRUE and the canvas would have + been left unpainted. */ + if (canvas->need_update) + { + goto update_again; + } +} + +/* Idle handler for the canvas. It deals with pending updates and redraws. */ +static gint +idle_handler (gpointer data) +{ + EelCanvas *canvas; + + GDK_THREADS_ENTER (); + + canvas = EEL_CANVAS (data); + do_update (canvas); + + /* Reset idle id */ + canvas->idle_id = 0; + + GDK_THREADS_LEAVE (); + + return FALSE; +} + +/* Convenience function to add an idle handler to a canvas */ +static void +add_idle (EelCanvas *canvas) +{ + if (!canvas->idle_id) + { + /* We let the update idle handler have higher priority + * than the redraw idle handler so the canvas state + * will be updated during the expose event. canvas in + * expose_event. + */ + canvas->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW - 20, + idle_handler, canvas, NULL); + } +} + +/** + * eel_canvas_root: + * @canvas: A canvas. + * + * Queries the root group of a canvas. + * + * Return value: The root group of the specified canvas. + **/ +EelCanvasGroup * +eel_canvas_root (EelCanvas *canvas) +{ + g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL); + + return EEL_CANVAS_GROUP (canvas->root); +} + + +/** + * eel_canvas_set_scroll_region: + * @canvas: A canvas. + * @x1: Leftmost limit of the scrolling region. + * @y1: Upper limit of the scrolling region. + * @x2: Rightmost limit of the scrolling region. + * @y2: Lower limit of the scrolling region. + * + * Sets the scrolling region of a canvas to the specified rectangle. The canvas + * will then be able to scroll only within this region. The view of the canvas + * is adjusted as appropriate to display as much of the new region as possible. + **/ +void +eel_canvas_set_scroll_region (EelCanvas *canvas, double x1, double y1, double x2, double y2) +{ + double wxofs, wyofs; + int xofs, yofs; + GtkAdjustment *vadjustment, *hadjustment; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + if ((canvas->scroll_x1 == x1) && (canvas->scroll_y1 == y1) && + (canvas->scroll_x2 == x2) && (canvas->scroll_y2 == y2)) + { + return; + } + + /* + * Set the new scrolling region. If possible, do not move the visible contents of the + * canvas. + */ + hadjustment = gtk_layout_get_hadjustment (GTK_LAYOUT (canvas)); + vadjustment = gtk_layout_get_vadjustment (GTK_LAYOUT (canvas)); + + eel_canvas_c2w (canvas, + gtk_adjustment_get_value (hadjustment) + canvas->zoom_xofs, + gtk_adjustment_get_value (vadjustment) + canvas->zoom_yofs, + /*canvas->zoom_xofs, + canvas->zoom_yofs,*/ + &wxofs, &wyofs); + + canvas->scroll_x1 = x1; + canvas->scroll_y1 = y1; + canvas->scroll_x2 = x2; + canvas->scroll_y2 = y2; + + eel_canvas_w2c (canvas, wxofs, wyofs, &xofs, &yofs); + + scroll_to (canvas, xofs, yofs); + + canvas->need_repick = TRUE; + + if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) + { + canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; + eel_canvas_request_update (canvas); + } +} + + +/** + * eel_canvas_get_scroll_region: + * @canvas: A canvas. + * @x1: Leftmost limit of the scrolling region (return value). + * @y1: Upper limit of the scrolling region (return value). + * @x2: Rightmost limit of the scrolling region (return value). + * @y2: Lower limit of the scrolling region (return value). + * + * Queries the scrolling region of a canvas. + **/ +void +eel_canvas_get_scroll_region (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2) +{ + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + if (x1) + *x1 = canvas->scroll_x1; + + if (y1) + *y1 = canvas->scroll_y1; + + if (x2) + *x2 = canvas->scroll_x2; + + if (y2) + *y2 = canvas->scroll_y2; +} + +void +eel_canvas_set_center_scroll_region (EelCanvas *canvas, + gboolean center_scroll_region) +{ + GtkAdjustment *vadjustment, *hadjustment; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + canvas->center_scroll_region = center_scroll_region != 0; + + hadjustment = gtk_layout_get_hadjustment (&canvas->layout); + vadjustment = gtk_layout_get_vadjustment (&canvas->layout); + + scroll_to (canvas, + gtk_adjustment_get_value (hadjustment), + gtk_adjustment_get_value (vadjustment)); +} + + +/** + * eel_canvas_set_pixels_per_unit: + * @canvas: A canvas. + * @n: The number of pixels that correspond to one canvas unit. + * + * Sets the zooming factor of a canvas by specifying the number of pixels that + * correspond to one canvas unit. + **/ +void +eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n) +{ + GtkWidget *widget; + double cx, cy; + int x1, y1; + int center_x, center_y; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + GtkAllocation allocation; + GtkAdjustment *vadjustment, *hadjustment; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + g_return_if_fail (n > EEL_CANVAS_EPSILON); + + widget = GTK_WIDGET (canvas); + + gtk_widget_get_allocation (widget, &allocation); + center_x = allocation.width / 2; + center_y = allocation.height / 2; + + /* Find the coordinates of the screen center in units. */ + hadjustment = gtk_layout_get_hadjustment (&canvas->layout); + vadjustment = gtk_layout_get_vadjustment (&canvas->layout); + cx = (gtk_adjustment_get_value (hadjustment) + center_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs; + cy = (gtk_adjustment_get_value (vadjustment) + center_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs; + + /* Now calculate the new offset of the upper left corner. (round not truncate) */ + x1 = ((cx - canvas->scroll_x1) * n) - center_x + .5; + y1 = ((cy - canvas->scroll_y1) * n) - center_y + .5; + + canvas->pixels_per_unit = n; + + if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) + { + canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE; + eel_canvas_request_update (canvas); + } + + /* Map a background None window over the bin_window to avoid + * scrolling the window scroll causing exposes. + */ + window = NULL; + if (gtk_widget_get_mapped (widget)) + { + GtkAllocation allocation; + attributes.window_type = GDK_WINDOW_CHILD; + gtk_widget_get_allocation (widget, &allocation); + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_back_pixmap (window, NULL, FALSE); + gdk_window_set_user_data (window, widget); + + gdk_window_show (window); + } + + scroll_to (canvas, x1, y1); + + /* If we created a an overlapping background None window, remove it how. + * + * TODO: We would like to temporarily set the bin_window background to + * None to avoid clearing the bin_window to the background, but gdk doesn't + * expose enought to let us do this, so we get a flash-effect here. At least + * it looks better than scroll + expose. + */ + if (window != NULL) + { + gdk_window_hide (window); + gdk_window_set_user_data (window, NULL); + gdk_window_destroy (window); + } + + canvas->need_repick = TRUE; +} + +/** + * eel_canvas_scroll_to: + * @canvas: A canvas. + * @cx: Horizontal scrolling offset in canvas pixel units. + * @cy: Vertical scrolling offset in canvas pixel units. + * + * Makes a canvas scroll to the specified offsets, given in canvas pixel units. + * The canvas will adjust the view so that it is not outside the scrolling + * region. This function is typically not used, as it is better to hook + * scrollbars to the canvas layout's scrolling adjusments. + **/ +void +eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy) +{ + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + scroll_to (canvas, cx, cy); +} + +/** + * eel_canvas_get_scroll_offsets: + * @canvas: A canvas. + * @cx: Horizontal scrolling offset (return value). + * @cy: Vertical scrolling offset (return value). + * + * Queries the scrolling offsets of a canvas. The values are returned in canvas + * pixel units. + **/ +void +eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy) +{ + GtkAdjustment *vadjustment, *hadjustment; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + hadjustment = gtk_layout_get_hadjustment (&canvas->layout); + vadjustment = gtk_layout_get_vadjustment (&canvas->layout); + + if (cx) + *cx = gtk_adjustment_get_value (hadjustment); + + if (cy) + *cy = gtk_adjustment_get_value (vadjustment); +} + +/** + * eel_canvas_update_now: + * @canvas: A canvas. + * + * Forces an immediate update and redraw of a canvas. If the canvas does not + * have any pending update or redraw requests, then no action is taken. This is + * typically only used by applications that need explicit control of when the + * display is updated, like games. It is not needed by normal applications. + */ +void +eel_canvas_update_now (EelCanvas *canvas) +{ + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + if (!(canvas->need_update || canvas->need_redraw)) + return; + remove_idle (canvas); + do_update (canvas); +} + +/** + * eel_canvas_get_item_at: + * @canvas: A canvas. + * @x: X position in world coordinates. + * @y: Y position in world coordinates. + * + * Looks for the item that is under the specified position, which must be + * specified in world coordinates. + * + * Return value: The sought item, or NULL if no item is at the specified + * coordinates. + **/ +EelCanvasItem * +eel_canvas_get_item_at (EelCanvas *canvas, double x, double y) +{ + EelCanvasItem *item; + double dist; + int cx, cy; + + g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL); + + eel_canvas_w2c (canvas, x, y, &cx, &cy); + + dist = eel_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &item); + if ((int) (dist * canvas->pixels_per_unit + 0.5) <= canvas->close_enough) + return item; + else + return NULL; +} + +/* Queues an update of the canvas */ +static void +eel_canvas_request_update (EelCanvas *canvas) +{ + EEL_CANVAS_GET_CLASS (canvas)->request_update (canvas); +} + +static void +eel_canvas_request_update_real (EelCanvas *canvas) +{ + canvas->need_update = TRUE; + add_idle (canvas); +} + +/** + * eel_canvas_request_redraw: + * @canvas: A canvas. + * @x1: Leftmost coordinate of the rectangle to be redrawn. + * @y1: Upper coordinate of the rectangle to be redrawn. + * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1. + * @y2: Lower coordinate of the rectangle to be redrawn, plus 1. + * + * Convenience function that informs a canvas that the specified rectangle needs + * to be repainted. The rectangle includes @x1 and @y1, but not @x2 and @y2. + * To be used only by item implementations. + **/ +void +eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2) +{ + GdkRectangle bbox; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + if (!gtk_widget_is_drawable (GTK_WIDGET (canvas)) + || (x1 >= x2) || (y1 >= y2)) return; + + bbox.x = x1; + bbox.y = y1; + bbox.width = x2 - x1; + bbox.height = y2 - y1; + + gdk_window_invalidate_rect (gtk_layout_get_bin_window (&canvas->layout), + &bbox, FALSE); +} + +/** + * eel_canvas_w2c: + * @canvas: A canvas. + * @wx: World X coordinate. + * @wy: World Y coordinate. + * @cx: X pixel coordinate (return value). + * @cy: Y pixel coordinate (return value). + * + * Converts world coordinates into canvas pixel coordinates. + **/ +void +eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy) +{ + double zoom; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + zoom = canvas->pixels_per_unit; + + if (cx) + *cx = floor ((wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs + 0.5); + if (cy) + *cy = floor ((wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs + 0.5); +} + +/** + * eel_canvas_w2c: + * @canvas: A canvas. + * @world: rectangle in world coordinates. + * @canvas: rectangle in canvase coordinates. + * + * Converts rectangles in world coordinates into canvas pixel coordinates. + **/ +void +eel_canvas_w2c_rect_d (EelCanvas *canvas, + double *x1, double *y1, + double *x2, double *y2) +{ + eel_canvas_w2c_d (canvas, + *x1, *y1, + x1, y1); + eel_canvas_w2c_d (canvas, + *x2, *y2, + x2, y2); +} + + + +/** + * eel_canvas_w2c_d: + * @canvas: A canvas. + * @wx: World X coordinate. + * @wy: World Y coordinate. + * @cx: X pixel coordinate (return value). + * @cy: Y pixel coordinate (return value). + * + * Converts world coordinates into canvas pixel coordinates. This version + * produces coordinates in floating point coordinates, for greater precision. + **/ +void +eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy) +{ + double zoom; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + zoom = canvas->pixels_per_unit; + + if (cx) + *cx = (wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs; + if (cy) + *cy = (wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs; +} + + +/** + * eel_canvas_c2w: + * @canvas: A canvas. + * @cx: Canvas pixel X coordinate. + * @cy: Canvas pixel Y coordinate. + * @wx: X world coordinate (return value). + * @wy: Y world coordinate (return value). + * + * Converts canvas pixel coordinates to world coordinates. + **/ +void +eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy) +{ + double zoom; + + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + zoom = canvas->pixels_per_unit; + + if (wx) + *wx = (cx - canvas->zoom_xofs)/zoom + canvas->scroll_x1; + if (wy) + *wy = (cy - canvas->zoom_yofs)/zoom + canvas->scroll_y1; +} + + +/** + * eel_canvas_window_to_world: + * @canvas: A canvas. + * @winx: Window-relative X coordinate. + * @winy: Window-relative Y coordinate. + * @worldx: X world coordinate (return value). + * @worldy: Y world coordinate (return value). + * + * Converts window-relative coordinates into world coordinates. You can use + * this when you need to convert mouse coordinates into world coordinates, for + * example. + * Window coordinates are really the same as canvas coordinates now, but this + * function is here for backwards compatibility reasons. + **/ +void +eel_canvas_window_to_world (EelCanvas *canvas, double winx, double winy, + double *worldx, double *worldy) +{ + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + if (worldx) + *worldx = canvas->scroll_x1 + ((winx - canvas->zoom_xofs) + / canvas->pixels_per_unit); + + if (worldy) + *worldy = canvas->scroll_y1 + ((winy - canvas->zoom_yofs) + / canvas->pixels_per_unit); +} + + +/** + * eel_canvas_world_to_window: + * @canvas: A canvas. + * @worldx: World X coordinate. + * @worldy: World Y coordinate. + * @winx: X window-relative coordinate. + * @winy: Y window-relative coordinate. + * + * Converts world coordinates into window-relative coordinates. + * Window coordinates are really the same as canvas coordinates now, but this + * function is here for backwards compatibility reasons. + **/ +void +eel_canvas_world_to_window (EelCanvas *canvas, double worldx, double worldy, + double *winx, double *winy) +{ + g_return_if_fail (EEL_IS_CANVAS (canvas)); + + if (winx) + *winx = (canvas->pixels_per_unit)*(worldx - canvas->scroll_x1) + canvas->zoom_xofs; + + if (winy) + *winy = (canvas->pixels_per_unit)*(worldy - canvas->scroll_y1) + canvas->zoom_yofs; +} + + + +/** + * eel_canvas_get_color: + * @canvas: A canvas. + * @spec: X color specification, or NULL for "transparent". + * @color: Returns the allocated color. + * + * Allocates a color based on the specified X color specification. As a + * convenience to item implementations, it returns TRUE if the color was + * allocated, or FALSE if the specification was NULL. A NULL color + * specification is considered as "transparent" by the canvas. + * + * Return value: TRUE if @spec is non-NULL and the color is allocated. If @spec + * is NULL, then returns FALSE. + **/ +int +eel_canvas_get_color (EelCanvas *canvas, const char *spec, GdkColor *color) +{ + GdkColormap *colormap; + + g_return_val_if_fail (EEL_IS_CANVAS (canvas), FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + if (!spec) + { + color->pixel = 0; + color->red = 0; + color->green = 0; + color->blue = 0; + return FALSE; + } + + gdk_color_parse (spec, color); + + colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas)); + + gdk_rgb_find_color (colormap, color); + + return TRUE; +} + +/** + * eel_canvas_get_color_pixel: + * @canvas: A canvas. + * @rgba: RGBA color specification. + * + * Allocates a color from the RGBA value passed into this function. The alpha + * opacity value is discarded, since normal X colors do not support it. + * + * Return value: Allocated pixel value corresponding to the specified color. + **/ +gulong +eel_canvas_get_color_pixel (EelCanvas *canvas, guint rgba) +{ + GdkColormap *colormap; + GdkColor color; + + g_return_val_if_fail (EEL_IS_CANVAS (canvas), 0); + + color.red = ((rgba & 0xff000000) >> 16) + ((rgba & 0xff000000) >> 24); + color.green = ((rgba & 0x00ff0000) >> 8) + ((rgba & 0x00ff0000) >> 16); + color.blue = (rgba & 0x0000ff00) + ((rgba & 0x0000ff00) >> 8); + color.pixel = 0; + + colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas)); + + gdk_rgb_find_color (colormap, &color); + + return color.pixel; +} + + +/* FIXME: This function is not useful anymore */ +/** + * eel_canvas_set_stipple_origin: + * @canvas: A canvas. + * @gc: GC on which to set the stipple origin. + * + * Sets the stipple origin of the specified GC as is appropriate for the canvas, + * so that it will be aligned with other stipple patterns used by canvas items. + * This is typically only needed by item implementations. + **/ +void +eel_canvas_set_stipple_origin (EelCanvas *canvas, GdkGC *gc) +{ + g_return_if_fail (EEL_IS_CANVAS (canvas)); + g_return_if_fail (GDK_IS_GC (gc)); + + gdk_gc_set_ts_origin (gc, 0, 0); +} + +static gboolean +boolean_handled_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + gboolean continue_emission; + gboolean signal_handled; + + signal_handled = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accu, signal_handled); + continue_emission = !signal_handled; + + return continue_emission; +} + +static guint +eel_canvas_item_accessible_add_focus_handler (AtkComponent *component, + AtkFocusHandler handler) +{ + GSignalMatchType match_type; + guint signal_id; + + match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC; + signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT); + + if (!g_signal_handler_find (component, match_type, signal_id, 0, NULL, + (gpointer) handler, NULL)) + { + return g_signal_connect_closure_by_id (component, + signal_id, 0, + g_cclosure_new ( + G_CALLBACK (handler), NULL, + (GClosureNotify) NULL), + FALSE); + } + return 0; +} + +static void +eel_canvas_item_accessible_get_item_extents (EelCanvasItem *item, + GdkRectangle *rect) +{ + double bx1, bx2, by1, by2; + gint scroll_x, scroll_y; + gint x1, x2, y1, y2; + + eel_canvas_item_get_bounds (item, &bx1, &by1, &bx2, &by2); + eel_canvas_w2c_rect_d (item->canvas, &bx1, &by1, &bx2, &by2); + eel_canvas_get_scroll_offsets (item->canvas, &scroll_x, &scroll_y); + x1 = floor (bx1 + .5); + y1 = floor (by1 + .5); + x2 = floor (bx2 + .5); + y2 = floor (by2 + .5); + rect->x = x1 - scroll_x; + rect->y = y1 - scroll_y; + rect->width = x2 - x1; + rect->height = y2 - y1; +} + +static gboolean +eel_canvas_item_accessible_is_item_in_window (EelCanvasItem *item, + GdkRectangle *rect) +{ + GtkWidget *widget; + gboolean retval; + + widget = GTK_WIDGET (item->canvas); + if (gtk_widget_get_window (widget)) + { + int window_width, window_height; + + gdk_window_get_geometry (gtk_widget_get_window (widget), NULL, NULL, + &window_width, &window_height, NULL); + /* + * Check whether rectangles intersect + */ + if (rect->x + rect->width < 0 || + rect->y + rect->height < 0 || + rect->x > window_width || + rect->y > window_height) + { + retval = FALSE; + } + else + { + retval = TRUE; + } + } + else + { + retval = FALSE; + } + return retval; +} + + +static void +eel_canvas_item_accessible_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + AtkGObjectAccessible *atk_gobj; + GObject *obj; + EelCanvasItem *item; + gint window_x, window_y; + gint toplevel_x, toplevel_y; + GdkRectangle rect; + GdkWindow *window; + GtkWidget *canvas; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (component); + obj = atk_gobject_accessible_get_object (atk_gobj); + + if (obj == NULL) + { + /* item is defunct */ + return; + } + + /* Get the CanvasItem */ + item = EEL_CANVAS_ITEM (obj); + + /* If this item has no parent canvas, something's broken */ + g_return_if_fail (GTK_IS_WIDGET (item->canvas)); + + eel_canvas_item_accessible_get_item_extents (item, &rect); + *width = rect.width; + *height = rect.height; + if (!eel_canvas_item_accessible_is_item_in_window (item, &rect)) + { + *x = G_MININT; + *y = G_MININT; + return; + } + + canvas = GTK_WIDGET (item->canvas); + window = gtk_widget_get_parent_window (canvas); + gdk_window_get_origin (window, &window_x, &window_y); + *x = rect.x + window_x; + *y = rect.y + window_y; + if (coord_type == ATK_XY_WINDOW) + { + window = gdk_window_get_toplevel (gtk_widget_get_window (canvas)); + gdk_window_get_origin (window, &toplevel_x, &toplevel_y); + *x -= toplevel_x; + *y -= toplevel_y; + } + return; +} + +static gint +eel_canvas_item_accessible_get_mdi_zorder (AtkComponent *component) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EelCanvasItem *item; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (component); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (g_obj == NULL) + { + /* Object is defunct */ + return -1; + } + + item = EEL_CANVAS_ITEM (g_obj); + if (item->parent) + { + return g_list_index (EEL_CANVAS_GROUP (item->parent)->item_list, item); + } + else + { + g_return_val_if_fail (item->canvas->root == item, -1); + return 0; + } +} + +static gboolean +eel_canvas_item_accessible_grab_focus (AtkComponent *component) +{ + AtkGObjectAccessible *atk_gobj; + GObject *obj; + EelCanvasItem *item; + GtkWidget *toplevel; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (component); + obj = atk_gobject_accessible_get_object (atk_gobj); + + item = EEL_CANVAS_ITEM (obj); + if (item == NULL) + { + /* item is defunct */ + return FALSE; + } + + eel_canvas_item_grab_focus (item); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->canvas)); + if (gtk_widget_is_toplevel (toplevel)) + { + gtk_window_present (GTK_WINDOW (toplevel)); + } + + return TRUE; +} + +static void +eel_canvas_item_accessible_remove_focus_handler (AtkComponent *component, + guint handler_id) +{ + g_signal_handler_disconnect (component, handler_id); +} + +static void +eel_canvas_item_accessible_component_interface_init (AtkComponentIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->add_focus_handler = eel_canvas_item_accessible_add_focus_handler; + iface->get_extents = eel_canvas_item_accessible_get_extents; + iface->get_mdi_zorder = eel_canvas_item_accessible_get_mdi_zorder; + iface->grab_focus = eel_canvas_item_accessible_grab_focus; + iface->remove_focus_handler = eel_canvas_item_accessible_remove_focus_handler; +} + +static gboolean +eel_canvas_item_accessible_is_item_on_screen (EelCanvasItem *item) +{ + GdkRectangle rect; + + eel_canvas_item_accessible_get_item_extents (item, &rect); + return eel_canvas_item_accessible_is_item_in_window (item, &rect); +} + +static void +eel_canvas_item_accessible_initialize (AtkObject *obj, gpointer data) +{ + if (ATK_OBJECT_CLASS (accessible_item_parent_class)->initialize != NULL) + ATK_OBJECT_CLASS (accessible_item_parent_class)->initialize (obj, data); + g_object_set_data (G_OBJECT (obj), "atk-component-layer", + GINT_TO_POINTER (ATK_LAYER_MDI)); +} + +static AtkStateSet* +eel_canvas_item_accessible_ref_state_set (AtkObject *accessible) +{ + AtkGObjectAccessible *atk_gobj; + GObject *obj; + EelCanvasItem *item; + AtkStateSet *state_set; + + state_set = ATK_OBJECT_CLASS (accessible_item_parent_class)->ref_state_set (accessible); + atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible); + obj = atk_gobject_accessible_get_object (atk_gobj); + + item = EEL_CANVAS_ITEM (obj); + if (item == NULL) + { + atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); + } + else + { + if (item->flags & EEL_CANVAS_ITEM_VISIBLE) + { + atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); + + if (eel_canvas_item_accessible_is_item_on_screen (item)) + { + atk_state_set_add_state (state_set, ATK_STATE_SHOWING); + } + } + if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))) + { + atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); + + if (item->canvas->focused_item == item) + { + atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); + } + } + } + + return state_set; +} + +static void +eel_canvas_item_accessible_class_init (AtkObjectClass *klass) +{ + accessible_item_parent_class = g_type_class_peek_parent (klass); + + klass->initialize = eel_canvas_item_accessible_initialize; + klass->ref_state_set = eel_canvas_item_accessible_ref_state_set; +} + +static GType +eel_canvas_item_accessible_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GInterfaceInfo atk_component_info = + { + (GInterfaceInitFunc) eel_canvas_item_accessible_component_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + AtkObjectFactory *factory; + GType parent_atk_type; + GTypeQuery query; + GTypeInfo tinfo = { 0 }; + + factory = atk_registry_get_factory (atk_get_default_registry(), + GTK_TYPE_OBJECT); + if (!factory) + { + return G_TYPE_INVALID; + } + parent_atk_type = atk_object_factory_get_accessible_type (factory); + if (!parent_atk_type) + { + return G_TYPE_INVALID; + } + g_type_query (parent_atk_type, &query); + tinfo.class_init = (GClassInitFunc) eel_canvas_item_accessible_class_init; + tinfo.class_size = query.class_size; + tinfo.instance_size = query.instance_size; + type = g_type_register_static (parent_atk_type, + "EelCanvasItemAccessibility", + &tinfo, 0); + + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, + &atk_component_info); + + } + + return type; +} + +static AtkObject * +eel_canvas_item_accessible_create (GObject *for_object) +{ + GType type; + AtkObject *accessible; + EelCanvasItem *item; + + item = EEL_CANVAS_ITEM (for_object); + g_return_val_if_fail (item != NULL, NULL); + + type = eel_canvas_item_accessible_get_type (); + if (type == G_TYPE_INVALID) + { + return atk_no_op_object_new (for_object); + } + + accessible = g_object_new (type, NULL); + atk_object_initialize (accessible, for_object); + return accessible; +} + +static GType +eel_canvas_item_accessible_factory_get_accessible_type (void) +{ + return eel_canvas_item_accessible_get_type (); +} + +static AtkObject* +eel_canvas_item_accessible_factory_create_accessible (GObject *obj) +{ + AtkObject *accessible; + + g_return_val_if_fail (G_IS_OBJECT (obj), NULL); + + accessible = eel_canvas_item_accessible_create (obj); + + return accessible; +} + +static void +eel_canvas_item_accessible_factory_class_init (AtkObjectFactoryClass *klass) +{ + klass->create_accessible = eel_canvas_item_accessible_factory_create_accessible; + klass->get_accessible_type = eel_canvas_item_accessible_factory_get_accessible_type; +} + +static GType +eel_canvas_item_accessible_factory_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo tinfo = + { + sizeof (AtkObjectFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_canvas_item_accessible_factory_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (AtkObjectFactory), + 0, /* n_preallocs */ + NULL + }; + type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, + "EelCanvasItemAccessibilityFactory", + &tinfo, 0); + } + + return type; +} + +/* Class initialization function for EelCanvasItemClass */ +static void +eel_canvas_item_class_init (EelCanvasItemClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + item_parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = eel_canvas_item_set_property; + gobject_class->get_property = eel_canvas_item_get_property; + gobject_class->dispose = eel_canvas_item_dispose; + + g_object_class_install_property + (gobject_class, ITEM_PROP_PARENT, + g_param_spec_object ("parent", NULL, NULL, + EEL_TYPE_CANVAS_ITEM, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, ITEM_PROP_VISIBLE, + g_param_spec_boolean ("visible", NULL, NULL, + TRUE, + G_PARAM_READWRITE)); + + item_signals[ITEM_EVENT] = + g_signal_new ("event", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelCanvasItemClass, event), + boolean_handled_accumulator, NULL, + eel_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, 1, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); + + klass->realize = eel_canvas_item_realize; + klass->unrealize = eel_canvas_item_unrealize; + klass->map = eel_canvas_item_map; + klass->unmap = eel_canvas_item_unmap; + klass->update = eel_canvas_item_update; + + atk_registry_set_factory_type (atk_get_default_registry (), + EEL_TYPE_CANVAS_ITEM, + eel_canvas_item_accessible_factory_get_type ()); +} diff --git a/eel/eel-canvas.h b/eel/eel-canvas.h new file mode 100644 index 00000000..1d185a76 --- /dev/null +++ b/eel/eel-canvas.h @@ -0,0 +1,545 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + @NOTATION@ + */ +/* EelCanvas widget - Tk-like canvas widget for Mate + * + * EelCanvas is basically a port of the Tk toolkit's most excellent canvas + * widget. Tk is copyrighted by the Regents of the University of California, + * Sun Microsystems, and other parties. + * + * + * Authors: Federico Mena <[email protected]> + * Raph Levien <[email protected]> + */ + +#ifndef EEL_CANVAS_H +#define EEL_CANVAS_H + +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + + + /* "Small" value used by canvas stuff */ +#define EEL_CANVAS_EPSILON 1e-10 + + + /* Macros for building colors that fit in a 32-bit integer. The values are in + * [0, 255]. + */ + +#define EEL_CANVAS_COLOR(r, g, b) ((((int) (r) & 0xff) << 24) \ + | (((int) (g) & 0xff) << 16) \ + | (((int) (b) & 0xff) << 8) \ + | 0xff) + +#define EEL_CANVAS_COLOR_A(r, g, b, a) ((((int) (r) & 0xff) << 24) \ + | (((int) (g) & 0xff) << 16) \ + | (((int) (b) & 0xff) << 8) \ + | ((int) (a) & 0xff)) + + + typedef struct _EelCanvas EelCanvas; + typedef struct _EelCanvasClass EelCanvasClass; + typedef struct _EelCanvasItem EelCanvasItem; + typedef struct _EelCanvasItemClass EelCanvasItemClass; + typedef struct _EelCanvasGroup EelCanvasGroup; + typedef struct _EelCanvasGroupClass EelCanvasGroupClass; + + + /* EelCanvasItem - base item class for canvas items + * + * All canvas items are derived from EelCanvasItem. The only information a + * EelCanvasItem contains is its parent canvas, its parent canvas item group, + * and its bounding box in world coordinates. + * + * Items inside a canvas are organized in a tree of EelCanvasItemGroup nodes + * and EelCanvasItem leaves. Each canvas has a single root group, which can + * be obtained with the eel_canvas_get_root() function. + * + * The abstract EelCanvasItem class does not have any configurable or + * queryable attributes. + */ + + /* Object flags for items */ + enum + { + EEL_CANVAS_ITEM_REALIZED = 1 << 4, + EEL_CANVAS_ITEM_MAPPED = 1 << 5, + EEL_CANVAS_ITEM_ALWAYS_REDRAW = 1 << 6, + EEL_CANVAS_ITEM_VISIBLE = 1 << 7, + EEL_CANVAS_ITEM_NEED_UPDATE = 1 << 8, + EEL_CANVAS_ITEM_NEED_DEEP_UPDATE = 1 << 9 + }; + + /* Update flags for items */ + enum + { + EEL_CANVAS_UPDATE_REQUESTED = 1 << 0, + EEL_CANVAS_UPDATE_DEEP = 1 << 1 + }; + +#define EEL_TYPE_CANVAS_ITEM (eel_canvas_item_get_type ()) +#define EEL_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItem)) +#define EEL_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass)) +#define EEL_IS_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_ITEM)) +#define EEL_IS_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_ITEM)) +#define EEL_CANVAS_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass)) + + + struct _EelCanvasItem + { + GtkObject object; + + /* Parent canvas for this item */ + EelCanvas *canvas; + + /* Parent canvas group for this item (a EelCanvasGroup) */ + EelCanvasItem *parent; + + /* Bounding box for this item (in canvas coordinates) */ + double x1, y1, x2, y2; + + /* Object flags */ + guint flags; + }; + + struct _EelCanvasItemClass + { + GtkObjectClass parent_class; + + /* Tell the item to update itself. The flags are from the update flags + * defined above. The item should update its internal state from its + * queued state, and recompute and request its repaint area. The + * update method also recomputes the bounding box of the item. + */ + void (* update) (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags); + + /* Realize an item -- create GCs, etc. */ + void (* realize) (EelCanvasItem *item); + + /* Unrealize an item */ + void (* unrealize) (EelCanvasItem *item); + + /* Map an item - normally only need by items with their own GdkWindows */ + void (* map) (EelCanvasItem *item); + + /* Unmap an item */ + void (* unmap) (EelCanvasItem *item); + + /* Draw an item of this type. (x, y) are the upper-left canvas pixel + * coordinates of the drawable, a temporary pixmap, where things get + * drawn. (width, height) are the dimensions of the drawable. + */ + void (* draw) (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose); + + /* Calculate the distance from an item to the specified point. It also + * returns a canvas item which is the item itself in the case of the + * object being an actual leaf item, or a child in case of the object + * being a canvas group. (cx, cy) are the canvas pixel coordinates that + * correspond to the item-relative coordinates (x, y). + */ + double (* point) (EelCanvasItem *item, double x, double y, int cx, int cy, + EelCanvasItem **actual_item); + + void (* translate) (EelCanvasItem *item, double dx, double dy); + + /* Fetch the item's bounding box (need not be exactly tight). This + * should be in item-relative coordinates. + */ + void (* bounds) (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2); + + /* Signal: an event ocurred for an item of this type. The (x, y) + * coordinates are in the canvas world coordinate system. + */ + gboolean (* event) (EelCanvasItem *item, GdkEvent *event); + + /* Reserved for future expansion */ + gpointer spare_vmethods [4]; + }; + + + /* Standard Gtk function */ + GType eel_canvas_item_get_type (void) G_GNUC_CONST; + + /* Create a canvas item using the standard Gtk argument mechanism. The item is + * automatically inserted at the top of the specified canvas group. The last + * argument must be a NULL pointer. + */ + EelCanvasItem *eel_canvas_item_new (EelCanvasGroup *parent, GType type, + const gchar *first_arg_name, ...); + + /* Constructors for use in derived classes and language wrappers */ + void eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent, + const gchar *first_arg_name, va_list args); + + /* Configure an item using the standard Gtk argument mechanism. The last + * argument must be a NULL pointer. + */ + void eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...); + + /* Used only for language wrappers and the like */ + void eel_canvas_item_set_valist (EelCanvasItem *item, + const gchar *first_arg_name, va_list args); + + /* Move an item by the specified amount */ + void eel_canvas_item_move (EelCanvasItem *item, double dx, double dy); + + /* Raise an item in the z-order of its parent group by the specified number of + * positions. + */ + void eel_canvas_item_raise (EelCanvasItem *item, int positions); + + /* Lower an item in the z-order of its parent group by the specified number of + * positions. + */ + void eel_canvas_item_lower (EelCanvasItem *item, int positions); + + /* Raise an item to the top of its parent group's z-order. */ + void eel_canvas_item_raise_to_top (EelCanvasItem *item); + + /* Lower an item to the bottom of its parent group's z-order */ + void eel_canvas_item_lower_to_bottom (EelCanvasItem *item); + + /* Send an item behind another item */ + void eel_canvas_item_send_behind (EelCanvasItem *item, + EelCanvasItem *behind_item); + + + /* Show an item (make it visible). If the item is already shown, it has no + * effect. + */ + void eel_canvas_item_show (EelCanvasItem *item); + + /* Hide an item (make it invisible). If the item is already invisible, it has + * no effect. + */ + void eel_canvas_item_hide (EelCanvasItem *item); + + /* Grab the mouse for the specified item. Only the events in event_mask will be + * reported. If cursor is non-NULL, it will be used during the duration of the + * grab. Time is a proper X event time parameter. Returns the same values as + * XGrabPointer(). + */ + int eel_canvas_item_grab (EelCanvasItem *item, unsigned int event_mask, + GdkCursor *cursor, guint32 etime); + + /* Ungrabs the mouse -- the specified item must be the same that was passed to + * eel_canvas_item_grab(). Time is a proper X event time parameter. + */ + void eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime); + + /* These functions convert from a coordinate system to another. "w" is world + * coordinates and "i" is item coordinates. + */ + void eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y); + void eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y); + + /* Remove the item from its parent group and make the new group its parent. The + * item will be put on top of all the items in the new group. The item's + * coordinates relative to its new parent to *not* change -- this means that the + * item could potentially move on the screen. + * + * The item and the group must be in the same canvas. An item cannot be + * reparented to a group that is the item itself or that is an inferior of the + * item. + */ + void eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group); + + /* Used to send all of the keystroke events to a specific item as well as + * GDK_FOCUS_CHANGE events. + */ + void eel_canvas_item_grab_focus (EelCanvasItem *item); + + /* Fetch the bounding box of the item. The bounding box may not be exactly + * tight, but the canvas items will do the best they can. The returned bounding + * box is in the coordinate system of the item's parent. + */ + void eel_canvas_item_get_bounds (EelCanvasItem *item, + double *x1, double *y1, double *x2, double *y2); + + /* Request that the update method eventually get called. This should be used + * only by item implementations. + */ + void eel_canvas_item_request_update (EelCanvasItem *item); + + /* Request a redraw of the bounding box of the canvas item */ + void eel_canvas_item_request_redraw (EelCanvasItem *item); + + /* EelCanvasGroup - a group of canvas items + * + * A group is a node in the hierarchical tree of groups/items inside a canvas. + * Groups serve to give a logical structure to the items. + * + * Consider a circuit editor application that uses the canvas for its schematic + * display. Hierarchically, there would be canvas groups that contain all the + * components needed for an "adder", for example -- this includes some logic + * gates as well as wires. You can move stuff around in a convenient way by + * doing a eel_canvas_item_move() of the hierarchical groups -- to move an + * adder, simply move the group that represents the adder. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * x double RW X coordinate of group's origin + * y double RW Y coordinate of group's origin + */ + + +#define EEL_TYPE_CANVAS_GROUP (eel_canvas_group_get_type ()) +#define EEL_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroup)) +#define EEL_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass)) +#define EEL_IS_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_GROUP)) +#define EEL_IS_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_GROUP)) +#define EEL_CANVAS_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass)) + + + struct _EelCanvasGroup + { + EelCanvasItem item; + + double xpos, ypos; + + /* Children of the group */ + GList *item_list; + GList *item_list_end; + }; + + struct _EelCanvasGroupClass + { + EelCanvasItemClass parent_class; + }; + + + /* Standard Gtk function */ + GType eel_canvas_group_get_type (void) G_GNUC_CONST; + + + /*** EelCanvas ***/ + + +#define EEL_TYPE_CANVAS (eel_canvas_get_type ()) +#define EEL_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS, EelCanvas)) +#define EEL_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS, EelCanvasClass)) +#define EEL_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS)) +#define EEL_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS)) +#define EEL_CANVAS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS, EelCanvasClass)) + + + struct _EelCanvas + { + GtkLayout layout; + + /* Root canvas group */ + EelCanvasItem *root; + + /* The item containing the mouse pointer, or NULL if none */ + EelCanvasItem *current_item; + + /* Item that is about to become current (used to track deletions and such) */ + EelCanvasItem *new_current_item; + + /* Item that holds a pointer grab, or NULL if none */ + EelCanvasItem *grabbed_item; + + /* If non-NULL, the currently focused item */ + EelCanvasItem *focused_item; + + /* GC for temporary draw pixmap */ + GdkGC *pixmap_gc; + + /* Event on which selection of current item is based */ + GdkEvent pick_event; + + /* Scrolling region */ + double scroll_x1, scroll_y1; + double scroll_x2, scroll_y2; + + /* Scaling factor to be used for display */ + double pixels_per_unit; + + /* Idle handler ID */ + guint idle_id; + + /* Signal handler ID for destruction of the root item */ + guint root_destroy_id; + + /* Internal pixel offsets when zoomed out */ + int zoom_xofs, zoom_yofs; + + /* Last known modifier state, for deferred repick when a button is down */ + int state; + + /* Event mask specified when grabbing an item */ + guint grabbed_event_mask; + + /* Tolerance distance for picking items */ + int close_enough; + + /* Whether the canvas should center the canvas in the middle of + * the window if the scroll region is smaller than the window */ + unsigned int center_scroll_region : 1; + + /* Whether items need update at next idle loop iteration */ + unsigned int need_update : 1; + + /* Are we in the midst of an update */ + unsigned int doing_update : 1; + + /* Whether the canvas needs redrawing at the next idle loop iteration */ + unsigned int need_redraw : 1; + + /* Whether current item will be repicked at next idle loop iteration */ + unsigned int need_repick : 1; + + /* For use by internal pick_current_item() function */ + unsigned int left_grabbed_item : 1; + + /* For use by internal pick_current_item() function */ + unsigned int in_repick : 1; + }; + + struct _EelCanvasClass + { + GtkLayoutClass parent_class; + + /* Draw the background for the area given. + */ + void (* draw_background) (EelCanvas *canvas, + int x, int y, int width, int height); + + /* Private Virtual methods for groping the canvas inside matecomponent */ + void (* request_update) (EelCanvas *canvas); + + /* Reserved for future expansion */ + gpointer spare_vmethods [4]; + }; + + + /* Standard Gtk function */ + GType eel_canvas_get_type (void) G_GNUC_CONST; + + /* Creates a new canvas. You should check that the canvas is created with the + * proper visual and colormap. Any visual will do unless you intend to insert + * gdk_imlib images into it, in which case you should use the gdk_imlib visual. + * + * You should call eel_canvas_set_scroll_region() soon after calling this + * function to set the desired scrolling limits for the canvas. + */ + GtkWidget *eel_canvas_new (void); + + /* Returns the root canvas item group of the canvas */ + EelCanvasGroup *eel_canvas_root (EelCanvas *canvas); + + /* Sets the limits of the scrolling region, in world coordinates */ + void eel_canvas_set_scroll_region (EelCanvas *canvas, + double x1, double y1, double x2, double y2); + + /* Gets the limits of the scrolling region, in world coordinates */ + void eel_canvas_get_scroll_region (EelCanvas *canvas, + double *x1, double *y1, double *x2, double *y2); + + /* Sets the number of pixels that correspond to one unit in world coordinates */ + void eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n); + + /* Wether the canvas centers the scroll region if it is smaller than the window */ + void eel_canvas_set_center_scroll_region (EelCanvas *canvas, gboolean center_scroll_region); + + /* Scrolls the canvas to the specified offsets, given in canvas pixel coordinates */ + void eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy); + + /* Returns the scroll offsets of the canvas in canvas pixel coordinates. You + * can specify NULL for any of the values, in which case that value will not be + * queried. + */ + void eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy); + + /* Requests that the canvas be repainted immediately instead of in the idle + * loop. + */ + void eel_canvas_update_now (EelCanvas *canvas); + + /* Returns the item that is at the specified position in world coordinates, or + * NULL if no item is there. + */ + EelCanvasItem *eel_canvas_get_item_at (EelCanvas *canvas, double x, double y); + + /* For use only by item type implementations. Request that the canvas + * eventually redraw the specified region, specified in canvas pixel + * coordinates. The region contains (x1, y1) but not (x2, y2). + */ + void eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2); + + /* These functions convert from a coordinate system to another. "w" is world + * coordinates, "c" is canvas pixel coordinates (pixel coordinates that are + * (0,0) for the upper-left scrolling limit and something else for the + * lower-left scrolling limit). + */ + void eel_canvas_w2c_rect_d (EelCanvas *canvas, + double *x1, double *y1, + double *x2, double *y2); + void eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy); + void eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy); + void eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy); + + /* This function takes in coordinates relative to the GTK_LAYOUT + * (canvas)->bin_window and converts them to world coordinates. + * These days canvas coordinates and window coordinates are the same, but + * these are left for backwards compat reasons. + */ + void eel_canvas_window_to_world (EelCanvas *canvas, + double winx, double winy, double *worldx, double *worldy); + + /* This is the inverse of eel_canvas_window_to_world() */ + void eel_canvas_world_to_window (EelCanvas *canvas, + double worldx, double worldy, double *winx, double *winy); + + /* Takes a string specification for a color and allocates it into the specified + * GdkColor. If the string is null, then it returns FALSE. Otherwise, it + * returns TRUE. + */ + int eel_canvas_get_color (EelCanvas *canvas, const char *spec, GdkColor *color); + + /* Allocates a color from the RGB value passed into this function. */ + gulong eel_canvas_get_color_pixel (EelCanvas *canvas, + guint rgba); + + + /* Sets the stipple origin of the specified gc so that it will be aligned with + * all the stipples used in the specified canvas. This is intended for use only + * by canvas item implementations. + */ + void eel_canvas_set_stipple_origin (EelCanvas *canvas, GdkGC *gc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/eel/eel-debug-drawing.c b/eel/eel-debug-drawing.c new file mode 100644 index 00000000..aee400d5 --- /dev/null +++ b/eel/eel-debug-drawing.c @@ -0,0 +1,566 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-debug-drawing.c: Eel drawing debugging aids. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-debug-drawing.h" + +#include "eel-art-gtk-extensions.h" +#include "eel-debug.h" +#include "eel-gdk-extensions.h" +#include "eel-gdk-extensions.h" +#include "eel-gdk-pixbuf-extensions.h" +#include "eel-gtk-extensions.h" +#include "eel-gtk-extensions.h" +#include "eel-gtk-macros.h" + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> + +/* + * PixbufViewer is a very simple "private" widget that displays + * a GdkPixbuf. It is used by eel_debug_show_pixbuf() to + * display a pixbuf in an in process pixbuf debugging window. + * + * We cant use EelImage for this because part of the reason + * for pixbuf debugging is to debug EelImage itself. + */ + +#define DEBUG_TYPE_PIXBUF_VIEWER debug_pixbuf_viewer_get_type() +#define DEBUG_PIXBUF_VIEWER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEBUG_TYPE_PIXBUF_VIEWER, DebugPixbufViewer)) +#define DEBUG_IS_PIXBUF_VIEWER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEBUG_TYPE_PIXBUF_VIEWER)) + +typedef struct DebugPixbufViewer DebugPixbufViewer; +typedef struct DebugPixbufViewerClass DebugPixbufViewerClass; + +static GType debug_pixbuf_viewer_get_type (void); +static void debug_pixbuf_viewer_set_pixbuf (DebugPixbufViewer *viewer, + GdkPixbuf *pixbuf); + +struct DebugPixbufViewer +{ + GtkWidget widget; + GdkPixbuf *pixbuf; +}; + +struct DebugPixbufViewerClass +{ + GtkWidgetClass parent_class; +}; + +/* GtkObjectClass methods */ +static void debug_pixbuf_viewer_class_init (DebugPixbufViewerClass *pixbuf_viewer_class); +static void debug_pixbuf_viewer_init (DebugPixbufViewer *pixbuf_viewer); +static void debug_pixbuf_viewer_finalize (GObject *object); + +/* GtkWidgetClass methods */ +static void debug_pixbuf_viewer_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static int debug_pixbuf_viewer_expose_event (GtkWidget *widget, + GdkEventExpose *event); + +EEL_CLASS_BOILERPLATE (DebugPixbufViewer, debug_pixbuf_viewer, GTK_TYPE_WIDGET) + +static void +debug_pixbuf_viewer_class_init (DebugPixbufViewerClass *pixbuf_viewer_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (pixbuf_viewer_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (pixbuf_viewer_class); + + object_class->finalize = debug_pixbuf_viewer_finalize; + widget_class->size_request = debug_pixbuf_viewer_size_request; + widget_class->expose_event = debug_pixbuf_viewer_expose_event; +} + +static void +debug_pixbuf_viewer_init (DebugPixbufViewer *viewer) +{ + gtk_widget_set_can_focus (GTK_WIDGET (viewer), FALSE); + gtk_widget_set_has_window (GTK_WIDGET (viewer), FALSE); +} + +static void +debug_pixbuf_viewer_finalize (GObject *object) +{ + DebugPixbufViewer *viewer; + + viewer = DEBUG_PIXBUF_VIEWER (object); + eel_gdk_pixbuf_unref_if_not_null (viewer->pixbuf); + viewer->pixbuf = NULL; + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +debug_pixbuf_viewer_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + DebugPixbufViewer *viewer; + EelDimensions dimensions; + + g_assert (DEBUG_IS_PIXBUF_VIEWER (widget)); + g_assert (requisition != NULL); + + viewer = DEBUG_PIXBUF_VIEWER (widget); + + if (viewer->pixbuf != NULL) + { + dimensions = eel_gdk_pixbuf_get_dimensions (viewer->pixbuf); + } + else + { + dimensions = eel_dimensions_empty; + } + + requisition->width = MAX (2, dimensions.width); + requisition->height = MAX (2, dimensions.height); +} + +static int +debug_pixbuf_viewer_expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + DebugPixbufViewer *viewer; + EelIRect clipped_dirty_area; + EelIRect dirty_area; + EelIRect bounds; + GtkAllocation allocation; + + g_assert (DEBUG_IS_PIXBUF_VIEWER (widget)); + g_assert (event != NULL); + g_assert (event->window == gtk_widget_get_window (widget)); + g_assert (gtk_widget_get_realized (widget)); + + viewer = DEBUG_PIXBUF_VIEWER (widget); + + if (viewer->pixbuf == NULL) + { + return TRUE; + } + + gtk_widget_get_allocation (widget, &allocation); + bounds.x0 = allocation.x + (allocation.width - gdk_pixbuf_get_width (viewer->pixbuf)) / 2; + bounds.y0 = allocation.y + (allocation.height - gdk_pixbuf_get_height (viewer->pixbuf)) / 2; + bounds.x1 = bounds.x0 + gdk_pixbuf_get_width (viewer->pixbuf); + bounds.y1 = bounds.y0 + gdk_pixbuf_get_height (viewer->pixbuf); + + /* Clip the dirty area to the screen; bail if no work to do */ + dirty_area = eel_gdk_rectangle_to_eel_irect (event->area); + clipped_dirty_area = eel_gdk_window_clip_dirty_area_to_screen (event->window, + dirty_area); + if (!eel_irect_is_empty (&clipped_dirty_area)) + { + EelIRect clipped_bounds; + + eel_irect_intersect (&clipped_bounds, &bounds, &clipped_dirty_area); + + if (!eel_irect_is_empty (&clipped_bounds)) + { + g_assert (clipped_bounds.x0 >= bounds.x0); + g_assert (clipped_bounds.y0 >= bounds.y0); + + eel_gdk_pixbuf_draw_to_drawable (viewer->pixbuf, + event->window, + gtk_widget_get_style (widget)->white_gc, + clipped_bounds.x0 - bounds.x0, + clipped_bounds.y0 - bounds.y0, + clipped_bounds, + GDK_RGB_DITHER_NONE, + GDK_PIXBUF_ALPHA_BILEVEL, + EEL_STANDARD_ALPHA_THRESHHOLD); + } + } + + bounds.x0 -= 1; + bounds.y0 -= 1; + bounds.x1 += 1; + bounds.y1 += 1; + + return TRUE; +} + +static void +debug_pixbuf_viewer_set_pixbuf (DebugPixbufViewer *viewer, GdkPixbuf *pixbuf) +{ + g_assert (DEBUG_IS_PIXBUF_VIEWER (viewer)); + + if (pixbuf != viewer->pixbuf) + { + eel_gdk_pixbuf_unref_if_not_null (viewer->pixbuf); + eel_gdk_pixbuf_ref_if_not_null (pixbuf); + viewer->pixbuf = pixbuf; + gtk_widget_queue_resize (GTK_WIDGET (viewer)); + } +} + +/** + * eel_debug_draw_rectangle_and_cross: + * @rectangle: Rectangle bounding the rectangle. + * @color: Color to use for the rectangle and cross. + * + * Draw a rectangle and cross. Useful for debugging exposure events. + */ +void +eel_debug_draw_rectangle_and_cross (GdkDrawable *drawable, + EelIRect rectangle, + guint32 color, + gboolean draw_cross) +{ + GdkGC *gc; + GdkColor color_gdk = { 0 }; + + int width; + int height; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (!eel_irect_is_empty (&rectangle)); + + width = rectangle.x1 - rectangle.x0; + height = rectangle.y1 - rectangle.y0; + + gc = gdk_gc_new (drawable); + gdk_gc_set_function (gc, GDK_COPY); + + color_gdk.red = ((color >> 16) & 0xff) << 8; + color_gdk.green = ((color >> 8) & 0xff) << 8; + color_gdk.blue = ((color ) & 0xff) << 8; + gdk_colormap_alloc_color ( + gdk_drawable_get_colormap (drawable), + &color_gdk, FALSE, FALSE); + gdk_gc_set_rgb_fg_color (gc, &color_gdk); + + gdk_draw_rectangle (drawable, + gc, + FALSE, + rectangle.x0, + rectangle.y0, + width - 1, + height - 1); + + if (draw_cross) + { + gdk_draw_line (drawable, + gc, + rectangle.x0, + rectangle.y0, + rectangle.x0 + width - 1, + rectangle.y0 + height - 1); + + gdk_draw_line (drawable, + gc, + rectangle.x0 + width - 1, + rectangle.y0, + rectangle.x0, + rectangle.y0 + height - 1); + } + + g_object_unref (gc); +} + +/** + * eel_debug_show_pixbuf_in_external_viewer: + * @pixbuf: Pixbuf to show. + * @viewer_name: Viewer name. + * + * Show the given pixbuf in an external out of process viewer. + * This is very useful for debugging pixbuf stuff. + * + * Perhaps this function should be #ifdef DEBUG or something like that. + */ +void +eel_debug_show_pixbuf_in_external_viewer (const GdkPixbuf *pixbuf, + const char *viewer_name) +{ + char *command; + char *file_name; + gboolean save_result; + int ignore; + int fd; + + g_return_if_fail (pixbuf != NULL); + g_return_if_fail (viewer_name != NULL); + + file_name = g_strdup ("/tmp/eel-debug-png-file-XXXXXX"); + + fd = g_mkstemp (file_name); + if (fd == -1) + { + g_free (file_name); + file_name = g_strdup_printf ("/tmp/isis-debug-png-file-%d", getpid ()); + } + else + { + close (fd); + } + + save_result = eel_gdk_pixbuf_save_to_file (pixbuf, file_name); + + if (save_result == FALSE) + { + g_warning ("Failed to save '%s'", file_name); + g_free (file_name); + return; + } + + command = g_strdup_printf ("%s %s", viewer_name, file_name); + + ignore = system (command); + g_free (command); + remove (file_name); + g_free (file_name); +} + +static GtkWidget *debug_window = NULL; +static GtkWidget *debug_image = NULL; + +static void +debug_delete_event (GtkWidget *widget, GdkEvent *event, gpointer callback_data) +{ + gtk_widget_hide (widget); +} + +static void +destroy_debug_window (void) +{ + if (debug_window != NULL) + { + gtk_widget_destroy (debug_window); + debug_window = NULL; + } +} + +/** + * eel_debug_show_pixbuf_in: + * @pixbuf: Pixbuf to show. + * + * Show the given pixbuf in an in process window. + */ +void +eel_debug_show_pixbuf (GdkPixbuf *pixbuf) +{ + if (debug_window == NULL) + { + GtkWidget *vbox; + + debug_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (debug_window), vbox); + gtk_window_set_title (GTK_WINDOW (debug_window), "Pixbuf debugging"); + gtk_window_set_resizable (GTK_WINDOW (debug_window), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (debug_window), 10); + g_signal_connect (debug_window, "delete_event", G_CALLBACK (debug_delete_event), NULL); + + debug_image = gtk_widget_new (debug_pixbuf_viewer_get_type (), NULL); + + gtk_box_pack_start (GTK_BOX (vbox), debug_image, TRUE, TRUE, 0); + + eel_gtk_widget_set_background_color (debug_window, "white"); + + eel_debug_call_at_shutdown (destroy_debug_window); + + gtk_widget_show (debug_image); + gtk_widget_show (vbox); + } + + gtk_widget_show (debug_window); + debug_pixbuf_viewer_set_pixbuf (DEBUG_PIXBUF_VIEWER (debug_image), pixbuf); + + gdk_window_clear_area_e (gtk_widget_get_window (debug_window), 0, 0, -1, -1); +} + +void +eel_debug_pixbuf_draw_point (GdkPixbuf *pixbuf, + int x, + int y, + guint32 color, + int opacity) +{ + EelDimensions dimensions; + guchar *pixels; + gboolean has_alpha; + guint pixel_offset; + guint rowstride; + guchar red; + guchar green; + guchar blue; + guchar alpha; + guchar *offset; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + g_return_if_fail (opacity >= EEL_OPACITY_FULLY_TRANSPARENT); + g_return_if_fail (opacity <= EEL_OPACITY_FULLY_OPAQUE); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + + g_return_if_fail (x >= 0 && x < dimensions.width); + g_return_if_fail (y >= 0 && y < dimensions.height); + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + pixel_offset = has_alpha ? 4 : 3; + + red = EEL_RGBA_COLOR_GET_R (color); + green = EEL_RGBA_COLOR_GET_G (color); + blue = EEL_RGBA_COLOR_GET_B (color); + alpha = (guchar) opacity; + + offset = pixels + y * rowstride + x * pixel_offset; + + *(offset + 0) = red; + *(offset + 1) = green; + *(offset + 2) = blue; + + if (has_alpha) + { + *(offset + 3) = alpha; + } +} + +void +eel_debug_pixbuf_draw_rectangle (GdkPixbuf *pixbuf, + gboolean filled, + int x0, + int y0, + int x1, + int y1, + guint32 color, + int opacity) +{ + EelDimensions dimensions; + int x; + int y; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + g_return_if_fail (opacity >= EEL_OPACITY_FULLY_TRANSPARENT); + g_return_if_fail (opacity <= EEL_OPACITY_FULLY_OPAQUE); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + + if (x0 == -1) + { + x0 = 0; + } + + if (y0 == -1) + { + y0 = 0; + } + + if (x1 == -1) + { + x1 = dimensions.width - 1; + } + + if (y1 == -1) + { + y1 = dimensions.height - 1; + } + + g_return_if_fail (x1 > x0); + g_return_if_fail (y1 > y0); + g_return_if_fail (x0 >= 0 && x0 < dimensions.width); + g_return_if_fail (y0 >= 0 && y0 < dimensions.height); + g_return_if_fail (x1 >= 0 && x1 < dimensions.width); + g_return_if_fail (y1 >= 0 && y1 < dimensions.height); + + if (filled) + { + for (y = y0; y <= y1; y++) + { + for (x = x0; x <= x1; x++) + { + eel_debug_pixbuf_draw_point (pixbuf, x, y, color, opacity); + } + } + } + else + { + /* Top / Bottom */ + for (x = x0; x <= x1; x++) + { + eel_debug_pixbuf_draw_point (pixbuf, x, y0, color, opacity); + eel_debug_pixbuf_draw_point (pixbuf, x, y1, color, opacity); + } + + /* Left / Right */ + for (y = y0; y <= y1; y++) + { + eel_debug_pixbuf_draw_point (pixbuf, x0, y, color, opacity); + eel_debug_pixbuf_draw_point (pixbuf, x1, y, color, opacity); + } + } +} + +void +eel_debug_pixbuf_draw_rectangle_inset (GdkPixbuf *pixbuf, + gboolean filled, + int x0, + int y0, + int x1, + int y1, + guint32 color, + int opacity, + int inset) +{ + EelDimensions dimensions; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + g_return_if_fail (opacity >= EEL_OPACITY_FULLY_TRANSPARENT); + g_return_if_fail (opacity <= EEL_OPACITY_FULLY_OPAQUE); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + + if (x0 == -1) + { + x0 = 0; + } + + if (y0 == -1) + { + y0 = 0; + } + + if (x1 == -1) + { + x1 = dimensions.width - 1; + } + + if (y1 == -1) + { + y1 = dimensions.height - 1; + } + + x0 += inset; + y0 += inset; + x1 -= inset; + y1 -= inset; + + g_return_if_fail (x1 > x0); + g_return_if_fail (y1 > y0); + + eel_debug_pixbuf_draw_rectangle (pixbuf, filled, x0, y0, x1, y1, color, opacity); +} diff --git a/eel/eel-debug-drawing.h b/eel/eel-debug-drawing.h new file mode 100644 index 00000000..ce655c23 --- /dev/null +++ b/eel/eel-debug-drawing.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-debug-drawing.h: Eel drawing debugging aids. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_DEBUG_DRAWING_H +#define EEL_DEBUG_DRAWING_H + +#include <eel/eel-gdk-pixbuf-extensions.h> + +/* Draw a rectangle and cross on the given window */ +void eel_debug_draw_rectangle_and_cross (GdkDrawable *drawable, + EelIRect rectangle, + guint32 color, + gboolean draw_cross); + +/* Show the given pixbuf in an external out of process viewer */ +void eel_debug_show_pixbuf_in_external_viewer (const GdkPixbuf *pixbuf, + const char *viewer_name); + +/* Show the given pixbuf in an in process window */ +void eel_debug_show_pixbuf (GdkPixbuf *pixbuf); + +/* Draw a point in a pixbuf */ +void eel_debug_pixbuf_draw_point (GdkPixbuf *pixbuf, + int x, + int y, + guint32 color, + int opacity); +/* Draw a rectangle in a pixbuf. The coordinates (-1,-1( (-1,-1) will use + * the whole pixbuf. */ +void eel_debug_pixbuf_draw_rectangle (GdkPixbuf *pixbuf, + gboolean filled, + int x0, + int y0, + int x1, + int y1, + guint32 color, + int opacity); +/* Draw an inset rectangle in a pixbuf. Positive inset make the rectangle + * smaller. Negative inset makes it larger. + */ +void eel_debug_pixbuf_draw_rectangle_inset (GdkPixbuf *pixbuf, + gboolean filled, + int x0, + int y0, + int x1, + int y1, + guint32 color, + int opacity, + int inset); + +#endif /* EEL_DEBUG_DRAWING_H */ diff --git a/eel/eel-debug.c b/eel/eel-debug.c new file mode 100644 index 00000000..e651baed --- /dev/null +++ b/eel/eel-debug.c @@ -0,0 +1,135 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-debug.c: Eel debugging aids. + + Copyright (C) 2000, 2001 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-debug.h" + +#include <glib.h> +#include <signal.h> +#include <stdio.h> + +typedef struct +{ + gpointer data; + GFreeFunc function; +} ShutdownFunction; + +static GList *shutdown_functions; + +/* Raise a SIGINT signal to get the attention of the debugger. + * When not running under the debugger, we don't want to stop, + * so we ignore the signal for just the moment that we raise it. + */ +void +eel_stop_in_debugger (void) +{ + void (* saved_handler) (int); + + saved_handler = signal (SIGINT, SIG_IGN); + raise (SIGINT); + signal (SIGINT, saved_handler); +} + +/* Stop in the debugger after running the default log handler. + * This makes certain kinds of messages stop in the debugger + * without making them fatal (you can continue). + */ +static void +log_handler (const char *domain, + GLogLevelFlags level, + const char *message, + gpointer data) +{ + g_log_default_handler (domain, level, message, data); + if ((level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) != 0) + { + eel_stop_in_debugger (); + } +} + +void +eel_make_warnings_and_criticals_stop_in_debugger (void) +{ + g_log_set_default_handler (log_handler, NULL); +} + +int +eel_get_available_file_descriptor_count (void) +{ + int count; + GList *list; + GList *p; + FILE *file; + + list = NULL; + for (count = 0; ; count++) + { + file = fopen ("/dev/null", "r"); + if (file == NULL) + { + break; + } + list = g_list_prepend (list, file); + } + + for (p = list; p != NULL; p = p->next) + { + fclose (p->data); + } + g_list_free (list); + + return count; +} + +void +eel_debug_shut_down (void) +{ + ShutdownFunction *f; + + while (shutdown_functions != NULL) + { + f = shutdown_functions->data; + shutdown_functions = g_list_remove (shutdown_functions, f); + + f->function (f->data); + g_free (f); + } +} + +void +eel_debug_call_at_shutdown (EelFunction function) +{ + eel_debug_call_at_shutdown_with_data ((GFreeFunc) function, NULL); +} + +void +eel_debug_call_at_shutdown_with_data (GFreeFunc function, gpointer data) +{ + ShutdownFunction *f; + + f = g_new (ShutdownFunction, 1); + f->data = data; + f->function = function; + shutdown_functions = g_list_prepend (shutdown_functions, f); +} diff --git a/eel/eel-debug.h b/eel/eel-debug.h new file mode 100644 index 00000000..be7f0ab7 --- /dev/null +++ b/eel/eel-debug.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-debug.h: Eel debugging aids. + + Copyright (C) 2000, 2001 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#ifndef EEL_DEBUG_H +#define EEL_DEBUG_H + +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void (* EelFunction) (void); + + void eel_stop_in_debugger (void); + void eel_make_warnings_and_criticals_stop_in_debugger (void); + int eel_get_available_file_descriptor_count (void); + + /* A way to do cleanup at exit for compatibility with shutdown tools + * like the ones in MateComponent. + */ + void eel_debug_shut_down (void); + void eel_debug_call_at_shutdown (EelFunction function); + void eel_debug_call_at_shutdown_with_data (GFreeFunc function, + gpointer data); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_DEBUG_H */ diff --git a/eel/eel-editable-label.c b/eel/eel-editable-label.c new file mode 100644 index 00000000..b41f197d --- /dev/null +++ b/eel/eel-editable-label.c @@ -0,0 +1,4402 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> +#include <math.h> +#include <string.h> + +#include "eel-editable-label.h" +#include "eel-i18n.h" +#include "eel-marshal.h" +#include "eel-accessibility.h" +#include <libgail-util/gailmisc.h> + +#include <pango/pango.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +enum +{ + MOVE_CURSOR, + POPULATE_POPUP, + DELETE_FROM_CURSOR, + CUT_CLIPBOARD, + COPY_CLIPBOARD, + PASTE_CLIPBOARD, + TOGGLE_OVERWRITE, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_TEXT, + PROP_JUSTIFY, + PROP_WRAP, + PROP_CURSOR_POSITION, + PROP_SELECTION_BOUND +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void eel_editable_label_editable_init (GtkEditableClass *iface); +static void eel_editable_label_class_init (EelEditableLabelClass *klass); +static void eel_editable_label_init (EelEditableLabel *label); +static void eel_editable_label_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void eel_editable_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void eel_editable_label_finalize (GObject *object); +static void eel_editable_label_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void eel_editable_label_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void eel_editable_label_state_changed (GtkWidget *widget, + GtkStateType state); +static void eel_editable_label_style_set (GtkWidget *widget, + GtkStyle *previous_style); +static void eel_editable_label_direction_changed (GtkWidget *widget, + GtkTextDirection previous_dir); +static gint eel_editable_label_expose (GtkWidget *widget, + GdkEventExpose *event); +static void eel_editable_label_realize (GtkWidget *widget); +static void eel_editable_label_unrealize (GtkWidget *widget); +static void eel_editable_label_map (GtkWidget *widget); +static void eel_editable_label_unmap (GtkWidget *widget); +static gint eel_editable_label_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint eel_editable_label_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint eel_editable_label_motion (GtkWidget *widget, + GdkEventMotion *event); +static gint eel_editable_label_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint eel_editable_label_key_release (GtkWidget *widget, + GdkEventKey *event); +static gint eel_editable_label_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint eel_editable_label_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static AtkObject *eel_editable_label_get_accessible (GtkWidget *widget); +static void eel_editable_label_commit_cb (GtkIMContext *context, + const gchar *str, + EelEditableLabel *label); +static void eel_editable_label_preedit_changed_cb (GtkIMContext *context, + EelEditableLabel *label); +static gboolean eel_editable_label_retrieve_surrounding_cb (GtkIMContext *context, + EelEditableLabel *label); +static gboolean eel_editable_label_delete_surrounding_cb (GtkIMContext *slave, + gint offset, + gint n_chars, + EelEditableLabel *label); +static void eel_editable_label_clear_layout (EelEditableLabel *label); +static void eel_editable_label_recompute (EelEditableLabel *label); +static void eel_editable_label_ensure_layout (EelEditableLabel *label, + gboolean include_preedit); +static void eel_editable_label_select_region_index (EelEditableLabel *label, + gint anchor_index, + gint end_index); +static gboolean eel_editable_label_focus (GtkWidget *widget, + GtkDirectionType direction); +static void eel_editable_label_move_cursor (EelEditableLabel *label, + GtkMovementStep step, + gint count, + gboolean extend_selection); +static void eel_editable_label_delete_from_cursor (EelEditableLabel *label, + GtkDeleteType type, + gint count); +static void eel_editable_label_copy_clipboard (EelEditableLabel *label); +static void eel_editable_label_cut_clipboard (EelEditableLabel *label); +static void eel_editable_label_paste (EelEditableLabel *label, + GdkAtom selection); +static void eel_editable_label_paste_clipboard (EelEditableLabel *label); +static void eel_editable_label_select_all (EelEditableLabel *label); +static void eel_editable_label_do_popup (EelEditableLabel *label, + GdkEventButton *event); +static void eel_editable_label_toggle_overwrite (EelEditableLabel *label); +static gint eel_editable_label_move_forward_word (EelEditableLabel *label, + gint start); +static gint eel_editable_label_move_backward_word (EelEditableLabel *label, + gint start); +static void eel_editable_label_reset_im_context (EelEditableLabel *label); +static void eel_editable_label_check_cursor_blink (EelEditableLabel *label); +static void eel_editable_label_pend_cursor_blink (EelEditableLabel *label); + +/* Editable implementation: */ +static void editable_insert_text_emit (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position); +static void editable_delete_text_emit (GtkEditable *editable, + gint start_pos, + gint end_pos); +static void editable_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position); +static void editable_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos); +static gchar * editable_get_chars (GtkEditable *editable, + gint start_pos, + gint end_pos); +static void editable_set_selection_bounds (GtkEditable *editable, + gint start, + gint end); +static gboolean editable_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end); +static void editable_real_set_position (GtkEditable *editable, + gint position); +static gint editable_get_position (GtkEditable *editable); + +static GdkGC * make_cursor_gc (GtkWidget *widget, + const gchar *property_name, + GdkColor *fallback); + +G_DEFINE_TYPE_WITH_CODE (EelEditableLabel, eel_editable_label, GTK_TYPE_MISC, + G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, eel_editable_label_editable_init)); + +static void +add_move_binding (GtkBindingSet *binding_set, + guint keyval, + guint modmask, + GtkMovementStep step, + gint count) +{ + g_assert ((modmask & GDK_SHIFT_MASK) == 0); + + gtk_binding_entry_add_signal (binding_set, keyval, modmask, + "move_cursor", 3, + G_TYPE_ENUM, step, + G_TYPE_INT, count, + G_TYPE_BOOLEAN, FALSE); + + /* Selection-extending version */ + gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK, + "move_cursor", 3, + G_TYPE_ENUM, step, + G_TYPE_INT, count, + G_TYPE_BOOLEAN, TRUE); +} + +static void +eel_editable_label_class_init (EelEditableLabelClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkObjectClass *object_class = GTK_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkBindingSet *binding_set; + + gobject_class->set_property = eel_editable_label_set_property; + gobject_class->get_property = eel_editable_label_get_property; + gobject_class->finalize = eel_editable_label_finalize; + + widget_class->size_request = eel_editable_label_size_request; + widget_class->size_allocate = eel_editable_label_size_allocate; + widget_class->state_changed = eel_editable_label_state_changed; + widget_class->style_set = eel_editable_label_style_set; + widget_class->direction_changed = eel_editable_label_direction_changed; + widget_class->expose_event = eel_editable_label_expose; + widget_class->realize = eel_editable_label_realize; + widget_class->unrealize = eel_editable_label_unrealize; + widget_class->map = eel_editable_label_map; + widget_class->unmap = eel_editable_label_unmap; + widget_class->button_press_event = eel_editable_label_button_press; + widget_class->button_release_event = eel_editable_label_button_release; + widget_class->motion_notify_event = eel_editable_label_motion; + widget_class->focus = eel_editable_label_focus; + widget_class->key_press_event = eel_editable_label_key_press; + widget_class->key_release_event = eel_editable_label_key_release; + widget_class->focus_in_event = eel_editable_label_focus_in; + widget_class->focus_out_event = eel_editable_label_focus_out; + widget_class->get_accessible = eel_editable_label_get_accessible; + + class->move_cursor = eel_editable_label_move_cursor; + class->delete_from_cursor = eel_editable_label_delete_from_cursor; + class->copy_clipboard = eel_editable_label_copy_clipboard; + class->cut_clipboard = eel_editable_label_cut_clipboard; + class->paste_clipboard = eel_editable_label_paste_clipboard; + class->toggle_overwrite = eel_editable_label_toggle_overwrite; + + signals[MOVE_CURSOR] = + g_signal_new ("move_cursor", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelEditableLabelClass, move_cursor), + NULL, NULL, + eel_marshal_VOID__ENUM_INT_BOOLEAN, + G_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, G_TYPE_INT, G_TYPE_BOOLEAN); + + signals[COPY_CLIPBOARD] = + g_signal_new ("copy_clipboard", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelEditableLabelClass, copy_clipboard), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[POPULATE_POPUP] = + g_signal_new ("populate_popup", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelEditableLabelClass, populate_popup), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_MENU); + + signals[DELETE_FROM_CURSOR] = + g_signal_new ("delete_from_cursor", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelEditableLabelClass, delete_from_cursor), + NULL, NULL, + eel_marshal_VOID__ENUM_INT, + G_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, G_TYPE_INT); + + signals[CUT_CLIPBOARD] = + g_signal_new ("cut_clipboard", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelEditableLabelClass, cut_clipboard), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[PASTE_CLIPBOARD] = + g_signal_new ("paste_clipboard", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelEditableLabelClass, paste_clipboard), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[TOGGLE_OVERWRITE] = + g_signal_new ("toggle_overwrite", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelEditableLabelClass, toggle_overwrite), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + + g_object_class_install_property (G_OBJECT_CLASS(object_class), + PROP_TEXT, + g_param_spec_string ("text", + _("Text"), + _("The text of the label."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_JUSTIFY, + g_param_spec_enum ("justify", + _("Justification"), + _("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that."), + GTK_TYPE_JUSTIFICATION, + GTK_JUSTIFY_LEFT, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_WRAP, + g_param_spec_boolean ("wrap", + _("Line wrap"), + _("If set, wrap lines if the text becomes too wide."), + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_CURSOR_POSITION, + g_param_spec_int ("cursor_position", + _("Cursor Position"), + _("The current position of the insertion cursor in chars."), + 0, + G_MAXINT, + 0, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_SELECTION_BOUND, + g_param_spec_int ("selection_bound", + _("Selection Bound"), + _("The position of the opposite end of the selection from the cursor in chars."), + 0, + G_MAXINT, + 0, + G_PARAM_READABLE)); + + /* + * Key bindings + */ + + binding_set = gtk_binding_set_by_class (class); + + /* Moving the insertion point */ + add_move_binding (binding_set, GDK_Right, 0, + GTK_MOVEMENT_VISUAL_POSITIONS, 1); + + add_move_binding (binding_set, GDK_Left, 0, + GTK_MOVEMENT_VISUAL_POSITIONS, -1); + + add_move_binding (binding_set, GDK_KP_Right, 0, + GTK_MOVEMENT_VISUAL_POSITIONS, 1); + + add_move_binding (binding_set, GDK_KP_Left, 0, + GTK_MOVEMENT_VISUAL_POSITIONS, -1); + + add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK, + GTK_MOVEMENT_LOGICAL_POSITIONS, 1); + + add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK, + GTK_MOVEMENT_LOGICAL_POSITIONS, -1); + + add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, + GTK_MOVEMENT_WORDS, 1); + + add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, + GTK_MOVEMENT_WORDS, -1); + + add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, + GTK_MOVEMENT_WORDS, 1); + + add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, + GTK_MOVEMENT_WORDS, -1); + + add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK, + GTK_MOVEMENT_PARAGRAPH_ENDS, -1); + + add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK, + GTK_MOVEMENT_PARAGRAPH_ENDS, 1); + + add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK, + GTK_MOVEMENT_WORDS, 1); + + add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK, + GTK_MOVEMENT_WORDS, -1); + + add_move_binding (binding_set, GDK_Home, 0, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + + add_move_binding (binding_set, GDK_End, 0, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + + add_move_binding (binding_set, GDK_KP_Home, 0, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + + add_move_binding (binding_set, GDK_KP_End, 0, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + + add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK, + GTK_MOVEMENT_BUFFER_ENDS, -1); + + add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK, + GTK_MOVEMENT_BUFFER_ENDS, 1); + + add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK, + GTK_MOVEMENT_BUFFER_ENDS, -1); + + add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK, + GTK_MOVEMENT_BUFFER_ENDS, 1); + + add_move_binding (binding_set, GDK_Up, 0, + GTK_MOVEMENT_DISPLAY_LINES, -1); + + add_move_binding (binding_set, GDK_KP_Up, 0, + GTK_MOVEMENT_DISPLAY_LINES, -1); + + add_move_binding (binding_set, GDK_Down, 0, + GTK_MOVEMENT_DISPLAY_LINES, 1); + + add_move_binding (binding_set, GDK_KP_Down, 0, + GTK_MOVEMENT_DISPLAY_LINES, 1); + + /* Select all + */ + gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, + "move_cursor", 3, + GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, + G_TYPE_INT, -1, + G_TYPE_BOOLEAN, FALSE); + gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, + "move_cursor", 3, + GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS, + G_TYPE_INT, 1, + G_TYPE_BOOLEAN, TRUE); + + /* Deleting text */ + gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_CHARS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_CHARS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_CHARS, + G_TYPE_INT, -1); + + /* Make this do the same as Backspace, to help with mis-typing */ + gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_CHARS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, + "delete_from_cursor", 2, + G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, + G_TYPE_INT, -1); + + /* Cut/copy/paste */ + + gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK, + "cut_clipboard", 0); + gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK, + "copy_clipboard", 0); + gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK, + "paste_clipboard", 0); + + gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_SHIFT_MASK, + "cut_clipboard", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_CONTROL_MASK, + "copy_clipboard", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_SHIFT_MASK, + "paste_clipboard", 0); + + /* Overwrite */ + gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0, + "toggle_overwrite", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0, + "toggle_overwrite", 0); +} + +static void +eel_editable_label_editable_init (GtkEditableClass *iface) +{ + iface->do_insert_text = editable_insert_text_emit; + iface->do_delete_text = editable_delete_text_emit; + iface->insert_text = editable_insert_text; + iface->delete_text = editable_delete_text; + iface->get_chars = editable_get_chars; + iface->set_selection_bounds = editable_set_selection_bounds; + iface->get_selection_bounds = editable_get_selection_bounds; + iface->set_position = editable_real_set_position; + iface->get_position = editable_get_position; +} + + +static void +eel_editable_label_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EelEditableLabel *label; + + label = EEL_EDITABLE_LABEL (object); + + switch (prop_id) + { + case PROP_TEXT: + eel_editable_label_set_text (label, g_value_get_string (value)); + break; + case PROP_JUSTIFY: + eel_editable_label_set_justify (label, g_value_get_enum (value)); + break; + case PROP_WRAP: + eel_editable_label_set_line_wrap (label, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eel_editable_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EelEditableLabel *label; + gint offset; + + label = EEL_EDITABLE_LABEL (object); + + switch (prop_id) + { + case PROP_TEXT: + g_value_set_string (value, label->text); + break; + case PROP_JUSTIFY: + g_value_set_enum (value, label->jtype); + break; + case PROP_WRAP: + g_value_set_boolean (value, label->wrap); + break; + case PROP_CURSOR_POSITION: + offset = g_utf8_pointer_to_offset (label->text, + label->text + label->selection_end); + g_value_set_int (value, offset); + break; + case PROP_SELECTION_BOUND: + offset = g_utf8_pointer_to_offset (label->text, + label->text + label->selection_anchor); + g_value_set_int (value, offset); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +eel_editable_label_init (EelEditableLabel *label) +{ + label->jtype = GTK_JUSTIFY_LEFT; + label->wrap = FALSE; + label->wrap_mode = PANGO_WRAP_WORD; + + label->layout = NULL; + label->text_size = 1; + label->text = g_malloc (label->text_size); + label->text[0] = '\0'; + label->n_bytes = 0; + + gtk_widget_set_can_focus (GTK_WIDGET (label), TRUE); + + /* This object is completely private. No external entity can gain a reference + * to it; so we create it here and destroy it in finalize(). + */ + label->im_context = gtk_im_multicontext_new (); + + g_signal_connect (G_OBJECT (label->im_context), "commit", + G_CALLBACK (eel_editable_label_commit_cb), label); + g_signal_connect (G_OBJECT (label->im_context), "preedit_changed", + G_CALLBACK (eel_editable_label_preedit_changed_cb), label); + g_signal_connect (G_OBJECT (label->im_context), "retrieve_surrounding", + G_CALLBACK (eel_editable_label_retrieve_surrounding_cb), label); + g_signal_connect (G_OBJECT (label->im_context), "delete_surrounding", + G_CALLBACK (eel_editable_label_delete_surrounding_cb), label); +} + +/** + * eel_editable_label_new: + * @str: The text of the label + * + * Creates a new label with the given text inside it. You can + * pass %NULL to get an empty label widget. + * + * Return value: the new #EelEditableLabel + **/ +GtkWidget* +eel_editable_label_new (const gchar *str) +{ + EelEditableLabel *label; + + label = g_object_new (EEL_TYPE_EDITABLE_LABEL, NULL); + + if (str && *str) + eel_editable_label_set_text (label, str); + + return GTK_WIDGET (label); +} + +/** + * eel_editable_label_set_text: + * @label: a #EelEditableLabel + * @str: The text you want to set. + * + * Sets the text within the #EelEditableLabel widget. It overwrites any text that + * was there before. + * + * This will also clear any previously set mnemonic accelerators. + **/ +void +eel_editable_label_set_text (EelEditableLabel *label, + const gchar *str) +{ + GtkEditable *editable; + int tmp_pos; + + g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); + g_return_if_fail (str != NULL); + + if (strcmp (label->text, str) == 0) + return; + + editable = GTK_EDITABLE (label); + gtk_editable_delete_text (editable, 0, -1); + tmp_pos = 0; + gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos); +} + +/** + * eel_editable_label_get_text: + * @label: a #EelEditableLabel + * + * Fetches the text from a label widget, as displayed on the + * screen. This does not include any embedded underlines + * indicating mnemonics or Pango markup. (See eel_editable_label_get_label()) + * + * Return value: the text in the label widget. This is the internal + * string used by the label, and must not be modified. + **/ +const gchar* eel_editable_label_get_text(EelEditableLabel* label) +{ + g_return_val_if_fail(EEL_IS_EDITABLE_LABEL(label), NULL); + + return label->text; +} + +/** + * eel_editable_label_set_justify: + * @label: a #EelEditableLabel + * @jtype: a #GtkJustification + * + * Sets the alignment of the lines in the text of the label relative to + * each other. %GTK_JUSTIFY_LEFT is the default value when the + * widget is first created with eel_editable_label_new(). If you instead want + * to set the alignment of the label as a whole, use + * gtk_misc_set_alignment() instead. eel_editable_label_set_justify() has no + * effect on labels containing only a single line. + **/ +void +eel_editable_label_set_justify (EelEditableLabel *label, + GtkJustification jtype) +{ + g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); + g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL); + + if ((GtkJustification) label->jtype != jtype) + { + label->jtype = jtype; + + /* No real need to be this drastic, but easier than duplicating the code */ + eel_editable_label_recompute (label); + + g_object_notify (G_OBJECT (label), "justify"); + gtk_widget_queue_resize (GTK_WIDGET (label)); + } +} + +/** + * eel_editable_label_get_justify: + * @label: a #EelEditableLabel + * + * Returns the justification of the label. See eel_editable_label_set_justify (). + * + * Return value: #GtkJustification + **/ +GtkJustification +eel_editable_label_get_justify (EelEditableLabel *label) +{ + g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), 0); + + return label->jtype; +} + +void +eel_editable_label_set_draw_outline (EelEditableLabel *label, + gboolean draw_outline) +{ + draw_outline = draw_outline != FALSE; + + if (label->draw_outline != draw_outline) + { + label->draw_outline = draw_outline; + + gtk_widget_queue_draw (GTK_WIDGET (label)); + } + +} + + +/** + * eel_editable_label_set_line_wrap: + * @label: a #EelEditableLabel + * @wrap: the setting + * + * Toggles line wrapping within the #EelEditableLabel widget. %TRUE makes it break + * lines if text exceeds the widget's size. %FALSE lets the text get cut off + * by the edge of the widget if it exceeds the widget size. + **/ +void +eel_editable_label_set_line_wrap (EelEditableLabel *label, + gboolean wrap) +{ + g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); + + wrap = wrap != FALSE; + + if (label->wrap != wrap) + { + label->wrap = wrap; + g_object_notify (G_OBJECT (label), "wrap"); + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } +} + + +void +eel_editable_label_set_line_wrap_mode (EelEditableLabel *label, + PangoWrapMode mode) +{ + g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); + + if (label->wrap_mode != mode) + { + label->wrap_mode = mode; + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } + +} + + +/** + * eel_editable_label_get_line_wrap: + * @label: a #EelEditableLabel + * + * Returns whether lines in the label are automatically wrapped. See eel_editable_label_set_line_wrap (). + * + * Return value: %TRUE if the lines of the label are automatically wrapped. + */ +gboolean +eel_editable_label_get_line_wrap (EelEditableLabel *label) +{ + g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), FALSE); + + return label->wrap; +} + +PangoFontDescription * +eel_editable_label_get_font_description (EelEditableLabel *label) +{ + if (label->font_desc) + return pango_font_description_copy (label->font_desc); + + return NULL; +} + +void +eel_editable_label_set_font_description (EelEditableLabel *label, + const PangoFontDescription *desc) +{ + if (label->font_desc) + pango_font_description_free (label->font_desc); + + if (desc) + label->font_desc = pango_font_description_copy (desc); + else + label->font_desc = NULL; + + eel_editable_label_clear_layout (label); +} + +static void +eel_editable_label_finalize (GObject *object) +{ + EelEditableLabel *label; + + g_assert (EEL_IS_EDITABLE_LABEL (object)); + + label = EEL_EDITABLE_LABEL (object); + + if (label->font_desc) + { + pango_font_description_free (label->font_desc); + label->font_desc = NULL; + } + + g_object_unref (G_OBJECT (label->im_context)); + label->im_context = NULL; + + g_free (label->text); + label->text = NULL; + + if (label->layout) + { + g_object_unref (G_OBJECT (label->layout)); + label->layout = NULL; + } + + G_OBJECT_CLASS (eel_editable_label_parent_class)->finalize (object); +} + +static void +eel_editable_label_clear_layout (EelEditableLabel *label) +{ + if (label->layout) + { + g_object_unref (G_OBJECT (label->layout)); + label->layout = NULL; + } +} + +static void +eel_editable_label_recompute (EelEditableLabel *label) +{ + eel_editable_label_clear_layout (label); + eel_editable_label_check_cursor_blink (label); +} + +typedef struct _LabelWrapWidth LabelWrapWidth; +struct _LabelWrapWidth +{ + gint width; + PangoFontDescription *font_desc; +}; + +static void +label_wrap_width_free (gpointer data) +{ + LabelWrapWidth *wrap_width = data; + pango_font_description_free (wrap_width->font_desc); + g_free (wrap_width); +} + +static gint +get_label_wrap_width (EelEditableLabel *label) +{ + PangoLayout *layout; + GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (label)); + + LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width"); + if (!wrap_width) + { + wrap_width = g_new0 (LabelWrapWidth, 1); + g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width", + wrap_width, label_wrap_width_free); + } + + if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, style->font_desc)) + return wrap_width->width; + + if (wrap_width->font_desc) + pango_font_description_free (wrap_width->font_desc); + + wrap_width->font_desc = pango_font_description_copy (style->font_desc); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), + "This long string gives a good enough length for any line to have."); + pango_layout_get_size (layout, &wrap_width->width, NULL); + g_object_unref (layout); + + return wrap_width->width; +} + +static void +eel_editable_label_ensure_layout (EelEditableLabel *label, + gboolean include_preedit) +{ + GtkWidget *widget; + PangoRectangle logical_rect; + + /* Normalize for comparisons */ + include_preedit = include_preedit != 0; + + if (label->preedit_length > 0 && + include_preedit != label->layout_includes_preedit) + eel_editable_label_clear_layout (label); + + widget = GTK_WIDGET (label); + + if (label->layout == NULL) + { + gchar *preedit_string = NULL; + gint preedit_length = 0; + PangoAttrList *preedit_attrs = NULL; + PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */ + PangoAttrList *tmp_attrs = pango_attr_list_new (); + + if (include_preedit) + { + gtk_im_context_get_preedit_string (label->im_context, + &preedit_string, &preedit_attrs, NULL); + preedit_length = label->preedit_length; + } + + if (preedit_length) + { + GString *tmp_string = g_string_new (NULL); + + g_string_prepend_len (tmp_string, label->text, label->n_bytes); + g_string_insert (tmp_string, label->selection_anchor, preedit_string); + + label->layout = gtk_widget_create_pango_layout (widget, tmp_string->str); + + pango_attr_list_splice (tmp_attrs, preedit_attrs, + label->selection_anchor, preedit_length); + + g_string_free (tmp_string, TRUE); + } + else + { + label->layout = gtk_widget_create_pango_layout (widget, label->text); + } + label->layout_includes_preedit = include_preedit; + + if (label->font_desc != NULL) + pango_layout_set_font_description (label->layout, label->font_desc); + + pango_layout_set_attributes (label->layout, tmp_attrs); + + if (preedit_string) + g_free (preedit_string); + if (preedit_attrs) + pango_attr_list_unref (preedit_attrs); + pango_attr_list_unref (tmp_attrs); + + switch (label->jtype) + { + case GTK_JUSTIFY_LEFT: + align = PANGO_ALIGN_LEFT; + break; + case GTK_JUSTIFY_RIGHT: + align = PANGO_ALIGN_RIGHT; + break; + case GTK_JUSTIFY_CENTER: + align = PANGO_ALIGN_CENTER; + break; + case GTK_JUSTIFY_FILL: + /* FIXME: This just doesn't work to do this */ + align = PANGO_ALIGN_LEFT; + pango_layout_set_justify (label->layout, TRUE); + break; + default: + g_assert_not_reached(); + } + + pango_layout_set_alignment (label->layout, align); + + if (label->wrap) + { + gint longest_paragraph; + gint width, height; + gint set_width; + + gtk_widget_get_size_request (widget, &set_width, NULL); + if (set_width > 0) + pango_layout_set_width (label->layout, set_width * PANGO_SCALE); + else + { + gint wrap_width; + + pango_layout_set_width (label->layout, -1); + pango_layout_get_extents (label->layout, NULL, &logical_rect); + + width = logical_rect.width; + + /* Try to guess a reasonable maximum width */ + longest_paragraph = width; + + wrap_width = get_label_wrap_width (label); + width = MIN (width, wrap_width); + width = MIN (width, + PANGO_SCALE * (gdk_screen_width () + 1) / 2); + + pango_layout_set_width (label->layout, width); + pango_layout_get_extents (label->layout, NULL, &logical_rect); + width = logical_rect.width; + height = logical_rect.height; + + /* Unfortunately, the above may leave us with a very unbalanced looking paragraph, + * so we try short search for a narrower width that leaves us with the same height + */ + if (longest_paragraph > 0) + { + gint nlines, perfect_width; + + nlines = pango_layout_get_line_count (label->layout); + perfect_width = (longest_paragraph + nlines - 1) / nlines; + + if (perfect_width < width) + { + pango_layout_set_width (label->layout, perfect_width); + pango_layout_get_extents (label->layout, NULL, &logical_rect); + + if (logical_rect.height <= height) + width = logical_rect.width; + else + { + gint mid_width = (perfect_width + width) / 2; + + if (mid_width > perfect_width) + { + pango_layout_set_width (label->layout, mid_width); + pango_layout_get_extents (label->layout, NULL, &logical_rect); + + if (logical_rect.height <= height) + width = logical_rect.width; + } + } + } + } + pango_layout_set_width (label->layout, width); + } + pango_layout_set_wrap (label->layout, label->wrap_mode); + } + else /* !label->wrap */ + pango_layout_set_width (label->layout, -1); + } +} + +static void +eel_editable_label_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EelEditableLabel *label; + gint width, height; + PangoRectangle logical_rect; + gint set_width; + gfloat xpad, ypad; + + g_assert (EEL_IS_EDITABLE_LABEL (widget)); + g_assert (requisition != NULL); + + label = EEL_EDITABLE_LABEL (widget); + + /* + * If word wrapping is on, then the height requisition can depend + * on: + * + * - Any width set on the widget via gtk_widget_set_size_request(). + * - The padding of the widget (xpad, set by gtk_misc_set_padding) + * + * Instead of trying to detect changes to these quantities, if we + * are wrapping, we just rewrap for each size request. Since + * size requisitions are cached by the GTK+ core, this is not + * expensive. + */ + + if (label->wrap) + eel_editable_label_recompute (label); + + eel_editable_label_ensure_layout (label, TRUE); + + gtk_misc_get_alignment (&label->misc, + &xpad, &ypad); + width = xpad * 2; + height = ypad * 2; + + pango_layout_get_extents (label->layout, NULL, &logical_rect); + + gtk_widget_get_size_request (widget, &set_width, NULL); + if (label->wrap && set_width > 0) + width += set_width; + else + width += PANGO_PIXELS (logical_rect.width); + + height += PANGO_PIXELS (logical_rect.height); + + requisition->width = width; + requisition->height = height; +} + +static void +eel_editable_label_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->size_allocate) (widget, allocation); +} + +static void +eel_editable_label_state_changed (GtkWidget *widget, + GtkStateType prev_state) +{ + EelEditableLabel *label; + + label = EEL_EDITABLE_LABEL (widget); + + eel_editable_label_select_region (label, 0, 0); + + if (GTK_WIDGET_CLASS (eel_editable_label_parent_class)->state_changed) + GTK_WIDGET_CLASS (eel_editable_label_parent_class)->state_changed (widget, prev_state); +} + +static void +eel_editable_label_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + EelEditableLabel *label; + static GdkColor gray = { 0, 0x8888, 0x8888, 0x8888 }; + + g_assert (EEL_IS_EDITABLE_LABEL (widget)); + + label = EEL_EDITABLE_LABEL (widget); + + /* We have to clear the layout, fonts etc. may have changed */ + eel_editable_label_recompute (label); + + /* Set the background, foreground and cursor colors based on + * the new theme selected. + */ + if (gtk_widget_get_realized (widget)) + { + GtkStyle *style; + + style = gtk_widget_get_style (widget); + gdk_window_set_background (gtk_widget_get_window (widget), &style->base[gtk_widget_get_state (widget)]); + + if (label->primary_cursor_gc != NULL) + { + gtk_gc_release (label->primary_cursor_gc); + label->primary_cursor_gc = NULL; + } + + if (label->secondary_cursor_gc != NULL) + { + gtk_gc_release (label->secondary_cursor_gc); + label->secondary_cursor_gc = NULL; + } + + label->primary_cursor_gc = make_cursor_gc (widget, + "cursor-color", + &style->black); + + label->secondary_cursor_gc = make_cursor_gc (widget, + "secondary-cursor-color", + &gray); + } +} + +static void +eel_editable_label_direction_changed (GtkWidget *widget, + GtkTextDirection previous_dir) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); + + if (label->layout) + pango_layout_context_changed (label->layout); + + GTK_WIDGET_CLASS (eel_editable_label_parent_class)->direction_changed (widget, previous_dir); +} + +static void +get_layout_location (EelEditableLabel *label, + gint *xp, + gint *yp) +{ + GtkMisc *misc; + GtkWidget *widget; + gfloat xalign, yalign; + GtkRequisition req; + gint x, y, xpad, ypad; + GtkAllocation allocation; + + misc = GTK_MISC (label); + widget = GTK_WIDGET (label); + gtk_misc_get_alignment (misc, &xalign, &yalign); + + if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) + xalign = 1.0 - xalign; + + gtk_widget_get_child_requisition (widget, &req); + gtk_misc_get_padding (misc, &xpad, &ypad); + + gtk_widget_get_allocation (widget, &allocation); + x = floor (xpad + + ((allocation.width - req.width) * xalign) + + 0.5); + + y = floor (ypad + + ((allocation.height - req.height) * yalign) + + 0.5); + + if (xp) + *xp = x; + + if (yp) + *yp = y; +} + +static void +eel_editable_label_get_cursor_pos (EelEditableLabel *label, + PangoRectangle *strong_pos, + PangoRectangle *weak_pos) +{ + const gchar *text; + const gchar *preedit_text; + gint index; + + eel_editable_label_ensure_layout (label, TRUE); + + text = pango_layout_get_text (label->layout); + preedit_text = text + label->selection_anchor; + index = label->selection_anchor + + g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor) - preedit_text; + + pango_layout_get_cursor_pos (label->layout, index, strong_pos, weak_pos); +} + +/* Copied from gtkutil private function */ +static gboolean +eel_editable_label_get_block_cursor_location (EelEditableLabel *label, + gint *index, + PangoRectangle *pos, + gboolean *at_line_end) +{ + const gchar *text; + const gchar *preedit_text; + PangoLayoutLine *layout_line; + PangoRectangle strong_pos, weak_pos; + gint line_no; + gboolean rtl; + PangoContext *context; + PangoFontMetrics *metrics; + const PangoFontDescription *font_desc; + + eel_editable_label_ensure_layout (label, TRUE); + + text = pango_layout_get_text (label->layout); + preedit_text = text + label->selection_anchor; + text = g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor); + index[0] = label->selection_anchor + text - preedit_text; + + pango_layout_index_to_pos (label->layout, index[0], pos); + + index[1] = label->selection_anchor + g_utf8_next_char (text) - preedit_text; + + if (pos->width != 0) + { + if (at_line_end) + *at_line_end = FALSE; + if (pos->width < 0) /* RTL char, shift x value back to top left of rect */ + { + pos->x += pos->width; + pos->width = -pos->width; + } + return TRUE; + } + + pango_layout_index_to_line_x (label->layout, index[0], FALSE, &line_no, NULL); + layout_line = pango_layout_get_line_readonly (label->layout, line_no); + if (layout_line == NULL) + return FALSE; + + text = pango_layout_get_text (label->layout); + if (index[0] < layout_line->start_index + layout_line->length) + { + /* this may be a zero-width character in the middle of the line, + * or it could be a character where line is wrapped, we do want + * block cursor in latter case */ + if (g_utf8_next_char (text + index[0]) - text != + layout_line->start_index + layout_line->length) + { + /* zero-width character in the middle of the line, do not + * bother with block cursor */ + return FALSE; + } + } + + /* Cursor is at the line end. It may be an empty line, or it could + * be on the left or on the right depending on text direction, or it + * even could be in the middle of visual layout in bidi text. */ + + pango_layout_get_cursor_pos (label->layout, index[0], &strong_pos, &weak_pos); + + if (strong_pos.x != weak_pos.x) + { + /* do not show block cursor in this case, since the character typed + * in may or may not appear at the cursor position */ + return FALSE; + } + + context = pango_layout_get_context (label->layout); + + /* In case when index points to the end of line, pos->x is always most right + * pixel of the layout line, so we need to correct it for RTL text. */ + if (layout_line->length) + { + if (layout_line->resolved_dir == PANGO_DIRECTION_RTL) + { + PangoLayoutIter *iter; + PangoRectangle line_rect; + gint i; + gint left, right; + const gchar *p; + + p = g_utf8_prev_char (text + index[0]); + + pango_layout_line_index_to_x (layout_line, p - text, FALSE, &left); + pango_layout_line_index_to_x (layout_line, p - text, TRUE, &right); + pos->x = MIN (left, right); + + iter = pango_layout_get_iter (label->layout); + for (i = 0; i < line_no; i++) + pango_layout_iter_next_line (iter); + pango_layout_iter_get_line_extents (iter, NULL, &line_rect); + pango_layout_iter_free (iter); + + rtl = TRUE; + pos->x += line_rect.x; + } + else + rtl = FALSE; + } + else + { + rtl = pango_context_get_base_dir (context) == PANGO_DIRECTION_RTL; + } + + font_desc = pango_layout_get_font_description (label->layout); + if (!font_desc) + font_desc = pango_context_get_font_description (context); + + metrics = pango_context_get_metrics (context, font_desc, NULL); + pos->width = pango_font_metrics_get_approximate_char_width (metrics); + pango_font_metrics_unref (metrics); + + if (rtl) + pos->x -= pos->width - 1; + + if (at_line_end) + *at_line_end = TRUE; + + return pos->width != 0; +} + + +/* These functions are copies from gtk+, as they are not exported from gtk+ */ + +static GdkGC * +make_cursor_gc (GtkWidget *widget, + const gchar *property_name, + GdkColor *fallback) +{ + GdkGCValues gc_values; + GdkGCValuesMask gc_values_mask; + GdkColor *cursor_color; + GtkStyle *style; + + style = gtk_widget_get_style (widget); + gtk_widget_style_get (widget, property_name, &cursor_color, NULL); + + gc_values_mask = GDK_GC_FOREGROUND; + if (cursor_color) + { + gc_values.foreground = *cursor_color; + gdk_color_free (cursor_color); + } + else + gc_values.foreground = *fallback; + + gdk_rgb_find_color (style->colormap, &gc_values.foreground); + return gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); +} + +static void +_eel_draw_insertion_cursor (GtkWidget *widget, + GdkDrawable *drawable, + GdkGC *gc, + GdkRectangle *location, + GtkTextDirection direction, + gboolean draw_arrow) +{ + gint stem_width; + gint arrow_width; + gint x, y; + gint i; + gfloat cursor_aspect_ratio; + gint offset; + + g_assert (direction != GTK_TEXT_DIR_NONE); + + gtk_widget_style_get (widget, "cursor-aspect-ratio", &cursor_aspect_ratio, NULL); + + stem_width = location->height * cursor_aspect_ratio + 1; + arrow_width = stem_width + 1; + + /* put (stem_width % 2) on the proper side of the cursor */ + if (direction == GTK_TEXT_DIR_LTR) + offset = stem_width / 2; + else + offset = stem_width - stem_width / 2; + + for (i = 0; i < stem_width; i++) + gdk_draw_line (drawable, gc, + location->x + i - offset, location->y, + location->x + i - offset, location->y + location->height - 1); + + if (draw_arrow) + { + if (direction == GTK_TEXT_DIR_RTL) + { + x = location->x - offset - 1; + y = location->y + location->height - arrow_width * 2 - arrow_width + 1; + + for (i = 0; i < arrow_width; i++) + { + gdk_draw_line (drawable, gc, + x, y + i + 1, + x, y + 2 * arrow_width - i - 1); + x --; + } + } + else if (direction == GTK_TEXT_DIR_LTR) + { + x = location->x + stem_width - offset; + y = location->y + location->height - arrow_width * 2 - arrow_width + 1; + + for (i = 0; i < arrow_width; i++) + { + gdk_draw_line (drawable, gc, + x, y + i + 1, + x, y + 2 * arrow_width - i - 1); + x++; + } + } + } +} + +static void +eel_editable_label_draw_cursor (EelEditableLabel *label, gint xoffset, gint yoffset) +{ + if (gtk_widget_is_drawable (GTK_WIDGET (label))) + { + GtkWidget *widget = GTK_WIDGET (label); + + GtkTextDirection keymap_direction; + GtkTextDirection widget_direction; + gboolean split_cursor; + gboolean block; + gboolean block_at_line_end; + gint range[2]; + PangoRectangle strong_pos, weak_pos; + PangoRectangle *cursor1 = NULL; + PangoRectangle *cursor2 = NULL; + GdkRectangle cursor_location; + GtkTextDirection dir1 = GTK_TEXT_DIR_NONE; + GtkTextDirection dir2 = GTK_TEXT_DIR_NONE; + + keymap_direction = + (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ? + GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; + + widget_direction = gtk_widget_get_direction (widget); + + if (label->overwrite_mode && + eel_editable_label_get_block_cursor_location (label, range, + &strong_pos, + &block_at_line_end)) + block = TRUE; + else + block = FALSE; + + if (!block) + { + eel_editable_label_get_cursor_pos (label, &strong_pos, &weak_pos); + + g_object_get (gtk_widget_get_settings (widget), + "gtk-split-cursor", &split_cursor, + NULL); + + dir1 = widget_direction; + + if (split_cursor) + { + cursor1 = &strong_pos; + + if (strong_pos.x != weak_pos.x || + strong_pos.y != weak_pos.y) + { + dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR; + cursor2 = &weak_pos; + } + } + else + { + if (keymap_direction == widget_direction) + cursor1 = &strong_pos; + else + cursor1 = &weak_pos; + } + + cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x); + cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y); + cursor_location.width = 0; + cursor_location.height = PANGO_PIXELS (cursor1->height); + + _eel_draw_insertion_cursor (widget, gtk_widget_get_window (widget), + label->primary_cursor_gc, + &cursor_location, dir1, + dir2 != GTK_TEXT_DIR_NONE); + + if (dir2 != GTK_TEXT_DIR_NONE) + { + cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x); + cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y); + cursor_location.width = 0; + cursor_location.height = PANGO_PIXELS (cursor2->height); + + _eel_draw_insertion_cursor (widget, gtk_widget_get_window (widget), + label->secondary_cursor_gc, + &cursor_location, dir2, TRUE); + } + } + else /* Block cursor */ + { + GdkRegion *clip; + + gdk_draw_rectangle (gtk_widget_get_window (widget), label->primary_cursor_gc, TRUE, + xoffset + PANGO_PIXELS (strong_pos.x), + yoffset + PANGO_PIXELS (strong_pos.y), + PANGO_PIXELS (strong_pos.width), + PANGO_PIXELS (strong_pos.height)); + + if (!block_at_line_end) + { + clip = gdk_pango_layout_get_clip_region (label->layout, + xoffset, yoffset, + range, 1); + + /* FIXME should use gtk_paint, but it can't use a clip + * region + */ + + gdk_gc_set_clip_region (label->primary_cursor_gc, clip); + + gdk_draw_layout_with_colors (gtk_widget_get_window (widget), + label->primary_cursor_gc, + xoffset, yoffset, + label->layout, + >k_widget_get_style (widget)->base[GTK_STATE_NORMAL], + NULL); + + gdk_gc_set_clip_region (label->primary_cursor_gc, NULL); + gdk_region_destroy (clip); + } + } + } +} + + +static gint +eel_editable_label_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EelEditableLabel *label; + GtkStyle *style; + gint x, y; + + g_assert (EEL_IS_EDITABLE_LABEL (widget)); + g_assert (event != NULL); + + label = EEL_EDITABLE_LABEL (widget); + style = gtk_widget_get_style (widget); + + eel_editable_label_ensure_layout (label, TRUE); + + if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) && + label->text) + { + get_layout_location (label, &x, &y); + + gtk_paint_layout (style, + gtk_widget_get_window (widget), + gtk_widget_get_state (widget), + TRUE, + &event->area, + widget, + "label", + x, y, + label->layout); + + if (label->selection_anchor != label->selection_end) + { + gint range[2]; + const char *text; + GdkRegion *clip; + GtkStateType state; + + range[0] = label->selection_anchor; + range[1] = label->selection_end; + + /* Handle possible preedit string */ + if (label->preedit_length > 0 && + range[1] > label->selection_anchor) + { + text = pango_layout_get_text (label->layout) + label->selection_anchor; + range[1] += g_utf8_offset_to_pointer (text, label->preedit_length) - text; + } + + if (range[0] > range[1]) + { + gint tmp = range[0]; + range[0] = range[1]; + range[1] = tmp; + } + + clip = gdk_pango_layout_get_clip_region (label->layout, + x, y, + range, + 1); + + /* FIXME should use gtk_paint, but it can't use a clip + * region + */ + + gdk_gc_set_clip_region (style->black_gc, clip); + + + state = GTK_STATE_SELECTED; + if (!gtk_widget_has_focus (widget)) + state = GTK_STATE_ACTIVE; + + gdk_draw_layout_with_colors (gtk_widget_get_window (widget), + style->black_gc, + x, y, + label->layout, + &style->text[state], + &style->base[state]); + + gdk_gc_set_clip_region (style->black_gc, NULL); + gdk_region_destroy (clip); + } + else if (gtk_widget_has_focus (widget)) + eel_editable_label_draw_cursor (label, x, y); + + if (label->draw_outline) + { + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + gdk_draw_rectangle (gtk_widget_get_window (widget), + style->text_gc [gtk_widget_get_state (widget)], + FALSE, + 0, 0, + allocation.width - 1, + allocation.height - 1); + } + } + + return FALSE; +} + +static void +eel_editable_label_realize (GtkWidget *widget) +{ + EelEditableLabel *label; + GdkWindowAttr attributes; + gint attributes_mask; + static GdkColor gray = { 0, 0x8888, 0x8888, 0x8888 }; + GtkAllocation allocation; + GdkWindow *window; + GtkStyle *style; + + gtk_widget_set_realized (widget, TRUE); + label = EEL_EDITABLE_LABEL (widget); + gtk_widget_get_allocation (widget, &allocation); + + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.cursor = gdk_cursor_new (GDK_XTERM); + attributes.event_mask = gtk_widget_get_events (widget) | + (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON3_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_POINTER_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR; + + window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gtk_widget_set_window (widget, window); + gdk_window_set_user_data (window, widget); + + gdk_cursor_unref (attributes.cursor); + + style = gtk_style_attach (gtk_widget_get_style (widget) , gtk_widget_get_window (widget)); + gtk_widget_set_style (widget, style); + + gdk_window_set_background (gtk_widget_get_window (widget), &style->base[gtk_widget_get_state (widget)]); + + gtk_im_context_set_client_window (label->im_context, gtk_widget_get_window (widget)); + + label->primary_cursor_gc = make_cursor_gc (widget, + "cursor-color", + &style->black); + + label->secondary_cursor_gc = make_cursor_gc (widget, + "secondary-cursor-color", + &gray); +} + +static void +eel_editable_label_unrealize (GtkWidget *widget) +{ + EelEditableLabel *label; + + label = EEL_EDITABLE_LABEL (widget); + + gtk_gc_release (label->primary_cursor_gc); + label->primary_cursor_gc = NULL; + + gtk_gc_release (label->secondary_cursor_gc); + label->secondary_cursor_gc = NULL; + + /* Strange. Copied from GtkEntry, should be NULL? */ + gtk_im_context_set_client_window (label->im_context, NULL); + + (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->unrealize) (widget); +} + +static void +eel_editable_label_map (GtkWidget *widget) +{ + (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->map) (widget); +} + +static void +eel_editable_label_unmap (GtkWidget *widget) +{ + (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->unmap) (widget); +} + +static void +window_to_layout_coords (EelEditableLabel *label, + gint *x, + gint *y) +{ + gint lx, ly; + + /* get layout location in gtk_widget_get_window (widget) coords */ + get_layout_location (label, &lx, &ly); + + if (x) + *x -= lx; /* go to layout */ + + if (y) + *y -= ly; /* go to layout */ +} + +static void +get_layout_index (EelEditableLabel *label, + gint x, + gint y, + gint *index) +{ + gint trailing = 0; + const gchar *cluster; + const gchar *cluster_end; + + *index = 0; + + eel_editable_label_ensure_layout (label, TRUE); + + window_to_layout_coords (label, &x, &y); + + x *= PANGO_SCALE; + y *= PANGO_SCALE; + + pango_layout_xy_to_index (label->layout, + x, y, + index, &trailing); + + if (*index >= label->selection_anchor && label->preedit_length) + { + if (*index >= label->selection_anchor + label->preedit_length) + *index -= label->preedit_length; + else + { + *index = label->selection_anchor; + trailing = 0; + } + } + + cluster = label->text + *index; + cluster_end = cluster; + while (trailing) + { + cluster_end = g_utf8_next_char (cluster_end); + --trailing; + } + + *index += (cluster_end - cluster); +} + +static void +eel_editable_label_select_word (EelEditableLabel *label) +{ + gint min, max; + + gint start_index = eel_editable_label_move_backward_word (label, label->selection_end); + gint end_index = eel_editable_label_move_forward_word (label, label->selection_end); + + min = MIN (label->selection_anchor, + label->selection_end); + max = MAX (label->selection_anchor, + label->selection_end); + + min = MIN (min, start_index); + max = MAX (max, end_index); + + eel_editable_label_select_region_index (label, min, max); +} + +static gint +eel_editable_label_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + EelEditableLabel *label; + gint index = 0; + + label = EEL_EDITABLE_LABEL (widget); + + if (event->button == 1) + { + if (!gtk_widget_has_focus (widget)) + gtk_widget_grab_focus (widget); + + if (event->type == GDK_3BUTTON_PRESS) + { + eel_editable_label_select_region_index (label, 0, strlen (label->text)); + return TRUE; + } + + if (event->type == GDK_2BUTTON_PRESS) + { + eel_editable_label_select_word (label); + return TRUE; + } + + get_layout_index (label, event->x, event->y, &index); + + if ((label->selection_anchor != + label->selection_end) && + (event->state & GDK_SHIFT_MASK)) + { + gint min, max; + + /* extend (same as motion) */ + min = MIN (label->selection_anchor, + label->selection_end); + max = MAX (label->selection_anchor, + label->selection_end); + + min = MIN (min, index); + max = MAX (max, index); + + /* ensure the anchor is opposite index */ + if (index == min) + { + gint tmp = min; + min = max; + max = tmp; + } + + eel_editable_label_select_region_index (label, min, max); + } + else + { + if (event->type == GDK_3BUTTON_PRESS) + eel_editable_label_select_region_index (label, 0, strlen (label->text)); + else if (event->type == GDK_2BUTTON_PRESS) + eel_editable_label_select_word (label); + else + /* start a replacement */ + eel_editable_label_select_region_index (label, index, index); + } + + return TRUE; + } + else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) + { + get_layout_index (label, event->x, event->y, &index); + + eel_editable_label_select_region_index (label, index, index); + eel_editable_label_paste (label, GDK_SELECTION_PRIMARY); + + return TRUE; + } + else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) + { + eel_editable_label_do_popup (label, event); + + return TRUE; + + } + return FALSE; +} + +static gint +eel_editable_label_button_release (GtkWidget *widget, + GdkEventButton *event) + +{ + if (event->button != 1) + return FALSE; + + /* The goal here is to return TRUE iff we ate the + * button press to start selecting. + */ + + return TRUE; +} + +static gint +eel_editable_label_motion (GtkWidget *widget, + GdkEventMotion *event) +{ + EelEditableLabel *label; + gint index; + gint x, y; + + label = EEL_EDITABLE_LABEL (widget); + + if ((event->state & GDK_BUTTON1_MASK) == 0) + return FALSE; + + gdk_window_get_pointer (gtk_widget_get_window (widget), + &x, &y, NULL); + + get_layout_index (label, x, y, &index); + + eel_editable_label_select_region_index (label, + label->selection_anchor, + index); + + return TRUE; +} + +static void +get_text_callback (GtkClipboard *clipboard, + GtkSelectionData *selection_data, + guint info, + gpointer user_data_or_owner) +{ + EelEditableLabel *label; + + label = EEL_EDITABLE_LABEL (user_data_or_owner); + + if ((label->selection_anchor != label->selection_end) && + label->text) + { + gint start, end; + gint len; + + start = MIN (label->selection_anchor, + label->selection_end); + end = MAX (label->selection_anchor, + label->selection_end); + + len = strlen (label->text); + + if (end > len) + end = len; + + if (start > len) + start = len; + + gtk_selection_data_set_text (selection_data, + label->text + start, + end - start); + } +} + +static void +clear_text_callback (GtkClipboard *clipboard, + gpointer user_data_or_owner) +{ + EelEditableLabel *label; + + label = EEL_EDITABLE_LABEL (user_data_or_owner); + + label->selection_anchor = label->selection_end; + + gtk_widget_queue_draw (GTK_WIDGET (label)); +} + +static void +eel_editable_label_select_region_index (EelEditableLabel *label, + gint anchor_index, + gint end_index) +{ + GtkClipboard *clipboard; + + g_assert (EEL_IS_EDITABLE_LABEL (label)); + + + if (label->selection_anchor == anchor_index && + label->selection_end == end_index) + return; + + eel_editable_label_reset_im_context (label); + + label->selection_anchor = anchor_index; + label->selection_end = end_index; + + clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); + + if (anchor_index != end_index) + { + GtkTargetList *list; + GtkTargetEntry *targets; + guint n_targets; + + list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_text_targets (list, 0); + targets = gtk_target_table_new_from_list (list, &n_targets); + + gtk_clipboard_set_with_owner (clipboard, + targets, n_targets, + get_text_callback, + clear_text_callback, + G_OBJECT (label)); + + gtk_clipboard_set_can_store (clipboard, NULL, 0); + gtk_target_table_free (targets, n_targets); + gtk_target_list_unref (list); + } + else + { + if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label)) + gtk_clipboard_clear (clipboard); + } + + gtk_widget_queue_draw (GTK_WIDGET (label)); + + g_object_freeze_notify (G_OBJECT (label)); + g_object_notify (G_OBJECT (label), "cursor_position"); + g_object_notify (G_OBJECT (label), "selection_bound"); + g_object_thaw_notify (G_OBJECT (label)); +} + +/** + * eel_editable_label_select_region: + * @label: a #EelEditableLabel + * @start_offset: start offset (in characters not bytes) + * @end_offset: end offset (in characters not bytes) + * + * Selects a range of characters in the label, if the label is selectable. + * See eel_editable_label_set_selectable(). If the label is not selectable, + * this function has no effect. If @start_offset or + * @end_offset are -1, then the end of the label will be substituted. + * + **/ +void +eel_editable_label_select_region (EelEditableLabel *label, + gint start_offset, + gint end_offset) +{ + g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); + + if (label->text) + { + if (start_offset < 0) + start_offset = g_utf8_strlen (label->text, -1); + + if (end_offset < 0) + end_offset = g_utf8_strlen (label->text, -1); + + eel_editable_label_select_region_index (label, + g_utf8_offset_to_pointer (label->text, start_offset) - label->text, + g_utf8_offset_to_pointer (label->text, end_offset) - label->text); + } +} + +/** + * eel_editable_label_get_selection_bounds: + * @label: a #EelEditableLabel + * @start: return location for start of selection, as a character offset + * @end: return location for end of selection, as a character offset + * + * Gets the selected range of characters in the label, returning %TRUE + * if there's a selection. + * + * Return value: %TRUE if selection is non-empty + **/ +gboolean +eel_editable_label_get_selection_bounds (EelEditableLabel *label, + gint *start, + gint *end) +{ + gint start_index, end_index; + gint start_offset, end_offset; + gint len; + + g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), FALSE); + + + start_index = MIN (label->selection_anchor, + label->selection_end); + end_index = MAX (label->selection_anchor, + label->selection_end); + + len = strlen (label->text); + + if (end_index > len) + end_index = len; + + if (start_index > len) + start_index = len; + + start_offset = g_utf8_strlen (label->text, start_index); + end_offset = g_utf8_strlen (label->text, end_index); + + if (start_offset > end_offset) + { + gint tmp = start_offset; + start_offset = end_offset; + end_offset = tmp; + } + + if (start) + *start = start_offset; + + if (end) + *end = end_offset; + + return start_offset != end_offset; +} + + +/** + * eel_editable_label_get_layout: + * @label: a #EelEditableLabel + * + * Gets the #PangoLayout used to display the label. + * The layout is useful to e.g. convert text positions to + * pixel positions, in combination with eel_editable_label_get_layout_offsets(). + * The returned layout is owned by the label so need not be + * freed by the caller. + * + * Return value: the #PangoLayout for this label + **/ +PangoLayout* +eel_editable_label_get_layout (EelEditableLabel *label) +{ + g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), NULL); + + eel_editable_label_ensure_layout (label, TRUE); + + return label->layout; +} + +/** + * eel_editable_label_get_layout_offsets: + * @label: a #EelEditableLabel + * @x: location to store X offset of layout, or %NULL + * @y: location to store Y offset of layout, or %NULL + * + * Obtains the coordinates where the label will draw the #PangoLayout + * representing the text in the label; useful to convert mouse events + * into coordinates inside the #PangoLayout, e.g. to take some action + * if some part of the label is clicked. Of course you will need to + * create a #GtkEventBox to receive the events, and pack the label + * inside it, since labels are a #GTK_NO_WINDOW widget. Remember + * when using the #PangoLayout functions you need to convert to + * and from pixels using PANGO_PIXELS() or #PANGO_SCALE. + * + **/ +void +eel_editable_label_get_layout_offsets (EelEditableLabel *label, + gint *x, + gint *y) +{ + g_return_if_fail (EEL_IS_EDITABLE_LABEL (label)); + + get_layout_location (label, x, y); +} + +static void +eel_editable_label_pend_cursor_blink (EelEditableLabel *label) +{ + /* TODO */ +} + +static void +eel_editable_label_check_cursor_blink (EelEditableLabel *label) +{ + /* TODO */ +} + +static gint +eel_editable_label_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); + + eel_editable_label_pend_cursor_blink (label); + + if (gtk_im_context_filter_keypress (label->im_context, event)) + { + /*TODO eel_editable_label_obscure_mouse_cursor (label);*/ + label->need_im_reset = TRUE; + return TRUE; + } + + if (GTK_WIDGET_CLASS (eel_editable_label_parent_class)->key_press_event (widget, event)) + /* Activate key bindings + */ + return TRUE; + + return FALSE; +} + +static gint +eel_editable_label_key_release (GtkWidget *widget, + GdkEventKey *event) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); + + if (gtk_im_context_filter_keypress (label->im_context, event)) + { + label->need_im_reset = TRUE; + return TRUE; + } + + return GTK_WIDGET_CLASS (eel_editable_label_parent_class)->key_release_event (widget, event); +} + +static void +eel_editable_label_keymap_direction_changed (GdkKeymap *keymap, + EelEditableLabel *label) +{ + gtk_widget_queue_draw (GTK_WIDGET (label)); +} + +static gint +eel_editable_label_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); + + gtk_widget_queue_draw (widget); + + label->need_im_reset = TRUE; + gtk_im_context_focus_in (label->im_context); + + g_signal_connect (gdk_keymap_get_default (), + "direction_changed", + G_CALLBACK (eel_editable_label_keymap_direction_changed), label); + + eel_editable_label_check_cursor_blink (label); + + return FALSE; +} + +static gint +eel_editable_label_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (widget); + + gtk_widget_queue_draw (widget); + + label->need_im_reset = TRUE; + gtk_im_context_focus_out (label->im_context); + + eel_editable_label_check_cursor_blink (label); + + g_signal_handlers_disconnect_by_func (gdk_keymap_get_default (), + (gpointer) eel_editable_label_keymap_direction_changed, + label); + + return FALSE; +} + +static void +eel_editable_label_delete_text (EelEditableLabel *label, + int start_pos, + int end_pos) +{ + int anchor, end; + + if (start_pos < 0) + start_pos = 0; + if (end_pos < 0 || end_pos > label->n_bytes) + end_pos = label->n_bytes; + + if (start_pos < end_pos) + { + g_memmove (label->text + start_pos, label->text + end_pos, label->n_bytes + 1 - end_pos); + label->n_bytes -= (end_pos - start_pos); + + anchor = label->selection_anchor; + if (anchor > start_pos) + anchor -= MIN (anchor, end_pos) - start_pos; + + end = label->selection_end; + if (end > start_pos) + end -= MIN (end, end_pos) - start_pos; + + /* We might have changed the selection */ + eel_editable_label_select_region_index (label, anchor, end); + + eel_editable_label_recompute (label); + gtk_widget_queue_resize (GTK_WIDGET (label)); + + g_object_notify (G_OBJECT (label), "text"); + g_signal_emit_by_name (GTK_EDITABLE (label), "changed"); + } +} + +static void +eel_editable_label_insert_text (EelEditableLabel *label, + const gchar *new_text, + gint new_text_length, + gint *index) +{ + if (new_text_length + label->n_bytes + 1 > label->text_size) + { + while (new_text_length + label->n_bytes + 1 > label->text_size) + { + if (label->text_size == 0) + label->text_size = 16; + else + label->text_size *= 2; + } + + label->text = g_realloc (label->text, label->text_size); + } + + g_object_freeze_notify (G_OBJECT (label)); + + g_memmove (label->text + *index + new_text_length, label->text + *index, label->n_bytes - *index); + memcpy (label->text + *index, new_text, new_text_length); + + label->n_bytes += new_text_length; + + /* NUL terminate for safety and convenience */ + label->text[label->n_bytes] = '\0'; + + g_object_notify (G_OBJECT (label), "text"); + + if (label->selection_anchor > *index) + { + g_object_notify (G_OBJECT (label), "cursor_position"); + g_object_notify (G_OBJECT (label), "selection_bound"); + label->selection_anchor += new_text_length; + } + + if (label->selection_end > *index) + { + label->selection_end += new_text_length; + g_object_notify (G_OBJECT (label), "selection_bound"); + } + + *index += new_text_length; + + eel_editable_label_recompute (label); + gtk_widget_queue_resize (GTK_WIDGET (label)); + + g_object_thaw_notify (G_OBJECT (label)); + g_signal_emit_by_name (GTK_EDITABLE (label), "changed"); +} + +/* Used for im_commit_cb and inserting Unicode chars */ +static void +eel_editable_label_enter_text (EelEditableLabel *label, + const gchar *str) +{ + GtkEditable *editable = GTK_EDITABLE (label); + gint tmp_pos; + gboolean old_need_im_reset; + + /* Never reset the im while commiting, as that resets possible im state */ + old_need_im_reset = label->need_im_reset; + label->need_im_reset = FALSE; + + if (label->selection_end != label->selection_anchor) + gtk_editable_delete_selection (editable); + else + { + if (label->overwrite_mode) + eel_editable_label_delete_from_cursor (label, GTK_DELETE_CHARS, 1); + } + + tmp_pos = g_utf8_pointer_to_offset (label->text, + label->text + label->selection_anchor); + gtk_editable_insert_text (GTK_EDITABLE (label), str, strlen (str), &tmp_pos); + tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text; + eel_editable_label_select_region_index (label, tmp_pos, tmp_pos); + + label->need_im_reset = old_need_im_reset; +} + +/* IM Context Callbacks + */ + +static void +eel_editable_label_commit_cb (GtkIMContext *context, + const gchar *str, + EelEditableLabel *label) +{ + eel_editable_label_enter_text (label, str); +} + +static void +eel_editable_label_preedit_changed_cb (GtkIMContext *context, + EelEditableLabel *label) +{ + gchar *preedit_string; + gint cursor_pos; + + gtk_im_context_get_preedit_string (label->im_context, + &preedit_string, NULL, + &cursor_pos); + label->preedit_length = strlen (preedit_string); + cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); + label->preedit_cursor = cursor_pos; + g_free (preedit_string); + + eel_editable_label_recompute (label); + gtk_widget_queue_resize (GTK_WIDGET (label)); +} + +static gboolean +eel_editable_label_retrieve_surrounding_cb (GtkIMContext *context, + EelEditableLabel *label) +{ + gtk_im_context_set_surrounding (context, + label->text, + strlen (label->text) + 1, + label->selection_end); + + return TRUE; +} + +static gboolean +eel_editable_label_delete_surrounding_cb (GtkIMContext *slave, + gint offset, + gint n_chars, + EelEditableLabel *label) +{ + gint current_pos; + + current_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); + gtk_editable_delete_text (GTK_EDITABLE (label), + current_pos + offset, + current_pos + offset + n_chars); + + return TRUE; +} + +static gboolean +eel_editable_label_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + /* We never want to be in the tab chain */ + return FALSE; +} + +/* Compute the X position for an offset that corresponds to the "more important + * cursor position for that offset. We use this when trying to guess to which + * end of the selection we should go to when the user hits the left or + * right arrow key. + */ +static void +get_better_cursor (EelEditableLabel *label, + gint index, + gint *x, + gint *y) +{ + GtkTextDirection keymap_direction = + (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ? + GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; + GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label)); + gboolean split_cursor; + PangoRectangle strong_pos, weak_pos; + + g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)), + "gtk-split-cursor", &split_cursor, + NULL); + + eel_editable_label_get_cursor_pos (label, &strong_pos, &weak_pos); + + if (split_cursor) + { + *x = strong_pos.x / PANGO_SCALE; + *y = strong_pos.y / PANGO_SCALE; + } + else + { + if (keymap_direction == widget_direction) + { + *x = strong_pos.x / PANGO_SCALE; + *y = strong_pos.y / PANGO_SCALE; + } + else + { + *x = weak_pos.x / PANGO_SCALE; + *y = weak_pos.y / PANGO_SCALE; + } + } +} + + +static gint +eel_editable_label_move_logically (EelEditableLabel *label, + gint start, + gint count) +{ + gint offset = g_utf8_pointer_to_offset (label->text, + label->text + start); + + if (label->text) + { + PangoLogAttr *log_attrs; + gint n_attrs; + gint length; + + eel_editable_label_ensure_layout (label, FALSE); + + length = g_utf8_strlen (label->text, -1); + + pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); + + while (count > 0 && offset < length) + { + do + offset++; + while (offset < length && !log_attrs[offset].is_cursor_position); + + count--; + } + while (count < 0 && offset > 0) + { + do + offset--; + while (offset > 0 && !log_attrs[offset].is_cursor_position); + + count++; + } + + g_free (log_attrs); + } + + return g_utf8_offset_to_pointer (label->text, offset) - label->text; +} + +static gint +eel_editable_label_move_visually (EelEditableLabel *label, + gint start, + gint count) +{ + gint index; + + index = start; + + while (count != 0) + { + int new_index, new_trailing; + gboolean split_cursor; + gboolean strong; + + eel_editable_label_ensure_layout (label, FALSE); + + g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)), + "gtk-split-cursor", &split_cursor, + NULL); + + if (split_cursor) + strong = TRUE; + else + { + GtkTextDirection keymap_direction = + (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ? + GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; + + strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label)); + } + + if (count > 0) + { + pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing); + count--; + } + else + { + pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing); + count++; + } + + if (new_index < 0 || new_index == G_MAXINT) + break; + + index = new_index; + + while (new_trailing--) + index = g_utf8_next_char (label->text + new_index) - label->text; + } + + return index; +} + +static gint +eel_editable_label_move_line (EelEditableLabel *label, + gint start, + gint count) +{ + int n_lines, i; + int x; + PangoLayoutLine *line; + int index; + + eel_editable_label_ensure_layout (label, FALSE); + + n_lines = pango_layout_get_line_count (label->layout); + + for (i = 0; i < n_lines; i++) + { + line = pango_layout_get_line (label->layout, i); + if (start >= line->start_index && + start <= line->start_index + line->length) + { + pango_layout_line_index_to_x (line, start, FALSE, &x); + break; + } + } + if (i == n_lines) + i = n_lines - 1; + + i += count; + i = CLAMP (i, 0, n_lines - 1); + + line = pango_layout_get_line (label->layout, i); + if (pango_layout_line_x_to_index (line, + x, + &index, NULL)) + return index; + else + { + if (i == n_lines - 1) + return line->start_index + line->length; + else + return line->start_index + line->length - 1; + } +} + +static gint +eel_editable_label_move_forward_word (EelEditableLabel *label, + gint start) +{ + gint new_pos = g_utf8_pointer_to_offset (label->text, + label->text + start); + gint length; + + length = g_utf8_strlen (label->text, -1); + if (new_pos < length) + { + PangoLogAttr *log_attrs; + gint n_attrs; + + eel_editable_label_ensure_layout (label, FALSE); + + pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); + + /* Find the next word end, + (remember, n_attrs is one more than the number of of chars) */ + new_pos++; + while (new_pos < (n_attrs - 1) && !log_attrs[new_pos].is_word_end) + new_pos++; + + g_free (log_attrs); + } + + return g_utf8_offset_to_pointer (label->text, new_pos) - label->text; +} + + +static gint +eel_editable_label_move_backward_word (EelEditableLabel *label, + gint start) +{ + gint new_pos = g_utf8_pointer_to_offset (label->text, + label->text + start); + + if (new_pos > 0) + { + PangoLogAttr *log_attrs; + gint n_attrs; + + eel_editable_label_ensure_layout (label, FALSE); + + pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); + + new_pos -= 1; + + /* Find the previous word beginning */ + while (new_pos > 0 && !log_attrs[new_pos].is_word_start) + new_pos--; + + g_free (log_attrs); + } + + return g_utf8_offset_to_pointer (label->text, new_pos) - label->text; +} + +static void +eel_editable_label_move_cursor (EelEditableLabel *label, + GtkMovementStep step, + gint count, + gboolean extend_selection) +{ + gint new_pos; + + new_pos = label->selection_end; + + if (label->selection_end != label->selection_anchor && + !extend_selection) + { + /* If we have a current selection and aren't extending it, move to the + * start/or end of the selection as appropriate + */ + switch (step) + { + case GTK_MOVEMENT_DISPLAY_LINES: + case GTK_MOVEMENT_VISUAL_POSITIONS: + { + gint end_x, end_y; + gint anchor_x, anchor_y; + gboolean end_is_left; + + get_better_cursor (label, label->selection_end, &end_x, &end_y); + get_better_cursor (label, label->selection_anchor, &anchor_x, &anchor_y); + + end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x); + + if (count < 0) + new_pos = end_is_left ? label->selection_end : label->selection_anchor; + else + new_pos = !end_is_left ? label->selection_end : label->selection_anchor; + + break; + } + case GTK_MOVEMENT_LOGICAL_POSITIONS: + case GTK_MOVEMENT_WORDS: + if (count < 0) + new_pos = MIN (label->selection_end, label->selection_anchor); + else + new_pos = MAX (label->selection_end, label->selection_anchor); + break; + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_BUFFER_ENDS: + /* FIXME: Can do better here */ + new_pos = count < 0 ? 0 : strlen (label->text); + break; + case GTK_MOVEMENT_PARAGRAPHS: + case GTK_MOVEMENT_PAGES: + break; + default: + g_assert_not_reached (); + break; + } + } + else + { + switch (step) + { + case GTK_MOVEMENT_LOGICAL_POSITIONS: + new_pos = eel_editable_label_move_logically (label, new_pos, count); + break; + case GTK_MOVEMENT_VISUAL_POSITIONS: + new_pos = eel_editable_label_move_visually (label, new_pos, count); + break; + case GTK_MOVEMENT_WORDS: + while (count > 0) + { + new_pos = eel_editable_label_move_forward_word (label, new_pos); + count--; + } + while (count < 0) + { + new_pos = eel_editable_label_move_backward_word (label, new_pos); + count++; + } + break; + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_BUFFER_ENDS: + /* FIXME: Can do better here */ + new_pos = count < 0 ? 0 : strlen (label->text); + break; + case GTK_MOVEMENT_DISPLAY_LINES: + new_pos = eel_editable_label_move_line (label, new_pos, count); + break; + break; + case GTK_MOVEMENT_PARAGRAPHS: + case GTK_MOVEMENT_PAGES: + break; + default: + g_assert_not_reached (); + break; + } + } + + if (extend_selection) + eel_editable_label_select_region_index (label, + label->selection_anchor, + new_pos); + else + eel_editable_label_select_region_index (label, new_pos, new_pos); +} + +static void +eel_editable_label_reset_im_context (EelEditableLabel *label) +{ + if (label->need_im_reset) + { + label->need_im_reset = 0; + gtk_im_context_reset (label->im_context); + } +} + + +static void +eel_editable_label_delete_from_cursor (EelEditableLabel *label, + GtkDeleteType type, + gint count) +{ + GtkEditable *editable = GTK_EDITABLE (label); + gint start_pos = label->selection_anchor; + gint end_pos = label->selection_anchor; + + eel_editable_label_reset_im_context (label); + + if (label->selection_anchor != label->selection_end) + { + gtk_editable_delete_selection (editable); + return; + } + + switch (type) + { + case GTK_DELETE_CHARS: + end_pos = eel_editable_label_move_logically (label, start_pos, count); + start_pos = g_utf8_pointer_to_offset (label->text, label->text + start_pos); + end_pos = g_utf8_pointer_to_offset (label->text, label->text + end_pos); + gtk_editable_delete_text (GTK_EDITABLE (label), MIN (start_pos, end_pos), MAX (start_pos, end_pos)); + break; + case GTK_DELETE_WORDS: + if (count < 0) + { + /* Move to end of current word, or if not on a word, end of previous word */ + end_pos = eel_editable_label_move_backward_word (label, end_pos); + end_pos = eel_editable_label_move_forward_word (label, end_pos); + } + else if (count > 0) + { + /* Move to beginning of current word, or if not on a word, begining of next word */ + start_pos = eel_editable_label_move_forward_word (label, start_pos); + start_pos = eel_editable_label_move_backward_word (label, start_pos); + } + + /* Fall through */ + case GTK_DELETE_WORD_ENDS: + while (count < 0) + { + start_pos = eel_editable_label_move_backward_word (label, start_pos); + count++; + } + while (count > 0) + { + end_pos = eel_editable_label_move_forward_word (label, end_pos); + count--; + } + start_pos = g_utf8_pointer_to_offset (label->text, label->text + start_pos); + end_pos = g_utf8_pointer_to_offset (label->text, label->text + end_pos); + + gtk_editable_delete_text (GTK_EDITABLE (label), start_pos, end_pos); + break; + case GTK_DELETE_DISPLAY_LINE_ENDS: + case GTK_DELETE_PARAGRAPH_ENDS: + end_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); + if (count < 0) + gtk_editable_delete_text (GTK_EDITABLE (label), 0, end_pos); + else + gtk_editable_delete_text (GTK_EDITABLE (label), end_pos, -1); + break; + case GTK_DELETE_DISPLAY_LINES: + case GTK_DELETE_PARAGRAPHS: + gtk_editable_delete_text (GTK_EDITABLE (label), 0, -1); + break; + case GTK_DELETE_WHITESPACE: + /* TODO eel_editable_label_delete_whitespace (label); */ + break; + } + + eel_editable_label_pend_cursor_blink (label); +} + + +static void +eel_editable_label_copy_clipboard (EelEditableLabel *label) +{ + if (label->text) + { + gint start, end; + gint len; + + start = MIN (label->selection_anchor, + label->selection_end); + end = MAX (label->selection_anchor, + label->selection_end); + + len = strlen (label->text); + + if (end > len) + end = len; + + if (start > len) + start = len; + + if (start != end) + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), + label->text + start, end - start); + } +} + +static void +eel_editable_label_cut_clipboard (EelEditableLabel *label) +{ + if (label->text) + { + gint start, end; + gint len; + + start = MIN (label->selection_anchor, + label->selection_end); + end = MAX (label->selection_anchor, + label->selection_end); + + len = strlen (label->text); + + if (end > len) + end = len; + + if (start > len) + start = len; + + if (start != end) + { + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), + label->text + start, end - start); + start = g_utf8_pointer_to_offset (label->text, label->text + start); + end = g_utf8_pointer_to_offset (label->text, label->text + end); + gtk_editable_delete_text (GTK_EDITABLE (label), start, end); + } + } +} + +static void +paste_received (GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (data); + GtkEditable *editable = GTK_EDITABLE (label); + gint tmp_pos; + + if (text) + { + if (label->selection_end != label->selection_anchor) + gtk_editable_delete_selection (editable); + + tmp_pos = g_utf8_pointer_to_offset (label->text, + label->text + label->selection_anchor); + gtk_editable_insert_text (GTK_EDITABLE (label), text, strlen (text), &tmp_pos); + tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text; + eel_editable_label_select_region_index (label, tmp_pos, tmp_pos); + } + + g_object_unref (G_OBJECT (label)); +} + +static void +eel_editable_label_paste (EelEditableLabel *label, + GdkAtom selection) +{ + g_object_ref (G_OBJECT (label)); + gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (label), selection), + paste_received, label); +} + +static void +eel_editable_label_paste_clipboard (EelEditableLabel *label) +{ + eel_editable_label_paste (label, GDK_NONE); +} + +static void +eel_editable_label_select_all (EelEditableLabel *label) +{ + eel_editable_label_select_region_index (label, 0, strlen (label->text)); +} + +/* Quick hack of a popup menu + */ +static void +activate_cb (GtkWidget *menuitem, + EelEditableLabel *label) +{ + const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal"); + g_signal_emit_by_name (GTK_OBJECT (label), signal); +} + +static void +append_action_signal (EelEditableLabel *label, + GtkWidget *menu, + const gchar *stock_id, + const gchar *signal, + gboolean sensitive) +{ + GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL); + + g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal); + g_signal_connect (menuitem, "activate", + G_CALLBACK (activate_cb), label); + + gtk_widget_set_sensitive (menuitem, sensitive); + + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); +} + +static void +popup_menu_detach (GtkWidget *attach_widget, + GtkMenu *menu) +{ + EelEditableLabel *label; + label = EEL_EDITABLE_LABEL (attach_widget); + + label->popup_menu = NULL; +} + +static void +popup_position_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) +{ + EelEditableLabel *label; + GtkWidget *widget; + GtkRequisition req; + GtkAllocation allocation; + + label = EEL_EDITABLE_LABEL (user_data); + widget = GTK_WIDGET (label); + + g_assert (gtk_widget_get_realized (widget)); + + gdk_window_get_origin (gtk_widget_get_window (widget), x, y); + + /*gtk_widget_size_request (label->popup_menu, &req);*/ + gtk_widget_get_requisition (widget, &req); + gtk_widget_get_allocation (widget, &allocation); + + *x += allocation.width / 2; + *y += allocation.height; + + *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width)); + *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height)); +} + +static void +eel_editable_label_toggle_overwrite (EelEditableLabel *label) +{ + label->overwrite_mode = !label->overwrite_mode; + gtk_widget_queue_draw (GTK_WIDGET (label)); +} + +typedef struct +{ + EelEditableLabel *label; + gint button; + guint time; +} PopupInfo; + +static void +popup_targets_received (GtkClipboard *clipboard, + GtkSelectionData *data, + gpointer user_data) +{ + GtkWidget *menuitem, *submenu; + gboolean have_selection; + gboolean clipboard_contains_text; + PopupInfo *info; + EelEditableLabel *label; + + info = user_data; + label = info->label; + + if (gtk_widget_get_realized (GTK_WIDGET (label))) + { + if (label->popup_menu) + gtk_widget_destroy (label->popup_menu); + + label->popup_menu = gtk_menu_new (); + + gtk_menu_attach_to_widget (GTK_MENU (label->popup_menu), + GTK_WIDGET (label), + popup_menu_detach); + + have_selection = + label->selection_anchor != label->selection_end; + + clipboard_contains_text = gtk_selection_data_targets_include_text (data); + + append_action_signal (label, label->popup_menu, GTK_STOCK_CUT, "cut_clipboard", + have_selection); + append_action_signal (label, label->popup_menu, GTK_STOCK_COPY, "copy_clipboard", + have_selection); + append_action_signal (label, label->popup_menu, GTK_STOCK_PASTE, "paste_clipboard", + clipboard_contains_text); + + menuitem = gtk_menu_item_new_with_label (_("Select All")); + g_signal_connect_object (menuitem, "activate", + G_CALLBACK (eel_editable_label_select_all), label, + G_CONNECT_SWAPPED); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); + + menuitem = gtk_separator_menu_item_new (); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); + + menuitem = gtk_menu_item_new_with_label (_("Input Methods")); + gtk_widget_show (menuitem); + submenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + + gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); + + gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (label->im_context), + GTK_MENU_SHELL (submenu)); + + g_signal_emit (GTK_OBJECT (label), + signals[POPULATE_POPUP], 0, + label->popup_menu); + + if (info->button) + gtk_menu_popup (GTK_MENU (label->popup_menu), NULL, NULL, + NULL, NULL, + info->button, info->time); + else + { + gtk_menu_popup (GTK_MENU (label->popup_menu), NULL, NULL, + popup_position_func, label, + info->button, info->time); + gtk_menu_shell_select_first (GTK_MENU_SHELL (label->popup_menu), FALSE); + } + } + + g_object_unref (label); + g_free (info); +} + +static void +eel_editable_label_do_popup (EelEditableLabel *label, + GdkEventButton *event) +{ + PopupInfo *info = g_new (PopupInfo, 1); + + /* In order to know what entries we should make sensitive, we + * ask for the current targets of the clipboard, and when + * we get them, then we actually pop up the menu. + */ + info->label = g_object_ref (label); + + if (event) + { + info->button = event->button; + info->time = event->time; + } + else + { + info->button = 0; + info->time = gtk_get_current_event_time (); + } + + gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD), + gdk_atom_intern ("TARGETS", FALSE), + popup_targets_received, + info); +} + +/************ Editable implementation ****************/ + +static void +editable_insert_text_emit (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + gchar buf[64]; + gchar *text; + int text_length; + + text_length = g_utf8_strlen (label->text, -1); + + if (*position < 0 || *position > text_length) + *position = text_length; + + g_object_ref (G_OBJECT (editable)); + + if (new_text_length <= 63) + text = buf; + else + text = g_new (gchar, new_text_length + 1); + + text[new_text_length] = '\0'; + strncpy (text, new_text, new_text_length); + + g_signal_emit_by_name (editable, "insert_text", text, new_text_length, position); + + if (new_text_length > 63) + g_free (text); + + g_object_unref (G_OBJECT (editable)); +} + +static void +editable_delete_text_emit (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + int text_length; + + text_length = g_utf8_strlen (label->text, -1); + + if (end_pos < 0 || end_pos > text_length) + end_pos = text_length; + if (start_pos < 0) + start_pos = 0; + if (start_pos > end_pos) + start_pos = end_pos; + + g_object_ref (G_OBJECT (editable)); + + g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos); + + g_object_unref (G_OBJECT (editable)); +} + +static void +editable_insert_text (GtkEditable *editable, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + gint index; + + if (new_text_length < 0) + new_text_length = strlen (new_text); + + index = g_utf8_offset_to_pointer (label->text, *position) - label->text; + + eel_editable_label_insert_text (label, + new_text, + new_text_length, + &index); + + *position = g_utf8_pointer_to_offset (label->text, label->text + index); +} + +static void +editable_delete_text (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + int text_length; + gint start_index, end_index; + + text_length = g_utf8_strlen (label->text, -1); + + if (end_pos < 0 || end_pos > text_length) + end_pos = text_length; + if (start_pos < 0) + start_pos = 0; + if (start_pos > end_pos) + start_pos = end_pos; + + start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text; + end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text; + + eel_editable_label_delete_text (label, start_index, end_index); +} + +static gchar * +editable_get_chars (GtkEditable *editable, + gint start_pos, + gint end_pos) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + int text_length; + gint start_index, end_index; + + text_length = g_utf8_strlen (label->text, -1); + + if (end_pos < 0 || end_pos > text_length) + end_pos = text_length; + if (start_pos < 0) + start_pos = 0; + if (start_pos > end_pos) + start_pos = end_pos; + + start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text; + end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text; + + return g_strndup (label->text + start_index, end_index - start_index); +} + +static void +editable_set_selection_bounds (GtkEditable *editable, + gint start, + gint end) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + int text_length; + gint start_index, end_index; + + text_length = g_utf8_strlen (label->text, -1); + + if (end < 0 || end > text_length) + end = text_length; + if (start < 0) + start = text_length; + if (start > text_length) + start = text_length; + + eel_editable_label_reset_im_context (label); + + start_index = g_utf8_offset_to_pointer (label->text, start) - label->text; + end_index = g_utf8_offset_to_pointer (label->text, end) - label->text; + + eel_editable_label_select_region_index (label, start_index, end_index); +} + +static gboolean +editable_get_selection_bounds (GtkEditable *editable, + gint *start, + gint *end) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + + *start = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); + *end = g_utf8_pointer_to_offset (label->text, label->text + label->selection_end); + + return (label->selection_anchor != label->selection_end); +} + +static void +editable_real_set_position (GtkEditable *editable, + gint position) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + int text_length; + int index; + + text_length = g_utf8_strlen (label->text, -1); + + if (position < 0 || position > text_length) + position = text_length; + + index = g_utf8_offset_to_pointer (label->text, position) - label->text; + + if (index != label->selection_anchor || + index != label->selection_end) + { + eel_editable_label_select_region_index (label, index, index); + } +} + +static gint +editable_get_position (GtkEditable *editable) +{ + EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); + + return g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); +} + + +static AtkObjectClass *a11y_parent_class = NULL; + +static const char* eel_editable_label_accessible_data = "eel-editable-label-accessible-data"; + +/************ Accessible implementation ****************/ + +typedef struct +{ + GailTextUtil *textutil; + gint selection_anchor; + gint selection_end; + gchar *signal_name; + gint position; + gint length; +} EelEditableLabelAccessiblePrivate; + +typedef struct +{ + EelEditableLabel* label; + gint position; +} EelEditableLabelAccessiblePaste; + + +static gchar* +eel_editable_label_accessible_get_text (AtkText *text, + gint start_pos, + gint end_pos) +{ + GtkWidget *widget; + EelEditableLabelAccessiblePrivate *priv; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); + return gail_text_util_get_substring (priv->textutil, start_pos, end_pos); +} + +static gunichar +eel_editable_label_accessible_get_character_at_offset (AtkText *text, + gint offset) +{ + GtkWidget *widget; + EelEditableLabelAccessiblePrivate *priv; + gchar *string; + gchar *index; + gunichar unichar; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return '\0'; + + priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); + string = gail_text_util_get_substring (priv->textutil, 0, -1); + if (offset >= g_utf8_strlen (string, -1)) + { + unichar = '\0'; + } + else + { + index = g_utf8_offset_to_pointer (string, offset); + + unichar = g_utf8_get_char(index); + } + + g_free(string); + return unichar; +} + +static gchar* +eel_editable_label_accessible_get_text_before_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + GtkWidget *widget; + EelEditableLabel *label; + EelEditableLabelAccessiblePrivate *priv; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + label = EEL_EDITABLE_LABEL (widget); + priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); + + return gail_text_util_get_text (priv->textutil, + eel_editable_label_get_layout (label), + GAIL_BEFORE_OFFSET, + boundary_type, offset, + start_offset, end_offset); +} + +static gchar* +eel_editable_label_accessible_get_text_at_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + GtkWidget *widget; + EelEditableLabel *label; + EelEditableLabelAccessiblePrivate *priv; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + + label = EEL_EDITABLE_LABEL (widget); + priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); + return gail_text_util_get_text (priv->textutil, + eel_editable_label_get_layout (label), + GAIL_AT_OFFSET, + boundary_type, offset, + start_offset, end_offset); +} + +static gchar* +eel_editable_label_accessible_get_text_after_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + GtkWidget *widget; + EelEditableLabel *label; + EelEditableLabelAccessiblePrivate *priv; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + label = EEL_EDITABLE_LABEL (widget); + priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); + return gail_text_util_get_text (priv->textutil, + eel_editable_label_get_layout (label), + GAIL_AFTER_OFFSET, + boundary_type, offset, + start_offset, end_offset); +} + +static gint +eel_editable_label_accessible_get_caret_offset (AtkText *text) +{ + GtkWidget *widget; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return 0; + + return gtk_editable_get_position (GTK_EDITABLE (widget)); +} + +static gboolean +eel_editable_label_accessible_set_caret_offset (AtkText *text, gint offset) +{ + GtkWidget *widget; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return FALSE; + + gtk_editable_set_position (GTK_EDITABLE (widget), offset); + return TRUE; +} + +static gint +eel_editable_label_accessible_get_character_count (AtkText *text) +{ + GtkWidget *widget; + EelEditableLabel *label; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return 0; + + label = EEL_EDITABLE_LABEL (widget); + return g_utf8_strlen (eel_editable_label_get_text (label), -1); +} + +static gint +eel_editable_label_accessible_get_n_selections (AtkText *text) +{ + GtkWidget *widget; + EelEditableLabel *label; + gint select_start, select_end; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return -1; + + label = EEL_EDITABLE_LABEL (widget); + gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, + &select_end); + + if (select_start != select_end) + return 1; + else + return 0; +} + +static gchar* +eel_editable_label_accessible_get_selection (AtkText *text, + gint selection_num, + gint *start_pos, + gint *end_pos) +{ + GtkWidget *widget; + EelEditableLabel *label; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + /* Only let the user get the selection if one is set, and if the + * selection_num is 0. + */ + if (selection_num != 0) + return NULL; + + label = EEL_EDITABLE_LABEL (widget); + gtk_editable_get_selection_bounds (GTK_EDITABLE (label), start_pos, end_pos); + + if (*start_pos != *end_pos) + return gtk_editable_get_chars (GTK_EDITABLE (label), *start_pos, *end_pos); + else + return NULL; +} + +static gboolean +eel_editable_label_accessible_add_selection (AtkText *text, + gint start_pos, + gint end_pos) +{ + GtkWidget *widget; + EelEditableLabel *label; + gint select_start, select_end; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return FALSE; + + label = EEL_EDITABLE_LABEL (widget); + gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, + &select_end); + + /* If there is already a selection, then don't allow another to be added, + * since EelEditableLabel only supports one selected region. + */ + if (select_start == select_end) + { + gtk_editable_select_region (GTK_EDITABLE (label), start_pos, end_pos); + return TRUE; + } + else + return FALSE; +} + +static gboolean +eel_editable_label_accessible_remove_selection (AtkText *text, + gint selection_num) +{ + GtkWidget *widget; + EelEditableLabel *label; + gint select_start, select_end, caret_pos; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return FALSE; + + if (selection_num != 0) + return FALSE; + + label = EEL_EDITABLE_LABEL (widget); + gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, + &select_end); + + if (select_start != select_end) + { + /* Setting the start & end of the selected region to the caret position + * turns off the selection. + */ + caret_pos = gtk_editable_get_position (GTK_EDITABLE (label)); + gtk_editable_select_region (GTK_EDITABLE (label), caret_pos, caret_pos); + return TRUE; + } + else + return FALSE; +} + +static gboolean +eel_editable_label_accessible_set_selection (AtkText *text, + gint selection_num, + gint start_pos, + gint end_pos) +{ + GtkWidget *widget; + EelEditableLabel *label; + gint select_start, select_end; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return FALSE; + + /* Only let the user move the selection if one is set, and if the + * selection_num is 0 + */ + if (selection_num != 0) + return FALSE; + + label = EEL_EDITABLE_LABEL (widget); + gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, + &select_end); + + if (select_start != select_end) + { + gtk_editable_select_region (GTK_EDITABLE (label), start_pos, end_pos); + return TRUE; + } + else + return FALSE; +} + +static AtkAttributeSet* +eel_editable_label_accessible_get_run_attributes (AtkText *text, + gint offset, + gint *start_offset, + gint *end_offset) +{ + GtkWidget *widget; + EelEditableLabel *label; + AtkAttributeSet *at_set = NULL; + GtkTextDirection dir; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + label = EEL_EDITABLE_LABEL (widget); + + dir = gtk_widget_get_direction (widget); + if (dir == GTK_TEXT_DIR_RTL) + { + at_set = gail_misc_add_attribute (at_set, + ATK_TEXT_ATTR_DIRECTION, + g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir))); + } + + at_set = gail_misc_layout_get_run_attributes (at_set, + eel_editable_label_get_layout (label), + label->text, + offset, + start_offset, + end_offset); + return at_set; +} + +static AtkAttributeSet* +eel_editable_label_accessible_get_default_attributes (AtkText *text) +{ + GtkWidget *widget; + EelEditableLabel *label; + AtkAttributeSet *at_set = NULL; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return NULL; + + label = EEL_EDITABLE_LABEL (widget); + + at_set = gail_misc_get_default_attributes (at_set, + eel_editable_label_get_layout (label), + widget); + return at_set; +} + +static void +eel_editable_label_accessible_get_character_extents (AtkText *text, + gint offset, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coords) +{ + GtkWidget *widget; + EelEditableLabel *label; + PangoRectangle char_rect; + gint index, cursor_index, x_layout, y_layout; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + label = EEL_EDITABLE_LABEL (widget); + eel_editable_label_get_layout_offsets (label, &x_layout, &y_layout); + index = g_utf8_offset_to_pointer (label->text, offset) - label->text; + cursor_index = label->selection_anchor; + if (index > cursor_index) + index += label->preedit_length; + pango_layout_index_to_pos (eel_editable_label_get_layout(label), index, &char_rect); + + gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, + x_layout, y_layout, x, y, width, height, coords); +} + +static gint +eel_editable_label_accessible_get_offset_at_point (AtkText *text, + gint x, + gint y, + AtkCoordType coords) +{ + GtkWidget *widget; + EelEditableLabel *label; + gint index, cursor_index, x_layout, y_layout; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return -1; + + label = EEL_EDITABLE_LABEL (widget); + + eel_editable_label_get_layout_offsets (label, &x_layout, &y_layout); + + index = gail_misc_get_index_at_point_in_layout (widget, + eel_editable_label_get_layout(label), x_layout, y_layout, x, y, coords); + if (index == -1) + { + if (coords == ATK_XY_SCREEN || coords == ATK_XY_WINDOW) + return g_utf8_strlen (label->text, -1); + + return index; + } + else + { + cursor_index = label->selection_anchor; + if (index >= cursor_index && label->preedit_length) + { + if (index >= cursor_index + label->preedit_length) + index -= label->preedit_length; + else + index = cursor_index; + } + return g_utf8_pointer_to_offset (label->text, label->text + index); + } +} + +static void +atk_text_interface_init (AtkTextIface *iface) +{ + g_assert (iface != NULL); + + iface->get_text = eel_editable_label_accessible_get_text; + iface->get_character_at_offset = eel_editable_label_accessible_get_character_at_offset; + iface->get_text_before_offset = eel_editable_label_accessible_get_text_before_offset; + iface->get_text_at_offset = eel_editable_label_accessible_get_text_at_offset; + iface->get_text_after_offset = eel_editable_label_accessible_get_text_after_offset; + iface->get_caret_offset = eel_editable_label_accessible_get_caret_offset; + iface->set_caret_offset = eel_editable_label_accessible_set_caret_offset; + iface->get_character_count = eel_editable_label_accessible_get_character_count; + iface->get_n_selections = eel_editable_label_accessible_get_n_selections; + iface->get_selection = eel_editable_label_accessible_get_selection; + iface->add_selection = eel_editable_label_accessible_add_selection; + iface->remove_selection = eel_editable_label_accessible_remove_selection; + iface->set_selection = eel_editable_label_accessible_set_selection; + iface->get_run_attributes = eel_editable_label_accessible_get_run_attributes; + iface->get_default_attributes = eel_editable_label_accessible_get_default_attributes; + iface->get_character_extents = eel_editable_label_accessible_get_character_extents; + iface->get_offset_at_point = eel_editable_label_accessible_get_offset_at_point; +} + +static void +eel_editable_label_accessible_set_text_contents (AtkEditableText *text, + const gchar *string) +{ + GtkWidget *widget; + EelEditableLabel *label; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + label = EEL_EDITABLE_LABEL (widget); + + eel_editable_label_set_text (label, string); +} + +static void +eel_editable_label_accessible_insert_text (AtkEditableText *text, + const gchar *string, + gint length, + gint *position) +{ + GtkWidget *widget; + EelEditableLabel *label; + GtkEditable *editable; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + label = EEL_EDITABLE_LABEL (widget); + editable = GTK_EDITABLE (label); + + gtk_editable_insert_text (editable, string, length, position); +} + +static void +eel_editable_label_accessible_copy_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GtkWidget *widget; + EelEditableLabel *label; + GtkEditable *editable; + gchar *str; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + label = EEL_EDITABLE_LABEL (widget); + editable = GTK_EDITABLE (label); + str = gtk_editable_get_chars (editable, start_pos, end_pos); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); +} + +static void +eel_editable_label_accessible_cut_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GtkWidget *widget; + EelEditableLabel *label; + GtkEditable *editable; + gchar *str; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + label = EEL_EDITABLE_LABEL (widget); + editable = GTK_EDITABLE (label); + str = gtk_editable_get_chars (editable, start_pos, end_pos); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); + gtk_editable_delete_text (editable, start_pos, end_pos); +} + +static void +eel_editable_label_accessible_delete_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GtkWidget *widget; + EelEditableLabel *label; + GtkEditable *editable; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + label = EEL_EDITABLE_LABEL (widget); + editable = GTK_EDITABLE (label); + + gtk_editable_delete_text (editable, start_pos, end_pos); +} + +static void +eel_editable_label_accessible_paste_received (GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + EelEditableLabelAccessiblePaste* paste_struct = (EelEditableLabelAccessiblePaste *)data; + + if (text) + gtk_editable_insert_text (GTK_EDITABLE (paste_struct->label), text, -1, + &(paste_struct->position)); + + g_object_unref (paste_struct->label); +} + +static void +eel_editable_label_accessible_paste_text (AtkEditableText *text, + gint position) +{ + GtkWidget *widget; + GtkEditable *editable; + EelEditableLabelAccessiblePaste paste_struct; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + /* State is defunct */ + return; + + editable = GTK_EDITABLE (widget); + if (!gtk_editable_get_editable (editable)) + return; + paste_struct.label = EEL_EDITABLE_LABEL (widget); + paste_struct.position = position; + + g_object_ref (paste_struct.label); + gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE), + eel_editable_label_accessible_paste_received, &paste_struct); +} + +static void +atk_editable_text_interface_init (AtkEditableTextIface *iface) +{ + g_assert (iface != NULL); + + iface->set_text_contents = eel_editable_label_accessible_set_text_contents; + iface->insert_text = eel_editable_label_accessible_insert_text; + iface->copy_text = eel_editable_label_accessible_copy_text; + iface->cut_text = eel_editable_label_accessible_cut_text; + iface->delete_text = eel_editable_label_accessible_delete_text; + iface->paste_text = eel_editable_label_accessible_paste_text; +} + +static void +eel_editable_label_accessible_notify_insert (AtkObject *accessible) +{ + EelEditableLabelAccessiblePrivate *priv; + + priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); + if (priv->signal_name) + { + g_signal_emit_by_name (accessible, + priv->signal_name, + priv->position, + priv->length); + priv->signal_name = NULL; + } +} + +static gboolean +eel_editable_label_accessible_idle_notify_insert (gpointer data) +{ + eel_editable_label_accessible_notify_insert (data); + return FALSE; +} + +/* Note arg1 returns the character at the start of the insert. + * arg2 returns the number of characters inserted. + */ +static void +eel_editable_label_accessible_insert_text_cb (EelEditableLabel *label, + gchar *arg1, + gint arg2, + gpointer arg3) +{ + AtkObject *accessible; + EelEditableLabelAccessiblePrivate *priv; + gint *position = (gint *) arg3; + + accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); + priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); + if (!priv->signal_name) + { + priv->signal_name = "text_changed::insert"; + priv->position = *position; + priv->length = arg2; + } + /* + * The signal will be emitted when the cursor position is updated. + * or in an idle handler if it not updated. + */ + g_idle_add (eel_editable_label_accessible_idle_notify_insert, accessible); +} + +/* Note arg1 returns the start of the delete range, arg2 returns the + * end of the delete range if multiple characters are deleted. + */ +static void +eel_editable_label_accessible_delete_text_cb (EelEditableLabel *label, + gint arg1, + gint arg2) +{ + AtkObject *accessible; + + accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); + + /* + * Zero length text deleted so ignore + */ + if (arg2 - arg1 == 0) + return; + + g_signal_emit_by_name (accessible, "text_changed::delete", arg1, arg2 - arg1); +} + +static void +eel_editable_label_accessible_changed_cb (EelEditableLabel *label) +{ + AtkObject *accessible; + EelEditableLabelAccessiblePrivate *priv; + + accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); + priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); + gail_text_util_text_setup (priv->textutil, eel_editable_label_get_text (label)); +} + +static gboolean +check_for_selection_change (AtkObject *accessible, + GtkWidget *widget) +{ + EelEditableLabelAccessiblePrivate *priv; + EelEditableLabel *label; + gboolean ret_val = FALSE; + + priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); + label = EEL_EDITABLE_LABEL (widget); + + if (label->selection_anchor != label->selection_end) + { + if (label->selection_anchor != priv->selection_anchor || + label->selection_end != priv->selection_end) + /* + * This check is here as this function can be called + * for notification of selection_end and selection_anchor. + * The values of selection_anchor and selection_end may be the same + * for both notifications and we only want to generate one + * text_selection_changed signal. + */ + ret_val = TRUE; + } + else + { + /* We had a selection */ + ret_val = (priv->selection_anchor != priv->selection_end); + } + priv->selection_anchor = label->selection_anchor; + priv->selection_end = label->selection_end; + + return ret_val; +} + +static void +eel_editable_label_accessible_notify_gtk (GObject *obj, + GParamSpec *pspec) +{ + GtkWidget *widget; + AtkObject *accessible; + EelEditableLabel *label; + + widget = GTK_WIDGET (obj); + label = EEL_EDITABLE_LABEL (widget); + accessible = gtk_widget_get_accessible (widget); + + if (strcmp (pspec->name, "cursor-position") == 0) + { + eel_editable_label_accessible_notify_insert (accessible); + if (check_for_selection_change (accessible, widget)) + g_signal_emit_by_name (accessible, "text_selection_changed"); + /* + * The label cursor position has moved so generate the signal. + */ + g_signal_emit_by_name (accessible, "text_caret_moved", + g_utf8_pointer_to_offset (label->text, + label->text + label->selection_anchor)); + } + else if (strcmp (pspec->name, "selection-bound") == 0) + { + eel_editable_label_accessible_notify_insert (accessible); + + if (check_for_selection_change (accessible, widget)) + g_signal_emit_by_name (accessible, "text_selection_changed"); + } +} + +static void +eel_editable_label_accessible_initialize (AtkObject *accessible, + gpointer widget) +{ + EelEditableLabelAccessiblePrivate *priv; + EelEditableLabel *label; + + a11y_parent_class->initialize (accessible, widget); + + label = EEL_EDITABLE_LABEL (widget); + priv = g_new0 (EelEditableLabelAccessiblePrivate, 1); + priv->textutil = gail_text_util_new (); + gail_text_util_text_setup (priv->textutil, eel_editable_label_get_text (EEL_EDITABLE_LABEL (widget))); + priv->selection_anchor = label->selection_anchor; + priv->selection_end = label->selection_end; + g_object_set_data (G_OBJECT (accessible), eel_editable_label_accessible_data, priv); + g_signal_connect (widget, "insert-text", + G_CALLBACK (eel_editable_label_accessible_insert_text_cb), NULL); + g_signal_connect (widget, "delete-text", + G_CALLBACK (eel_editable_label_accessible_delete_text_cb), NULL); + g_signal_connect (widget, "changed", + G_CALLBACK (eel_editable_label_accessible_changed_cb), NULL); + + g_signal_connect (widget, + "notify", + G_CALLBACK (eel_editable_label_accessible_notify_gtk), + NULL); + atk_object_set_role (accessible, ATK_ROLE_TEXT); +} + +static const gchar* eel_editable_label_accessible_get_name(AtkObject* accessible) +{ + if (accessible->name != NULL) + { + return accessible->name; + } + else + { + GtkWidget* widget; + + widget = gtk_accessible_get_widget(GTK_ACCESSIBLE(accessible)); + + if (widget == NULL) + { + /* State is defunct */ + return NULL; + } + + g_assert(EEL_IS_EDITABLE_LABEL(widget)); + + return eel_editable_label_get_text(EEL_EDITABLE_LABEL(widget)); + } +} + +static AtkStateSet* +eel_editable_label_accessible_ref_state_set (AtkObject *accessible) +{ + AtkStateSet *state_set; + GtkWidget *widget; + + state_set = a11y_parent_class->ref_state_set (accessible); + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); + + if (widget == NULL) + return state_set; + + atk_state_set_add_state (state_set, ATK_STATE_EDITABLE); + atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE); + return state_set; +} + +static void +eel_editable_label_accessible_finalize (GObject *object) +{ + EelEditableLabelAccessiblePrivate *priv; + + priv = g_object_get_data (object, eel_editable_label_accessible_data); + g_object_unref (priv->textutil); + g_free (priv); + G_OBJECT_CLASS (a11y_parent_class)->finalize (object); +} + +static void +eel_editable_label_accessible_class_init (AtkObjectClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + a11y_parent_class = g_type_class_peek_parent (klass); + + klass->initialize = eel_editable_label_accessible_initialize; + klass->get_name = eel_editable_label_accessible_get_name; + klass->ref_state_set = eel_editable_label_accessible_ref_state_set; + gobject_class->finalize = eel_editable_label_accessible_finalize; +} + +static AtkObject * +eel_editable_label_get_accessible (GtkWidget *widget) +{ + static GType type = 0; + AtkObject *accessible; + + if ((accessible = eel_accessibility_get_atk_object (widget))) + return accessible; + + if (!type) + { + const GInterfaceInfo atk_editable_text_info = + { + (GInterfaceInitFunc) atk_editable_text_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + const GInterfaceInfo atk_text_info = + { + (GInterfaceInitFunc) atk_text_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = eel_accessibility_create_derived_type ("EelEditableLabelAccessible", + G_TYPE_FROM_INSTANCE (widget), + eel_editable_label_accessible_class_init); + + if (!type) + return NULL; + + g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info); + g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info); + } + + accessible = g_object_new (type, NULL); + + return eel_accessibility_set_atk_object_return (widget, accessible); +} + diff --git a/eel/eel-editable-label.h b/eel/eel-editable-label.h new file mode 100644 index 00000000..559ac6a1 --- /dev/null +++ b/eel/eel-editable-label.h @@ -0,0 +1,145 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __EEL_EDITABLE_LABEL_H__ +#define __EEL_EDITABLE_LABEL_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define EEL_TYPE_EDITABLE_LABEL eel_editable_label_get_type() +#define EEL_EDITABLE_LABEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_EDITABLE_LABEL, EelEditableLabel)) +#define EEL_EDITABLE_LABEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_EDITABLE_LABEL, EelEditableLabelClass)) +#define EEL_IS_EDITABLE_LABEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_EDITABLE_LABEL)) +#define EEL_IS_EDITABLE_LABEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_EDITABLE_LABEL)) +#define EEL_EDITABLE_LABEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_EDITABLE_LABEL, EelEditableLabelClass)) + + typedef struct _EelEditableLabel EelEditableLabel; + typedef struct _EelEditableLabelClass EelEditableLabelClass; + + typedef struct _EelEditableLabelSelectionInfo EelEditableLabelSelectionInfo; + + struct _EelEditableLabel + { + GtkMisc misc; + + /*< private >*/ + guint jtype : 2; + guint wrap : 1; + guint overwrite_mode : 1; + guint draw_outline : 1; + PangoWrapMode wrap_mode; + + gchar *text; + int text_size; /* allocated size, in bytes */ + int n_bytes; /* length in use (not including terminating zero), in bytes */ + + PangoLayout *layout; + guint layout_includes_preedit : 1; + + int selection_anchor; /* cursor pos, byte index */ + int selection_end; /* byte index */ + + GtkWidget *popup_menu; + + GtkIMContext *im_context; + gboolean need_im_reset; + int preedit_length; /* length of preedit string, in bytes */ + int preedit_cursor; /* offset of cursor within preedit string, in chars */ + + GdkGC *primary_cursor_gc; + GdkGC *secondary_cursor_gc; + + PangoFontDescription *font_desc; + }; + + struct _EelEditableLabelClass + { + GtkMiscClass parent_class; + + void (* move_cursor) (EelEditableLabel *label, + GtkMovementStep step, + gint count, + gboolean extend_selection); + void (* insert_at_cursor) (EelEditableLabel *label, + const gchar *str); + void (* delete_from_cursor) (EelEditableLabel *label, + GtkDeleteType type, + gint count); + void (* cut_clipboard) (EelEditableLabel *label); + void (* copy_clipboard) (EelEditableLabel *label); + void (* paste_clipboard) (EelEditableLabel *label); + void (* toggle_overwrite) (EelEditableLabel *label); + + /* Hook to customize right-click popup for selectable labels */ + void (* populate_popup) (EelEditableLabel *label, + GtkMenu *menu); + }; + + GType eel_editable_label_get_type (void) G_GNUC_CONST; + GtkWidget* eel_editable_label_new (const char *str); + void eel_editable_label_set_text (EelEditableLabel *label, + const char *str); + const gchar* eel_editable_label_get_text(EelEditableLabel* label); + void eel_editable_label_set_justify (EelEditableLabel *label, + GtkJustification jtype); + GtkJustification eel_editable_label_get_justify (EelEditableLabel *label); + void eel_editable_label_set_line_wrap (EelEditableLabel *label, + gboolean wrap); + void eel_editable_label_set_line_wrap_mode (EelEditableLabel *label, + PangoWrapMode mode); + gboolean eel_editable_label_get_line_wrap (EelEditableLabel *label); + void eel_editable_label_set_draw_outline (EelEditableLabel *label, + gboolean wrap); + void eel_editable_label_select_region (EelEditableLabel *label, + gint start_offset, + gint end_offset); + gboolean eel_editable_label_get_selection_bounds (EelEditableLabel *label, + gint *start, + gint *end); + PangoLayout * eel_editable_label_get_layout (EelEditableLabel *label); + void eel_editable_label_get_layout_offsets (EelEditableLabel *label, + gint *x, + gint *y); + PangoFontDescription *eel_editable_label_get_font_description (EelEditableLabel *label); + void eel_editable_label_set_font_description (EelEditableLabel *label, + const PangoFontDescription *desc); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __EEL_EDITABLE_LABEL_H__ */ diff --git a/eel/eel-enumeration.c b/eel/eel-enumeration.c new file mode 100644 index 00000000..b9cd3bc3 --- /dev/null +++ b/eel/eel-enumeration.c @@ -0,0 +1,555 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-enumeration.c: Enumeration data structure. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-enumeration.h" + +#include "eel-debug.h" +#include "eel-glib-extensions.h" +#include "eel-lib-self-check-functions.h" +#include "eel-string.h" +#include "eel-i18n.h" + +static gboolean suppress_duplicate_registration_warning; + +struct EelEnumeration +{ + char *id; + GPtrArray *entries; /* array of EelEnumerationEntry */ +}; + +static EelEnumeration * +eel_enumeration_new (const char *id) +{ + EelEnumeration *enumeration; + + g_assert (id != NULL); + g_assert (id[0] != '\0'); + + enumeration = g_new0 (EelEnumeration, 1); + + enumeration->id = g_strdup (id); + enumeration->entries = g_ptr_array_new (); + + return enumeration; +} + +static void +free_entry (EelEnumerationEntry *entry) +{ + g_free (entry->name); + g_free (entry->description); + g_free (entry); +} + +static void +eel_enumeration_free (EelEnumeration *enumeration) +{ + if (enumeration == NULL) + { + return; + } + + g_free (enumeration->id); + g_ptr_array_foreach (enumeration->entries, (GFunc) free_entry, NULL); + g_ptr_array_free (enumeration->entries, TRUE); + g_free (enumeration); +} + +char * +eel_enumeration_get_id (const EelEnumeration *enumeration) +{ + g_return_val_if_fail (enumeration != NULL, NULL); + + return g_strdup (enumeration->id); +} + +guint +eel_enumeration_get_length (const EelEnumeration *enumeration) +{ + g_return_val_if_fail (enumeration != NULL, 0); + + return enumeration->entries->len; +} + +const EelEnumerationEntry * +eel_enumeration_get_nth_entry (const EelEnumeration *enumeration, + guint n) +{ + g_return_val_if_fail (enumeration != NULL, NULL); + g_return_val_if_fail (n < enumeration->entries->len, NULL); + + return (EelEnumerationEntry *) g_ptr_array_index (enumeration->entries, n); +} + +int +eel_enumeration_get_name_position (const EelEnumeration *enumeration, + const char *name) +{ + int i; + + g_return_val_if_fail (enumeration != NULL, -1); + g_return_val_if_fail (name != NULL, -1); + + for (i = 0; i < enumeration->entries->len; ++i) + { + EelEnumerationEntry *entry = enumeration->entries->pdata[i]; + if (strcmp (name, entry->name) == 0) + { + return i; + } + } + + return -1; +} + +gboolean +eel_enumeration_contains_name (const EelEnumeration *enumeration, + const char *name) +{ + g_return_val_if_fail (enumeration != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + return eel_enumeration_get_name_position (enumeration, name) != -1; +} + +guint +eel_enumeration_get_value_for_name (const EelEnumeration *enumeration, + const char *name) +{ + int i; + + g_return_val_if_fail (enumeration != NULL, 0); + g_return_val_if_fail (name != NULL, 0); + + for (i = 0; i < enumeration->entries->len; ++i) + { + EelEnumerationEntry *entry = enumeration->entries->pdata[i]; + if (strcmp (name, entry->name) == 0) + { + return entry->value; + } + } + + g_warning ("No name '%s' in enumeration '%s'", name, enumeration->id); + + return 0; +} + +const char * +eel_enumeration_get_name_for_value (const EelEnumeration *enumeration, + int value) +{ + int i; + + g_return_val_if_fail (enumeration != NULL, 0); + + for (i = 0; i < enumeration->entries->len; ++i) + { + EelEnumerationEntry *entry = enumeration->entries->pdata[i]; + if (value == entry->value) + { + return entry->name; + } + } + + g_warning ("No value '%d' in enumeration '%s'", value, enumeration->id); + + return NULL; +} + +char ** +eel_enumeration_get_names (const EelEnumeration *enumeration) +{ + GPtrArray *names; + int i; + + g_return_val_if_fail (enumeration != NULL, NULL); + + if (enumeration->entries->len == 0) + { + return NULL; + } + + names = g_ptr_array_sized_new (enumeration->entries->len + 1); + for (i = 0; i < enumeration->entries->len; ++i) + { + EelEnumerationEntry *entry = enumeration->entries->pdata[i]; + g_ptr_array_add (names, g_strdup (entry->name)); + } + g_ptr_array_add (names, NULL); + + return (char **) g_ptr_array_free (names, FALSE); +} + +static EelEnumeration * +eel_enumeration_new_from_tokens (const char *id, + const char *names, + const char *descriptions, + const char *values, + const char *delimiter) +{ + EelEnumeration *enumeration; + char **namev; + char **descriptionv; + char **valuev; + int length; + guint i; + + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (id[0] != '\0', NULL); + g_return_val_if_fail (names != NULL, NULL); + g_return_val_if_fail (names[0] != '\0', NULL); + g_return_val_if_fail (values != NULL, NULL); + g_return_val_if_fail (values[0] != '\0', NULL); + g_return_val_if_fail (delimiter != NULL, NULL); + g_return_val_if_fail (delimiter[0] != '\0', NULL); + + enumeration = eel_enumeration_new (id); + + namev = g_strsplit (names, delimiter, -1); + valuev = g_strsplit (values, delimiter, -1); + + length = g_strv_length (namev); + if (g_strv_length (valuev) != length) + { + g_warning ("names and values have different lengths."); + g_strfreev (namev); + g_strfreev (valuev); + return NULL; + } + + descriptionv = descriptions != NULL ? + g_strsplit (descriptions, delimiter, -1) : NULL; + + if (descriptionv != NULL) + { + if (g_strv_length (descriptionv) != length) + { + g_warning ("names and descriptions have different lengths."); + g_strfreev (namev); + g_strfreev (descriptionv); + g_strfreev (valuev); + return NULL; + } + } + + for (i = 0; i < length; i++) + { + EelEnumerationEntry *entry; + int value; + + if (!eel_str_to_int (valuev[i], &value)) + { + g_warning ("Could not convert value '%d' to an integer. Using 0.", i); + value = 0; + } + + entry = g_new0 (EelEnumerationEntry, 1); + entry->name = namev[i]; + entry->description = descriptionv ? descriptionv[i] : NULL; + entry->value = value; + + g_ptr_array_add (enumeration->entries, entry); + } + + return enumeration; +} + +static EelEnumerationEntry * +dup_entry (const EelEnumerationEntry *entry) +{ + EelEnumerationEntry *res; + + res = g_new0 (EelEnumerationEntry, 1); + res->name = g_strdup (entry->name); + res->description = g_strdup (entry->description); + res->value = entry->value; + + return res; +} + +static EelEnumeration * +eel_enumeration_new_from_entries (const char *id, + const EelEnumerationEntry entries[], + guint n_entries) +{ + EelEnumeration *enumeration; + guint i; + + g_assert (id != NULL); + g_assert (id[0] != '\0'); + g_assert (entries != NULL); + + enumeration = eel_enumeration_new (id); + + for (i = 0; i < n_entries; i++) + { + g_ptr_array_add (enumeration->entries, dup_entry (&entries[i])); + } + + return enumeration; +} + +static GHashTable *enumeration_table = NULL; + +static void +enumeration_table_free (void) +{ + if (enumeration_table != NULL) + { + g_hash_table_destroy (enumeration_table); + enumeration_table = NULL; + } +} + +static GHashTable * +enumeration_table_get (void) +{ + if (enumeration_table != NULL) + { + return enumeration_table; + } + + enumeration_table = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) eel_enumeration_free); + + eel_debug_call_at_shutdown (enumeration_table_free); + + return enumeration_table; +} + +const EelEnumeration * +eel_enumeration_lookup (const char *id) +{ + GHashTable *table; + + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (id[0] != '\0', NULL); + + table = enumeration_table_get (); + g_return_val_if_fail (table != NULL, NULL); + + return g_hash_table_lookup (table, id); +} + +void +eel_enumeration_register (const char *id, + const EelEnumerationEntry entries[], + guint n_entries) +{ + GHashTable *table; + EelEnumeration *enumeration; + + g_return_if_fail (id != NULL); + g_return_if_fail (id[0] != '\0'); + g_return_if_fail (entries != NULL); + + table = enumeration_table_get (); + g_return_if_fail (table != NULL); + + if (eel_enumeration_lookup (id) != NULL) + { + if (!suppress_duplicate_registration_warning) + { + g_warning ("Trying to register duplicate enumeration '%s'.", id); + } + + return; + } + + enumeration = eel_enumeration_new_from_entries (id, entries, n_entries); + + g_hash_table_insert (table, g_strdup (id), enumeration); +} + + +#if !defined (EEL_OMIT_SELF_CHECK) + +#define CHECK_ENUMERATION_ENTRY(enumeration, i, name, description, value) \ + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_name_position (enumeration, name), i); \ + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_value_for_name (enumeration, name), value); \ + EEL_CHECK_STRING_RESULT (g_strdup (eel_enumeration_get_name_for_value (enumeration, value)), name); + +static EelEnumerationEntry speed_tradeoff_enum_entries[] = +{ + { "always", "Always", 10 }, + { "local_only", "Local Files Only", 20 }, + { "never", "Never", 30 } +}; + +static EelEnumerationEntry standard_zoom_levels_enum_entries[] = +{ + { "smallest", "25%", 25 }, + { "smaller", "50%", 50 }, + { "small", "75%", 75 }, + { "standard", "100%", 100 }, + { "large", "150%", 150 }, + { "larger", "200%", 200 }, + { "largest", "400%", 400 } +}; + +static EelEnumerationEntry file_size_enum_entries[] = +{ + { "102400", "100 K", 102400 }, + { "512000", "500 K", 512000 }, + { "1048576", "1 MB", 1048576 }, + { "3145728", "3 MB", 3145728 }, + { "5242880", "5 MB", 5242880 }, + { "10485760", "10 MB", 10485760 }, + { "104857600", "100 MB", 104857600 } +}; + +#define CHECK_REGISTERED_ENUMERATION(enumname) \ +G_STMT_START { \ + const EelEnumeration *e; \ + int i; \ + e = eel_enumeration_lookup (#enumname); \ + g_return_if_fail (e != NULL); \ + for (i = 0; i < G_N_ELEMENTS (enumname##_enum_entries); i++) { \ + CHECK_ENUMERATION_ENTRY (e, \ + i, \ + enumname##_enum_entries[i].name, \ + enumname##_enum_entries[i].description, \ + enumname##_enum_entries[i].value); \ + } \ + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), i); \ +} G_STMT_END + +void +eel_self_check_enumeration (void) +{ + EelEnumeration *e; + char **names; + + /***/ + e = eel_enumeration_new_from_tokens ("id", + "single", + NULL, + "1", + ","); + + CHECK_ENUMERATION_ENTRY (e, 0, "single", "", 1); + EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 1); + eel_enumeration_free (e); + + /***/ + e = eel_enumeration_new_from_tokens ("id", + "apple,orange,banana", + NULL, + "1,2,3", + ","); + + CHECK_ENUMERATION_ENTRY (e, 0, "apple", "", 1); + CHECK_ENUMERATION_ENTRY (e, 1, "orange", "", 2); + CHECK_ENUMERATION_ENTRY (e, 2, "banana", "", 3); + EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 3); + eel_enumeration_free (e); + + /***/ + e = eel_enumeration_new_from_tokens ("id", + "foo", + NULL, + "666", + ","); + CHECK_ENUMERATION_ENTRY (e, 0, "foo", "", 666); + EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 1); + eel_enumeration_free (e); + + /***/ + e = eel_enumeration_new_from_tokens ("id", + "one,two,---,three", + "One,Two,---,Three", + "1,2,0,3", + ","); + CHECK_ENUMERATION_ENTRY (e, 0, "one", "One", 1); + CHECK_ENUMERATION_ENTRY (e, 1, "two", "Two", 2); + CHECK_ENUMERATION_ENTRY (e, 2, "---", "---", 0); + CHECK_ENUMERATION_ENTRY (e, 3, "three", "Three", 3); + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 4); + eel_enumeration_free (e); + + /***/ + e = eel_enumeration_new_from_tokens ("id", + "red,green,blue", + "Red Desc,Green Desc,Blue Desc", + "10,20,30", + ","); + + CHECK_ENUMERATION_ENTRY (e, 0, "red", "Red Desc", 10); + CHECK_ENUMERATION_ENTRY (e, 1, "green", "Green Desc", 20); + CHECK_ENUMERATION_ENTRY (e, 2, "blue", "Blue Desc", 30); + EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 3); + + EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "red"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "green"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "blue"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "pink"), FALSE); + + eel_enumeration_free (e); + + /***/ + e = eel_enumeration_new_from_tokens ("id", + "red,foo:green,bar:blue,baz", + "Red,Desc:Green,Desc:Blue,Desc", + "10:20:30", + ":"); + + CHECK_ENUMERATION_ENTRY (e, 0, "red,foo", "Red,Desc", 10); + CHECK_ENUMERATION_ENTRY (e, 1, "green,bar", "Green,Desc", 20); + CHECK_ENUMERATION_ENTRY (e, 2, "blue,baz", "Blue,Desc", 30); + EEL_CHECK_STRING_RESULT (eel_enumeration_get_id (e), "id"); + EEL_CHECK_INTEGER_RESULT (eel_enumeration_get_length (e), 3); + EEL_CHECK_BOOLEAN_RESULT (eel_enumeration_contains_name (e, "black"), FALSE); + + names = eel_enumeration_get_names (e); + EEL_CHECK_INTEGER_RESULT (strcmp(names[2], "blue,baz"), 0); + g_strfreev (names); + eel_enumeration_free (e); + + /***/ + suppress_duplicate_registration_warning = TRUE; + eel_enumeration_register ("speed_tradeoff", + speed_tradeoff_enum_entries, + G_N_ELEMENTS (speed_tradeoff_enum_entries)); + eel_enumeration_register ("standard_zoom_levels", + standard_zoom_levels_enum_entries, + G_N_ELEMENTS (standard_zoom_levels_enum_entries)); + eel_enumeration_register ("file_size", + file_size_enum_entries, + G_N_ELEMENTS (file_size_enum_entries)); + suppress_duplicate_registration_warning = FALSE; + + CHECK_REGISTERED_ENUMERATION(speed_tradeoff); + CHECK_REGISTERED_ENUMERATION(standard_zoom_levels); + CHECK_REGISTERED_ENUMERATION(file_size); +} + +#endif /* !EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-enumeration.h b/eel/eel-enumeration.h new file mode 100644 index 00000000..8b08aaa0 --- /dev/null +++ b/eel/eel-enumeration.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-enumeration.h: Enumeration data structure. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_ENUMERATION_H +#define EEL_ENUMERATION_H + +#include <glib.h> + +/* Opaque EelEnumeration declaration. */ +typedef struct EelEnumeration EelEnumeration; + +typedef struct +{ + char *name; + char *description; + guint value; +} EelEnumerationEntry; + +char * eel_enumeration_get_id (const EelEnumeration *enumeration); + +guint eel_enumeration_get_length (const EelEnumeration *enumeration); +const EelEnumerationEntry * +eel_enumeration_get_nth_entry (const EelEnumeration *enumeration, + guint n); +int eel_enumeration_get_name_position (const EelEnumeration *enumeration, + const char *name); +gboolean eel_enumeration_contains_name (const EelEnumeration *enumeration, + const char *name); +guint eel_enumeration_get_value_for_name (const EelEnumeration *enumeration, + const char *name); +const char * eel_enumeration_get_name_for_value (const EelEnumeration *enumeration, + int value); +char ** eel_enumeration_get_names (const EelEnumeration *enumeration); + +void eel_enumeration_register (const char *id, + const EelEnumerationEntry entries[], + guint n_entries); +const EelEnumeration * +eel_enumeration_lookup (const char *id); + +#endif /* EEL_ENUMERATION_H */ + diff --git a/eel/eel-gdk-extensions.c b/eel/eel-gdk-extensions.c new file mode 100644 index 00000000..acd85af5 --- /dev/null +++ b/eel/eel-gdk-extensions.c @@ -0,0 +1,971 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gdk-extensions.c: Graphics routines to augment what's in gdk. + + Copyright (C) 1999, 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]>, + Pavel Cisler <[email protected]>, + Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-gdk-extensions.h" + +#include "eel-glib-extensions.h" +#include "eel-lib-self-check-functions.h" +#include "eel-string.h" +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk/gdkprivate.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <stdlib.h> +#include <pango/pango.h> + +#define GRADIENT_BAND_SIZE 4 + +/** + * eel_gdk_rectangle_contains_rectangle: + * @outer: Rectangle possibly containing another rectangle. + * @inner: Rectangle that might be inside. + * + * Retun TRUE if inner rectangle is contained inside outer rectangle + */ +gboolean +eel_gdk_rectangle_contains_rectangle (GdkRectangle outer, GdkRectangle inner) +{ + return outer.x <= inner.x && outer.x + outer.width >= inner.x + inner.width + && outer.y <= inner.y && outer.y + outer.height >= inner.y + inner.height; +} + +/** + * eel_interpolate_color: + * @ratio: Place on line between colors to interpolate. + * @start_color: Color for one end. + * @end_color: Color for the other end + * @interpolated_color: Result. + * + * Compute a color between @start_color and @end_color in color space. + * Currently, the color space used is RGB, but a future version could + * instead do the interpolation in the best color space for expressing + * human perception. + */ +guint32 +eel_interpolate_color (gdouble ratio, + guint32 start_rgb, + guint32 end_rgb) +{ + guchar red, green, blue; + + g_return_val_if_fail (ratio >= 0.0, 0); + g_return_val_if_fail (ratio <= 1.0, 0); + + red = ((start_rgb >> 16) & 0xFF) * (1.0 - ratio) + ((end_rgb >> 16) & 0xFF) * ratio; + green = ((start_rgb >> 8) & 0xFF) * (1.0 - ratio) + ((end_rgb >> 8) & 0xFF) * ratio; + blue = (start_rgb & 0xFF) * (1.0 - ratio) + (end_rgb & 0xFF) * ratio; + return (((red << 8) | green) << 8) | blue; +} + +/** + * eel_gradient_new + * @start_color: Color for the top or left. + * @end_color: Color for the bottom or right. + * @is_horizontal: Direction of the gradient. + * + * Create a string that combines the start and end colors along + * with the direction of the gradient in a standard format. + */ +char * +eel_gradient_new (const char *start_color, + const char *end_color, + gboolean is_horizontal) +{ + /* Handle the special case where the start and end colors are identical. + Handle the special case where the end color is an empty string. + */ + if (eel_strcmp(start_color, end_color) == 0 || end_color == NULL || end_color[0] == '\0') + { + return g_strdup (start_color); + } + + /* Handle the special case where the start color is an empty string. */ + if (start_color == NULL || start_color[0] == '\0') + { + return g_strdup (end_color); + } + + /* Handle the general case. */ + return g_strconcat (start_color, "-", end_color, is_horizontal ? ":h" : NULL, NULL); +} + +/** + * eel_gradient_is_gradient + * @gradient_spec: A gradient spec. string. + * + * Return true if the spec. specifies a gradient instead of a solid color. + */ +gboolean +eel_gradient_is_gradient (const char *gradient_spec) +{ + return eel_strchr (gradient_spec, '-') != NULL; +} + +/** + * eel_gradient_is_horizontal + * @gradient_spec: A gradient spec. string. + * + * Return true if the spec. specifies a horizontal gradient. + */ +gboolean +eel_gradient_is_horizontal (const char *gradient_spec) +{ + size_t length; + + length = eel_strlen (gradient_spec); + return length >= 2 && gradient_spec[length - 2] == ':' && gradient_spec[length - 1] == 'h'; +} + +static char * +eel_gradient_strip_trailing_direction_if_any (const char *gradient_spec) +{ + size_t length; + + length = eel_strlen (gradient_spec); + if (length >= 2 && gradient_spec[length - 2] == ':' + && (gradient_spec[length - 1] == 'v' || gradient_spec[length - 1] == 'h')) + { + length -= 2; + } + + return g_strndup (gradient_spec, length); +} + +/* For parsing n-point gradients. Successive calls should pass the next_spec value + * set by the previous call as their first argument - to continue parsing where the + * previous call left off. + */ +char * +eel_gradient_parse_one_color_spec (const char *spec, int *percent, const char **next_spec) +{ + char *result; + const char *rgb_end_ptr; + const char *percent_ptr; + const char *separator_ptr; + + percent_ptr = eel_strchr (spec, '%'); + separator_ptr = eel_strchr (spec, '-'); + + if (percent_ptr != NULL && (separator_ptr == NULL || percent_ptr < separator_ptr)) + { + if (percent != NULL) + { + *percent = (int) strtol (percent_ptr + 1, NULL, 10); + } + rgb_end_ptr = percent_ptr; + } + else + { + if (percent != NULL) + { + *percent = 100; + } + rgb_end_ptr = separator_ptr; + } + + if (rgb_end_ptr != NULL) + { + result = g_strndup (spec, rgb_end_ptr - spec); + } + else + { + result = eel_gradient_strip_trailing_direction_if_any (spec); + } + + /* It's important not to use spec after setting *next_spec because it's + * likely that *next_spec == spec. + */ + if (next_spec != NULL) + { + *next_spec = (separator_ptr != NULL) ? separator_ptr + 1 : NULL; + } + + return result; +} + +/* FIXME bugzilla.eazel.com 5076: + * anyone using eel_gradient_get_start_color_spec or + * eel_gradient_get_end_color_spec is assuming the gradient + * is 2 colors which is questionable. + * + * Callers should be rewritten and these fns eliminated. + */ + +/** + * eel_gradient_get_start_color_spec + * @gradient_spec: A gradient spec. string. + * + * Return the start color. + * This may be the entire gradient_spec if it's a solid color. + */ +char * +eel_gradient_get_start_color_spec (const char *gradient_spec) +{ + return eel_gradient_parse_one_color_spec (gradient_spec, NULL, NULL); +} + +/** + * eel_gradient_get_end_color_spec + * @gradient_spec: A gradient spec. string. + * + * Return the end color. + * This may be the entire gradient_spec if it's a solid color. + */ +char * +eel_gradient_get_end_color_spec (const char *gradient_spec) +{ + char* color = NULL; + + do + { + g_free (color); + color = eel_gradient_parse_one_color_spec (gradient_spec, NULL, &gradient_spec); + } + while (gradient_spec != NULL); + + return color; +} + +/* Do the work shared by all the set_color_spec functions below. */ +static char * +eel_gradient_set_edge_color (const char *gradient_spec, + const char *edge_color, + gboolean is_horizontal, + gboolean change_end) +{ + char *opposite_color; + char *result; + + g_assert (edge_color != NULL); + + /* Get the color from the existing gradient spec. for the opposite + edge. This will parse away all the stuff we don't want from the + old gradient spec. + */ + opposite_color = change_end + ? eel_gradient_get_start_color_spec (gradient_spec) + : eel_gradient_get_end_color_spec (gradient_spec); + + /* Create a new gradient spec. The eel_gradient_new function handles + some special cases, so we don't have to bother with them here. + */ + result = eel_gradient_new (change_end ? opposite_color : edge_color, + change_end ? edge_color : opposite_color, + is_horizontal); + + g_free (opposite_color); + + return result; +} + +/** + * eel_gradient_set_left_color_spec + * @gradient_spec: A gradient spec. string. + * @left_color: Color spec. to replace left color with. + * + * Changes the left color to what's passed in. + * This creates a horizontal gradient. + */ +char * +eel_gradient_set_left_color_spec (const char *gradient_spec, + const char *left_color) +{ + g_return_val_if_fail (gradient_spec != NULL, NULL); + g_return_val_if_fail (left_color != NULL, NULL); + + return eel_gradient_set_edge_color (gradient_spec, left_color, TRUE, FALSE); +} + +/** + * eel_gradient_set_top_color_spec + * @gradient_spec: A gradient spec. string. + * @top_color: Color spec. to replace top color with. + * + * Changes the top color to what's passed in. + * This creates a vertical gradient. + */ +char * +eel_gradient_set_top_color_spec (const char *gradient_spec, + const char *top_color) +{ + g_return_val_if_fail (gradient_spec != NULL, NULL); + g_return_val_if_fail (top_color != NULL, NULL); + + return eel_gradient_set_edge_color (gradient_spec, top_color, FALSE, FALSE); +} + +/** + * eel_gradient_set_right_color_spec + * @gradient_spec: A gradient spec. string. + * @right_color: Color spec. to replace right color with. + * + * Changes the right color to what's passed in. + * This creates a horizontal gradient. + */ +char * +eel_gradient_set_right_color_spec (const char *gradient_spec, + const char *right_color) +{ + g_return_val_if_fail (gradient_spec != NULL, NULL); + g_return_val_if_fail (right_color != NULL, NULL); + + return eel_gradient_set_edge_color (gradient_spec, right_color, TRUE, TRUE); +} + +/** + * eel_gradient_set_bottom_color_spec + * @gradient_spec: A gradient spec. string. + * @bottom_color: Color spec. to replace bottom color with. + * + * Changes the bottom color to what's passed in. + * This creates a vertical gradient. + */ +char * +eel_gradient_set_bottom_color_spec (const char *gradient_spec, + const char *bottom_color) +{ + g_return_val_if_fail (gradient_spec != NULL, NULL); + g_return_val_if_fail (bottom_color != NULL, NULL); + + return eel_gradient_set_edge_color (gradient_spec, bottom_color, FALSE, TRUE); +} + +/** + * eel_gdk_color_parse_with_white_default + * @color_spec: A color spec, or NULL. + * @color: Pointer to place to put resulting color. + * + * The same as gdk_color_parse, except sets the color to white if + * the spec. can't be parsed, instead of returning a boolean flag. + */ +void +eel_gdk_color_parse_with_white_default (const char *color_spec, + GdkColor *color) +{ + gboolean got_color; + + g_return_if_fail (color != NULL); + + got_color = FALSE; + if (color_spec != NULL) + { + if (gdk_color_parse (color_spec, color)) + { + got_color = TRUE; + } + } + + if (!got_color) + { + color->red = 0xFFFF; + color->green = 0xFFFF; + color->blue = 0xFFFF; + } +} + +/** + * eel_parse_rgb_with_white_default + * @color_spec: A color spec, or NULL. + * Returns: An rgb value. + * + * The same as gdk_color_parse, except sets the color to white if + * the spec. can't be parsed instead of returning a boolean flag + * and returns a guint32 rgb value instead of a GdkColor. + */ +guint32 +eel_parse_rgb_with_white_default (const char *color_spec) +{ + GdkColor color; + + eel_gdk_color_parse_with_white_default (color_spec, &color); + return ((color.red << 8) & EEL_RGB_COLOR_RED) + | (color.green & EEL_RGB_COLOR_GREEN) + | ((color.blue >> 8) & EEL_RGB_COLOR_BLUE); +} + +guint32 +eel_rgb16_to_rgb (gushort r, gushort g, gushort b) +{ + guint32 result; + + result = (0xff0000 | (r & 0xff00)); + result <<= 8; + result |= ((g & 0xff00) | (b >> 8)); + + return result; +} + +guint32 +eel_rgb8_to_rgb (guchar r, guchar g, guchar b) +{ + return eel_rgb16_to_rgb (r << 8, g << 8, b << 8); +} + +/** + * eel_gdk_color_to_rgb + * @color: A GdkColor style color. + * Returns: An rgb value. + * + * Converts from a GdkColor stlye color to a gdk_rgb one. + * Alpha gets set to fully opaque + */ +guint32 +eel_gdk_color_to_rgb (const GdkColor *color) +{ + return eel_rgb16_to_rgb (color->red, color->green, color->blue); +} + +/** + * eel_gdk_rgb_to_color + * @color: a gdk_rgb style value. + * + * Converts from a gdk_rgb value style to a GdkColor one. + * The gdk_rgb color alpha channel is ignored. + * + * Return value: A GdkColor structure version of the given RGB color. + */ +GdkColor +eel_gdk_rgb_to_color (guint32 color) +{ + GdkColor result; + + result.red = ((color >> 16) & 0xFF) * 0x101; + result.green = ((color >> 8) & 0xFF) * 0x101; + result.blue = (color & 0xff) * 0x101; + result.pixel = 0; + + return result; +} + +/** + * eel_gdk_rgb_to_color_spec + * @color: a gdk_rgb style value. + * + * Converts from a gdk_rgb value style to a string color spec. + * The gdk_rgb color alpha channel is ignored. + * + * Return value: a newly allocated color spec. + */ +char * +eel_gdk_rgb_to_color_spec (const guint32 color) +{ + return g_strdup_printf ("#%06X", (guint) (color & 0xFFFFFF)); +} + +static guint32 +eel_shift_color_component (guchar component, float shift_by) +{ + guint32 result; + if (shift_by > 1.0) + { + result = component * (2 - shift_by); + } + else + { + result = 0xff - shift_by * (0xff - component); + } + + return result & 0xff; +} + +/** + * eel_rgb_shift_color + * @color: A color. + * @shift_by: darken or lighten factor. + * Returns: An darkened or lightened rgb value. + * + * Darkens (@shift_by > 1) or lightens (@shift_by < 1) + * @color. + */ +guint32 +eel_rgb_shift_color (guint32 color, float shift_by) +{ + guint32 result; + + /* shift red by shift_by */ + result = eel_shift_color_component((color & 0x00ff0000) >> 16, shift_by); + result <<= 8; + /* shift green by shift_by */ + result |= eel_shift_color_component((color & 0x0000ff00) >> 8, shift_by); + result <<= 8; + /* shift blue by shift_by */ + result |= eel_shift_color_component((color & 0x000000ff), shift_by); + + /* alpha doesn't change */ + result |= (0xff000000 & color); + + return result; +} + +/** + * eel_gdk_color_is_dark: + * + * Return true if the given color is `dark' + */ +gboolean +eel_gdk_color_is_dark (GdkColor *color) +{ + int intensity; + + intensity = (((color->red >> 8) * 77) + + ((color->green >> 8) * 150) + + ((color->blue >> 8) * 28)) >> 8; + + return intensity < 128; +} + +/** + * eel_stipple_bitmap_for_screen: + * + * Get pointer to 50% stippled bitmap suitable for use + * on @screen. This is a global object; do not free. + */ +GdkBitmap * +eel_stipple_bitmap_for_screen (GdkScreen *screen) +{ + static char stipple_bits[] = { 0x02, 0x01 }; + static GPtrArray *stipples = NULL; + int screen_num, n_screens, i; + + if (stipples == NULL) + { + n_screens = gdk_display_get_n_screens ( + gdk_screen_get_display (screen)); + stipples = g_ptr_array_sized_new (n_screens); + + for (i = 0; i < n_screens; i++) + { + g_ptr_array_index (stipples, i) = NULL; + } + } + + screen_num = gdk_screen_get_number (screen); + + if (g_ptr_array_index (stipples, screen_num) == NULL) + { + g_ptr_array_index (stipples, screen_num) = + gdk_bitmap_create_from_data ( + gdk_screen_get_root_window (screen), + stipple_bits, 2, 2); + } + + return g_ptr_array_index (stipples, screen_num); +} + +/** + * eel_stipple_bitmap: + * + * Get pointer to 50% stippled bitmap suitable for use + * on the default screen. This is a global object; do + * not free. + * + * This method is not multiscreen safe. Do not use it. + */ +GdkBitmap * +eel_stipple_bitmap (void) +{ + return eel_stipple_bitmap_for_screen (gdk_screen_get_default ()); +} + +/** + * eel_gdk_window_bring_to_front: + * + * Raise window and give it focus. + */ +void +eel_gdk_window_bring_to_front (GdkWindow *window) +{ + /* This takes care of un-iconifying the window and + * raising it if needed. + */ + gdk_window_show (window); + + /* If the window was already showing, it would not have + * the focus at this point. Do a little X trickery to + * ensure it is focused. + */ + eel_gdk_window_focus (window, GDK_CURRENT_TIME); +} + +void +eel_gdk_window_focus (GdkWindow *window, guint32 timestamp) +{ + gdk_error_trap_push (); + XSetInputFocus (GDK_DISPLAY (), + GDK_WINDOW_XWINDOW (window), + RevertToParent, + timestamp); + gdk_flush(); + gdk_error_trap_pop (); +} + +void +eel_gdk_window_set_wm_protocols (GdkWindow *window, + GdkAtom *protocols, + int nprotocols) +{ + Atom *atoms; + int i; + + atoms = g_new (Atom, nprotocols); + for (i = 0; i < nprotocols; i++) + { + atoms[i] = gdk_x11_atom_to_xatom (protocols[i]); + } + + XSetWMProtocols (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + atoms, nprotocols); + + g_free (atoms); +} + +/** + * eel_gdk_window_set_wm_hints_input: + * + * Set the WM_HINTS.input flag to the passed in value + */ +void +eel_gdk_window_set_wm_hints_input (GdkWindow *window, gboolean status) +{ + Display *dpy; + Window id; + XWMHints *wm_hints; + + g_return_if_fail (window != NULL); + + dpy = GDK_WINDOW_XDISPLAY (window); + id = GDK_WINDOW_XWINDOW (window); + + wm_hints = XGetWMHints (dpy, id); + if (wm_hints == 0) + { + wm_hints = XAllocWMHints (); + } + + wm_hints->flags |= InputHint; + wm_hints->input = (status == FALSE) ? False : True; + + XSetWMHints (dpy, id, wm_hints); + XFree (wm_hints); +} + +void +eel_gdk_window_set_invisible_cursor (GdkWindow *window) +{ + GdkBitmap *empty_bitmap; + GdkCursor *cursor; + GdkColor useless; + char invisible_cursor_bits[] = { 0x0 }; + + useless.red = useless.green = useless.blue = 0; + useless.pixel = 0; + + empty_bitmap = gdk_bitmap_create_from_data (window, + invisible_cursor_bits, + 1, 1); + + cursor = gdk_cursor_new_from_pixmap (empty_bitmap, + empty_bitmap, + &useless, + &useless, 0, 0); + + gdk_window_set_cursor (window, cursor); + + gdk_cursor_unref (cursor); + + g_object_unref (empty_bitmap); +} + +EelGdkGeometryFlags +eel_gdk_parse_geometry (const char *string, int *x_return, int *y_return, + guint *width_return, guint *height_return) +{ + int x11_flags; + EelGdkGeometryFlags gdk_flags; + + g_return_val_if_fail (string != NULL, EEL_GDK_NO_VALUE); + g_return_val_if_fail (x_return != NULL, EEL_GDK_NO_VALUE); + g_return_val_if_fail (y_return != NULL, EEL_GDK_NO_VALUE); + g_return_val_if_fail (width_return != NULL, EEL_GDK_NO_VALUE); + g_return_val_if_fail (height_return != NULL, EEL_GDK_NO_VALUE); + + x11_flags = XParseGeometry (string, x_return, y_return, + width_return, height_return); + + gdk_flags = EEL_GDK_NO_VALUE; + if (x11_flags & XValue) + { + gdk_flags |= EEL_GDK_X_VALUE; + } + if (x11_flags & YValue) + { + gdk_flags |= EEL_GDK_Y_VALUE; + } + if (x11_flags & WidthValue) + { + gdk_flags |= EEL_GDK_WIDTH_VALUE; + } + if (x11_flags & HeightValue) + { + gdk_flags |= EEL_GDK_HEIGHT_VALUE; + } + if (x11_flags & XNegative) + { + gdk_flags |= EEL_GDK_X_NEGATIVE; + } + if (x11_flags & YNegative) + { + gdk_flags |= EEL_GDK_Y_NEGATIVE; + } + + return gdk_flags; +} + +void +eel_gdk_draw_layout_with_drop_shadow (GdkDrawable *drawable, + GdkGC *gc, + GdkColor *text_color, + GdkColor *shadow_color, + int x, + int y, + PangoLayout *layout) +{ + gdk_draw_layout_with_colors (drawable, gc, + x+1, y+1, + layout, + shadow_color, NULL); + + gdk_draw_layout_with_colors (drawable, gc, + x, y, + layout, + text_color, NULL); +} + +#if ! defined (EEL_OMIT_SELF_CHECK) + +static char * +eel_gdk_color_as_hex_string (GdkColor color) +{ + return g_strdup_printf ("%04X%04X%04X", + color.red, color.green, color.blue); +} + +static char * +eel_self_check_parse (const char *color_spec) +{ + GdkColor color; + + eel_gdk_color_parse_with_white_default (color_spec, &color); + return eel_gdk_color_as_hex_string (color); +} + +static char * +eel_self_check_gdk_rgb_to_color (guint32 color) +{ + GdkColor result; + + result = eel_gdk_rgb_to_color (color); + + return eel_gdk_color_as_hex_string (result); +} + +void +eel_self_check_gdk_extensions (void) +{ + /* eel_interpolate_color */ + EEL_CHECK_INTEGER_RESULT (eel_interpolate_color (0.0, 0, 0), 0); + EEL_CHECK_INTEGER_RESULT (eel_interpolate_color (0.0, 0, 0xFFFFFF), 0); + EEL_CHECK_INTEGER_RESULT (eel_interpolate_color (0.5, 0, 0xFFFFFF), 0x7F7F7F); + EEL_CHECK_INTEGER_RESULT (eel_interpolate_color (1.0, 0, 0xFFFFFF), 0xFFFFFF); + + /* eel_gradient_new */ + EEL_CHECK_STRING_RESULT (eel_gradient_new ("", "", FALSE), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_new ("a", "b", FALSE), "a-b"); + EEL_CHECK_STRING_RESULT (eel_gradient_new ("a", "b", TRUE), "a-b:h"); + EEL_CHECK_STRING_RESULT (eel_gradient_new ("a", "a", FALSE), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_new ("a", "a", TRUE), "a"); + + /* eel_gradient_is_gradient */ + EEL_CHECK_BOOLEAN_RESULT (eel_gradient_is_gradient (""), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_gradient_is_gradient ("-"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_gradient_is_gradient ("a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_gradient_is_gradient ("a-b"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_gradient_is_gradient ("a-b:h"), TRUE); + + /* eel_gradient_get_start_color_spec */ + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec (""), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("-"), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a-b"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a-"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("-b"), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a:h"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a:v"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a:c"), "a:c"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a:-b"), "a:"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_start_color_spec ("a:-b:v"), "a:"); + + /* eel_gradient_get_end_color_spec */ + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec (""), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("-"), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a-b"), "b"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a-"), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("-b"), "b"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a:h"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a:v"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a:c"), "a:c"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a:-b"), "b"); + EEL_CHECK_STRING_RESULT (eel_gradient_get_end_color_spec ("a:-b:v"), "b"); + + /* eel_gradient_set_left_color_spec */ + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("", ""), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("a", ""), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("a", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("a", "b"), "b-a:h"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("a-c:v", "b"), "b-c:h"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("a-c:v", "c"), "c"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_left_color_spec ("a:-b:v", "d"), "d-b:h"); + + /* eel_gradient_set_top_color_spec */ + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("", ""), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("a", ""), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("a", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("a", "b"), "b-a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("a-c:v", "b"), "b-c"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("a-c:v", "c"), "c"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_top_color_spec ("a:-b:h", "d"), "d-b"); + + /* eel_gradient_set_right_color_spec */ + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("", ""), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("a", ""), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("a", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("a", "b"), "a-b:h"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("a-c:v", "b"), "a-b:h"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("a-c:v", "c"), "a-c:h"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_right_color_spec ("a:-b:v", "d"), "a:-d:h"); + + /* eel_gradient_set_bottom_color_spec */ + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("", ""), ""); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("a", ""), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("a", "a"), "a"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("a", "b"), "a-b"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("a-c:v", "b"), "a-b"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("a-c:v", "c"), "a-c"); + EEL_CHECK_STRING_RESULT (eel_gradient_set_bottom_color_spec ("a:-b:h", "d"), "a:-d"); + + /* eel_gdk_color_parse_with_white_default */ + EEL_CHECK_STRING_RESULT (eel_self_check_parse (""), "FFFFFFFFFFFF"); + EEL_CHECK_STRING_RESULT (eel_self_check_parse ("a"), "FFFFFFFFFFFF"); + EEL_CHECK_STRING_RESULT (eel_self_check_parse ("white"), "FFFFFFFFFFFF"); + EEL_CHECK_STRING_RESULT (eel_self_check_parse ("black"), "000000000000"); + EEL_CHECK_STRING_RESULT (eel_self_check_parse ("red"), "FFFF00000000"); + EEL_CHECK_STRING_RESULT (eel_self_check_parse ("#012345"), "010123234545"); + /* EEL_CHECK_STRING_RESULT (eel_self_check_parse ("rgb:0123/4567/89AB"), "#014589"); */ + + /* eel_gdk_rgb_to_color */ + EEL_CHECK_STRING_RESULT (eel_self_check_gdk_rgb_to_color (EEL_RGB_COLOR_RED), "FFFF00000000"); + EEL_CHECK_STRING_RESULT (eel_self_check_gdk_rgb_to_color (EEL_RGB_COLOR_BLACK), "000000000000"); + EEL_CHECK_STRING_RESULT (eel_self_check_gdk_rgb_to_color (EEL_RGB_COLOR_WHITE), "FFFFFFFFFFFF"); + EEL_CHECK_STRING_RESULT (eel_self_check_gdk_rgb_to_color (EEL_RGB_COLOR_PACK (0x01, 0x23, 0x45)), "010123234545"); + + /* EEL_RGBA_COLOR_PACK */ + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0xFF, 0x00, 0x00, 00), EEL_RGB_COLOR_RED); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0x00, 0xFF, 0x00, 00), EEL_RGB_COLOR_GREEN); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0x00, 0x00, 0xFF, 00), EEL_RGB_COLOR_BLUE); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0xFF, 0xFF, 0xFF, 00), EEL_RGB_COLOR_WHITE); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0x00, 0x00, 0x00, 00), EEL_RGB_COLOR_BLACK); + + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0xFF, 0x00, 0x00, 0xFF), EEL_RGBA_COLOR_OPAQUE_RED); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0x00, 0xFF, 0x00, 0xFF), EEL_RGBA_COLOR_OPAQUE_GREEN); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0x00, 0x00, 0xFF, 0xFF), EEL_RGBA_COLOR_OPAQUE_BLUE); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0xFF, 0xFF, 0xFF, 0xFF), EEL_RGBA_COLOR_OPAQUE_WHITE); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_PACK (0x00, 0x00, 0x00, 0xFF), EEL_RGBA_COLOR_OPAQUE_BLACK); + + /* EEL_RGB_COLOR_PACK */ + EEL_CHECK_INTEGER_RESULT (EEL_RGB_COLOR_PACK (0xFF, 0x00, 0x00), EEL_RGBA_COLOR_OPAQUE_RED); + EEL_CHECK_INTEGER_RESULT (EEL_RGB_COLOR_PACK (0x00, 0xFF, 0x00), EEL_RGBA_COLOR_OPAQUE_GREEN); + EEL_CHECK_INTEGER_RESULT (EEL_RGB_COLOR_PACK (0x00, 0x00, 0xFF), EEL_RGBA_COLOR_OPAQUE_BLUE); + EEL_CHECK_INTEGER_RESULT (EEL_RGB_COLOR_PACK (0xFF, 0xFF, 0xFF), EEL_RGBA_COLOR_OPAQUE_WHITE); + EEL_CHECK_INTEGER_RESULT (EEL_RGB_COLOR_PACK (0x00, 0x00, 0x00), EEL_RGBA_COLOR_OPAQUE_BLACK); + + /* EEL_RGBA_COLOR_GET_R */ + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGBA_COLOR_OPAQUE_RED), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGBA_COLOR_OPAQUE_GREEN), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGBA_COLOR_OPAQUE_BLUE), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGBA_COLOR_OPAQUE_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGBA_COLOR_OPAQUE_BLACK), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGB_COLOR_RED), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGB_COLOR_GREEN), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGB_COLOR_BLUE), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGB_COLOR_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_R (EEL_RGB_COLOR_BLACK), 0x00); + + /* EEL_RGBA_COLOR_GET_G */ + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGBA_COLOR_OPAQUE_RED), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGBA_COLOR_OPAQUE_GREEN), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGBA_COLOR_OPAQUE_BLUE), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGBA_COLOR_OPAQUE_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGBA_COLOR_OPAQUE_BLACK), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGB_COLOR_RED), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGB_COLOR_GREEN), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGB_COLOR_BLUE), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGB_COLOR_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_G (EEL_RGB_COLOR_BLACK), 0x00); + + /* EEL_RGBA_COLOR_GET_B */ + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGBA_COLOR_OPAQUE_RED), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGBA_COLOR_OPAQUE_GREEN), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGBA_COLOR_OPAQUE_BLUE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGBA_COLOR_OPAQUE_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGBA_COLOR_OPAQUE_BLACK), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGB_COLOR_RED), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGB_COLOR_GREEN), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGB_COLOR_BLUE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGB_COLOR_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_B (EEL_RGB_COLOR_BLACK), 0x00); + + /* EEL_RGBA_COLOR_GET_A */ + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGBA_COLOR_OPAQUE_RED), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGBA_COLOR_OPAQUE_GREEN), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGBA_COLOR_OPAQUE_BLUE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGBA_COLOR_OPAQUE_WHITE), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGBA_COLOR_OPAQUE_BLACK), 0xFF); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGB_COLOR_RED), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGB_COLOR_GREEN), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGB_COLOR_BLUE), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGB_COLOR_WHITE), 0x00); + EEL_CHECK_INTEGER_RESULT (EEL_RGBA_COLOR_GET_A (EEL_RGB_COLOR_BLACK), 0x00); + +} + +#endif /* ! EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-gdk-extensions.h b/eel/eel-gdk-extensions.h new file mode 100644 index 00000000..d5e041c5 --- /dev/null +++ b/eel/eel-gdk-extensions.h @@ -0,0 +1,164 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gdk-extensions.h: Graphics routines to augment what's in gdk. + + Copyright (C) 1999, 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]>, + Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_GDK_EXTENSIONS_H +#define EEL_GDK_EXTENSIONS_H + +#include <gdk/gdk.h> + +#define EEL_RGB_COLOR_RED 0xFF0000 +#define EEL_RGB_COLOR_GREEN 0x00FF00 +#define EEL_RGB_COLOR_BLUE 0x0000FF +#define EEL_RGB_COLOR_WHITE 0xFFFFFF +#define EEL_RGB_COLOR_BLACK 0x000000 + +#define EEL_RGBA_COLOR_OPAQUE_RED 0xFFFF0000 +#define EEL_RGBA_COLOR_OPAQUE_GREEN 0xFF00FF00 +#define EEL_RGBA_COLOR_OPAQUE_BLUE 0xFF0000FF +#define EEL_RGBA_COLOR_OPAQUE_WHITE 0xFFFFFFFF +#define EEL_RGBA_COLOR_OPAQUE_BLACK 0xFF000000 + +/* Pack RGBA values into 32 bits */ +#define EEL_RGBA_COLOR_PACK(r, g, b, a) \ +( (((guint32)a) << 24) | \ + (((guint32)r) << 16) | \ + (((guint32)g) << 8) | \ + (((guint32)b) << 0) ) + +/* Pack opaque RGBA values into 32 bits */ +#define EEL_RGB_COLOR_PACK(r, g, b) \ +EEL_RGBA_COLOR_PACK((r), (g), (b), 0xFF) + +/* Access the individual RGBA components */ +#define EEL_RGBA_COLOR_GET_R(color) (((color) >> 16) & 0xff) +#define EEL_RGBA_COLOR_GET_G(color) (((color) >> 8) & 0xff) +#define EEL_RGBA_COLOR_GET_B(color) (((color) >> 0) & 0xff) +#define EEL_RGBA_COLOR_GET_A(color) (((color) >> 24) & 0xff) + +/* Bits returned by eel_gdk_parse_geometry */ +typedef enum +{ + EEL_GDK_NO_VALUE = 0x00, + EEL_GDK_X_VALUE = 0x01, + EEL_GDK_Y_VALUE = 0x02, + EEL_GDK_WIDTH_VALUE = 0x04, + EEL_GDK_HEIGHT_VALUE = 0x08, + EEL_GDK_ALL_VALUES = 0x0f, + EEL_GDK_X_NEGATIVE = 0x10, + EEL_GDK_Y_NEGATIVE = 0x20 +} EelGdkGeometryFlags; + +/* A gradient spec. is a string that contains a specifier for either a + color or a gradient. If the string has a "-" in it, then it's a gradient. + The gradient is vertical by default and the spec. can end with ":v" to indicate that. + If the gradient ends with ":h", the gradient is horizontal. +*/ +char * eel_gradient_new (const char *start_color, + const char *end_color, + gboolean is_horizontal); +char * eel_gradient_parse_one_color_spec (const char *spec, + int *percent, + const char **next_spec); +gboolean eel_gradient_is_gradient (const char *gradient_spec); +char * eel_gradient_get_start_color_spec (const char *gradient_spec); +char * eel_gradient_get_end_color_spec (const char *gradient_spec); +gboolean eel_gradient_is_horizontal (const char *gradient_spec); +char * eel_gradient_set_left_color_spec (const char *gradient_spec, + const char *left_color); +char * eel_gradient_set_top_color_spec (const char *gradient_spec, + const char *top_color); +char * eel_gradient_set_right_color_spec (const char *gradient_spec, + const char *right_color); +char * eel_gradient_set_bottom_color_spec (const char *gradient_spec, + const char *bottom_color); + + +/* A version of parse_color that substitutes a default color instead of returning + a boolean to indicate it cannot be parsed. +*/ +void eel_gdk_color_parse_with_default (const char *color_spec, + const GdkColor *default_color, + GdkColor *parsed_color); +void eel_gdk_color_parse_with_white_default (const char *color_spec, + GdkColor *parsed_color); +guint32 eel_parse_rgb_with_default (const char *color_spec, + guint32 default_rgb); +guint32 eel_parse_rgb_with_white_default (const char *color_spec); +guint32 eel_rgb_shift_color (guint32 color, + float shift_by); +guint32 eel_rgb16_to_rgb (gushort r, + gushort g, + gushort b); +guint32 eel_rgb8_to_rgb (guchar r, + guchar g, + guchar b); +guint32 eel_gdk_color_to_rgb (const GdkColor *color); +GdkColor eel_gdk_rgb_to_color (guint32 color); +char * eel_gdk_rgb_to_color_spec (guint32 color); + +gboolean eel_gdk_color_is_dark (GdkColor *color); + +/* A routine to get a 50% gray stippled bitmap for use in some types of highlighting. */ +GdkBitmap * eel_stipple_bitmap_for_screen (GdkScreen *screen); +GdkBitmap * eel_stipple_bitmap (void); + + +/* Misc GdkRectangle helper functions */ +gboolean eel_gdk_rectangle_contains_rectangle (GdkRectangle outer, + GdkRectangle inner); + + +/* A basic operation we use for drawing gradients is interpolating two colors.*/ +guint32 eel_interpolate_color (gdouble ratio, + guint32 start_rgb, + guint32 end_rgb); + +/* Misc GdkWindow helper functions */ +void eel_gdk_window_bring_to_front (GdkWindow *window); +void eel_gdk_window_set_invisible_cursor (GdkWindow *window); +void eel_gdk_window_focus (GdkWindow *window, + guint32 timestamp); +void eel_gdk_window_set_wm_protocols (GdkWindow *window, + GdkAtom *protocols, + int nprotocols); + + +void eel_gdk_window_set_wm_hints_input (GdkWindow *w, + gboolean status); + +/* Wrapper for XParseGeometry */ +EelGdkGeometryFlags eel_gdk_parse_geometry (const char *string, + int *x_return, + int *y_return, + guint *width_return, + guint *height_return); +void eel_gdk_draw_layout_with_drop_shadow (GdkDrawable *drawable, + GdkGC *gc, + GdkColor *text_color, + GdkColor *shadow_color, + int x, + int y, + PangoLayout *layout); +#endif /* EEL_GDK_EXTENSIONS_H */ diff --git a/eel/eel-gdk-pixbuf-extensions.c b/eel/eel-gdk-pixbuf-extensions.c new file mode 100644 index 00000000..a58ef4c5 --- /dev/null +++ b/eel/eel-gdk-pixbuf-extensions.c @@ -0,0 +1,1510 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gdk-pixbuf-extensions.c: Routines to augment what's in gdk-pixbuf. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-gdk-pixbuf-extensions.h" + +#include "eel-art-gtk-extensions.h" +#include "eel-debug-drawing.h" +#include "eel-debug.h" +#include "eel-gdk-extensions.h" +#include "eel-glib-extensions.h" +#include "eel-graphic-effects.h" +#include "eel-lib-self-check-functions.h" +#include "eel-string.h" +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk/gdkprivate.h> +#include <gdk/gdkx.h> +#include <gio/gio.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#define LOAD_BUFFER_SIZE 65536 + +const EelIRect eel_gdk_pixbuf_whole_pixbuf = { G_MININT, G_MININT, G_MAXINT, G_MAXINT }; + +struct EelPixbufLoadHandle +{ + GCancellable *cancellable; + GInputStream *stream; + EelPixbufLoadCallback callback; + gpointer callback_data; + GdkPixbufLoader *loader; + char buffer[LOAD_BUFFER_SIZE]; +}; + +/** + * eel_gdk_pixbuf_list_ref + * @pixbuf_list: A list of GdkPixbuf objects. + * + * Refs all the pixbufs. + **/ +void +eel_gdk_pixbuf_list_ref (GList *pixbuf_list) +{ + g_list_foreach (pixbuf_list, (GFunc) g_object_ref, NULL); +} + +/** + * eel_gdk_pixbuf_list_free + * @pixbuf_list: A list of GdkPixbuf objects. + * + * Unrefs all the pixbufs, then frees the list. + **/ +void +eel_gdk_pixbuf_list_free (GList *pixbuf_list) +{ + eel_g_list_free_deep_custom (pixbuf_list, (GFunc) g_object_unref, NULL); +} + +GdkPixbuf * +eel_gdk_pixbuf_load (const char *uri) +{ + GdkPixbuf *pixbuf; + GFile *file; + GFileInputStream *stream; + + g_return_val_if_fail (uri != NULL, NULL); + + file = g_file_new_for_uri (uri); + + stream = g_file_read (file, NULL, NULL); + + g_object_unref (file); + + if (stream == NULL) + { + return NULL; + } + + pixbuf = eel_gdk_pixbuf_load_from_stream (G_INPUT_STREAM (stream)); + + g_object_unref (stream); + + return pixbuf; +} + +GdkPixbuf * +eel_gdk_pixbuf_load_from_stream (GInputStream *stream) +{ + return eel_gdk_pixbuf_load_from_stream_at_size (stream, -1); +} + +static void +pixbuf_loader_size_prepared (GdkPixbufLoader *loader, + int width, + int height, + gpointer desired_size_ptr) +{ + int size, desired_size; + float scale; + + size = MAX (width, height); + desired_size = GPOINTER_TO_INT (desired_size_ptr); + + if (size != desired_size) + { + scale = (float) desired_size / size; + gdk_pixbuf_loader_set_size (loader, + floor (scale * width + 0.5), + floor (scale * height + 0.5)); + } +} + +GdkPixbuf * +eel_gdk_pixbuf_load_from_stream_at_size (GInputStream *stream, + int size) +{ + char buffer[LOAD_BUFFER_SIZE]; + gssize bytes_read; + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf; + gboolean got_eos; + + + g_return_val_if_fail (stream != NULL, NULL); + + got_eos = FALSE; + loader = gdk_pixbuf_loader_new (); + + if (size > 0) + { + g_signal_connect (loader, "size-prepared", + G_CALLBACK (pixbuf_loader_size_prepared), + GINT_TO_POINTER (size)); + } + + while (1) + { + bytes_read = g_input_stream_read (stream, buffer, sizeof (buffer), + NULL, NULL); + + if (bytes_read < 0) + { + break; + } + if (bytes_read == 0) + { + got_eos = TRUE; + break; + } + if (!gdk_pixbuf_loader_write (loader, + buffer, + bytes_read, + NULL)) + { + break; + } + } + + g_input_stream_close (stream, NULL, NULL); + gdk_pixbuf_loader_close (loader, NULL); + + pixbuf = NULL; + if (got_eos) + { + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf != NULL) + { + g_object_ref (pixbuf); + } + } + + g_object_unref (loader); + + return pixbuf; +} + +static void +free_pixbuf_load_handle (EelPixbufLoadHandle *handle) +{ + g_object_unref (handle->cancellable); + if (handle->loader != NULL) + { + g_object_unref (handle->loader); + } + if (handle->stream) + { + g_input_stream_close_async (handle->stream, 0, NULL, NULL, NULL); + g_object_unref (handle->stream); + } + g_free (handle); +} + +static void +load_done (EelPixbufLoadHandle *handle, GError *error, gboolean get_pixbuf) +{ + GdkPixbuf *pixbuf; + + if (handle->loader != NULL) + { + gdk_pixbuf_loader_close (handle->loader, NULL); + } + + pixbuf = get_pixbuf ? gdk_pixbuf_loader_get_pixbuf (handle->loader) : NULL; + + handle->callback (error, pixbuf, handle->callback_data); + + free_pixbuf_load_handle (handle); +} + +static void +file_read_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EelPixbufLoadHandle *handle; + gssize bytes_read; + GError *error; + + handle = user_data; + + if (g_cancellable_is_cancelled (handle->cancellable)) + { + free_pixbuf_load_handle (handle); + return; + } + + error = NULL; + bytes_read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), + res, &error); + + if (bytes_read > 0) + { + if (!gdk_pixbuf_loader_write (handle->loader, + handle->buffer, + bytes_read, + &error)) + { + bytes_read = -1; + } + else + { + g_input_stream_read_async (handle->stream, + handle->buffer, + sizeof (handle->buffer), + 0, + handle->cancellable, + file_read_callback, handle); + return; + } + } + + load_done (handle, error, bytes_read == 0); + + if (error != NULL) + { + g_error_free (error); + } +} + +static void +file_opened_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EelPixbufLoadHandle *handle; + GFileInputStream *stream; + GError *error; + + handle = user_data; + + if (g_cancellable_is_cancelled (handle->cancellable)) + { + free_pixbuf_load_handle (handle); + return; + } + + error = NULL; + stream = g_file_read_finish (G_FILE (source_object), res, &error); + + if (stream == NULL) + { + load_done (handle, error, FALSE); + g_error_free (error); + return; + } + + handle->stream = G_INPUT_STREAM (stream); + handle->loader = gdk_pixbuf_loader_new (); + + + g_input_stream_read_async (handle->stream, + handle->buffer, + sizeof (handle->buffer), + 0, + handle->cancellable, + file_read_callback, handle); +} + +EelPixbufLoadHandle * +eel_gdk_pixbuf_load_async (const char *uri, + int priority, + EelPixbufLoadCallback callback, + gpointer callback_data) +{ + EelPixbufLoadHandle *handle; + GFile *file; + + handle = g_new0 (EelPixbufLoadHandle, 1); + handle->cancellable = g_cancellable_new (); + handle->callback = callback; + handle->callback_data = callback_data; + + file = g_file_new_for_uri (uri); + + g_file_read_async (file, priority, handle->cancellable, + file_opened_callback, handle); + + return handle; +} + +void +eel_cancel_gdk_pixbuf_load (EelPixbufLoadHandle *handle) +{ + if (handle == NULL) + { + return; + } + + g_cancellable_cancel (handle->cancellable); +} + +/* return the average value of each component */ +guint32 +eel_gdk_pixbuf_average_value (GdkPixbuf *pixbuf) +{ + guint64 a_total, r_total, g_total, b_total; + guint row, column; + int row_stride; + const guchar *pixels, *p; + int r, g, b, a; + guint64 dividend; + guint width, height; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + row_stride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + + /* iterate through the pixbuf, counting up each component */ + a_total = 0; + r_total = 0; + g_total = 0; + b_total = 0; + + if (gdk_pixbuf_get_has_alpha (pixbuf)) + { + for (row = 0; row < height; row++) + { + p = pixels + (row * row_stride); + for (column = 0; column < width; column++) + { + r = *p++; + g = *p++; + b = *p++; + a = *p++; + + a_total += a; + r_total += r * a; + g_total += g * a; + b_total += b * a; + } + } + dividend = height * width * 0xFF; + a_total *= 0xFF; + } + else + { + for (row = 0; row < height; row++) + { + p = pixels + (row * row_stride); + for (column = 0; column < width; column++) + { + r = *p++; + g = *p++; + b = *p++; + + r_total += r; + g_total += g; + b_total += b; + } + } + dividend = height * width; + a_total = dividend * 0xFF; + } + + return ((a_total + dividend / 2) / dividend) << 24 + | ((r_total + dividend / 2) / dividend) << 16 + | ((g_total + dividend / 2) / dividend) << 8 + | ((b_total + dividend / 2) / dividend); +} + +double +eel_gdk_scale_to_fit_factor (int width, int height, + int max_width, int max_height, + int *scaled_width, int *scaled_height) +{ + double scale_factor; + + scale_factor = MIN (max_width / (double) width, max_height / (double) height); + + *scaled_width = floor (width * scale_factor + .5); + *scaled_height = floor (height * scale_factor + .5); + + return scale_factor; +} + +/* Returns a scaled copy of pixbuf, preserving aspect ratio. The copy will + * be scaled as large as possible without exceeding the specified width and height. + */ +GdkPixbuf * +eel_gdk_pixbuf_scale_to_fit (GdkPixbuf *pixbuf, int max_width, int max_height) +{ + int scaled_width; + int scaled_height; + + eel_gdk_scale_to_fit_factor (gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), + max_width, max_height, + &scaled_width, &scaled_height); + + return gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height, GDK_INTERP_BILINEAR); +} + +/* Returns a copy of pixbuf scaled down, preserving aspect ratio, to fit + * within the specified width and height. If it already fits, a copy of + * the original, without scaling, is returned. + */ +GdkPixbuf * +eel_gdk_pixbuf_scale_down_to_fit (GdkPixbuf *pixbuf, int max_width, int max_height) +{ + int scaled_width; + int scaled_height; + + double scale_factor; + + scale_factor = eel_gdk_scale_to_fit_factor (gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), + max_width, max_height, + &scaled_width, &scaled_height); + + if (scale_factor >= 1.0) + { + return gdk_pixbuf_copy (pixbuf); + } + else + { + return eel_gdk_pixbuf_scale_down (pixbuf, scaled_width, scaled_height); + } +} + +double +eel_gdk_scale_to_min_factor (int width, int height, + int min_width, int min_height, + int *scaled_width, int *scaled_height) +{ + double scale_factor; + + scale_factor = MAX (min_width / (double) width, min_height / (double) height); + + *scaled_width = floor (width * scale_factor + .5); + *scaled_height = floor (height * scale_factor + .5); + + return scale_factor; +} + +/* Returns a scaled copy of pixbuf, preserving aspect ratio. The copy will + * be scaled as small as possible without going under the specified width and height. + */ +GdkPixbuf * +eel_gdk_pixbuf_scale_to_min (GdkPixbuf *pixbuf, int min_width, int min_height) +{ + int scaled_width; + int scaled_height; + + eel_gdk_scale_to_min_factor (gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), + min_width, min_height, + &scaled_width, &scaled_height); + + return gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height, GDK_INTERP_BILINEAR); +} + +/** + * eel_gdk_pixbuf_is_valid: + * @pixbuf: A GdkPixbuf + * + * Return value: A boolean indicating whether the given pixbuf is valid. + * + * A pixbuf is valid if: + * + * 1. It is non NULL + * 2. It is has non NULL pixel data. + * 3. It has width and height greater than 0. + */ +gboolean +eel_gdk_pixbuf_is_valid (const GdkPixbuf *pixbuf) +{ + return ((pixbuf != NULL) + && (gdk_pixbuf_get_pixels (pixbuf) != NULL) + && (gdk_pixbuf_get_width (pixbuf) > 0) + && (gdk_pixbuf_get_height (pixbuf) > 0)); +} + +/** + * eel_gdk_pixbuf_get_dimensions: + * @pixbuf: A GdkPixbuf + * + * Return value: The dimensions of the pixbuf as a EelDimensions. + * + * This function is useful in code that uses libart rect + * intersection routines. + */ +EelDimensions +eel_gdk_pixbuf_get_dimensions (const GdkPixbuf *pixbuf) +{ + EelDimensions dimensions; + + g_return_val_if_fail (eel_gdk_pixbuf_is_valid (pixbuf), eel_dimensions_empty); + + dimensions.width = gdk_pixbuf_get_width (pixbuf); + dimensions.height = gdk_pixbuf_get_height (pixbuf); + + return dimensions; +} + +/** + * eel_gdk_pixbuf_fill_rectangle_with_color: + * @pixbuf: Target pixbuf to fill into. + * @area: Rectangle to fill. + * @color: The color to use. + * + * Fill the rectangle with the the given color. + */ +void +eel_gdk_pixbuf_fill_rectangle_with_color (GdkPixbuf *pixbuf, + EelIRect area, + guint32 color) +{ + EelIRect target; + guchar red; + guchar green; + guchar blue; + guchar alpha; + guchar *pixels; + gboolean has_alpha; + guint pixel_offset; + guint rowstride; + guchar *row_offset; + int x; + int y; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + + target = eel_gdk_pixbuf_intersect (pixbuf, 0, 0, area); + if (eel_irect_is_empty (&target)) + { + return; + } + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + pixel_offset = has_alpha ? 4 : 3; + red = EEL_RGBA_COLOR_GET_R (color); + green = EEL_RGBA_COLOR_GET_G (color); + blue = EEL_RGBA_COLOR_GET_B (color); + alpha = EEL_RGBA_COLOR_GET_A (color); + + row_offset = pixels + target.y0 * rowstride; + + for (y = target.y0; y < target.y1; y++) + { + guchar *offset = row_offset + (target.x0 * pixel_offset); + + for (x = target.x0; x < target.x1; x++) + { + *(offset++) = red; + *(offset++) = green; + *(offset++) = blue; + + if (has_alpha) + { + *(offset++) = alpha; + } + + } + + row_offset += rowstride; + } +} + +gboolean +eel_gdk_pixbuf_save_to_file (const GdkPixbuf *pixbuf, + const char *file_name) +{ + return gdk_pixbuf_save ((GdkPixbuf *) pixbuf, + file_name, "png", NULL, NULL); +} + +void +eel_gdk_pixbuf_ref_if_not_null (GdkPixbuf *pixbuf_or_null) +{ + if (pixbuf_or_null != NULL) + { + g_object_ref (pixbuf_or_null); + } +} + +void +eel_gdk_pixbuf_unref_if_not_null (GdkPixbuf *pixbuf_or_null) +{ + if (pixbuf_or_null != NULL) + { + g_object_unref (pixbuf_or_null); + } +} + +void +eel_gdk_pixbuf_draw_to_drawable (const GdkPixbuf *pixbuf, + GdkDrawable *drawable, + GdkGC *gc, + int source_x, + int source_y, + EelIRect destination_area, + GdkRgbDither dither, + GdkPixbufAlphaMode alpha_compositing_mode, + int alpha_threshold) +{ + EelDimensions dimensions; + EelIRect target; + EelIRect source; + int target_width; + int target_height; + int source_width; + int source_height; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (!eel_irect_is_empty (&destination_area)); + g_return_if_fail (alpha_threshold > EEL_OPACITY_FULLY_TRANSPARENT); + g_return_if_fail (alpha_threshold <= EEL_OPACITY_FULLY_OPAQUE); + g_return_if_fail (alpha_compositing_mode >= GDK_PIXBUF_ALPHA_BILEVEL); + g_return_if_fail (alpha_compositing_mode <= GDK_PIXBUF_ALPHA_FULL); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + + g_return_if_fail (source_x >= 0); + g_return_if_fail (source_y >= 0); + g_return_if_fail (source_x < dimensions.width); + g_return_if_fail (source_y < dimensions.height); + + /* Clip the destination area to the pixbuf dimensions; bail if no work */ + target = eel_gdk_pixbuf_intersect (pixbuf, + destination_area.x0, + destination_area.y0, + destination_area); + if (eel_irect_is_empty (&target)) + { + return; + } + + /* Assign the source area */ + source = eel_irect_assign (source_x, + source_y, + dimensions.width - source_x, + dimensions.height - source_y); + + /* Adjust the target width if the source area is smaller than the + * source pixbuf dimensions */ + target_width = target.x1 - target.x0; + target_height = target.y1 - target.y0; + source_width = source.x1 - source.x0; + source_height = source.y1 - source.y0; + + target.x1 = target.x0 + MIN (target_width, source_width); + target.y1 = target.y0 + MIN (target_height, source_height); + + gdk_draw_pixbuf (drawable, gc, (GdkPixbuf *) pixbuf, + source.x0, + source.y0, + target.x0, + target.y0, + target.x1 - target.x0, + target.y1 - target.y0, + dither, + 0, + 0); +} + +/** + * eel_gdk_pixbuf_draw_to_pixbuf: + * @pixbuf: The source pixbuf to draw. + * @destination_pixbuf: The destination pixbuf. + * @source_x: The source pixbuf x coordiate to composite from. + * @source_y: The source pixbuf y coordiate to composite from. + * @destination_area: The destination area within the destination pixbuf. + * This area will be clipped if invalid in any way. + * + * Copy one pixbuf onto another another.. This function has some advantages + * over plain gdk_pixbuf_copy_area(): + * + * Composition paramters (source coordinate, destination area) are + * given in a way that is consistent with the rest of the extensions + * in this file. That is, it matches the declaration of + * eel_gdk_pixbuf_draw_to_pixbuf_alpha() and + * eel_gdk_pixbuf_draw_to_drawable() very closely. + * + * All values are clipped to make sure they are valid. + * + */ +void +eel_gdk_pixbuf_draw_to_pixbuf (const GdkPixbuf *pixbuf, + GdkPixbuf *destination_pixbuf, + int source_x, + int source_y, + EelIRect destination_area) +{ + EelDimensions dimensions; + EelIRect target; + EelIRect source; + int target_width; + int target_height; + int source_width; + int source_height; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + g_return_if_fail (eel_gdk_pixbuf_is_valid (destination_pixbuf)); + g_return_if_fail (!eel_irect_is_empty (&destination_area)); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + + g_return_if_fail (source_x >= 0); + g_return_if_fail (source_y >= 0); + g_return_if_fail (source_x < dimensions.width); + g_return_if_fail (source_y < dimensions.height); + + /* Clip the destination area to the pixbuf dimensions; bail if no work */ + target = eel_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); + if (eel_irect_is_empty (&target)) + { + return; + } + + /* Assign the source area */ + source = eel_irect_assign (source_x, + source_y, + dimensions.width - source_x, + dimensions.height - source_y); + + /* Adjust the target width if the source area is smaller than the + * source pixbuf dimensions */ + target_width = target.x1 - target.x0; + target_height = target.y1 - target.y0; + source_width = source.x1 - source.x0; + source_height = source.y1 - source.y0; + + target.x1 = target.x0 + MIN (target_width, source_width); + target.y1 = target.y0 + MIN (target_height, source_height); + + gdk_pixbuf_copy_area (pixbuf, + source.x0, + source.y0, + target.x1 - target.x0, + target.y1 - target.y0, + destination_pixbuf, + target.x0, + target.y0); +} + +/** + * eel_gdk_pixbuf_draw_to_pixbuf_alpha: + * @pixbuf: The source pixbuf to draw. + * @destination_pixbuf: The destination pixbuf. + * @source_x: The source pixbuf x coordiate to composite from. + * @source_y: The source pixbuf y coordiate to composite from. + * @destination_area: The destination area within the destination pixbuf. + * This area will be clipped if invalid in any way. + * @opacity: The opacity of the drawn tiles where 0 <= opacity <= 255. + * @interpolation_mode: The interpolation mode. See <gdk-pixbuf.h> + * + * Composite one pixbuf over another. This function has some advantages + * over plain gdk_pixbuf_composite(): + * + * Composition paramters (source coordinate, destination area) are + * given in a way that is consistent with the rest of the extensions + * in this file. That is, it matches the declaration of + * eel_gdk_pixbuf_draw_to_pixbuf() and + * eel_gdk_pixbuf_draw_to_drawable() very closely. + * + * All values are clipped to make sure they are valid. + * + * Workaround a limitation in gdk_pixbuf_composite() that does not allow + * the source (x,y) to be greater than (0,0) + * + */ +void +eel_gdk_pixbuf_draw_to_pixbuf_alpha (const GdkPixbuf *pixbuf, + GdkPixbuf *destination_pixbuf, + int source_x, + int source_y, + EelIRect destination_area, + int opacity, + GdkInterpType interpolation_mode) +{ + EelDimensions dimensions; + EelIRect target; + EelIRect source; + int target_width; + int target_height; + int source_width; + int source_height; + + g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); + g_return_if_fail (eel_gdk_pixbuf_is_valid (destination_pixbuf)); + g_return_if_fail (!eel_irect_is_empty (&destination_area)); + g_return_if_fail (opacity >= EEL_OPACITY_FULLY_TRANSPARENT); + g_return_if_fail (opacity <= EEL_OPACITY_FULLY_OPAQUE); + g_return_if_fail (interpolation_mode >= GDK_INTERP_NEAREST); + g_return_if_fail (interpolation_mode <= GDK_INTERP_HYPER); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + + g_return_if_fail (source_x >= 0); + g_return_if_fail (source_y >= 0); + g_return_if_fail (source_x < dimensions.width); + g_return_if_fail (source_y < dimensions.height); + + /* Clip the destination area to the pixbuf dimensions; bail if no work */ + target = eel_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); + if (eel_irect_is_empty (&target)) + { + return; + } + + /* Assign the source area */ + source = eel_irect_assign (source_x, + source_y, + dimensions.width - source_x, + dimensions.height - source_y); + + /* Adjust the target width if the source area is smaller than the + * source pixbuf dimensions */ + target_width = target.x1 - target.x0; + target_height = target.y1 - target.y0; + source_width = source.x1 - source.x0; + source_height = source.y1 - source.y0; + + target.x1 = target.x0 + MIN (target_width, source_width); + target.y1 = target.y0 + MIN (target_height, source_height); + + /* If the source point is not (0,0), then we need to create a sub pixbuf + * with only the source area. This is needed to work around a limitation + * in gdk_pixbuf_composite() that requires the source area to be (0,0). */ + if (source.x0 != 0 || source.y0 != 0) + { + EelIRect area; + int width; + int height; + + width = dimensions.width - source.x0; + height = dimensions.height - source.y0; + + area.x0 = source.x0; + area.y0 = source.y0; + area.x1 = area.x0 + width; + area.y1 = area.y0 + height; + + pixbuf = eel_gdk_pixbuf_new_from_pixbuf_sub_area ((GdkPixbuf *) pixbuf, area); + } + else + { + g_object_ref (G_OBJECT (pixbuf)); + } + + gdk_pixbuf_composite (pixbuf, + destination_pixbuf, + target.x0, + target.y0, + target.x1 - target.x0, + target.y1 - target.y0, + target.x0, + target.y0, + 1.0, + 1.0, + interpolation_mode, + opacity); + + g_object_unref (G_OBJECT (pixbuf)); +} + +static void +pixbuf_destroy_callback (guchar *pixels, + gpointer callback_data) +{ + g_assert (pixels != NULL); + g_assert (callback_data != NULL); + + g_object_unref (callback_data); +} + +/** + * eel_gdk_pixbuf_new_from_pixbuf_sub_area: + * @pixbuf: The source pixbuf. + * @area: The area within the source pixbuf to use for the sub pixbuf. + * This area needs to be contained within the bounds of the + * source pixbuf, otherwise it will be clipped to that. + * + * Return value: A newly allocated pixbuf that shares the pixel data + * of the source pixbuf in order to represent a sub area. + * + * Create a pixbuf from a sub area of another pixbuf. The resulting pixbuf + * will share the pixel data of the source pixbuf. Memory bookeeping is + * all taken care for the caller. All you need to do is g_object_unref() + * the resulting pixbuf to properly free resources. + */ +GdkPixbuf * +eel_gdk_pixbuf_new_from_pixbuf_sub_area (GdkPixbuf *pixbuf, + EelIRect area) +{ + GdkPixbuf *sub_pixbuf; + EelIRect target; + guchar *pixels; + + g_return_val_if_fail (eel_gdk_pixbuf_is_valid (pixbuf), NULL); + g_return_val_if_fail (!eel_irect_is_empty (&area), NULL); + + /* Clip the pixbuf by the given area; bail if no work */ + target = eel_gdk_pixbuf_intersect (pixbuf, 0, 0, area); + if (eel_irect_is_empty (&target)) + { + return NULL; + } + + /* Since we are going to be sharing the given pixbuf's data, we need + * to ref it. It will be unreffed in the destroy function above */ + g_object_ref (pixbuf); + + /* Compute the offset into the pixel data */ + pixels = + gdk_pixbuf_get_pixels (pixbuf) + + (target.y0 * gdk_pixbuf_get_rowstride (pixbuf)) + + (target.x0 * (gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3)); + + /* Make a pixbuf pretending its real estate is the sub area */ + sub_pixbuf = gdk_pixbuf_new_from_data (pixels, + GDK_COLORSPACE_RGB, + gdk_pixbuf_get_has_alpha (pixbuf), + 8, + eel_irect_get_width (target), + eel_irect_get_height (target), + gdk_pixbuf_get_rowstride (pixbuf), + pixbuf_destroy_callback, + pixbuf); + + return sub_pixbuf; +} + +/** + * eel_gdk_pixbuf_new_from_existing_buffer: + * @buffer: The existing buffer. + * @buffer_rowstride: The existing buffer's rowstride. + * @buffer_has_alpha: A boolean value indicating whether the buffer has alpha. + * @area: The area within the existing buffer to use for the pixbuf. + * This area needs to be contained within the bounds of the + * buffer, otherwise memory will be trashed. + * + * Return value: A newly allocated pixbuf that uses the existing buffer + * for its pixel data. + * + * Create a pixbuf from an existing buffer. + * + * The resulting pixbuf is only valid for as long as &buffer is valid. It is + * up to the caller to make sure they both exist in the same scope. + * Also, it is up to the caller to make sure that the given area is fully + * contained in the buffer, otherwise memory trashing will happen. + */ +GdkPixbuf * +eel_gdk_pixbuf_new_from_existing_buffer (guchar *buffer, + int buffer_rowstride, + gboolean buffer_has_alpha, + EelIRect area) +{ + GdkPixbuf *pixbuf; + guchar *pixels; + + g_return_val_if_fail (buffer != NULL, NULL); + g_return_val_if_fail (buffer_rowstride > 0, NULL); + g_return_val_if_fail (!eel_irect_is_empty (&area), NULL); + + /* Compute the offset into the buffer */ + pixels = + buffer + + (area.y0 * buffer_rowstride) + + (area.x0 * (buffer_has_alpha ? 4 : 3)); + + pixbuf = gdk_pixbuf_new_from_data (pixels, + GDK_COLORSPACE_RGB, + buffer_has_alpha, + 8, + eel_irect_get_width (area), + eel_irect_get_height (area), + buffer_rowstride, + NULL, + NULL); + + return pixbuf; +} + +/** + * eel_gdk_pixbuf_intersect: + * @pixbuf: A GdkPixbuf. + * @pixbuf_x: X coordinate of pixbuf. + * @pixbuf_y: Y coordinate of pixbuf. + * @rectangle: An EelIRect. + * + * Return value: The intersection of the pixbuf and the given rectangle. + * + */ +EelIRect +eel_gdk_pixbuf_intersect (const GdkPixbuf *pixbuf, + int pixbuf_x, + int pixbuf_y, + EelIRect rectangle) +{ + EelIRect intersection; + EelIRect bounds; + EelDimensions dimensions; + + g_return_val_if_fail (eel_gdk_pixbuf_is_valid (pixbuf), eel_irect_empty); + + dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); + bounds = eel_irect_assign_dimensions (pixbuf_x, pixbuf_y, dimensions); + + eel_irect_intersect (&intersection, &rectangle, &bounds); + + /* In theory, this is not needed because a rectangle is empty + * regardless of how MUCH negative the dimensions are. + * However, to make debugging and self checks simpler, we + * consistenly return a standard empty rectangle. + */ + if (eel_irect_is_empty (&intersection)) + { + return eel_irect_empty; + } + + return intersection; +} + +GdkPixbuf * +eel_gdk_pixbuf_scale_down (GdkPixbuf *pixbuf, + int dest_width, + int dest_height) +{ + int source_width, source_height; + int s_x1, s_y1, s_x2, s_y2; + int s_xfrac, s_yfrac; + int dx, dx_frac, dy, dy_frac; + div_t ddx, ddy; + int x, y; + int r, g, b, a; + int n_pixels; + gboolean has_alpha; + guchar *dest, *src, *xsrc, *src_pixels; + GdkPixbuf *dest_pixbuf; + int pixel_stride; + int source_rowstride, dest_rowstride; + + if (dest_width == 0 || dest_height == 0) + { + return NULL; + } + + source_width = gdk_pixbuf_get_width (pixbuf); + source_height = gdk_pixbuf_get_height (pixbuf); + + g_assert (source_width >= dest_width); + g_assert (source_height >= dest_height); + + ddx = div (source_width, dest_width); + dx = ddx.quot; + dx_frac = ddx.rem; + + ddy = div (source_height, dest_height); + dy = ddy.quot; + dy_frac = ddy.rem; + + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + source_rowstride = gdk_pixbuf_get_rowstride (pixbuf); + src_pixels = gdk_pixbuf_get_pixels (pixbuf); + + dest_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8, + dest_width, dest_height); + dest = gdk_pixbuf_get_pixels (dest_pixbuf); + dest_rowstride = gdk_pixbuf_get_rowstride (dest_pixbuf); + + pixel_stride = (has_alpha)?4:3; + + s_y1 = 0; + s_yfrac = -dest_height/2; + while (s_y1 < source_height) + { + s_y2 = s_y1 + dy; + s_yfrac += dy_frac; + if (s_yfrac > 0) + { + s_y2++; + s_yfrac -= dest_height; + } + + s_x1 = 0; + s_xfrac = -dest_width/2; + while (s_x1 < source_width) + { + s_x2 = s_x1 + dx; + s_xfrac += dx_frac; + if (s_xfrac > 0) + { + s_x2++; + s_xfrac -= dest_width; + } + + /* Average block of [x1,x2[ x [y1,y2[ and store in dest */ + r = g = b = a = 0; + n_pixels = 0; + + src = src_pixels + s_y1 * source_rowstride + s_x1 * pixel_stride; + for (y = s_y1; y < s_y2; y++) + { + xsrc = src; + if (has_alpha) + { + for (x = 0; x < s_x2-s_x1; x++) + { + n_pixels++; + + r += xsrc[3] * xsrc[0]; + g += xsrc[3] * xsrc[1]; + b += xsrc[3] * xsrc[2]; + a += xsrc[3]; + xsrc += 4; + } + } + else + { + for (x = 0; x < s_x2-s_x1; x++) + { + n_pixels++; + r += *xsrc++; + g += *xsrc++; + b += *xsrc++; + } + } + src += source_rowstride; + } + + if (has_alpha) + { + if (a != 0) + { + *dest++ = r / a; + *dest++ = g / a; + *dest++ = b / a; + *dest++ = a / n_pixels; + } + else + { + *dest++ = 0; + *dest++ = 0; + *dest++ = 0; + *dest++ = 0; + } + } + else + { + *dest++ = r / n_pixels; + *dest++ = g / n_pixels; + *dest++ = b / n_pixels; + } + + s_x1 = s_x2; + } + s_y1 = s_y2; + dest += dest_rowstride - dest_width * pixel_stride; + } + + return dest_pixbuf; +} + +static guchar +eel_gdk_pixbuf_lighten_pixbuf_component (guchar cur_value, + guint lighten_value) +{ + int new_value = cur_value; + if (lighten_value > 0) + { + new_value += lighten_value + (new_value >> 3); + if (new_value > 255) + { + new_value = 255; + } + } + return (guchar) new_value; +} + +static GdkPixbuf * +eel_gdk_pixbuf_lighten (GdkPixbuf* src, + guint lighten_value) +{ + GdkPixbuf *dest; + int i, j; + int width, height, has_alpha, src_row_stride, dst_row_stride; + guchar *target_pixels, *original_pixels; + guchar *pixsrc, *pixdest; + + g_assert (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB); + g_assert ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4)); + g_assert (gdk_pixbuf_get_bits_per_sample (src) == 8); + + dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + gdk_pixbuf_get_has_alpha (src), + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + src_row_stride = gdk_pixbuf_get_rowstride (src); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i * dst_row_stride; + pixsrc = original_pixels + i * src_row_stride; + for (j = 0; j < width; j++) + { + *pixdest++ = eel_gdk_pixbuf_lighten_pixbuf_component (*pixsrc++, lighten_value); + *pixdest++ = eel_gdk_pixbuf_lighten_pixbuf_component (*pixsrc++, lighten_value); + *pixdest++ = eel_gdk_pixbuf_lighten_pixbuf_component (*pixsrc++, lighten_value); + if (has_alpha) + { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} + +GdkPixbuf * +eel_gdk_pixbuf_render (GdkPixbuf *pixbuf, + guint render_mode, + guint saturation, + guint brightness, + guint lighten_value, + guint color) +{ + GdkPixbuf *temp_pixbuf, *old_pixbuf; + + if (render_mode == 1) + { + /* lighten icon */ + temp_pixbuf = eel_create_spotlight_pixbuf (pixbuf); + } + else if (render_mode == 2) + { + /* colorize icon */ + temp_pixbuf = eel_create_colorized_pixbuf (pixbuf, + EEL_RGBA_COLOR_GET_R (color), + EEL_RGBA_COLOR_GET_G (color), + EEL_RGBA_COLOR_GET_B (color)); + } + else if (render_mode == 3) + { + /* monochromely colorize icon */ + old_pixbuf = eel_create_darkened_pixbuf (pixbuf, 0, 255); + temp_pixbuf = eel_create_colorized_pixbuf (old_pixbuf, + EEL_RGBA_COLOR_GET_R (color), + EEL_RGBA_COLOR_GET_G (color), + EEL_RGBA_COLOR_GET_B (color)); + g_object_unref (old_pixbuf); + } + else + { + temp_pixbuf = NULL; + } + + if (saturation < 255 || brightness < 255 || temp_pixbuf == NULL) // temp_pixbuf == NULL just for safer code (return copy) + { + old_pixbuf = temp_pixbuf; + temp_pixbuf = eel_create_darkened_pixbuf (temp_pixbuf ? temp_pixbuf : pixbuf, saturation, brightness); + if (old_pixbuf) + { + g_object_unref (old_pixbuf); + } + } + + if (lighten_value > 0) + { + old_pixbuf = temp_pixbuf; + temp_pixbuf = eel_gdk_pixbuf_lighten (temp_pixbuf ? temp_pixbuf : pixbuf, lighten_value); + if (old_pixbuf) + { + g_object_unref (old_pixbuf); + } + } + + return temp_pixbuf; +} + + +#if !defined (EEL_OMIT_SELF_CHECK) + +static char * +check_average_value (int width, int height, const char* fill) +{ + char c; + guint r, g, b, a; + gboolean alpha, gray; + int gray_tweak; + GdkPixbuf *pixbuf; + int x, y, rowstride, n_channels; + guchar *pixels; + guint32 average; + guchar v; + + r = g = b = a = 0; + alpha = FALSE; + gray = FALSE; + gray_tweak = 0; + if (sscanf (fill, " %x,%x,%x,%x %c", &r, &g, &b, &a, &c) == 4) + { + alpha = TRUE; + } + else if (sscanf (fill, " %x,%x,%x %c", &r, &g, &b, &c) == 3) + { + } + else if (sscanf (fill, " gray%d %c", &gray_tweak, &c) == 1) + { + gray = TRUE; + } + else + { + return g_strdup ("bad fill string format"); + } + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, alpha, 8, width, height); + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + + if (!gray) + { + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + pixels [y * rowstride + x * n_channels + 0] = r; + pixels [y * rowstride + x * n_channels + 1] = g; + pixels [y * rowstride + x * n_channels + 2] = b; + if (alpha) + { + pixels [y * rowstride + x * n_channels + 3] = a; + } + } + } + } + else + { + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + v = ((x + y) & 1) ? 0x80 : 0x7F; + if (((x + y) & 0xFF) == 0) + v += gray_tweak; + pixels [y * rowstride + x * n_channels + 0] = v; + pixels [y * rowstride + x * n_channels + 1] = v; + pixels [y * rowstride + x * n_channels + 2] = v; + } + } + pixels [0] += gray_tweak; + pixels [1] += gray_tweak; + pixels [2] += gray_tweak; + } + + average = eel_gdk_pixbuf_average_value (pixbuf); + g_object_unref (pixbuf); + + return g_strdup_printf ("%02X,%02X,%02X,%02X", + (average >> 16) & 0xFF, + (average >> 8) & 0xFF, + average & 0xFF, + average >> 24); +} + +void +eel_self_check_gdk_pixbuf_extensions (void) +{ + GdkPixbuf *pixbuf; + EelIRect clip_area; + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 100, 100); + + EEL_CHECK_BOOLEAN_RESULT (eel_gdk_pixbuf_is_valid (pixbuf), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_gdk_pixbuf_is_valid (NULL), FALSE); + + EEL_CHECK_DIMENSIONS_RESULT (eel_gdk_pixbuf_get_dimensions (pixbuf), 100, 100); + + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, eel_gdk_pixbuf_whole_pixbuf), 0, 0, 100, 100); + + clip_area = eel_irect_assign (0, 0, 0, 0); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); + + clip_area = eel_irect_assign (0, 0, 0, 0); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); + + clip_area = eel_irect_assign (0, 0, 100, 100); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 100, 100); + + clip_area = eel_irect_assign (-10, -10, 100, 100); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 90, 90); + + clip_area = eel_irect_assign (-10, -10, 110, 110); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 100, 100); + + clip_area = eel_irect_assign (0, 0, 99, 99); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 99, 99); + + clip_area = eel_irect_assign (0, 0, 1, 1); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 1, 1); + + clip_area = eel_irect_assign (-1, -1, 1, 1); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); + + clip_area = eel_irect_assign (-1, -1, 2, 2); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 1, 1); + + clip_area = eel_irect_assign (100, 100, 1, 1); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); + + clip_area = eel_irect_assign (101, 101, 1, 1); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); + + clip_area = eel_irect_assign (80, 0, 100, 100); + EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 80, 0, 100, 100); + + g_object_unref (pixbuf); + + /* No checks for empty pixbufs because GdkPixbuf doesn't seem to allow them. */ + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "00,00,00"), "00,00,00,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "00,00,00,00"), "00,00,00,00"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "00,00,00,FF"), "00,00,00,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "01,01,01"), "01,01,01,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "FE,FE,FE"), "FE,FE,FE,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "FF,FF,FF"), "FF,FF,FF,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "FF,FF,FF,00"), "00,00,00,00"); + EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "11,22,33"), "11,22,33,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "00,00,00"), "00,00,00,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "00,00,00,00"), "00,00,00,00"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "00,00,00,FF"), "00,00,00,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "01,01,01"), "01,01,01,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "FE,FE,FE"), "FE,FE,FE,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "FF,FF,FF"), "FF,FF,FF,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "FF,FF,FF,00"), "00,00,00,00"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "11,22,33"), "11,22,33,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "gray -1"), "7F,7F,7F,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "gray 0"), "80,80,80,FF"); + EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "gray 1"), "80,80,80,FF"); +} + +#endif /* !EEL_OMIT_SELF_CHECK */ + diff --git a/eel/eel-gdk-pixbuf-extensions.h b/eel/eel-gdk-pixbuf-extensions.h new file mode 100644 index 00000000..cb66348c --- /dev/null +++ b/eel/eel-gdk-pixbuf-extensions.h @@ -0,0 +1,162 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gdk-pixbuf-extensions.h: Routines to augment what's in gdk-pixbuf. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_GDK_PIXBUF_EXTENSIONS_H +#define EEL_GDK_PIXBUF_EXTENSIONS_H + +#include <eel/eel-art-extensions.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk/gdk.h> +#include <gio/gio.h> + +#define EEL_STANDARD_ALPHA_THRESHHOLD 128 +#define EEL_OPACITY_FULLY_TRANSPARENT 0 +#define EEL_OPACITY_FULLY_OPAQUE 255 + +extern const EelIRect eel_gdk_pixbuf_whole_pixbuf; + +typedef struct EelPixbufLoadHandle EelPixbufLoadHandle; +typedef void (* EelPixbufLoadCallback) (GError *error, + GdkPixbuf *pixbuf, + gpointer callback_data); + +/* Convenience functions for lists of GdkPixbuf objects. */ +void eel_gdk_pixbuf_list_ref (GList *pixbuf_list); +void eel_gdk_pixbuf_list_unref (GList *pixbuf_list); +void eel_gdk_pixbuf_list_free (GList *pixbuf_list); + + +/* Loading a GdkPixbuf with a URI. */ +GdkPixbuf * eel_gdk_pixbuf_load (const char *uri); +GdkPixbuf * eel_gdk_pixbuf_load_from_stream (GInputStream *stream); +GdkPixbuf * eel_gdk_pixbuf_load_from_stream_at_size (GInputStream *stream, + int size); + + +/* Same thing async. */ +EelPixbufLoadHandle *eel_gdk_pixbuf_load_async (const char *uri, + int priority, + EelPixbufLoadCallback callback, + gpointer callback_data); +void eel_cancel_gdk_pixbuf_load (EelPixbufLoadHandle *handle); +GdkPixbuf * eel_gdk_pixbuf_scale_down_to_fit (GdkPixbuf *pixbuf, + int max_width, + int max_height); +GdkPixbuf * eel_gdk_pixbuf_scale_to_fit (GdkPixbuf *pixbuf, + int max_width, + int max_height); +double eel_gdk_scale_to_fit_factor (int width, + int height, + int max_width, + int max_height, + int *scaled_width, + int *scaled_height); +GdkPixbuf * eel_gdk_pixbuf_scale_to_min (GdkPixbuf *pixbuf, + int min_width, + int min_height); +double eel_gdk_scale_to_min_factor (int width, + int height, + int min_width, + int min_height, + int *scaled_width, + int *scaled_height); + +/* return average color values for each component (argb) */ +guint32 eel_gdk_pixbuf_average_value (GdkPixbuf *pixbuf); +void eel_gdk_pixbuf_fill_rectangle_with_color (GdkPixbuf *pixbuf, + EelIRect area, + guint32 color); + + +/* Save a pixbuf to a png file. Return value indicates succss/TRUE or failure/FALSE */ +gboolean eel_gdk_pixbuf_save_to_file (const GdkPixbuf *pixbuf, + const char *file_name); +void eel_gdk_pixbuf_ref_if_not_null (GdkPixbuf *pixbuf_or_null); +void eel_gdk_pixbuf_unref_if_not_null (GdkPixbuf *pixbuf_or_null); + + +/* Copy a pixbuf to an area of a GdkDrawable */ +void eel_gdk_pixbuf_draw_to_drawable (const GdkPixbuf *pixbuf, + GdkDrawable *drawable, + GdkGC *gc, + int source_x, + int source_y, + EelIRect destination_area, + GdkRgbDither dither, + GdkPixbufAlphaMode alpha_compositing_mode, + int alpha_threshold); + +/* Copy a pixbuf to an area of another pixbuf */ +void eel_gdk_pixbuf_draw_to_pixbuf (const GdkPixbuf *pixbuf, + GdkPixbuf *destination_pixbuf, + int source_x, + int source_y, + EelIRect destination_area); + + +/* Composite one pixbuf over another with the given opacity */ +void eel_gdk_pixbuf_draw_to_pixbuf_alpha (const GdkPixbuf *pixbuf, + GdkPixbuf *destination_pixbuf, + int source_x, + int source_y, + EelIRect destination_area, + int opacity, + GdkInterpType interpolation_mode); + + +/* Create a pixbuf from a sub area of another pixbuf */ +GdkPixbuf * eel_gdk_pixbuf_new_from_pixbuf_sub_area (GdkPixbuf *pixbuf, + EelIRect area); +/* Create a pixbuf from an existing buffer. */ +GdkPixbuf * eel_gdk_pixbuf_new_from_existing_buffer (guchar *buffer, + int buffer_rowstride, + gboolean buffer_has_alpha, + EelIRect area); + +/* Determine whether a pixbuf is valid or not */ +gboolean eel_gdk_pixbuf_is_valid (const GdkPixbuf *pixbuf); + +/* Access the dimensions of a pixbuf. */ +EelDimensions eel_gdk_pixbuf_get_dimensions (const GdkPixbuf *pixbuf); + +/* Return the intersection of the pixbuf with the given rectangle. */ +EelIRect eel_gdk_pixbuf_intersect (const GdkPixbuf *pixbuf, + int pixbuf_x, + int pixbuf_y, + EelIRect rectangle); + +/* Scales large pixbufs down fast */ +GdkPixbuf * eel_gdk_pixbuf_scale_down (GdkPixbuf *pixbuf, + int dest_width, + int dest_height); + +GdkPixbuf * eel_gdk_pixbuf_render (GdkPixbuf *pixbuf, + guint render_mode, + guint saturation, + guint brightness, + guint lighten_value, + guint color); + +#endif /* EEL_GDK_PIXBUF_EXTENSIONS_H */ diff --git a/eel/eel-glib-extensions.c b/eel/eel-glib-extensions.c new file mode 100644 index 00000000..b72029fd --- /dev/null +++ b/eel/eel-glib-extensions.c @@ -0,0 +1,1231 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-glib-extensions.c - implementation of new functions that conceptually + belong in glib. Perhaps some of these will be + actually rolled into glib someday. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: John Sullivan <[email protected]> +*/ + +#include <config.h> +#include "eel-glib-extensions.h" + +#include "eel-debug.h" +#include "eel-lib-self-check-functions.h" +#include "eel-string.h" +#include "eel-i18n.h" +#include <glib-object.h> +#include <math.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/utsname.h> +#include <time.h> +#include <locale.h> + +/* Legal conversion specifiers, as specified in the C standard. */ +#define C_STANDARD_STRFTIME_CHARACTERS "aAbBcdHIjmMpSUwWxXyYZ" +#define C_STANDARD_NUMERIC_STRFTIME_CHARACTERS "dHIjmMSUwWyY" +#define SUS_EXTENDED_STRFTIME_MODIFIERS "EO" + +#define SAFE_SHELL_CHARACTERS "-_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +typedef struct +{ + GHashTable *hash_table; + char *display_name; + gboolean keys_known_to_be_strings; +} HashTableToFree; + +static GList *hash_tables_to_free_at_exit; + +/** + * eel_g_date_new_tm: + * + * Get a new GDate * for the date represented by a tm struct. + * The caller is responsible for g_free-ing the result. + * @time_pieces: Pointer to a tm struct representing the date to be converted. + * + * Returns: Newly allocated date. + * + **/ +GDate * +eel_g_date_new_tm (struct tm *time_pieces) +{ + /* tm uses 0-based months; GDate uses 1-based months. + * tm_year needs 1900 added to get the full year. + */ + return g_date_new_dmy (time_pieces->tm_mday, + time_pieces->tm_mon + 1, + time_pieces->tm_year + 1900); +} + +/** + * eel_strdup_strftime: + * + * Cover for standard date-and-time-formatting routine strftime that returns + * a newly-allocated string of the correct size. The caller is responsible + * for g_free-ing the returned string. + * + * Besides the buffer management, there are two differences between this + * and the library strftime: + * + * 1) The modifiers "-" and "_" between a "%" and a numeric directive + * are defined as for the GNU version of strftime. "-" means "do not + * pad the field" and "_" means "pad with spaces instead of zeroes". + * 2) Non-ANSI extensions to strftime are flagged at runtime with a + * warning, so it's easy to notice use of the extensions without + * testing with multiple versions of the library. + * + * @format: format string to pass to strftime. See strftime documentation + * for details. + * @time_pieces: date/time, in struct format. + * + * Return value: Newly allocated string containing the formatted time. + **/ +char * +eel_strdup_strftime (const char *format, struct tm *time_pieces) +{ + GString *string; + const char *remainder, *percent; + char code[4], buffer[512]; + char *piece, *result, *converted; + size_t string_length; + gboolean strip_leading_zeros, turn_leading_zeros_to_spaces; + char modifier; + int i; + + /* Format could be translated, and contain UTF-8 chars, + * so convert to locale encoding which strftime uses */ + converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL); + g_return_val_if_fail (converted != NULL, NULL); + + string = g_string_new (""); + remainder = converted; + + /* Walk from % character to % character. */ + for (;;) + { + percent = strchr (remainder, '%'); + if (percent == NULL) + { + g_string_append (string, remainder); + break; + } + g_string_append_len (string, remainder, + percent - remainder); + + /* Handle the "%" character. */ + remainder = percent + 1; + switch (*remainder) + { + case '-': + strip_leading_zeros = TRUE; + turn_leading_zeros_to_spaces = FALSE; + remainder++; + break; + case '_': + strip_leading_zeros = FALSE; + turn_leading_zeros_to_spaces = TRUE; + remainder++; + break; + case '%': + g_string_append_c (string, '%'); + remainder++; + continue; + case '\0': + g_warning ("Trailing %% passed to eel_strdup_strftime"); + g_string_append_c (string, '%'); + continue; + default: + strip_leading_zeros = FALSE; + turn_leading_zeros_to_spaces = FALSE; + break; + } + + modifier = 0; + if (strchr (SUS_EXTENDED_STRFTIME_MODIFIERS, *remainder) != NULL) + { + modifier = *remainder; + remainder++; + + if (*remainder == 0) + { + g_warning ("Unfinished %%%c modifier passed to eel_strdup_strftime", modifier); + break; + } + } + + if (strchr (C_STANDARD_STRFTIME_CHARACTERS, *remainder) == NULL) + { + g_warning ("eel_strdup_strftime does not support " + "non-standard escape code %%%c", + *remainder); + } + + /* Convert code to strftime format. We have a fixed + * limit here that each code can expand to a maximum + * of 512 bytes, which is probably OK. There's no + * limit on the total size of the result string. + */ + i = 0; + code[i++] = '%'; + if (modifier != 0) + { +#ifdef HAVE_STRFTIME_EXTENSION + code[i++] = modifier; +#endif + } + code[i++] = *remainder; + code[i++] = '\0'; + string_length = strftime (buffer, sizeof (buffer), + code, time_pieces); + if (string_length == 0) + { + /* We could put a warning here, but there's no + * way to tell a successful conversion to + * empty string from a failure. + */ + buffer[0] = '\0'; + } + + /* Strip leading zeros if requested. */ + piece = buffer; + if (strip_leading_zeros || turn_leading_zeros_to_spaces) + { + if (strchr (C_STANDARD_NUMERIC_STRFTIME_CHARACTERS, *remainder) == NULL) + { + g_warning ("eel_strdup_strftime does not support " + "modifier for non-numeric escape code %%%c%c", + remainder[-1], + *remainder); + } + if (*piece == '0') + { + do + { + piece++; + } + while (*piece == '0'); + if (!g_ascii_isdigit (*piece)) + { + piece--; + } + } + if (turn_leading_zeros_to_spaces) + { + memset (buffer, ' ', piece - buffer); + piece = buffer; + } + } + remainder++; + + /* Add this piece. */ + g_string_append (string, piece); + } + + /* Convert the string back into utf-8. */ + result = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL); + + g_string_free (string, TRUE); + g_free (converted); + + return result; +} + +/** + * eel_g_list_exactly_one_item + * + * Like g_list_length (list) == 1, only O(1) instead of O(n). + * @list: List. + * + * Return value: TRUE if the list has exactly one item. + **/ +gboolean +eel_g_list_exactly_one_item (GList *list) +{ + return list != NULL && list->next == NULL; +} + +/** + * eel_g_list_more_than_one_item + * + * Like g_list_length (list) > 1, only O(1) instead of O(n). + * @list: List. + * + * Return value: TRUE if the list has more than one item. + **/ +gboolean +eel_g_list_more_than_one_item (GList *list) +{ + return list != NULL && list->next != NULL; +} + +/** + * eel_g_list_equal + * + * Compares two lists to see if they are equal. + * @list_a: First list. + * @list_b: Second list. + * + * Return value: TRUE if the lists are the same length with the same elements. + **/ +gboolean +eel_g_list_equal (GList *list_a, GList *list_b) +{ + GList *p, *q; + + for (p = list_a, q = list_b; p != NULL && q != NULL; p = p->next, q = q->next) + { + if (p->data != q->data) + { + return FALSE; + } + } + return p == NULL && q == NULL; +} + +/** + * eel_g_str_list_equal + * + * Compares two lists of C strings to see if they are equal. + * @list_a: First list. + * @list_b: Second list. + * + * Return value: TRUE if the lists contain the same strings. + **/ +gboolean +eel_g_str_list_equal (GList *list_a, GList *list_b) +{ + GList *p, *q; + + for (p = list_a, q = list_b; p != NULL && q != NULL; p = p->next, q = q->next) + { + if (eel_strcmp (p->data, q->data) != 0) + { + return FALSE; + } + } + return p == NULL && q == NULL; +} + +/** + * eel_g_str_list_copy + * + * @list: List of strings and/or NULLs to copy. + * Return value: Deep copy of @list. + **/ +GList * +eel_g_str_list_copy (GList *list) +{ + GList *node, *result; + + result = NULL; + + for (node = g_list_last (list); node != NULL; node = node->prev) + { + result = g_list_prepend (result, g_strdup (node->data)); + } + return result; +} + +/** + * eel_g_str_list_alphabetize + * + * Sort a list of strings using locale-sensitive rules. + * + * @list: List of strings and/or NULLs. + * + * Return value: @list, sorted. + **/ +GList * +eel_g_str_list_alphabetize (GList *list) +{ + return g_list_sort (list, (GCompareFunc) g_utf8_collate); +} + +int +eel_g_str_list_index (GList *str_list, + const char *str) +{ + int i; + GList *l; + for (i = 0, l = str_list; l != NULL; l = l->next, i++) + { + if (!strcmp (str, (const char*)l->data)) + { + return i; + } + } + return -1; +} + +/** + * eel_g_list_free_deep_custom + * + * Frees the elements of a list and then the list, using a custom free function. + * + * @list: List of elements that can be freed with the provided free function. + * @element_free_func: function to call with the data pointer and user_data to free it. + * @user_data: User data to pass to element_free_func + **/ +void +eel_g_list_free_deep_custom (GList *list, GFunc element_free_func, gpointer user_data) +{ + g_list_foreach (list, element_free_func, user_data); + g_list_free (list); +} + +/** + * eel_g_list_free_deep + * + * Frees the elements of a list and then the list. + * @list: List of elements that can be freed with g_free. + **/ +void +eel_g_list_free_deep (GList *list) +{ + eel_g_list_free_deep_custom (list, (GFunc) g_free, NULL); +} + +/** + * eel_g_list_free_deep_custom + * + * Frees the elements of a list and then the list, using a custom free function. + * + * @list: List of elements that can be freed with the provided free function. + * @element_free_func: function to call with the data pointer and user_data to free it. + * @user_data: User data to pass to element_free_func + **/ +void +eel_g_slist_free_deep_custom (GSList *list, GFunc element_free_func, gpointer user_data) +{ + g_slist_foreach (list, element_free_func, user_data); + g_slist_free (list); +} + +/** + * eel_g_slist_free_deep + * + * Frees the elements of a list and then the list. + * @list: List of elements that can be freed with g_free. + **/ +void +eel_g_slist_free_deep (GSList *list) +{ + eel_g_slist_free_deep_custom (list, (GFunc) g_free, NULL); +} + + +/** + * eel_g_strv_find + * + * Get index of string in array of strings. + * + * @strv: NULL-terminated array of strings. + * @find_me: string to search for. + * + * Return value: index of array entry in @strv that + * matches @find_me, or -1 if no matching entry. + */ +int +eel_g_strv_find (char **strv, const char *find_me) +{ + int index; + + g_return_val_if_fail (find_me != NULL, -1); + + for (index = 0; strv[index] != NULL; ++index) + { + if (strcmp (strv[index], find_me) == 0) + { + return index; + } + } + + return -1; +} + +gboolean +eel_g_strv_equal (char **a, char **b) +{ + int i; + + if (g_strv_length (a) != g_strv_length (b)) + { + return FALSE; + } + + for (i = 0; a[i] != NULL; i++) + { + if (strcmp (a[i], b[i]) != 0) + { + return FALSE; + } + } + return TRUE; +} + +static int +compare_pointers (gconstpointer pointer_1, gconstpointer pointer_2) +{ + if ((const char *) pointer_1 < (const char *) pointer_2) + { + return -1; + } + if ((const char *) pointer_1 > (const char *) pointer_2) + { + return +1; + } + return 0; +} + +gboolean +eel_g_lists_sort_and_check_for_intersection (GList **list_1, + GList **list_2) + +{ + GList *node_1, *node_2; + int compare_result; + + *list_1 = g_list_sort (*list_1, compare_pointers); + *list_2 = g_list_sort (*list_2, compare_pointers); + + node_1 = *list_1; + node_2 = *list_2; + + while (node_1 != NULL && node_2 != NULL) + { + compare_result = compare_pointers (node_1->data, node_2->data); + if (compare_result == 0) + { + return TRUE; + } + if (compare_result <= 0) + { + node_1 = node_1->next; + } + if (compare_result >= 0) + { + node_2 = node_2->next; + } + } + + return FALSE; +} + + +/** + * eel_g_list_partition + * + * Parition a list into two parts depending on whether the data + * elements satisfy a provided predicate. Order is preserved in both + * of the resulting lists, and the original list is consumed. A list + * of the items that satisfy the predicate is returned, and the list + * of items not satisfying the predicate is returned via the failed + * out argument. + * + * @list: List to partition. + * @predicate: Function to call on each element. + * @user_data: Data to pass to function. + * @failed: The GList * variable pointed to by this argument will be + * set to the list of elements for which the predicate returned + * false. */ + +GList * +eel_g_list_partition (GList *list, + EelPredicateFunction predicate, + gpointer user_data, + GList **failed) +{ + GList *predicate_true; + GList *predicate_false; + GList *reverse; + GList *p; + GList *next; + + predicate_true = NULL; + predicate_false = NULL; + + reverse = g_list_reverse (list); + + for (p = reverse; p != NULL; p = next) + { + next = p->next; + + if (next != NULL) + { + next->prev = NULL; + } + + if (predicate (p->data, user_data)) + { + p->next = predicate_true; + if (predicate_true != NULL) + { + predicate_true->prev = p; + } + predicate_true = p; + } + else + { + p->next = predicate_false; + if (predicate_false != NULL) + { + predicate_false->prev = p; + } + predicate_false = p; + } + } + + *failed = predicate_false; + return predicate_true; +} + +/** + * eel_get_system_time + * + * Return value: number of microseconds since the machine was turned on + */ +gint64 +eel_get_system_time (void) +{ + struct timeval tmp; + + gettimeofday (&tmp, NULL); + return (gint64)tmp.tv_usec + (gint64)tmp.tv_sec * G_GINT64_CONSTANT (1000000); +} + +static void +print_key_string (gpointer key, gpointer value, gpointer callback_data) +{ + g_assert (callback_data == NULL); + + g_print ("--> %s\n", (char *) key); +} + +static void +free_hash_tables_at_exit (void) +{ + GList *p; + HashTableToFree *hash_table_to_free; + guint size; + + for (p = hash_tables_to_free_at_exit; p != NULL; p = p->next) + { + hash_table_to_free = p->data; + + size = g_hash_table_size (hash_table_to_free->hash_table); + if (size != 0) + { + if (hash_table_to_free->keys_known_to_be_strings) + { + g_print ("\n--- Hash table keys for warning below:\n"); + g_hash_table_foreach (hash_table_to_free->hash_table, + print_key_string, + NULL); + } + g_warning ("\"%s\" hash table still has %u element%s at quit time%s", + hash_table_to_free->display_name, size, + size == 1 ? "" : "s", + hash_table_to_free->keys_known_to_be_strings + ? " (keys above)" : ""); + } + + g_hash_table_destroy (hash_table_to_free->hash_table); + g_free (hash_table_to_free->display_name); + g_free (hash_table_to_free); + } + g_list_free (hash_tables_to_free_at_exit); + hash_tables_to_free_at_exit = NULL; +} + +GHashTable * +eel_g_hash_table_new_free_at_exit (GHashFunc hash_func, + GCompareFunc key_compare_func, + const char *display_name) +{ + GHashTable *hash_table; + HashTableToFree *hash_table_to_free; + + /* FIXME: We can take out the CAJA_DEBUG check once we + * have fixed more of the leaks. For now, it's a bit too noisy + * for the general public. + */ + if (hash_tables_to_free_at_exit == NULL) + { + eel_debug_call_at_shutdown (free_hash_tables_at_exit); + } + + hash_table = g_hash_table_new (hash_func, key_compare_func); + + hash_table_to_free = g_new (HashTableToFree, 1); + hash_table_to_free->hash_table = hash_table; + hash_table_to_free->display_name = g_strdup (display_name); + hash_table_to_free->keys_known_to_be_strings = + hash_func == g_str_hash; + + hash_tables_to_free_at_exit = g_list_prepend + (hash_tables_to_free_at_exit, hash_table_to_free); + + return hash_table; +} + +typedef struct +{ + GList *keys; + GList *values; +} FlattenedHashTable; + +static void +flatten_hash_table_element (gpointer key, gpointer value, gpointer callback_data) +{ + FlattenedHashTable *flattened_table; + + flattened_table = callback_data; + flattened_table->keys = g_list_prepend + (flattened_table->keys, key); + flattened_table->values = g_list_prepend + (flattened_table->values, value); +} + +void +eel_g_hash_table_safe_for_each (GHashTable *hash_table, + GHFunc callback, + gpointer callback_data) +{ + FlattenedHashTable flattened; + GList *p, *q; + + flattened.keys = NULL; + flattened.values = NULL; + + g_hash_table_foreach (hash_table, + flatten_hash_table_element, + &flattened); + + for (p = flattened.keys, q = flattened.values; + p != NULL; + p = p->next, q = q->next) + { + (* callback) (p->data, q->data, callback_data); + } + + g_list_free (flattened.keys); + g_list_free (flattened.values); +} + +int +eel_round (double d) +{ + double val; + + val = floor (d + .5); + + /* The tests are needed because the result of floating-point to integral + * conversion is undefined if the floating point value is not representable + * in the new type. E.g. the magnititude is too large or a negative + * floating-point value being converted to an unsigned. + */ + g_return_val_if_fail (val <= INT_MAX, INT_MAX); + g_return_val_if_fail (val >= INT_MIN, INT_MIN); + + return val; +} + +GList * +eel_g_list_from_g_slist (GSList *slist) +{ + GList *list; + GSList *node; + + list = NULL; + for (node = slist; node != NULL; node = node->next) + { + list = g_list_prepend (list, node->data); + } + return g_list_reverse (list); +} + +GSList * +eel_g_slist_from_g_list (GList *list) +{ + GSList *slist; + GList *node; + + slist = NULL; + for (node = list; node != NULL; node = node->next) + { + slist = g_slist_prepend (slist, node->data); + } + return g_slist_reverse (slist); +} + +/* Return the operating system name: Linux, Solaris, etc. */ +char * +eel_get_operating_system_name (void) +{ + struct utsname buffer; + + if (uname (&buffer) != -1) + { + /* Check for special sysnames for which there is + * more accepted names. + */ + if (eel_str_is_equal (buffer.sysname, "SunOS")) + { + return g_strdup ("Solaris"); + } + + return g_strdup (buffer.sysname); + } + + return g_strdup ("Unix"); +} + +int +eel_compare_integer (gconstpointer a, + gconstpointer b) +{ + int int_a; + int int_b; + + int_a = GPOINTER_TO_INT (a); + int_b = GPOINTER_TO_INT (b); + + if (int_a == int_b) + { + return 0; + } + + return int_a < int_b ? -1 : 1; +} + +/** + * eel_g_object_list_ref + * + * Ref all the objects in a list. + * @list: GList of objects. + **/ +GList * +eel_g_object_list_ref (GList *list) +{ + g_list_foreach (list, (GFunc) g_object_ref, NULL); + return list; +} + +/** + * eel_g_object_list_unref + * + * Unref all the objects in a list. + * @list: GList of objects. + **/ +void +eel_g_object_list_unref (GList *list) +{ + g_list_foreach (list, (GFunc) g_object_unref, NULL); +} + +/** + * eel_g_object_list_free + * + * Free a list of objects after unrefing them. + * @list: GList of objects. + **/ +void +eel_g_object_list_free (GList *list) +{ + eel_g_object_list_unref (list); + g_list_free (list); +} + +/** + * eel_g_object_list_copy + * + * Copy the list of objects, ref'ing each one. + * @list: GList of objects. + **/ +GList * +eel_g_object_list_copy (GList *list) +{ + return g_list_copy (eel_g_object_list_ref (list)); +} + +/** + * eel_add_weak_pointer + * + * Nulls out a saved reference to an object when the object gets destroyed. + * + * @pointer_location: Address of the saved pointer. + **/ +void +eel_add_weak_pointer (gpointer pointer_location) +{ + gpointer *object_location; + + g_return_if_fail (pointer_location != NULL); + + object_location = (gpointer *) pointer_location; + if (*object_location == NULL) + { + /* The reference is NULL, nothing to do. */ + return; + } + + g_return_if_fail (G_IS_OBJECT (*object_location)); + + g_object_add_weak_pointer (G_OBJECT (*object_location), + object_location); +} + +/** + * eel_remove_weak_pointer + * + * Removes the weak pointer that was added by eel_add_weak_pointer. + * Also nulls out the pointer. + * + * @pointer_location: Pointer that was passed to eel_add_weak_pointer. + **/ +void +eel_remove_weak_pointer (gpointer pointer_location) +{ + gpointer *object_location; + + g_return_if_fail (pointer_location != NULL); + + object_location = (gpointer *) pointer_location; + if (*object_location == NULL) + { + /* The object was already destroyed and the reference + * nulled out, nothing to do. + */ + return; + } + + g_return_if_fail (G_IS_OBJECT (*object_location)); + + g_object_remove_weak_pointer (G_OBJECT (*object_location), + object_location); + + *object_location = NULL; +} + +/* Get the filename encoding, returns TRUE if utf8 */ + +typedef struct _EelFilenameCharsetCache EelFilenameCharsetCache; + +struct _EelFilenameCharsetCache +{ + gboolean is_utf8; + gchar *charset; + gchar *filename_charset; +}; + +static void +filename_charset_cache_free (gpointer data) +{ + EelFilenameCharsetCache *cache = data; + g_free (cache->charset); + g_free (cache->filename_charset); + g_free (cache); +} + +/* + * eel_get_filename_charset: + * @charset: return location for the name of the filename encoding + * + * Determines the character set used for filenames by consulting the + * environment variables G_FILENAME_ENCODING and G_BROKEN_FILENAMES. + * + * G_FILENAME_ENCODING may be set to a comma-separated list of character + * set names. The special token "@locale" is taken to mean the character set + * for the current locale. The first character set from the list is taken + * as the filename encoding. + * If G_FILENAME_ENCODING is not set, but G_BROKEN_FILENAMES is, the + * character set of the current locale is taken as the filename encoding. + * + * The returned @charset belongs to Eel and must not be freed. + * + * Return value: %TRUE if the charset used for filename is UTF-8. + */ +gboolean +eel_get_filename_charset (const gchar **filename_charset) +{ + static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT; + EelFilenameCharsetCache *cache = g_static_private_get (&cache_private); + const gchar *charset; + + if (!cache) + { + cache = g_new0 (EelFilenameCharsetCache, 1); + g_static_private_set (&cache_private, cache, filename_charset_cache_free); + } + + g_get_charset (&charset); + + if (!(cache->charset && strcmp (cache->charset, charset) == 0)) + { + const gchar *new_charset; + gchar *p, *q; + + g_free (cache->charset); + g_free (cache->filename_charset); + cache->charset = g_strdup (charset); + + p = getenv ("G_FILENAME_ENCODING"); + if (p != NULL) + { + q = strchr (p, ','); + if (!q) + q = p + strlen (p); + + if (strncmp ("@locale", p, q - p) == 0) + { + cache->is_utf8 = g_get_charset (&new_charset); + cache->filename_charset = g_strdup (new_charset); + } + else + { + cache->filename_charset = g_strndup (p, q - p); + cache->is_utf8 = (strcmp (cache->filename_charset, "UTF-8") == 0); + } + } + else if (getenv ("G_BROKEN_FILENAMES") != NULL) + { + cache->is_utf8 = g_get_charset (&new_charset); + cache->filename_charset = g_strdup (new_charset); + } + else + { + cache->filename_charset = g_strdup ("UTF-8"); + cache->is_utf8 = TRUE; + } + } + + if (filename_charset) + *filename_charset = cache->filename_charset; + + return cache->is_utf8; +} + +#if !defined (EEL_OMIT_SELF_CHECK) + +static void +check_tm_to_g_date (time_t time) +{ + struct tm *before_conversion; + struct tm after_conversion; + GDate *date; + + before_conversion = localtime (&time); + date = eel_g_date_new_tm (before_conversion); + + g_date_to_struct_tm (date, &after_conversion); + + g_date_free (date); + + EEL_CHECK_INTEGER_RESULT (after_conversion.tm_mday, + before_conversion->tm_mday); + EEL_CHECK_INTEGER_RESULT (after_conversion.tm_mon, + before_conversion->tm_mon); + EEL_CHECK_INTEGER_RESULT (after_conversion.tm_year, + before_conversion->tm_year); +} + +static gboolean +eel_test_predicate (gpointer data, + gpointer callback_data) +{ + return g_ascii_strcasecmp (data, callback_data) <= 0; +} + +static char * +test_strftime (const char *format, + int year, + int month, + int day, + int hour, + int minute, + int second) +{ + struct tm time_pieces; + + time_pieces.tm_sec = second; + time_pieces.tm_min = minute; + time_pieces.tm_hour = hour; + time_pieces.tm_mday = day; + time_pieces.tm_mon = month - 1; + time_pieces.tm_year = year - 1900; + time_pieces.tm_isdst = -1; + mktime (&time_pieces); + + return eel_strdup_strftime (format, &time_pieces); +} + +void +eel_self_check_glib_extensions (void) +{ + char **strv; + GList *compare_list_1; + GList *compare_list_2; + GList *compare_list_3; + GList *compare_list_4; + GList *compare_list_5; + gint64 time1, time2; + GList *list_to_partition; + GList *expected_passed; + GList *expected_failed; + GList *actual_passed; + GList *actual_failed; + char *huge_string; + + check_tm_to_g_date (0); /* lower limit */ + check_tm_to_g_date ((time_t) -1); /* upper limit */ + check_tm_to_g_date (time (NULL)); /* current time */ + + strv = g_strsplit ("zero|one|two|three|four", "|", 0); + EEL_CHECK_INTEGER_RESULT (eel_g_strv_find (strv, "zero"), 0); + EEL_CHECK_INTEGER_RESULT (eel_g_strv_find (strv, "one"), 1); + EEL_CHECK_INTEGER_RESULT (eel_g_strv_find (strv, "four"), 4); + EEL_CHECK_INTEGER_RESULT (eel_g_strv_find (strv, "five"), -1); + EEL_CHECK_INTEGER_RESULT (eel_g_strv_find (strv, ""), -1); + EEL_CHECK_INTEGER_RESULT (eel_g_strv_find (strv, "o"), -1); + g_strfreev (strv); + + /* eel_get_system_time */ + time1 = eel_get_system_time (); + time2 = eel_get_system_time (); + EEL_CHECK_BOOLEAN_RESULT (time1 - time2 > -1000, TRUE); + EEL_CHECK_BOOLEAN_RESULT (time1 - time2 <= 0, TRUE); + + /* eel_g_str_list_equal */ + + /* We g_strdup because identical string constants can be shared. */ + + compare_list_1 = NULL; + compare_list_1 = g_list_append (compare_list_1, g_strdup ("Apple")); + compare_list_1 = g_list_append (compare_list_1, g_strdup ("zebra")); + compare_list_1 = g_list_append (compare_list_1, g_strdup ("!@#!@$#@$!")); + + compare_list_2 = NULL; + compare_list_2 = g_list_append (compare_list_2, g_strdup ("Apple")); + compare_list_2 = g_list_append (compare_list_2, g_strdup ("zebra")); + compare_list_2 = g_list_append (compare_list_2, g_strdup ("!@#!@$#@$!")); + + compare_list_3 = NULL; + compare_list_3 = g_list_append (compare_list_3, g_strdup ("Apple")); + compare_list_3 = g_list_append (compare_list_3, g_strdup ("zebra")); + + compare_list_4 = NULL; + compare_list_4 = g_list_append (compare_list_4, g_strdup ("Apple")); + compare_list_4 = g_list_append (compare_list_4, g_strdup ("zebra")); + compare_list_4 = g_list_append (compare_list_4, g_strdup ("!@#!@$#@$!")); + compare_list_4 = g_list_append (compare_list_4, g_strdup ("foobar")); + + compare_list_5 = NULL; + compare_list_5 = g_list_append (compare_list_5, g_strdup ("Apple")); + compare_list_5 = g_list_append (compare_list_5, g_strdup ("zzzzzebraaaaaa")); + compare_list_5 = g_list_append (compare_list_5, g_strdup ("!@#!@$#@$!")); + + EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_2), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_3), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_4), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (compare_list_1, compare_list_5), FALSE); + + eel_g_list_free_deep (compare_list_1); + eel_g_list_free_deep (compare_list_2); + eel_g_list_free_deep (compare_list_3); + eel_g_list_free_deep (compare_list_4); + eel_g_list_free_deep (compare_list_5); + + /* eel_g_list_partition */ + + list_to_partition = NULL; + list_to_partition = g_list_append (list_to_partition, "Cadillac"); + list_to_partition = g_list_append (list_to_partition, "Pontiac"); + list_to_partition = g_list_append (list_to_partition, "Ford"); + list_to_partition = g_list_append (list_to_partition, "Range Rover"); + + expected_passed = NULL; + expected_passed = g_list_append (expected_passed, "Cadillac"); + expected_passed = g_list_append (expected_passed, "Ford"); + + expected_failed = NULL; + expected_failed = g_list_append (expected_failed, "Pontiac"); + expected_failed = g_list_append (expected_failed, "Range Rover"); + + actual_passed = eel_g_list_partition (list_to_partition, + eel_test_predicate, + "m", + &actual_failed); + + EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (expected_passed, actual_passed), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_g_str_list_equal (expected_failed, actual_failed), TRUE); + + /* Don't free "list_to_partition", since it is consumed + * by eel_g_list_partition. + */ + + g_list_free (expected_passed); + g_list_free (actual_passed); + g_list_free (expected_failed); + g_list_free (actual_failed); + + /* eel_strdup_strftime */ + huge_string = g_new (char, 10000+1); + memset (huge_string, 'a', 10000); + huge_string[10000] = '\0'; + + setlocale (LC_TIME, "C"); + + EEL_CHECK_STRING_RESULT (test_strftime ("", 2000, 1, 1, 0, 0, 0), ""); + EEL_CHECK_STRING_RESULT (test_strftime (huge_string, 2000, 1, 1, 0, 0, 0), huge_string); + EEL_CHECK_STRING_RESULT (test_strftime ("%%", 2000, 1, 1, 1, 0, 0), "%"); + EEL_CHECK_STRING_RESULT (test_strftime ("%%%%", 2000, 1, 1, 1, 0, 0), "%%"); + EEL_CHECK_STRING_RESULT (test_strftime ("%m/%d/%y, %I:%M %p", 2000, 1, 1, 1, 0, 0), "01/01/00, 01:00 AM"); + EEL_CHECK_STRING_RESULT (test_strftime ("%-m/%-d/%y, %-I:%M %p", 2000, 1, 1, 1, 0, 0), "1/1/00, 1:00 AM"); + EEL_CHECK_STRING_RESULT (test_strftime ("%_m/%_d/%y, %_I:%M %p", 2000, 1, 1, 1, 0, 0), " 1/ 1/00, 1:00 AM"); + + setlocale (LC_TIME, ""); + + g_free (huge_string); + + /* eel_shell_quote */ + EEL_CHECK_STRING_RESULT (g_shell_quote (""), "''"); + EEL_CHECK_STRING_RESULT (g_shell_quote ("a"), "'a'"); + EEL_CHECK_STRING_RESULT (g_shell_quote ("("), "'('"); + EEL_CHECK_STRING_RESULT (g_shell_quote ("'"), "''\\'''"); + EEL_CHECK_STRING_RESULT (g_shell_quote ("'a"), "''\\''a'"); + EEL_CHECK_STRING_RESULT (g_shell_quote ("a'"), "'a'\\'''"); + EEL_CHECK_STRING_RESULT (g_shell_quote ("a'a"), "'a'\\''a'"); + + /* eel_compare_integer */ + EEL_CHECK_INTEGER_RESULT (eel_compare_integer (GINT_TO_POINTER (0), GINT_TO_POINTER (0)), 0); + EEL_CHECK_INTEGER_RESULT (eel_compare_integer (GINT_TO_POINTER (0), GINT_TO_POINTER (1)), -1); + EEL_CHECK_INTEGER_RESULT (eel_compare_integer (GINT_TO_POINTER (1), GINT_TO_POINTER (0)), 1); + EEL_CHECK_INTEGER_RESULT (eel_compare_integer (GINT_TO_POINTER (-1), GINT_TO_POINTER (0)), -1); + EEL_CHECK_INTEGER_RESULT (eel_compare_integer (GINT_TO_POINTER (0), GINT_TO_POINTER (-1)), 1); + EEL_CHECK_INTEGER_RESULT (eel_compare_integer (GINT_TO_POINTER (-1), GINT_TO_POINTER (-1)), 0); + +#ifdef __linux__ + EEL_CHECK_STRING_RESULT (eel_get_operating_system_name (), "Linux"); +#endif +} + +#endif /* !EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-glib-extensions.h b/eel/eel-glib-extensions.h new file mode 100644 index 00000000..ac36fe7e --- /dev/null +++ b/eel/eel-glib-extensions.h @@ -0,0 +1,128 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-glib-extensions.h - interface for new functions that conceptually + belong in glib. Perhaps some of these will be + actually rolled into glib someday. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: John Sullivan <[email protected]> +*/ + +#ifndef EEL_GLIB_EXTENSIONS_H +#define EEL_GLIB_EXTENSIONS_H + +#include <glib.h> + +/* A gboolean variant for bit fields. */ +typedef guint eel_boolean_bit; + +/* Callback functions that have user data. */ +typedef int (* EelCompareFunction) (gconstpointer a, + gconstpointer b, + gpointer callback_data); +typedef int (* EelSearchFunction) (gconstpointer item, + gpointer callback_data); + +/* Predicate. */ +typedef gboolean (* EelPredicateFunction) (gpointer data, + gpointer callback_data); + +/* Date & time functions. */ +GDate * eel_g_date_new_tm (struct tm *time_pieces); +char * eel_strdup_strftime (const char *format, + struct tm *time_pieces); + +/* GList functions. */ +gboolean eel_g_list_exactly_one_item (GList *list); +gboolean eel_g_list_more_than_one_item (GList *list); +gboolean eel_g_list_equal (GList *list_a, + GList *list_b); +gboolean eel_g_lists_sort_and_check_for_intersection (GList **list_a, + GList **list_b); +GList * eel_g_list_partition (GList *list, + EelPredicateFunction predicate, + gpointer user_data, + GList **removed); + +/* List functions for lists of g_free'able objects. */ +void eel_g_list_free_deep (GList *list); +void eel_g_list_free_deep_custom (GList *list, + GFunc element_free_func, + gpointer user_data); + +/* GSList functions. */ +GList * eel_g_list_from_g_slist (GSList *list); +GSList * eel_g_slist_from_g_list (GList *list); + +/* List functions for slists of g_free'able objects. */ +void eel_g_slist_free_deep (GSList *list); +void eel_g_slist_free_deep_custom (GSList *list, + GFunc element_free_func, + gpointer user_data); + +/* List functions for lists of C strings. */ +gboolean eel_g_str_list_equal (GList *str_list_a, + GList *str_list_b); +GList * eel_g_str_list_copy (GList *str_list); +GList * eel_g_str_list_alphabetize (GList *str_list); +int eel_g_str_list_index (GList *str_list, + const char *str); + +/* List functions for lists of objects */ +GList * eel_g_object_list_ref (GList *list); +void eel_g_object_list_unref (GList *list); +void eel_g_object_list_free (GList *list); +GList * eel_g_object_list_copy (GList *list); + +/* GHashTable functions */ +GHashTable *eel_g_hash_table_new_free_at_exit (GHashFunc hash_function, + GCompareFunc key_compare_function, + const char *display_name); +void eel_g_hash_table_safe_for_each (GHashTable *hash_table, + GHFunc callback, + gpointer callback_data); + +/* NULL terminated string arrays (strv). */ +int eel_g_strv_find (char **strv, + const char *find_me); +gboolean eel_g_strv_equal (char **a, + char **b); + +/* return the time in microseconds since the machine was started */ +gint64 eel_get_system_time (void); + +/* math */ +int eel_round (double d); + +/* A GCompareFunc for integers */ +int eel_compare_integer (gconstpointer a, + gconstpointer b); + +/* Return the operating system name: Linux, Solaris, etc. */ +char * eel_get_operating_system_name (void); + +/* Better weak pointer functions */ +void eel_add_weak_pointer (gpointer pointer_location); +void eel_remove_weak_pointer (gpointer pointer_location); + +/* Get the filename encoding, returns TRUE if utf8 */ +gboolean eel_get_filename_charset (const gchar **filename_charset); + + +#endif /* EEL_GLIB_EXTENSIONS_H */ diff --git a/eel/eel-graphic-effects.c b/eel/eel-graphic-effects.c new file mode 100644 index 00000000..c96135d8 --- /dev/null +++ b/eel/eel-graphic-effects.c @@ -0,0 +1,421 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* Eel - pixbuf manipulation routines for graphical effects. + * + * Copyright (C) 2000 Eazel, Inc + * + * Author: Andy Hertzfeld <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* This file contains pixbuf manipulation routines used for graphical effects like pre-lighting + and selection hilighting */ + +#include <config.h> +#include "eel-graphic-effects.h" +#include <string.h> + +/* shared utility to create a new pixbuf from the passed-in one */ + +static GdkPixbuf * +create_new_pixbuf (GdkPixbuf *src) +{ + g_assert (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB); + g_assert ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4)); + + return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + gdk_pixbuf_get_has_alpha (src), + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); +} + +static GdkPixbuf * +create_new_pixbuf_with_alpha (GdkPixbuf *src) +{ + g_assert (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB); + g_assert ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4)); + + return gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + TRUE, + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); +} + +/* utility routine to bump the level of a color component with pinning */ + +static guchar +lighten_component (guchar cur_value) +{ + int new_value = cur_value; + new_value += 24 + (new_value >> 3); + if (new_value > 255) + { + new_value = 255; + } + return (guchar) new_value; +} + +GdkPixbuf * +eel_create_spotlight_pixbuf (GdkPixbuf* src) +{ + GdkPixbuf *dest; + int i, j; + int width, height, has_alpha, src_row_stride, dst_row_stride; + guchar *target_pixels, *original_pixels; + guchar *pixsrc, *pixdest; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest = create_new_pixbuf (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + src_row_stride = gdk_pixbuf_get_rowstride (src); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i * dst_row_stride; + pixsrc = original_pixels + i * src_row_stride; + for (j = 0; j < width; j++) + { + *pixdest++ = lighten_component (*pixsrc++); + *pixdest++ = lighten_component (*pixsrc++); + *pixdest++ = lighten_component (*pixsrc++); + if (has_alpha) + { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} + + +/* the following routine was stolen from the panel to darken a pixbuf, by manipulating the saturation */ + +/* saturation is 0-255, darken is 0-255 */ + +GdkPixbuf * +eel_create_darkened_pixbuf (GdkPixbuf *src, int saturation, int darken) +{ + gint i, j; + gint width, height, src_row_stride, dest_row_stride; + gboolean has_alpha; + guchar *target_pixels, *original_pixels; + guchar *pixsrc, *pixdest; + guchar intensity; + guchar alpha; + guchar negalpha; + guchar r, g, b; + GdkPixbuf *dest; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest = create_new_pixbuf (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + dest_row_stride = gdk_pixbuf_get_rowstride (dest); + src_row_stride = gdk_pixbuf_get_rowstride (src); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i * dest_row_stride; + pixsrc = original_pixels + i * src_row_stride; + for (j = 0; j < width; j++) + { + r = *pixsrc++; + g = *pixsrc++; + b = *pixsrc++; + intensity = (r * 77 + g * 150 + b * 28) >> 8; + negalpha = ((255 - saturation) * darken) >> 8; + alpha = (saturation * darken) >> 8; + *pixdest++ = (negalpha * intensity + alpha * r) >> 8; + *pixdest++ = (negalpha * intensity + alpha * g) >> 8; + *pixdest++ = (negalpha * intensity + alpha * b) >> 8; + if (has_alpha) + { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} + +/* this routine colorizes the passed-in pixbuf by multiplying each pixel with the passed in color */ + +GdkPixbuf * +eel_create_colorized_pixbuf (GdkPixbuf *src, + int red_value, + int green_value, + int blue_value) +{ + int i, j; + int width, height, has_alpha, src_row_stride, dst_row_stride; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + GdkPixbuf *dest; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest = create_new_pixbuf (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + src_row_stride = gdk_pixbuf_get_rowstride (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i*dst_row_stride; + pixsrc = original_pixels + i*src_row_stride; + for (j = 0; j < width; j++) + { + *pixdest++ = (*pixsrc++ * red_value) >> 8; + *pixdest++ = (*pixsrc++ * green_value) >> 8; + *pixdest++ = (*pixsrc++ * blue_value) >> 8; + if (has_alpha) + { + *pixdest++ = *pixsrc++; + } + } + } + return dest; +} + +/* utility to stretch a frame to the desired size */ + +static void +draw_frame_row (GdkPixbuf *frame_image, int target_width, int source_width, int source_v_position, int dest_v_position, GdkPixbuf *result_pixbuf, int left_offset, int height) +{ + int remaining_width, h_offset, slab_width; + + remaining_width = target_width; + h_offset = 0; + while (remaining_width > 0) + { + slab_width = remaining_width > source_width ? source_width : remaining_width; + gdk_pixbuf_copy_area (frame_image, left_offset, source_v_position, slab_width, height, result_pixbuf, left_offset + h_offset, dest_v_position); + remaining_width -= slab_width; + h_offset += slab_width; + } +} + +/* utility to draw the middle section of the frame in a loop */ +static void +draw_frame_column (GdkPixbuf *frame_image, int target_height, int source_height, int source_h_position, int dest_h_position, GdkPixbuf *result_pixbuf, int top_offset, int width) +{ + int remaining_height, v_offset, slab_height; + + remaining_height = target_height; + v_offset = 0; + while (remaining_height > 0) + { + slab_height = remaining_height > source_height ? source_height : remaining_height; + gdk_pixbuf_copy_area (frame_image, source_h_position, top_offset, width, slab_height, result_pixbuf, dest_h_position, top_offset + v_offset); + remaining_height -= slab_height; + v_offset += slab_height; + } +} + +GdkPixbuf * +eel_stretch_frame_image (GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset, + int dest_width, int dest_height, gboolean fill_flag) +{ + GdkPixbuf *result_pixbuf; + guchar *pixels_ptr; + int frame_width, frame_height; + int y, row_stride; + int target_width, target_frame_width; + int target_height, target_frame_height; + + frame_width = gdk_pixbuf_get_width (frame_image); + frame_height = gdk_pixbuf_get_height (frame_image ); + + if (fill_flag) + { + result_pixbuf = gdk_pixbuf_scale_simple (frame_image, dest_width, dest_height, GDK_INTERP_NEAREST); + } + else + { + result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height); + } + row_stride = gdk_pixbuf_get_rowstride (result_pixbuf); + pixels_ptr = gdk_pixbuf_get_pixels (result_pixbuf); + + /* clear the new pixbuf */ + if (!fill_flag) + { + for (y = 0; y < dest_height; y++) + { + memset (pixels_ptr, 255, row_stride); + pixels_ptr += row_stride; + } + } + + target_width = dest_width - left_offset - right_offset; + target_frame_width = frame_width - left_offset - right_offset; + + target_height = dest_height - top_offset - bottom_offset; + target_frame_height = frame_height - top_offset - bottom_offset; + + /* draw the left top corner and top row */ + gdk_pixbuf_copy_area (frame_image, 0, 0, left_offset, top_offset, result_pixbuf, 0, 0); + draw_frame_row (frame_image, target_width, target_frame_width, 0, 0, result_pixbuf, left_offset, top_offset); + + /* draw the right top corner and left column */ + gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, 0, right_offset, top_offset, result_pixbuf, dest_width - right_offset, 0); + draw_frame_column (frame_image, target_height, target_frame_height, 0, 0, result_pixbuf, top_offset, left_offset); + + /* draw the bottom right corner and bottom row */ + gdk_pixbuf_copy_area (frame_image, frame_width - right_offset, frame_height - bottom_offset, right_offset, bottom_offset, result_pixbuf, dest_width - right_offset, dest_height - bottom_offset); + draw_frame_row (frame_image, target_width, target_frame_width, frame_height - bottom_offset, dest_height - bottom_offset, result_pixbuf, left_offset, bottom_offset); + + /* draw the bottom left corner and the right column */ + gdk_pixbuf_copy_area (frame_image, 0, frame_height - bottom_offset, left_offset, bottom_offset, result_pixbuf, 0, dest_height - bottom_offset); + draw_frame_column (frame_image, target_height, target_frame_height, frame_width - right_offset, dest_width - right_offset, result_pixbuf, top_offset, right_offset); + + return result_pixbuf; +} + + +/* draw an arbitrary frame around an image, with the result passed back in a newly allocated pixbuf */ +GdkPixbuf * +eel_embed_image_in_frame (GdkPixbuf *source_image, GdkPixbuf *frame_image, int left_offset, int top_offset, int right_offset, int bottom_offset) +{ + GdkPixbuf *result_pixbuf; + int source_width, source_height; + int dest_width, dest_height; + + source_width = gdk_pixbuf_get_width (source_image); + source_height = gdk_pixbuf_get_height (source_image); + + dest_width = source_width + left_offset + right_offset; + dest_height = source_height + top_offset + bottom_offset; + + result_pixbuf = eel_stretch_frame_image (frame_image, left_offset, top_offset, right_offset, bottom_offset, + dest_width, dest_height, FALSE); + + /* Finally, copy the source image into the framed area */ + gdk_pixbuf_copy_area (source_image, 0, 0, source_width, source_height, result_pixbuf, left_offset, top_offset); + + return result_pixbuf; +} + + +/* this routine takes the source pixbuf and returns a new one that's semi-transparent, by + clearing every other pixel's alpha value in a checkerboard grip. We have to do the + checkerboard instead of reducing the alpha since it will be turned into an alpha-less + gdkpixmap and mask for the actual dragging */ + +GdkPixbuf * +eel_make_semi_transparent (GdkPixbuf *src) +{ + gint i, j, temp_alpha; + gint width, height, has_alpha, src_row_stride, dst_row_stride; + guchar *target_pixels, *original_pixels; + guchar *pixsrc, *pixdest; + guchar alpha_value; + GdkPixbuf *dest_pixbuf; + guchar start_alpha_value; + + g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL); + g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 3) + || (gdk_pixbuf_get_has_alpha (src) + && gdk_pixbuf_get_n_channels (src) == 4), NULL); + g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL); + + dest_pixbuf = create_new_pixbuf_with_alpha (src); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + src_row_stride = gdk_pixbuf_get_rowstride (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest_pixbuf); + + /* set up pointers to the actual pixels */ + target_pixels = gdk_pixbuf_get_pixels (dest_pixbuf); + original_pixels = gdk_pixbuf_get_pixels (src); + + /* loop through the pixels to do the actual work, copying from the source to the destination */ + start_alpha_value = ~0; + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i * dst_row_stride; + pixsrc = original_pixels + i * src_row_stride; + alpha_value = start_alpha_value; + for (j = 0; j < width; j++) + { + *pixdest++ = *pixsrc++; /* red */ + *pixdest++ = *pixsrc++; /* green */ + *pixdest++ = *pixsrc++; /* blue */ + + if (has_alpha) + { + temp_alpha = *pixsrc++; + } + else + { + temp_alpha = ~0; + } + *pixdest++ = temp_alpha & alpha_value; + + alpha_value = ~alpha_value; + } + + start_alpha_value = ~start_alpha_value; + } + + return dest_pixbuf; +} + diff --git a/eel/eel-graphic-effects.h b/eel/eel-graphic-effects.h new file mode 100644 index 00000000..5f174c83 --- /dev/null +++ b/eel/eel-graphic-effects.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-graphic-effects.h: Pixmap manipulation routines for graphical effects. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Andy Hertzfeld <[email protected]> + */ + +#ifndef EEL_GRAPHIC_EFFECTS_H +#define EEL_GRAPHIC_EFFECTS_H + +#include <gdk-pixbuf/gdk-pixbuf.h> + +/* return a lightened pixbuf for pre-lighting */ +GdkPixbuf *eel_create_spotlight_pixbuf (GdkPixbuf *source_pixbuf); + +/* return a darkened pixbuf for selection hiliting */ +GdkPixbuf *eel_create_darkened_pixbuf (GdkPixbuf *source_pixbuf, + int saturation, + int darken); + +/* return a pixbuf colorized with the color specified by the parameters */ +GdkPixbuf* eel_create_colorized_pixbuf (GdkPixbuf *source_pixbuf, + int red_value, + int green_value, + int blue_value); + +/* stretch a image frame */ +GdkPixbuf *eel_stretch_frame_image (GdkPixbuf *frame_image, + int left_offset, + int top_offset, + int right_offset, + int bottom_offset, + int dest_width, + int dest_height, + gboolean fill_flag); + +/* embed in image in a frame */ +GdkPixbuf *eel_embed_image_in_frame (GdkPixbuf *source_image, + GdkPixbuf *frame_image, + int left_offset, + int top_offset, + int right_offset, + int bottom_offset); + +/* return a semi-transparent pixbuf from the source pixbuf using a checkboard + stipple in the alpha channel (so it can be converted to an alpha-less pixmap) */ +GdkPixbuf *eel_make_semi_transparent (GdkPixbuf *source_pixbuf); + +#endif /* EEL_GRAPHIC_EFFECTS_H */ diff --git a/eel/eel-gtk-container.c b/eel/eel-gtk-container.c new file mode 100644 index 00000000..033579c5 --- /dev/null +++ b/eel/eel-gtk-container.c @@ -0,0 +1,225 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gtk-container.c - Functions to simplify the implementations of + GtkContainer widgets. + + Copyright (C) 2001 Ramiro Estrugo. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-gtk-container.h" +#include "eel-art-extensions.h" + +/** + * eel_gtk_container_child_expose_event: + * + * @container: A GtkContainer widget. + * @child: A child of @container or NULL; + * @event: The expose event. + * + * Forward an expose event to a child if needed. It is valid to give a NULL @child. + * In that case this function is a noop. Proper clipping is done to ensure that the @child + * does indeed need to be forwarded the exposure event. Finally, the forwarding + * only occurs if the child is a NO_WINDOW widget. Of course, it is valid to feed + * non NO_WINDOW widgets to this function, in which case this function is a noop. + */ +void +eel_gtk_container_child_expose_event (GtkContainer *container, + GtkWidget *child, + GdkEventExpose *event) +{ + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (child == NULL) + { + return; + } + + g_return_if_fail (GTK_IS_WIDGET (child)); + + gtk_container_propagate_expose (container, child, event); +} + +/** + * eel_gtk_container_child_map: + * + * @container: A GtkContainer widget. + * @child: A child of @container or NULL; + * + * Map a child if needed. This is usually called from the "GtkWidget::map" + * method of the @container widget. If @child is NULL, then this function is a noop. + */ +void +eel_gtk_container_child_map (GtkContainer *container, + GtkWidget *child) +{ + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (child == NULL) + { + return; + } + + g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (container)); + + if (gtk_widget_get_visible (child) && !gtk_widget_get_mapped (child)) + { + gtk_widget_map (child); + } +} + +/** + * eel_gtk_container_child_unmap: + * + * @container: A GtkContainer widget. + * @child: A child of @container or NULL; + * + * Unmap a child if needed. This is usually called from the "GtkWidget::unmap" + * method of the @container widget. If @child is NULL, then this function is a noop. + */ +void +eel_gtk_container_child_unmap (GtkContainer *container, + GtkWidget *child) +{ + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (child == NULL) + { + return; + } + + g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (container)); + + if (gtk_widget_get_visible (child) && gtk_widget_get_mapped (child)) + { + gtk_widget_unmap (child); + } +} + +/** + * eel_gtk_container_child_add: + * + * @container: A GtkContainer widget. + * @child: A non NULL unparented child. + * + * Add a @child to a @container. The @child is realized, mapped + * and resized if needed. This is usually called from the "GtkContainer::add" + * method of the @container. The @child cannot be NULL. + */ +void +eel_gtk_container_child_add (GtkContainer *container, + GtkWidget *child) +{ + GtkWidget *widget; + + g_return_if_fail (GTK_IS_CONTAINER (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + widget = GTK_WIDGET (container); + + gtk_widget_set_parent (child, widget); + + if (gtk_widget_get_realized (widget)) + { + gtk_widget_realize (child); + } + + if (gtk_widget_get_mapped (widget) + && gtk_widget_get_visible (child)) + { + if (gtk_widget_get_mapped (widget)) + { + gtk_widget_map (child); + } + + gtk_widget_queue_resize (child); + } +} + +/** + * eel_gtk_container_child_remove: + * + * @container: A GtkContainer widget. + * @child: A non NULL child of @container. + * + * Remove @child from @container. The @container is resized if needed. + * This is usually called from the "GtkContainer::remove" method of the + * @container. The child cannot be NULL. + */ +void +eel_gtk_container_child_remove (GtkContainer *container, + GtkWidget *child) +{ + gboolean child_was_visible; + + g_return_if_fail (GTK_IS_CONTAINER (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (container)); + + child_was_visible = gtk_widget_get_visible (child); + + gtk_widget_unparent (child); + + if (child_was_visible) + { + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +/** + * eel_gtk_container_child_size_allocate: + * + * @container: A GtkContainer widget. + * @child: A child of @container or NULL; + * + * Invoke the "GtkWidget::size_allocate" method of @child. + * This function is usually called from the "GtkWidget::size_allocate" + * method of @container. The child can be NULL, in which case this + * function is a noop. + */ +void +eel_gtk_container_child_size_allocate (GtkContainer *container, + GtkWidget *child, + EelIRect child_geometry) +{ + GtkAllocation child_allocation; + + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (child == NULL) + { + return; + } + + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (container)); + + if (eel_irect_is_empty (&child_geometry)) + { + return; + } + + child_allocation.x = child_geometry.x0; + child_allocation.y = child_geometry.y0; + child_allocation.width = eel_irect_get_width (child_geometry); + child_allocation.height = eel_irect_get_height (child_geometry); + + gtk_widget_size_allocate (child, &child_allocation); +} diff --git a/eel/eel-gtk-container.h b/eel/eel-gtk-container.h new file mode 100644 index 00000000..6b2dd0fa --- /dev/null +++ b/eel/eel-gtk-container.h @@ -0,0 +1,47 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gtk-container.h - Functions to simplify the implementations of + GtkContainer widgets. + + Copyright (C) 2001 Ramiro Estrugo. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_GTK_CONTAINER_H +#define EEL_GTK_CONTAINER_H + +#include <gtk/gtk.h> +#include <eel/eel-art-extensions.h> + +void eel_gtk_container_child_expose_event (GtkContainer *container, + GtkWidget *child, + GdkEventExpose *event); +void eel_gtk_container_child_map (GtkContainer *container, + GtkWidget *child); +void eel_gtk_container_child_unmap (GtkContainer *container, + GtkWidget *child); +void eel_gtk_container_child_add (GtkContainer *container, + GtkWidget *child); +void eel_gtk_container_child_remove (GtkContainer *container, + GtkWidget *child); +void eel_gtk_container_child_size_allocate (GtkContainer *container, + GtkWidget *child, + EelIRect child_geometry); + +#endif /* EEL_GTK_CONTAINER_H */ diff --git a/eel/eel-gtk-extensions.c b/eel/eel-gtk-extensions.c new file mode 100644 index 00000000..da78a532 --- /dev/null +++ b/eel/eel-gtk-extensions.c @@ -0,0 +1,1247 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gtk-extensions.c - implementation of new functions that operate on + gtk classes. Perhaps some of these should be + rolled into gtk someday. + + Copyright (C) 1999, 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: John Sullivan <[email protected]> + Ramiro Estrugo <[email protected]> + Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-gtk-extensions.h" + +#include "eel-gdk-pixbuf-extensions.h" +#include "eel-glib-extensions.h" +#include "eel-mate-extensions.h" +#include "eel-pango-extensions.h" +#include "eel-string.h" +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <gdk/gdk.h> +#include <gdk/gdkprivate.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include <math.h> +#include "eel-marshal.h" +#include "eel-marshal.c" + +/* This number is fairly arbitrary. Long enough to show a pretty long + * menu title, but not so long to make a menu grotesquely wide. + */ +#define MAXIMUM_MENU_TITLE_LENGTH 48 + +/* Used for window position & size sanity-checking. The sizes are big enough to prevent + * at least normal-sized mate panels from obscuring the window at the screen edges. + */ +#define MINIMUM_ON_SCREEN_WIDTH 100 +#define MINIMUM_ON_SCREEN_HEIGHT 100 + + +/** + * eel_gtk_window_get_geometry_string: + * @window: a #GtkWindow + * + * Obtains the geometry string for this window, suitable for + * set_geometry_string(); assumes the window has NorthWest gravity + * + * Return value: geometry string, must be freed + **/ +char* +eel_gtk_window_get_geometry_string (GtkWindow *window) +{ + char *str; + int w, h, x, y; + + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + g_return_val_if_fail (gtk_window_get_gravity (window) == + GDK_GRAVITY_NORTH_WEST, NULL); + + gtk_window_get_position (window, &x, &y); + gtk_window_get_size (window, &w, &h); + + str = g_strdup_printf ("%dx%d+%d+%d", w, h, x, y); + + return str; +} + +static void +send_delete_event (GtkWindow *window) +{ + /* Synthesize delete_event to close window. */ + + GdkEvent event; + GtkWidget *widget; + + widget = GTK_WIDGET (window); + + event.any.type = GDK_DELETE; + event.any.window = gtk_widget_get_window (widget); + event.any.send_event = TRUE; + + g_object_ref (event.any.window); + gtk_main_do_event (&event); + g_object_unref (event.any.window); +} + +static int +handle_standard_close_accelerator (GtkWindow *window, + GdkEventKey *event, + gpointer user_data) +{ + g_assert (GTK_IS_WINDOW (window)); + g_assert (event != NULL); + g_assert (user_data == NULL); + + if (eel_gtk_window_event_is_close_accelerator (window, event)) + { + send_delete_event (window); + g_signal_stop_emission_by_name ( + G_OBJECT (window), "key_press_event"); + return TRUE; + } + + return FALSE; +} + +/** + * eel_gtk_window_event_is_close_accelerator: + * + * Tests whether a key event is a standard window close accelerator. + * Not needed for clients that use eel_gtk_window_set_up_close_accelerator; + * use only if you must set up your own key_event handler for your own reasons. + **/ +gboolean +eel_gtk_window_event_is_close_accelerator (GtkWindow *window, GdkEventKey *event) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->state & GDK_CONTROL_MASK) + { + /* Note: menu item equivalents are case-sensitive, so we will + * be case-sensitive here too. + */ + if (event->keyval == EEL_STANDARD_CLOSE_WINDOW_CONTROL_KEY) + { + return TRUE; + } + } + + + return FALSE; +} + +/** + * eel_gtk_window_set_up_close_accelerator: + * + * Sets up the standard keyboard equivalent to close the window. + * Call this for windows that don't set up a keyboard equivalent to + * close the window some other way, e.g. via a menu item accelerator. + * + * NOTE: do not use for GtkDialog, it already sets up the right + * stuff here. + * + * @window: The GtkWindow that should be hidden when the standard + * keyboard equivalent is typed. + **/ +void +eel_gtk_window_set_up_close_accelerator (GtkWindow *window) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (GTK_IS_DIALOG (window)) + { + g_warning ("eel_gtk_window_set_up_close_accelerator: Should not mess with close accelerator on GtkDialogs"); + return; + } + + g_signal_connect (window, + "key_press_event", + G_CALLBACK (handle_standard_close_accelerator), + NULL); +} + +static void +sanity_check_window_position (int *left, int *top) +{ + g_assert (left != NULL); + g_assert (top != NULL); + + /* Make sure the top of the window is on screen, for + * draggability (might not be necessary with all window managers, + * but seems reasonable anyway). Make sure the top of the window + * isn't off the bottom of the screen, or so close to the bottom + * that it might be obscured by the panel. + */ + *top = CLAMP (*top, 0, gdk_screen_height() - MINIMUM_ON_SCREEN_HEIGHT); + + /* FIXME bugzilla.eazel.com 669: + * If window has negative left coordinate, set_uposition sends it + * somewhere else entirely. Not sure what level contains this bug (XWindows?). + * Hacked around by pinning the left edge to zero, which just means you + * can't set a window to be partly off the left of the screen using + * this routine. + */ + /* Make sure the left edge of the window isn't off the right edge of + * the screen, or so close to the right edge that it might be + * obscured by the panel. + */ + *left = CLAMP (*left, 0, gdk_screen_width() - MINIMUM_ON_SCREEN_WIDTH); +} + +static void +sanity_check_window_dimensions (guint *width, guint *height) +{ + g_assert (width != NULL); + g_assert (height != NULL); + + /* Pin the size of the window to the screen, so we don't end up in + * a state where the window is so big essential parts of it can't + * be reached (might not be necessary with all window managers, + * but seems reasonable anyway). + */ + *width = MIN (*width, gdk_screen_width()); + *height = MIN (*height, gdk_screen_height()); +} + +/** + * eel_gtk_window_set_initial_geometry: + * + * Sets the position and size of a GtkWindow before the + * GtkWindow is shown. It is an error to call this on a window that + * is already on-screen. Takes into account screen size, and does + * some sanity-checking on the passed-in values. + * + * @window: A non-visible GtkWindow + * @geometry_flags: A EelGdkGeometryFlags value defining which of + * the following parameters have defined values + * @left: pixel coordinate for left of window + * @top: pixel coordinate for top of window + * @width: width of window in pixels + * @height: height of window in pixels + */ +void +eel_gtk_window_set_initial_geometry (GtkWindow *window, + EelGdkGeometryFlags geometry_flags, + int left, + int top, + guint width, + guint height) +{ + GdkScreen *screen; + int real_left, real_top; + int screen_width, screen_height; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + /* Setting the default size doesn't work when the window is already showing. + * Someday we could make this move an already-showing window, but we don't + * need that functionality yet. + */ + g_return_if_fail (!gtk_widget_get_visible (GTK_WIDGET (window))); + + if ((geometry_flags & EEL_GDK_X_VALUE) && (geometry_flags & EEL_GDK_Y_VALUE)) + { + real_left = left; + real_top = top; + + screen = gtk_window_get_screen (window); + screen_width = gdk_screen_get_width (screen); + screen_height = gdk_screen_get_height (screen); + + /* This is sub-optimal. GDK doesn't allow us to set win_gravity + * to South/East types, which should be done if using negative + * positions (so that the right or bottom edge of the window + * appears at the specified position, not the left or top). + * However it does seem to be consistent with other MATE apps. + */ + if (geometry_flags & EEL_GDK_X_NEGATIVE) + { + real_left = screen_width - real_left; + } + if (geometry_flags & EEL_GDK_Y_NEGATIVE) + { + real_top = screen_height - real_top; + } + + sanity_check_window_position (&real_left, &real_top); + gtk_window_move (window, real_left, real_top); + } + + if ((geometry_flags & EEL_GDK_WIDTH_VALUE) && (geometry_flags & EEL_GDK_HEIGHT_VALUE)) + { + sanity_check_window_dimensions (&width, &height); + gtk_window_set_default_size (GTK_WINDOW (window), (int)width, (int)height); + } +} + +/** + * eel_gtk_window_set_initial_geometry_from_string: + * + * Sets the position and size of a GtkWindow before the + * GtkWindow is shown. The geometry is passed in as a string. + * It is an error to call this on a window that + * is already on-screen. Takes into account screen size, and does + * some sanity-checking on the passed-in values. + * + * @window: A non-visible GtkWindow + * @geometry_string: A string suitable for use with eel_gdk_parse_geometry + * @minimum_width: If the width from the string is smaller than this, + * use this for the width. + * @minimum_height: If the height from the string is smaller than this, + * use this for the height. + * @ignore_position: If true position data from string will be ignored. + */ +void +eel_gtk_window_set_initial_geometry_from_string (GtkWindow *window, + const char *geometry_string, + guint minimum_width, + guint minimum_height, + gboolean ignore_position) +{ + int left, top; + guint width, height; + EelGdkGeometryFlags geometry_flags; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (geometry_string != NULL); + + /* Setting the default size doesn't work when the window is already showing. + * Someday we could make this move an already-showing window, but we don't + * need that functionality yet. + */ + g_return_if_fail (!gtk_widget_get_visible (GTK_WIDGET (window))); + + geometry_flags = eel_gdk_parse_geometry (geometry_string, &left, &top, &width, &height); + + /* Make sure the window isn't smaller than makes sense for this window. + * Other sanity checks are performed in set_initial_geometry. + */ + if (geometry_flags & EEL_GDK_WIDTH_VALUE) + { + width = MAX (width, minimum_width); + } + if (geometry_flags & EEL_GDK_HEIGHT_VALUE) + { + height = MAX (height, minimum_height); + } + + /* Ignore saved window position if requested. */ + if (ignore_position) + { + geometry_flags &= ~(EEL_GDK_X_VALUE | EEL_GDK_Y_VALUE); + } + + eel_gtk_window_set_initial_geometry (window, geometry_flags, left, top, width, height); +} + +/** + * eel_pop_up_context_menu: + * + * Pop up a context menu under the mouse. + * The menu is sunk after use, so it will be destroyed unless the + * caller first ref'ed it. + * + * This function is more of a helper function than a gtk extension, + * so perhaps it belongs in a different file. + * + * @menu: The menu to pop up under the mouse. + * @offset_x: Number of pixels to displace the popup menu vertically + * @offset_y: Number of pixels to displace the popup menu horizontally + * @event: The event that invoked this popup menu. + **/ +void +eel_pop_up_context_menu (GtkMenu *menu, + gint16 offset_x, + gint16 offset_y, + GdkEventButton *event) +{ + GdkPoint offset; + int button; + + g_return_if_fail (GTK_IS_MENU (menu)); + + offset.x = offset_x; + offset.y = offset_y; + + /* The event button needs to be 0 if we're popping up this menu from + * a button release, else a 2nd click outside the menu with any button + * other than the one that invoked the menu will be ignored (instead + * of dismissing the menu). This is a subtle fragility of the GTK menu code. + */ + + if (event) + { + button = event->type == GDK_BUTTON_RELEASE + ? 0 + : event->button; + } + else + { + button = 0; + } + + gtk_menu_popup (menu, /* menu */ + NULL, /* parent_menu_shell */ + NULL, /* parent_menu_item */ + NULL, + &offset, /* data */ + button, /* button */ + event ? event->time : GDK_CURRENT_TIME); /* activate_time */ + + g_object_ref_sink (menu); + g_object_unref (menu); +} + +GtkMenuItem * +eel_gtk_menu_append_separator (GtkMenu *menu) +{ + return eel_gtk_menu_insert_separator (menu, -1); +} + +GtkMenuItem * +eel_gtk_menu_insert_separator (GtkMenu *menu, int index) +{ + GtkWidget *menu_item; + + menu_item = gtk_separator_menu_item_new (); + gtk_widget_show (menu_item); + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menu_item, index); + + return GTK_MENU_ITEM (menu_item); +} + +void +eel_gtk_menu_set_item_visibility (GtkMenu *menu, int index, gboolean visible) +{ + GList *children; + GtkWidget *menu_item; + + g_return_if_fail (GTK_IS_MENU (menu)); + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + g_return_if_fail (index >= 0 && index < (int) g_list_length (children)); + + menu_item = GTK_WIDGET (g_list_nth_data (children, index)); + if (visible) + { + gtk_widget_show (menu_item); + } + else + { + gtk_widget_hide (menu_item); + } + + g_list_free (children); +} + +GtkWidget * +eel_gtk_menu_tool_button_get_button (GtkMenuToolButton *tool_button) +{ + GtkContainer *container; + GList *children; + GtkWidget *button; + + g_return_val_if_fail (GTK_IS_MENU_TOOL_BUTTON (tool_button), NULL); + + /* The menu tool button's button is the first child + * of the child hbox. */ + container = GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (tool_button))); + children = gtk_container_get_children (container); + button = GTK_WIDGET (children->data); + + g_list_free (children); + + return button; +} + +gboolean +eel_point_in_allocation (const GtkAllocation *allocation, + int x, int y) +{ + g_return_val_if_fail (allocation != NULL, FALSE); + return x >= allocation->x + && y >= allocation->y + && x < allocation->x + allocation->width + && y < allocation->y + allocation->height; +} + +/* FIXME this function is dangerous, because gtk_widget_get_window (widget) coords (or + * other window-belonging-to-widget coords) do not need to be in the + * same coordinate system as widget->allocation. + * If you use this function, be aware of that. Someone should probably + * audit all uses, too. + */ +gboolean +eel_point_in_widget (GtkWidget *widget, + int x, int y) +{ + GtkAllocation allocation; + if (widget == NULL) + { + return FALSE; + } + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + gtk_widget_get_allocation (widget, &allocation); + return eel_point_in_allocation (&allocation, x, y); +} + +/** + * eel_gtk_widget_set_shown + * + * Show or hide a widget. + * @widget: The widget. + * @shown: Boolean value indicating whether the widget should be shown or hidden. + **/ +void +eel_gtk_widget_set_shown (GtkWidget *widget, gboolean shown) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (shown) + { + gtk_widget_show (widget); + } + else + { + gtk_widget_hide (widget); + } +} + +/* This stuff is stolen from Gtk. */ + +typedef struct DisconnectInfo +{ + GtkObject *object1; + guint disconnect_handler1; + guint signal_handler; + GtkObject *object2; + guint disconnect_handler2; +} DisconnectInfo; + +static void +alive_disconnecter (GtkObject *object, DisconnectInfo *info) +{ + g_assert (info != NULL); + g_assert (GTK_IS_OBJECT (info->object1)); + g_assert (info->disconnect_handler1 != 0); + g_assert (info->signal_handler != 0); + g_assert (GTK_IS_OBJECT (info->object2)); + g_assert (info->disconnect_handler2 != 0); + g_assert (object == info->object1 || object == info->object2); + + g_signal_handler_disconnect (info->object1, info->disconnect_handler1); + g_signal_handler_disconnect (info->object1, info->signal_handler); + g_signal_handler_disconnect (info->object2, info->disconnect_handler2); + + g_free (info); +} + +/** + * eel_gtk_signal_connect_full_while_alive + * + * Like gtk_signal_connect_while_alive, but works with full parameters. + **/ +void +eel_gtk_signal_connect_full_while_alive (GtkObject *object, + const gchar *name, + GCallback func, + GtkCallbackMarshal marshal, + gpointer data, + GDestroyNotify destroy_func, + gboolean object_signal, + gboolean after, + GtkObject *alive_object) +{ + DisconnectInfo *info; + + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (name != NULL); + g_return_if_fail (func != NULL || marshal != NULL); + g_return_if_fail (object_signal == FALSE || object_signal == TRUE); + g_return_if_fail (after == FALSE || after == TRUE); + g_return_if_fail (GTK_IS_OBJECT (alive_object)); + + info = g_new (DisconnectInfo, 1); + info->object1 = object; + info->object2 = alive_object; + + + info->signal_handler = g_signal_connect_closure ( + object, name, + (object_signal + ? g_cclosure_new_swap + : g_cclosure_new) (func, data, (GClosureNotify) destroy_func), + after); + + info->disconnect_handler1 = g_signal_connect (G_OBJECT (object), + "destroy", + G_CALLBACK (alive_disconnecter), + info); + info->disconnect_handler2 = g_signal_connect (G_OBJECT (alive_object), + "destroy", + G_CALLBACK (alive_disconnecter), + info); +} + +typedef struct +{ + GtkObject *object; + guint object_destroy_handler; + + GtkWidget *realized_widget; + guint realized_widget_destroy_handler; + guint realized_widget_unrealized_handler; + + guint signal_handler; +} RealizeDisconnectInfo; + +static void +while_realized_disconnecter (GtkObject *object, + RealizeDisconnectInfo *info) +{ + g_assert (GTK_IS_OBJECT (object)); + g_assert (info != NULL); + g_assert (GTK_IS_OBJECT (info->object)); + g_assert (info->object_destroy_handler != 0); + g_assert (info->object_destroy_handler != 0); + g_assert (info->realized_widget_destroy_handler != 0); + g_assert (info->realized_widget_unrealized_handler != 0); + + g_signal_handler_disconnect (info->object, info->object_destroy_handler); + g_signal_handler_disconnect (info->object, info->signal_handler); + g_signal_handler_disconnect (info->realized_widget, info->realized_widget_destroy_handler); + g_signal_handler_disconnect (info->realized_widget, info->realized_widget_unrealized_handler); + g_free (info); +} + +/** + * eel_gtk_signal_connect_while_realized: + * + * @object: Object to connect to. + * @name: Name of signal to connect to. + * @callback: Caller's callback. + * @callback_data: Caller's callback_data. + * @realized_widget: Widget to monitor for realized state. Signal is connected + * while this wigget is realized. + * + * Connect to a signal of an object while another widget is realized. This is + * useful for non windowed widgets that need to monitor events in their ancestored + * windowed widget. The signal is automatically disconnected when &widget is + * unrealized. Also, the signal is automatically disconnected when either &object + * or &widget are destroyed. + **/ +void +eel_gtk_signal_connect_while_realized (GtkObject *object, + const char *name, + GCallback callback, + gpointer callback_data, + GtkWidget *realized_widget) +{ + RealizeDisconnectInfo *info; + + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (name != NULL); + g_return_if_fail (name[0] != '\0'); + g_return_if_fail (callback != NULL); + g_return_if_fail (GTK_IS_WIDGET (realized_widget)); + g_return_if_fail (gtk_widget_get_realized (realized_widget)); + + info = g_new0 (RealizeDisconnectInfo, 1); + + info->object = object; + info->object_destroy_handler = + g_signal_connect (G_OBJECT (info->object), + "destroy", + G_CALLBACK (while_realized_disconnecter), + info); + + info->realized_widget = realized_widget; + info->realized_widget_destroy_handler = + g_signal_connect (G_OBJECT (info->realized_widget), + "destroy", + G_CALLBACK (while_realized_disconnecter), + info); + info->realized_widget_unrealized_handler = + g_signal_connect_after (G_OBJECT (info->realized_widget), + "unrealize", + G_CALLBACK (while_realized_disconnecter), + info); + + info->signal_handler = g_signal_connect (G_OBJECT (info->object), + name, callback, callback_data); +} + +/** + * eel_gtk_container_get_first_child. + * + * Returns the first child of a container. + * @container: The container. + **/ + +static void +get_first_callback (GtkWidget *widget, gpointer callback_data) +{ + GtkWidget **first_child_slot; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (callback_data != NULL); + + first_child_slot = callback_data; + + if (*first_child_slot == NULL) + { + *first_child_slot = widget; + /* We'd stop the iterating now if we could. */ + } + else + { + g_assert (GTK_IS_WIDGET (*first_child_slot)); + } +} + +GtkWidget * +eel_gtk_container_get_first_child (GtkContainer *container) +{ + GtkWidget *first_child; + + g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL); + + first_child = NULL; + gtk_container_foreach (container, get_first_callback, &first_child); + g_assert (first_child == NULL || GTK_IS_WIDGET (first_child)); + return first_child; +} + +typedef struct +{ + GtkCallback callback; + gpointer callback_data; +} container_foreach_deep_callback_data; + +static void +container_foreach_deep_callback (GtkWidget *child, gpointer data) +{ + container_foreach_deep_callback_data *deep_data; + + deep_data = (container_foreach_deep_callback_data *) data; + + deep_data->callback (child, deep_data->callback_data); + + if (GTK_IS_CONTAINER (child)) + { + gtk_container_foreach (GTK_CONTAINER (child), container_foreach_deep_callback, data); + } +} + +void +eel_gtk_container_foreach_deep (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + container_foreach_deep_callback_data deep_data; + deep_data.callback = callback; + deep_data.callback_data = callback_data; + gtk_container_foreach (container, container_foreach_deep_callback, &deep_data); +} + +/* The standard gtk_adjustment_set_value ignores page size, which + * disagrees with the logic used by scroll bars, for example. + */ +void +eel_gtk_adjustment_set_value (GtkAdjustment *adjustment, + float value) +{ + float upper_page_start, clamped_value; + + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + + upper_page_start = MAX (gtk_adjustment_get_upper (adjustment) - + gtk_adjustment_get_page_size (adjustment), + gtk_adjustment_get_lower (adjustment)); + clamped_value = CLAMP (value, gtk_adjustment_get_lower (adjustment), upper_page_start); + if (clamped_value != gtk_adjustment_get_value (adjustment)) + { + gtk_adjustment_set_value (adjustment, clamped_value); + gtk_adjustment_value_changed (adjustment); + } +} + +/* Clamp a value if the minimum or maximum has changed. */ +void +eel_gtk_adjustment_clamp_value (GtkAdjustment *adjustment) +{ + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + + eel_gtk_adjustment_set_value (adjustment, + gtk_adjustment_get_value (adjustment)); +} + +/** + * eel_gtk_label_make_bold. + * + * Switches the font of label to a bold equivalent. + * @label: The label. + **/ +void +eel_gtk_label_make_bold (GtkLabel *label) +{ + PangoFontDescription *font_desc; + + font_desc = pango_font_description_new (); + + pango_font_description_set_weight (font_desc, + PANGO_WEIGHT_BOLD); + + /* This will only affect the weight of the font, the rest is + * from the current state of the widget, which comes from the + * theme or user prefs, since the font desc only has the + * weight flag turned on. + */ + gtk_widget_modify_font (GTK_WIDGET (label), font_desc); + + pango_font_description_free (font_desc); +} + +/** + * eel_gtk_label_set_scale: + * @label: + * @num_steps: + * + * Function is broken, see eel_gtk_label_make_larger() for explanation + * + **/ +void +eel_gtk_label_set_scale (GtkLabel *label, + double scale_factor) +{ + PangoAttrList *old_attr_list; + PangoAttrList *attr_list; + + g_return_if_fail (GTK_IS_LABEL (label)); + g_return_if_fail (scale_factor > 0); + + old_attr_list = gtk_label_get_attributes (label); + attr_list = eel_pango_attr_list_apply_global_attribute (old_attr_list, + pango_attr_scale_new (scale_factor)); + gtk_label_set_attributes (label, attr_list); + pango_attr_list_unref (attr_list); +} + +static void +get_layout_location (GtkLabel *label, + gint *xp, + gint *yp) +{ + GtkMisc *misc; + GtkWidget *widget; + float xalign, yalign; + int x, y, xpad, ypad; + int shadow_offset; + GtkAllocation allocation; + GtkRequisition req; + + shadow_offset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), + "eel-label-shadow-offset")); + + misc = GTK_MISC (label); + widget = GTK_WIDGET (label); + gtk_misc_get_alignment (misc, &xalign, &yalign); + gtk_misc_get_padding (misc, &xpad, &ypad); + + if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) + xalign = 1.0 - xalign; + + gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_requisition (widget, &req); + x = floor (allocation.x + xpad + + ((allocation.width - req.width - shadow_offset) * xalign) + + 0.5); + + y = floor (allocation.y + ypad + + ((allocation.height - req.height - shadow_offset) * yalign) + + 0.5); + + + if (xp) + *xp = x; + + if (yp) + *yp = y; +} + +static gboolean +eel_gtk_label_expose_event (GtkLabel *label, GdkEventExpose *event, gpointer user_data) +{ + int x, y; + GdkColor color; + GtkWidget *widget; + GdkGC *gc; + guint32 shadow_color; + int shadow_offset; + + shadow_color = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), + "eel-label-shadow-color")); + shadow_offset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), + "eel-label-shadow-offset")); + + color = eel_gdk_rgb_to_color (shadow_color); + + get_layout_location (label, &x, &y); + + widget = GTK_WIDGET (label); + if (shadow_offset > 0) + { + gc = gdk_gc_new (gtk_widget_get_window (widget)); + gdk_gc_set_rgb_fg_color (gc, &color); + gdk_gc_set_clip_rectangle (gc, &event->area); + + gdk_draw_layout (gtk_widget_get_window (widget), + gc, + x + shadow_offset, y + shadow_offset, + gtk_label_get_layout (label)); + g_object_unref (gc); + } + + gtk_paint_layout (gtk_widget_get_style (widget), + gtk_widget_get_window (widget), + gtk_widget_get_state (widget), + FALSE, + &event->area, + widget, + "label", + x, y, + gtk_label_get_layout (label)); + + return TRUE; +} + +static void +eel_gtk_label_size_request (GtkLabel *label, GtkRequisition *requisition, gpointer user_data) +{ + gint shadow_offset; + + shadow_offset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label), + "eel-label-shadow-offset")); + + requisition->width += shadow_offset; + requisition->height += shadow_offset; +} + +static void +set_up_label (GtkLabel *label) +{ + + if (g_object_get_data (G_OBJECT (label), "eel-label-set-up") != NULL) + { + return; + } + + g_signal_connect (label, "expose_event", + G_CALLBACK (eel_gtk_label_expose_event), NULL); + g_signal_connect_after (label, "size_request", + G_CALLBACK (eel_gtk_label_size_request), NULL); + + g_object_set_data (G_OBJECT (label), "eel-label-set-up", "eel-label-set-up"); +} + +void +eel_gtk_label_set_drop_shadow_color (GtkLabel *label, + guint32 color) +{ + set_up_label (label); + + g_object_set_data (G_OBJECT (label), "eel-label-shadow-color", + GINT_TO_POINTER (color)); + + gtk_widget_queue_draw (GTK_WIDGET (label)); +} + +void +eel_gtk_label_set_drop_shadow_offset (GtkLabel *label, + gint offset) +{ + set_up_label (label); + + g_object_set_data (G_OBJECT (label), "eel-label-shadow-offset", + GINT_TO_POINTER (offset)); + + gtk_widget_queue_draw (GTK_WIDGET (label)); +} + +void +eel_gtk_widget_set_background_color (GtkWidget *widget, + const char *color_spec) +{ + GdkColor color; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + eel_gdk_color_parse_with_white_default (color_spec, &color); + + gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color); + gtk_widget_modify_base (widget, GTK_STATE_NORMAL, &color); + gtk_widget_modify_bg (widget, GTK_STATE_ACTIVE, &color); + gtk_widget_modify_base (widget, GTK_STATE_ACTIVE, &color); +} + +void +eel_gtk_widget_set_foreground_color (GtkWidget *widget, + const char *color_spec) +{ + GdkColor color; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + eel_gdk_color_parse_with_white_default (color_spec, &color); + + gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &color); + gtk_widget_modify_text (widget, GTK_STATE_NORMAL, &color); + gtk_widget_modify_fg (widget, GTK_STATE_ACTIVE, &color); + gtk_widget_modify_text (widget, GTK_STATE_ACTIVE, &color); +} + +GtkWidget * +eel_gtk_widget_find_windowed_ancestor (GtkWidget *widget) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + while (widget && !gtk_widget_get_has_window (widget)) + { + widget = gtk_widget_get_parent (widget); + } + + return widget; +} + +/* eel_gtk_get_system_font: + * + * Return the system font as selected in the control center. Need to + * g_object_unref() the result when done with it. + * + * Perhaps there is a better way to figure out what that font is, but + * the following is simple enough and it works. + */ +PangoFontDescription * +eel_gtk_get_system_font (void) +{ + GtkWidget *label; + PangoFontDescription *font; + + label = gtk_label_new (""); + + gtk_widget_ensure_style (label); + + font = pango_font_description_copy (gtk_widget_get_style (label)->font_desc); + + g_object_ref_sink (label); + g_object_unref (label); + + return font; +} + +void +eel_gtk_widget_get_button_event_location (GtkWidget *widget, + const GdkEventButton *event, + int *x, + int *y) +{ + int window_x, window_y; + GtkAllocation allocation; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (event != NULL); + + gdk_window_get_position (event->window, &window_x, &window_y); + gtk_widget_get_allocation (widget, &allocation); + if (x != NULL) + { + *x = event->x + window_x - allocation.x; + } + if (y != NULL) + { + *y = event->y + window_y - allocation.y; + } +} + +void +eel_gtk_widget_get_motion_event_location (GtkWidget *widget, + const GdkEventMotion *event, + int *x, + int *y) +{ + eel_gtk_widget_get_button_event_location (widget, (const GdkEventButton *) event, x, y); +} + +static gboolean +tree_view_button_press_callback (GtkWidget *tree_view, + GdkEventButton *event, + gpointer data) +{ + GtkTreePath *path; + GtkTreeViewColumn *column; + + if (event->button == 1 && event->type == GDK_BUTTON_PRESS) + { + if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), + event->x, event->y, + &path, + &column, + NULL, + NULL)) + { + gtk_tree_view_row_activated + (GTK_TREE_VIEW (tree_view), path, column); + } + } + + return FALSE; +} + +void +eel_gtk_tree_view_set_activate_on_single_click (GtkTreeView *tree_view, + gboolean should_activate) +{ + guint button_press_id; + + button_press_id = GPOINTER_TO_UINT + (g_object_get_data (G_OBJECT (tree_view), + "eel-tree-view-activate")); + + if (button_press_id && !should_activate) + { + g_signal_handler_disconnect (tree_view, button_press_id); + g_object_set_data (G_OBJECT (tree_view), + "eel-tree-view-activate", + NULL); + } + else if (!button_press_id && should_activate) + { + button_press_id = g_signal_connect + (tree_view, + "button_press_event", + G_CALLBACK (tree_view_button_press_callback), + NULL); + g_object_set_data (G_OBJECT (tree_view), + "eel-tree-view-activate", + GUINT_TO_POINTER (button_press_id)); + } +} + +gboolean +eel_gtk_viewport_get_visible_rect (GtkViewport *viewport, + GdkRectangle *rect) +{ + GdkRectangle viewport_rect; + GdkRectangle child_rect; + gboolean return_val; + + g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), FALSE); + g_return_val_if_fail (rect != NULL, FALSE); + + if (gtk_widget_get_realized (GTK_WIDGET (viewport))) + { + viewport_rect.x = 0; + viewport_rect.y = 0; + +#if GTK_CHECK_VERSION(3, 0, 0) + viewport_rect.width = gdk_window_get_width(GDK_WINDOW(gtk_viewport_get_view_window(viewport))); + viewport_rect.height = gdk_window_get_height(GDK_WINDOW(gtk_viewport_get_view_window(viewport))); +#else + gdk_drawable_get_size(gtk_viewport_get_view_window(viewport), &viewport_rect.width, &viewport_rect.height); +#endif + + gdk_window_get_position (gtk_viewport_get_bin_window (viewport), + &child_rect.x, + &child_rect.y); + +#if GTK_CHECK_VERSION(3, 0, 0) + child_rect.width = gdk_window_get_width(GDK_WINDOW(gtk_viewport_get_view_window(viewport))); + child_rect.height = gdk_window_get_height(GDK_WINDOW(gtk_viewport_get_view_window(viewport))); +#else + gdk_drawable_get_size(gtk_viewport_get_bin_window(viewport), &child_rect.width, &child_rect.height); +#endif + + return_val = gdk_rectangle_intersect (&viewport_rect, + &child_rect, + rect); + rect->x -= child_rect.x; + rect->y -= child_rect.y; + + return return_val; + } + + rect->x = rect->y = rect->width = rect->height = 0; + return FALSE; +} + +void +eel_gtk_viewport_scroll_to_rect (GtkViewport *viewport, + GdkRectangle *rect) +{ + GdkRectangle visible_rect; + int scroll_x; + int scroll_y; + GtkAdjustment *adjustment; + + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + g_return_if_fail (rect != NULL); + + if (eel_gtk_viewport_get_visible_rect (viewport, &visible_rect)) + { + scroll_x = -1; + scroll_y = -1; + + if (rect->x + rect->width > visible_rect.x + visible_rect.width) + { + scroll_x = rect->x - (visible_rect.width - rect->width); + } + if (rect->y + rect->height > visible_rect.y + visible_rect.height) + { + scroll_y = rect->y - (visible_rect.height - rect->height); + } + + if (rect->x < visible_rect.x) + { + scroll_x = rect->x; + } + + if (rect->y < visible_rect.y) + { + scroll_y = rect->y; + } + + adjustment = gtk_viewport_get_hadjustment (viewport); + if (adjustment && scroll_x != -1) + { + eel_gtk_adjustment_set_value (adjustment, + (double)scroll_x); + } + + adjustment = gtk_viewport_get_vadjustment (viewport); + if (adjustment && scroll_y != -1) + { + eel_gtk_adjustment_set_value (adjustment, + (double)scroll_y); + } + } +} diff --git a/eel/eel-gtk-extensions.h b/eel/eel-gtk-extensions.h new file mode 100644 index 00000000..21ab382d --- /dev/null +++ b/eel/eel-gtk-extensions.h @@ -0,0 +1,141 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-gtk-extensions.h - interface for new functions that operate on + gtk classes. Perhaps some of these should be + rolled into gtk someday. + + Copyright (C) 1999, 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: John Sullivan <[email protected]> + Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_GTK_EXTENSIONS_H +#define EEL_GTK_EXTENSIONS_H + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtk.h> +#include <eel/eel-gdk-extensions.h> + +#define EEL_DEFAULT_POPUP_MENU_DISPLACEMENT 2 +#define EEL_STANDARD_CLOSE_WINDOW_CONTROL_KEY 'w' + +/* signals */ +void eel_gtk_signal_connect_full_while_alive (GtkObject *object, + const gchar *name, + GCallback func, + GtkCallbackMarshal marshal, + gpointer data, + GDestroyNotify destroy_func, + gboolean object_signal, + gboolean after, + GtkObject *alive_object); +void eel_gtk_signal_connect_while_realized (GtkObject *object, + const char *name, + GCallback callback, + gpointer callback_data, + GtkWidget *realized_widget); + +/* GtkWidget */ +void eel_gtk_widget_set_shown (GtkWidget *widget, + gboolean shown); +gboolean eel_point_in_allocation (const GtkAllocation *allocation, + int x, + int y); +gboolean eel_point_in_widget (GtkWidget *widget, + int x, + int y); +void eel_gtk_widget_set_background_color (GtkWidget *widget, + const char *color_spec); +void eel_gtk_widget_set_foreground_color (GtkWidget *widget, + const char *color_spec); +GtkWidget * eel_gtk_widget_find_windowed_ancestor (GtkWidget *widget); +PangoFontDescription *eel_gtk_get_system_font (void); +void eel_gtk_widget_get_button_event_location (GtkWidget *widget, + const GdkEventButton *event, + int *x, + int *y); +void eel_gtk_widget_get_motion_event_location (GtkWidget *widget, + const GdkEventMotion *event, + int *x, + int *y); + +/* GtkContainer */ +GtkWidget * eel_gtk_container_get_first_child (GtkContainer *container); +void eel_gtk_container_foreach_deep (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + +/* GtkWindow */ +void eel_gtk_window_set_initial_geometry (GtkWindow *window, + EelGdkGeometryFlags geometry_flags, + int left, + int top, + guint width, + guint height); +void eel_gtk_window_set_initial_geometry_from_string (GtkWindow *window, + const char *geometry_string, + guint minimum_width, + guint minimum_height, + gboolean ignore_position); +void eel_gtk_window_set_up_close_accelerator (GtkWindow *window); +gboolean eel_gtk_window_event_is_close_accelerator (GtkWindow *window, + GdkEventKey *event); +char * eel_gtk_window_get_geometry_string (GtkWindow *window); + + +/* GtkMenu and GtkMenuItem */ +void eel_pop_up_context_menu (GtkMenu *menu, + gint16 offset_x, + gint16 offset_y, + GdkEventButton *event); +GtkMenuItem * eel_gtk_menu_append_separator (GtkMenu *menu); +GtkMenuItem * eel_gtk_menu_insert_separator (GtkMenu *menu, + int index); +void eel_gtk_menu_set_item_visibility (GtkMenu *menu, + int index, + gboolean visible); + +/* GtkMenuToolButton */ +GtkWidget * eel_gtk_menu_tool_button_get_button (GtkMenuToolButton *tool_button); + +/* GtkLabel */ +void eel_gtk_label_make_bold (GtkLabel *label); +void eel_gtk_label_set_scale (GtkLabel *label, + double scale_factor); +void eel_gtk_label_set_drop_shadow_color (GtkLabel *label, + guint32 color); +void eel_gtk_label_set_drop_shadow_offset (GtkLabel *label, + gint offset); +/* GtkAdjustment */ +void eel_gtk_adjustment_set_value (GtkAdjustment *adjustment, + float value); +void eel_gtk_adjustment_clamp_value (GtkAdjustment *adjustment); + +/* GtkTreeView */ +void eel_gtk_tree_view_set_activate_on_single_click (GtkTreeView *tree_view, + gboolean should_activate); + +/* GtkViewport */ +gboolean eel_gtk_viewport_get_visible_rect (GtkViewport *viewport, + GdkRectangle *rect); + +void eel_gtk_viewport_scroll_to_rect (GtkViewport *viewport, + GdkRectangle *rect); + +#endif /* EEL_GTK_EXTENSIONS_H */ diff --git a/eel/eel-gtk-macros.h b/eel/eel-gtk-macros.h new file mode 100644 index 00000000..996d75f8 --- /dev/null +++ b/eel/eel-gtk-macros.h @@ -0,0 +1,178 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-gtk-macros.h: Macros to reduce boilerplate when using GTK. + + Copyright (C) 1999, 2000, 2001 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_GTK_MACROS_H +#define EEL_GTK_MACROS_H + +#ifndef EEL_DISABLE_DEPRECATED + +/* Define a parent_class global and a get_type function for a GTK class. + Since this is boilerplate, it's better not to repeat it over and over again. + Called like this: + + EEL_CLASS_BOILERPLATE (EelBookmark, eel_bookmark, GTK_TYPE_OBJECT) + + The parent_class_type parameter is guaranteed to be evaluated only once + so it can be an expression, even an expression that contains a function call. +*/ + +#define EEL_CLASS_BOILERPLATE(class_name, prefix, parent_class_type) \ + EEL_BOILERPLATE (class_name, class_name, prefix, parent_class_type, \ + EEL_REGISTER_TYPE) +#define EEL_REGISTER_TYPE(class_name, corba_name) \ + g_type_register_static (parent_type, #class_name, &info, 0) + +#define EEL_BOILERPLATE(class_name, corba_name, prefix, parent_class_type, \ + register_type) \ + \ +static gpointer parent_class; \ + \ +GType \ +prefix##_get_type (void) \ +{ \ + GType parent_type; \ + static GType type; \ + \ + if (type == 0) { \ + static GTypeInfo info = { \ + sizeof (class_name##Class), \ + NULL, NULL, \ + (GClassInitFunc) prefix##_class_init, \ + NULL, NULL, \ + sizeof (class_name), 0, \ + (GInstanceInitFunc) prefix##_init, \ + NULL \ + }; \ + \ + parent_type = (parent_class_type); \ + type = register_type (class_name, corba_name); \ + parent_class = g_type_class_ref (parent_type); \ + } \ + \ + return type; \ +} + +/* Call a parent class version of a virtual function (or default + * signal handler since that's the same thing). Nice because it + * documents what it's doing and there is less chance for a + * typo. Depends on the parent class pointer having the conventional + * name "parent_class" as the boilerplate macro above does it. + */ +#define EEL_CALL_PARENT(parent_class_cast_macro, signal, parameters) \ + \ +G_STMT_START { \ + if (parent_class_cast_macro (parent_class)->signal != NULL) { \ + (* parent_class_cast_macro (parent_class)->signal) parameters;\ + } \ +} G_STMT_END + +/* Same thing, for functions with a return value. */ +#define EEL_CALL_PARENT_WITH_RETURN_VALUE(parent_class_cast_macro, signal, \ + parameters) \ + \ +(parent_class_cast_macro (parent_class)->signal == NULL) \ + ? 0 \ + : ((* parent_class_cast_macro (parent_class)->signal) parameters) + +#endif /* EEL_DISABLE_DEPRECATED */ + +/* Call a virtual function. Useful when the virtual function is not a + * signal, otherwise you want to gtk_signal emit. Nice because it + * documents what it's doing and there is less chance for a typo. + */ +#define EEL_CALL_METHOD(class_cast_macro, object, signal, parameters) \ + \ +G_STMT_START { \ + if (class_cast_macro (G_OBJECT_GET_CLASS (object))->signal != NULL) { \ + (* class_cast_macro (G_OBJECT_GET_CLASS (object))->signal) \ + parameters; \ + } \ +} G_STMT_END + +/* Same thing, for functions with a return value. */ +#define EEL_CALL_METHOD_WITH_RETURN_VALUE(class_cast_macro, object, signal, \ + parameters) \ + \ +(class_cast_macro (G_OBJECT_GET_CLASS (object))->signal == NULL) \ + ? 0 \ + : ((* class_cast_macro (G_OBJECT_GET_CLASS (object))->signal) \ + parameters) \ + +#ifndef G_DISABLE_ASSERT + +/* Define a signal that is not implemented by this class but must be + * implemented by subclasses. This macro should be used inside the + * class initialization function. The companion macro EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL + * must be used earlier in the file. Called like this: + * + * EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, + * fm_directory_view, + * clear); + */ +#define EEL_ASSIGN_MUST_OVERRIDE_SIGNAL(class_pointer, prefix, signal) \ + \ +* (void (**)(void)) & (class_pointer)->signal = prefix##_unimplemented_##signal + +/* Provide a debug-only implementation of a signal that must be implemented + * by subclasses. The debug-only implementation fires a warning if it is called. + * This macro should be placed as if it were a function, earlier in the file + * than the class initialization function. Called like this: + * + * EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, clear); + */ +#define EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL(prefix, signal) \ + \ +static void \ +prefix##_unimplemented_##signal (void) \ +{ \ + g_warning ("failed to override signal " #prefix "->" #signal); \ +} + +#else /* G_DISABLE_ASSERT */ + +#define EEL_DEFINE_MUST_OVERRIDE_SIGNAL(class_cast_macro, class_pointer, prefix, signal) +#define EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL(prefix, signal) +#define EEL_ASSIGN_MUST_OVERRIDE_SIGNAL(class_pointer, prefix, signal) + +#endif /* G_DISABLE_ASSERT */ + +/* Access a method. */ +#define EEL_ACCESS_METHOD(class_cast_macro, object, method) \ +(class_cast_macro (G_OBJECT_GET_CLASS (object))->method) + +/* Invoke a method for a given object. */ +#define EEL_INVOKE_METHOD(class_cast_macro, object, method, parameters) \ +((* EEL_ACCESS_METHOD (class_cast_macro, object, method)) parameters) + +/* Assert the non-nullness of a method for a given object. */ +#define EEL_ASSERT_METHOD(class_cast_macro, object, method) \ +g_assert (EEL_ACCESS_METHOD (class_cast_macro, object, method) != NULL) + +/* Invoke a method if it ain't null. */ +#define EEL_INVOKE_METHOD_IF(class_cast_macro, object, method, parameters) \ +(EEL_ACCESS_METHOD (class_cast_macro, object, method) ? 0 : \ + EEL_INVOKE_METHOD (class_cast_macro, object, method, parameters)) + +#endif /* EEL_GTK_MACROS_H */ diff --git a/eel/eel-i18n.c b/eel/eel-i18n.c new file mode 100644 index 00000000..b43163e3 --- /dev/null +++ b/eel/eel-i18n.c @@ -0,0 +1,52 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-i18n.c: I18n stuff for Eel. + + Copyright (C) 2002 MandrakeSoft. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Frederic Crozat <[email protected]> +*/ + +#include <config.h> +#include <glib.h> + +#include "eel-i18n.h" + +#ifdef ENABLE_NLS + +#include <libintl.h> + +const char* _eel_gettext(const char* str) +{ + static gboolean _eel_gettext_initialized = FALSE; + + if (!_eel_gettext_initialized) + { + bindtextdomain(GETTEXT_PACKAGE, MATELOCALEDIR); + +#ifdef HAVE_BIND_TEXTDOMAIN_CODESET + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); +#endif + + _eel_gettext_initialized = TRUE; + } + + return dgettext(GETTEXT_PACKAGE, str); +} + +#endif /* ENABLE_NLS */ diff --git a/eel/eel-i18n.h b/eel/eel-i18n.h new file mode 100644 index 00000000..827539d8 --- /dev/null +++ b/eel/eel-i18n.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-i18n.h: I18n stuff for Eel. + + Copyright (C) 2002 MandrakeSoft + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Frederic Crozat <[email protected]> +*/ + +#ifndef EEL_I18N_H +#define EEL_I18N_H + +#ifdef ENABLE_NLS + +#include <glib.h> + + +const char* _eel_gettext(const char* str) G_GNUC_FORMAT(1); + +#include <libintl.h> +#define _(String) _eel_gettext(String) + +#ifdef gettext_noop +#define N_(String) gettext_noop(String) +#else +#define N_(String) (String) +#endif + +#else /* NLS is disabled */ +#define _(String) (String) +#define N_(String) (String) +#define textdomain(String) (String) +#define gettext(String) (String) +#define dgettext(Domain,String) (String) +#define dcgettext(Domain,String,Type) (String) +#define bindtextdomain(Domain,Directory) (Domain) +#endif + + +#endif /* EEL_I18N_H */ diff --git a/eel/eel-image-table.c b/eel/eel-image-table.c new file mode 100644 index 00000000..25f67a0a --- /dev/null +++ b/eel/eel-image-table.c @@ -0,0 +1,601 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-image-table.c - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-image-table.h" + +#include "eel-art-extensions.h" +#include "eel-art-gtk-extensions.h" +#include "eel-debug-drawing.h" +#include "eel-gtk-extensions.h" +#include "eel-gtk-macros.h" +#include "eel-labeled-image.h" +#include "eel-marshal.h" +#include <gtk/gtk.h> + +/* Arguments */ +enum +{ + ARG_0, + ARG_CHILD_UNDER_POINTER +}; + +/* Detail member struct */ +struct EelImageTableDetails +{ + GtkWidget *child_under_pointer; + GtkWidget *child_being_pressed; + GdkGC *clear_gc; +}; + +/* Signals */ +typedef enum +{ + CHILD_ENTER, + CHILD_LEAVE, + CHILD_PRESSED, + CHILD_RELEASED, + CHILD_CLICKED, + LAST_SIGNAL +} ImageTableSignals; + +/* Signals */ +static guint image_table_signals[LAST_SIGNAL] = { 0 }; + +static void eel_image_table_class_init (EelImageTableClass *image_table_class); +static void eel_image_table_init (EelImageTable *image); + +/* GObjectClass methods */ +static void eel_image_table_finalize (GObject *object); + +/* GtkWidgetClass methods */ +static void eel_image_table_realize (GtkWidget *widget); +static void eel_image_table_unrealize (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void eel_image_table_remove (GtkContainer *container, + GtkWidget *widget); +static GType eel_image_table_child_type (GtkContainer *container); + +/* Private EelImageTable methods */ +static void image_table_emit_signal (EelImageTable *image_table, + GtkWidget *child, + guint signal_index, + int x, + int y, + int button, + guint state, + GdkEvent *event); + +/* Ancestor callbacks */ +static int ancestor_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data); +static int ancestor_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data); +static int ancestor_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer event_data); +static int ancestor_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data); +static int ancestor_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data); + +EEL_CLASS_BOILERPLATE (EelImageTable, eel_image_table, EEL_TYPE_WRAP_TABLE) + +static void +eel_image_table_class_init (EelImageTableClass *image_table_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (image_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (image_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (image_table_class); + + /* GObjectClass */ + object_class->finalize = eel_image_table_finalize; + + /* GtkWidgetClass */ + widget_class->realize = eel_image_table_realize; + widget_class->unrealize = eel_image_table_unrealize; + + /* GtkContainerClass */ + container_class->remove = eel_image_table_remove; + container_class->child_type = eel_image_table_child_type; + + /* Signals */ + image_table_signals[CHILD_ENTER] = g_signal_new ("child_enter", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_enter), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_LEAVE] = g_signal_new ("child_leave", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_leave), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_PRESSED] = g_signal_new ("child_pressed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_pressed), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_RELEASED] = g_signal_new ("child_released", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_released), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_CLICKED] = g_signal_new ("child_clicked", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_clicked), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); +} + +static void +eel_image_table_init (EelImageTable *image_table) +{ + gtk_widget_set_has_window (GTK_WIDGET (image_table), FALSE); + + image_table->details = g_new0 (EelImageTableDetails, 1); +} + +/* GObjectClass methods */ +static void +eel_image_table_finalize (GObject *object) +{ + EelImageTable *image_table; + + image_table = EEL_IMAGE_TABLE (object); + + g_free (image_table->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +eel_image_table_realize (GtkWidget *widget) +{ + GtkWidget *windowed_ancestor; + + g_assert (EEL_IS_IMAGE_TABLE (widget)); + + /* Chain realize */ + EEL_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget)); + + windowed_ancestor = eel_gtk_widget_find_windowed_ancestor (widget); + g_assert (GTK_IS_WIDGET (windowed_ancestor)); + + gtk_widget_add_events (windowed_ancestor, + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_POINTER_MOTION_MASK); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "enter_notify_event", + G_CALLBACK (ancestor_enter_notify_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "leave_notify_event", + G_CALLBACK (ancestor_leave_notify_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "motion_notify_event", + G_CALLBACK (ancestor_motion_notify_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "button_press_event", + G_CALLBACK (ancestor_button_press_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "button_release_event", + G_CALLBACK (ancestor_button_release_event), + widget, + widget); +} + +static void +eel_image_table_unrealize (GtkWidget *widget) +{ + EelImageTable *image_table; + + g_assert (EEL_IS_IMAGE_TABLE (widget)); + + image_table = EEL_IMAGE_TABLE (widget); + + if (image_table->details->clear_gc != NULL) + { + g_object_unref (image_table->details->clear_gc); + image_table->details->clear_gc = NULL; + } + + /* Chain unrealize */ + EEL_CALL_PARENT (GTK_WIDGET_CLASS, unrealize, (widget)); +} + +/* GtkContainerClass methods */ +static void +eel_image_table_remove (GtkContainer *container, + GtkWidget *child) +{ + EelImageTable *image_table; + + g_assert (EEL_IS_IMAGE_TABLE (container)); + g_assert (EEL_IS_LABELED_IMAGE (child)); + + image_table = EEL_IMAGE_TABLE (container); + + if (child == image_table->details->child_under_pointer) + { + image_table->details->child_under_pointer = NULL; + } + + if (child == image_table->details->child_being_pressed) + { + image_table->details->child_being_pressed = NULL; + } + + EEL_CALL_PARENT (GTK_CONTAINER_CLASS, remove, (container, child)); +} + +static GType +eel_image_table_child_type (GtkContainer *container) +{ + return EEL_TYPE_LABELED_IMAGE; +} + +/* Private EelImageTable methods */ + +static void +image_table_emit_signal (EelImageTable *image_table, + GtkWidget *child, + guint signal_index, + int x, + int y, + int button, + guint state, + GdkEvent *gdk_event) +{ + EelImageTableEvent event; + + g_assert (EEL_IS_IMAGE_TABLE (image_table)); + g_assert (GTK_IS_WIDGET (child)); + g_assert (signal_index < LAST_SIGNAL); + + event.x = x; + event.y = y; + event.button = button; + event.state = state; + event.event = gdk_event; + + g_signal_emit (image_table, + image_table_signals[signal_index], + 0, + child, + &event); +} + +static void +image_table_handle_motion (EelImageTable *image_table, + int x, + int y, + GdkEvent *event) +{ + GtkWidget *child; + GtkWidget *leave_emit_child = NULL; + GtkWidget *enter_emit_child = NULL; + + g_assert (EEL_IS_IMAGE_TABLE (image_table)); + + child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), x, y); + + if (child && !gtk_widget_get_sensitive (child)) + { + return; + } + + if (child == image_table->details->child_under_pointer) + { + return; + } + + if (child != NULL) + { + if (image_table->details->child_under_pointer != NULL) + { + leave_emit_child = image_table->details->child_under_pointer; + } + + image_table->details->child_under_pointer = child; + enter_emit_child = image_table->details->child_under_pointer; + } + else + { + if (image_table->details->child_under_pointer != NULL) + { + leave_emit_child = image_table->details->child_under_pointer; + } + + image_table->details->child_under_pointer = NULL; + } + + if (leave_emit_child != NULL) + { + image_table_emit_signal (image_table, + leave_emit_child, + CHILD_LEAVE, + x, + y, + 0, + 0, + (GdkEvent *)event); + } + + if (enter_emit_child != NULL) + { + image_table_emit_signal (image_table, + enter_emit_child, + CHILD_ENTER, + x, + y, + 0, + 0, + (GdkEvent *)event); + } +} + +static int +ancestor_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data) +{ + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table_handle_motion (EEL_IMAGE_TABLE (event_data), event->x, event->y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data) +{ + EelIRect bounds; + int x = -1; + int y = -1; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (event_data)); + + if (eel_irect_contains_point (bounds, event->x, event->y)) + { + x = event->x; + y = event->y; + } + + image_table_handle_motion (EEL_IMAGE_TABLE (event_data), x, y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer event_data) +{ + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table_handle_motion (EEL_IMAGE_TABLE (event_data), (int) event->x, (int) event->y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data) +{ + EelImageTable *image_table; + GtkWidget *child; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table = EEL_IMAGE_TABLE (event_data); + + child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), event->x, event->y); + + if (child && !gtk_widget_get_sensitive (child)) + { + return FALSE; + } + + if (child != NULL) + { + if (child == image_table->details->child_under_pointer) + { + image_table->details->child_being_pressed = child; + image_table_emit_signal (image_table, + child, + CHILD_PRESSED, + event->x, + event->y, + event->button, + event->state, + (GdkEvent *)event); + } + } + + return FALSE; +} + +static int +ancestor_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data) +{ + EelImageTable *image_table; + GtkWidget *child; + GtkWidget *released_emit_child = NULL; + GtkWidget *clicked_emit_child = NULL; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table = EEL_IMAGE_TABLE (event_data); + + child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), event->x, event->y); + + if (child && !gtk_widget_get_sensitive (child)) + { + return FALSE; + } + + if (image_table->details->child_being_pressed != NULL) + { + released_emit_child = image_table->details->child_being_pressed; + } + + if (child != NULL) + { + if (child == image_table->details->child_being_pressed) + { + clicked_emit_child = child; + } + } + + image_table->details->child_being_pressed = NULL; + + if (released_emit_child != NULL) + { + image_table_emit_signal (image_table, + released_emit_child, + CHILD_RELEASED, + event->x, + event->y, + event->button, + event->state, + (GdkEvent *)event); + } + + if (clicked_emit_child != NULL) + { + + image_table_emit_signal (image_table, + clicked_emit_child, + CHILD_CLICKED, + event->x, + event->y, + event->button, + event->state, + (GdkEvent *)event); + } + + return FALSE; +} + +/** + * eel_image_table_new: + */ +GtkWidget* +eel_image_table_new (gboolean homogeneous) +{ + EelImageTable *image_table; + + image_table = EEL_IMAGE_TABLE (gtk_widget_new (eel_image_table_get_type (), NULL)); + + eel_wrap_table_set_homogeneous (EEL_WRAP_TABLE (image_table), homogeneous); + + return GTK_WIDGET (image_table); +} + +/** + * eel_image_table_add_empty_child: + * @image_table: A EelImageTable. + * + * Add a "empty" child to the table. Useful when you want to have + * empty space between 2 children. + * + * Returns: The empty child - A EelLabeledImage widget with no label + * or pixbuf. + */ +GtkWidget * +eel_image_table_add_empty_image (EelImageTable *image_table) +{ + GtkWidget *empty; + + g_return_val_if_fail (EEL_IS_IMAGE_TABLE (image_table), NULL); + + empty = eel_labeled_image_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (image_table), empty); + gtk_widget_set_sensitive (empty, FALSE); + + return empty; +} diff --git a/eel/eel-image-table.h b/eel/eel-image-table.h new file mode 100644 index 00000000..90602a76 --- /dev/null +++ b/eel/eel-image-table.h @@ -0,0 +1,99 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-image-table.h - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_IMAGE_TABLE_H +#define EEL_IMAGE_TABLE_H + +#include <eel/eel-wrap-table.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_TYPE_IMAGE_TABLE eel_image_table_get_type() +#define EEL_IMAGE_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_IMAGE_TABLE, EelImageTable)) +#define EEL_IMAGE_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_IMAGE_TABLE, EelImageTableClass)) +#define EEL_IS_IMAGE_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_IMAGE_TABLE)) +#define EEL_IS_IMAGE_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_IMAGE_TABLE)) +#define EEL_IMAGE_TABLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_IMAGE_TABLE, EelImageTableClass)) + + typedef struct EelImageTable EelImageTable; + typedef struct EelImageTableClass EelImageTableClass; + typedef struct EelImageTableDetails EelImageTableDetails; + + typedef struct + { + int x; + int y; + int button; + guint state; + GdkEvent *event; + } EelImageTableEvent; + + struct EelImageTable + { + /* Superclass */ + EelWrapTable wrap_table; + + /* Private things */ + EelImageTableDetails *details; + }; + + struct EelImageTableClass + { + EelWrapTableClass parent_class; + + /* Signals */ + void (* child_enter) (EelImageTable *image_table, + GtkWidget *child, + const EelImageTableEvent *event); + void (* child_leave) (EelImageTable *image_table, + GtkWidget *child, + const EelImageTableEvent *event); + void (* child_pressed) (EelImageTable *image_table, + GtkWidget *child, + const EelImageTableEvent *event); + void (* child_released) (EelImageTable *image_table, + GtkWidget *child, + const EelImageTableEvent *event); + void (* child_clicked) (EelImageTable *image_table, + GtkWidget *child, + const EelImageTableEvent *event); + }; + + /* Public GtkImageTable methods */ + GType eel_image_table_get_type (void); + GtkWidget *eel_image_table_new (gboolean homogeneous); + GtkWidget *eel_image_table_add_empty_image (EelImageTable *image_table); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_IMAGE_TABLE_H */ diff --git a/eel/eel-labeled-image.c b/eel/eel-labeled-image.c new file mode 100644 index 00000000..76a23876 --- /dev/null +++ b/eel/eel-labeled-image.c @@ -0,0 +1,2493 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-labeled-image.c - A labeled image. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-labeled-image.h" + +#include "eel-art-extensions.h" +#include "eel-art-gtk-extensions.h" +#include "eel-debug-drawing.h" +#include "eel-gtk-container.h" +#include "eel-gtk-extensions.h" +#include "eel-gtk-macros.h" +#include "eel-accessibility.h" +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include <atk/atkimage.h> + +#define DEFAULT_SPACING 0 +#define DEFAULT_X_PADDING 0 +#define DEFAULT_Y_PADDING 0 +#define DEFAULT_X_ALIGNMENT 0.5 +#define DEFAULT_Y_ALIGNMENT 0.5 + +/* Signals */ +enum +{ + ACTIVATE, + LAST_SIGNAL +}; + +/* Arguments */ +enum +{ + PROP_0, + PROP_FILL, + PROP_LABEL, + PROP_LABEL_POSITION, + PROP_PIXBUF, + PROP_SHOW_IMAGE, + PROP_SHOW_LABEL, + PROP_SPACING, + PROP_X_ALIGNMENT, + PROP_X_PADDING, + PROP_Y_ALIGNMENT, + PROP_Y_PADDING +}; + +/* Detail member struct */ +struct EelLabeledImageDetails +{ + GtkWidget *image; + GtkWidget *label; + GtkPositionType label_position; + gboolean show_label; + gboolean show_image; + guint spacing; + float x_alignment; + float y_alignment; + int x_padding; + int y_padding; + int fixed_image_height; + gboolean fill; +}; + +/* derived types so we can add our accessibility interfaces */ +static GType eel_labeled_image_button_get_type (void); +static GType eel_labeled_image_check_button_get_type (void); +static GType eel_labeled_image_radio_button_get_type (void); +static GType eel_labeled_image_toggle_button_get_type (void); + + +static void eel_labeled_image_class_init (EelLabeledImageClass *labeled_image_class); +static void eel_labeled_image_init (EelLabeledImage *image); +static void eel_labeled_image_finalize (GObject *object); + + + +/* GObjectClass methods */ +static void eel_labeled_image_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void eel_labeled_image_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +/* GtkObjectClass methods */ +static void eel_labeled_image_destroy (GtkObject *object); + +/* GtkWidgetClass methods */ +static void eel_labeled_image_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static int eel_labeled_image_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static void eel_labeled_image_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void eel_labeled_image_map (GtkWidget *widget); +static void eel_labeled_image_unmap (GtkWidget *widget); +static AtkObject *eel_labeled_image_get_accessible (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void eel_labeled_image_add (GtkContainer *container, + GtkWidget *widget); +static void eel_labeled_image_remove (GtkContainer *container, + GtkWidget *widget); +static void eel_labeled_image_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); + +/* Private EelLabeledImage methods */ +static EelDimensions labeled_image_get_image_dimensions (const EelLabeledImage *labeled_image); +static EelDimensions labeled_image_get_label_dimensions (const EelLabeledImage *labeled_image); +static void labeled_image_ensure_label (EelLabeledImage *labeled_image); +static void labeled_image_ensure_image (EelLabeledImage *labeled_image); +static EelIRect labeled_image_get_content_bounds (const EelLabeledImage *labeled_image); +static EelDimensions labeled_image_get_content_dimensions (const EelLabeledImage *labeled_image); +static void labeled_image_update_alignments (EelLabeledImage *labeled_image); +static gboolean labeled_image_show_label (const EelLabeledImage *labeled_image); +static gboolean labeled_image_show_image (const EelLabeledImage *labeled_image); + +static guint labeled_image_signals[LAST_SIGNAL] = { 0 }; + +EEL_CLASS_BOILERPLATE (EelLabeledImage, eel_labeled_image, GTK_TYPE_CONTAINER) + +/* Class init methods */ +static void +eel_labeled_image_class_init (EelLabeledImageClass *labeled_image_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (labeled_image_class); + GtkObjectClass *object_class = GTK_OBJECT_CLASS (labeled_image_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (labeled_image_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (labeled_image_class); + GtkBindingSet *binding_set; + + gobject_class->finalize = eel_labeled_image_finalize; + + /* GObjectClass */ + gobject_class->set_property = eel_labeled_image_set_property; + gobject_class->get_property = eel_labeled_image_get_property; + + /* GtkObjectClass */ + object_class->destroy = eel_labeled_image_destroy; + + /* GtkWidgetClass */ + widget_class->size_request = eel_labeled_image_size_request; + widget_class->size_allocate = eel_labeled_image_size_allocate; + widget_class->expose_event = eel_labeled_image_expose_event; + widget_class->map = eel_labeled_image_map; + widget_class->unmap = eel_labeled_image_unmap; + widget_class->get_accessible = eel_labeled_image_get_accessible; + + /* GtkContainerClass */ + container_class->add = eel_labeled_image_add; + container_class->remove = eel_labeled_image_remove; + container_class->forall = eel_labeled_image_forall; + + labeled_image_signals[ACTIVATE] = + g_signal_new ("activate", + G_TYPE_FROM_CLASS (labeled_image_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EelLabeledImageClass, + activate), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + widget_class->activate_signal = labeled_image_signals[ACTIVATE]; + + binding_set = gtk_binding_set_by_class (gobject_class); + + gtk_binding_entry_add_signal (binding_set, + GDK_Return, 0, + "activate", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Enter, 0, + "activate", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_space, 0, + "activate", 0); + + + /* Properties */ + g_object_class_install_property ( + gobject_class, + PROP_PIXBUF, + g_param_spec_object ("pixbuf", NULL, NULL, + GDK_TYPE_PIXBUF, G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_LABEL, + g_param_spec_string ("label", NULL, NULL, + "", G_PARAM_READWRITE)); + + + g_object_class_install_property ( + gobject_class, + PROP_LABEL_POSITION, + g_param_spec_enum ("label_position", NULL, NULL, + GTK_TYPE_POSITION_TYPE, + GTK_POS_BOTTOM, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_SHOW_LABEL, + g_param_spec_boolean ("show_label", NULL, NULL, + TRUE, G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_SHOW_IMAGE, + g_param_spec_boolean ("show_image", NULL, NULL, + TRUE, G_PARAM_READWRITE)); + + + g_object_class_install_property ( + gobject_class, + PROP_SPACING, + g_param_spec_uint ("spacing", NULL, NULL, + 0, + G_MAXINT, + DEFAULT_SPACING, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_X_PADDING, + g_param_spec_int ("x_padding", NULL, NULL, + 0, + G_MAXINT, + DEFAULT_X_PADDING, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_Y_PADDING, + g_param_spec_int ("y_padding", NULL, NULL, + 0, + G_MAXINT, + DEFAULT_Y_PADDING, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_X_ALIGNMENT, + g_param_spec_float ("x_alignment", NULL, NULL, + 0.0, + 1.0, + DEFAULT_X_ALIGNMENT, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_Y_ALIGNMENT, + g_param_spec_float ("y_alignment", NULL, NULL, + 0.0, + 1.0, + DEFAULT_Y_ALIGNMENT, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_FILL, + g_param_spec_boolean ("fill", NULL, NULL, + FALSE, + G_PARAM_READWRITE)); +} + +static void +eel_labeled_image_init (EelLabeledImage *labeled_image) +{ + gtk_widget_set_has_window (GTK_WIDGET (labeled_image), FALSE); + + labeled_image->details = g_new0 (EelLabeledImageDetails, 1); + labeled_image->details->show_label = TRUE; + labeled_image->details->show_image = TRUE; + labeled_image->details->label_position = GTK_POS_BOTTOM; + labeled_image->details->spacing = DEFAULT_SPACING; + labeled_image->details->x_padding = DEFAULT_X_PADDING; + labeled_image->details->y_padding = DEFAULT_Y_PADDING; + labeled_image->details->x_alignment = DEFAULT_X_ALIGNMENT; + labeled_image->details->y_alignment = DEFAULT_Y_ALIGNMENT; + labeled_image->details->fixed_image_height = 0; + + eel_labeled_image_set_fill (labeled_image, FALSE); +} + +static void +eel_labeled_image_finalize (GObject *object) +{ + EelLabeledImage *labeled_image; + + labeled_image = EEL_LABELED_IMAGE (object); + + g_free (labeled_image->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + + +static void +eel_labeled_image_destroy (GtkObject *object) +{ + EelLabeledImage *labeled_image; + + labeled_image = EEL_LABELED_IMAGE (object); + + if (labeled_image->details->image != NULL) + { + gtk_widget_destroy (labeled_image->details->image); + } + + if (labeled_image->details->label != NULL) + { + gtk_widget_destroy (labeled_image->details->label); + } + + EEL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object)); +} + +/* GObjectClass methods */ +static void +eel_labeled_image_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EelLabeledImage *labeled_image; + + g_assert (EEL_IS_LABELED_IMAGE (object)); + + labeled_image = EEL_LABELED_IMAGE (object); + + switch (property_id) + { + case PROP_PIXBUF: + eel_labeled_image_set_pixbuf (labeled_image, + g_value_get_object (value)); + break; + + case PROP_LABEL: + eel_labeled_image_set_text (labeled_image, g_value_get_string (value)); + break; + + case PROP_LABEL_POSITION: + eel_labeled_image_set_label_position (labeled_image, + g_value_get_enum (value)); + break; + + case PROP_SHOW_LABEL: + eel_labeled_image_set_show_label (labeled_image, + g_value_get_boolean (value)); + break; + + case PROP_SHOW_IMAGE: + eel_labeled_image_set_show_image (labeled_image, + g_value_get_boolean (value)); + break; + + case PROP_SPACING: + eel_labeled_image_set_spacing (labeled_image, + g_value_get_uint (value)); + break; + + case PROP_X_PADDING: + eel_labeled_image_set_x_padding (labeled_image, + g_value_get_int (value)); + break; + + case PROP_Y_PADDING: + eel_labeled_image_set_y_padding (labeled_image, + g_value_get_int (value)); + break; + + case PROP_X_ALIGNMENT: + eel_labeled_image_set_x_alignment (labeled_image, + g_value_get_float (value)); + break; + + case PROP_Y_ALIGNMENT: + eel_labeled_image_set_y_alignment (labeled_image, + g_value_get_float (value)); + break; + + case PROP_FILL: + eel_labeled_image_set_fill (labeled_image, + g_value_get_boolean (value)); + break; + default: + g_assert_not_reached (); + } +} + +static void +eel_labeled_image_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EelLabeledImage *labeled_image; + + g_assert (EEL_IS_LABELED_IMAGE (object)); + + labeled_image = EEL_LABELED_IMAGE (object); + + switch (property_id) + { + case PROP_LABEL: + if (labeled_image->details->label == NULL) + { + g_value_set_string (value, NULL); + } + else + { + g_value_set_string (value, + gtk_label_get_text (GTK_LABEL ( + labeled_image->details->label))); + } + break; + + case PROP_LABEL_POSITION: + g_value_set_enum (value, eel_labeled_image_get_label_position (labeled_image)); + break; + + case PROP_SHOW_LABEL: + g_value_set_boolean (value, eel_labeled_image_get_show_label (labeled_image)); + break; + + case PROP_SHOW_IMAGE: + g_value_set_boolean (value, eel_labeled_image_get_show_image (labeled_image)); + break; + + case PROP_SPACING: + g_value_set_uint (value, eel_labeled_image_get_spacing (labeled_image)); + break; + + case PROP_X_PADDING: + g_value_set_int (value, eel_labeled_image_get_x_padding (labeled_image)); + break; + + case PROP_Y_PADDING: + g_value_set_int (value, eel_labeled_image_get_y_padding (labeled_image)); + break; + + case PROP_X_ALIGNMENT: + g_value_set_float (value, eel_labeled_image_get_x_alignment (labeled_image)); + break; + + case PROP_Y_ALIGNMENT: + g_value_set_float (value, eel_labeled_image_get_y_alignment (labeled_image)); + break; + + case PROP_FILL: + g_value_set_boolean (value, eel_labeled_image_get_fill (labeled_image)); + break; + + default: + g_assert_not_reached (); + } +} + +/* GtkWidgetClass methods */ +static void +eel_labeled_image_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EelLabeledImage *labeled_image; + EelDimensions content_dimensions; + + g_assert (EEL_IS_LABELED_IMAGE (widget)); + g_assert (requisition != NULL); + + labeled_image = EEL_LABELED_IMAGE (widget); + + content_dimensions = labeled_image_get_content_dimensions (labeled_image); + + requisition->width = + MAX (1, content_dimensions.width) + + 2 * labeled_image->details->x_padding; + + requisition->height = + MAX (1, content_dimensions.height) + + 2 * labeled_image->details->y_padding; +} + +static void +eel_labeled_image_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + EelLabeledImage *labeled_image; + EelIRect image_bounds; + EelIRect label_bounds; + + g_assert (EEL_IS_LABELED_IMAGE (widget)); + g_assert (allocation != NULL); + + labeled_image = EEL_LABELED_IMAGE (widget); + + gtk_widget_set_allocation (widget, allocation); + + label_bounds = eel_labeled_image_get_label_bounds (labeled_image); + eel_gtk_container_child_size_allocate (GTK_CONTAINER (widget), + labeled_image->details->label, + label_bounds); + + image_bounds = eel_labeled_image_get_image_bounds (labeled_image); + eel_gtk_container_child_size_allocate (GTK_CONTAINER (widget), + labeled_image->details->image, + image_bounds); +} + +static int +eel_labeled_image_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + EelLabeledImage *labeled_image; + EelIRect label_bounds; + GtkStyle *style; + GdkWindow *window; + + g_assert (EEL_IS_LABELED_IMAGE (widget)); + g_assert (gtk_widget_get_realized (widget)); + g_assert (event != NULL); + + labeled_image = EEL_LABELED_IMAGE (widget); + + style = gtk_widget_get_style (widget); + window = gtk_widget_get_window (widget); + if (gtk_widget_get_state (widget) == GTK_STATE_SELECTED || + gtk_widget_get_state (widget) == GTK_STATE_ACTIVE) + { + label_bounds = eel_labeled_image_get_label_bounds (EEL_LABELED_IMAGE (widget)); + + gtk_paint_flat_box (style, + window, + gtk_widget_get_state (widget), + GTK_SHADOW_NONE, + &event->area, + widget, + "eel-labeled-image", + label_bounds.x0, label_bounds.y0, + label_bounds.x1 - label_bounds.x0, + label_bounds.y1 - label_bounds.y0); + } + + if (labeled_image_show_label (labeled_image)) + { + eel_gtk_container_child_expose_event (GTK_CONTAINER (widget), + labeled_image->details->label, + event); + } + + if (labeled_image_show_image (labeled_image)) + { + eel_gtk_container_child_expose_event (GTK_CONTAINER (widget), + labeled_image->details->image, + event); + } + + if (gtk_widget_has_focus (widget)) + { + label_bounds = eel_labeled_image_get_image_bounds (EEL_LABELED_IMAGE (widget)); + gtk_paint_focus (style, window, + GTK_STATE_NORMAL, + &event->area, widget, + "eel-focusable-labeled-image", + label_bounds.x0, label_bounds.y0, + label_bounds.x1 - label_bounds.x0, + label_bounds.y1 - label_bounds.y0); + } + + return FALSE; +} + +static void +eel_labeled_image_map (GtkWidget *widget) +{ + EelLabeledImage *labeled_image; + + g_assert (EEL_IS_LABELED_IMAGE (widget)); + + labeled_image = EEL_LABELED_IMAGE (widget); + + gtk_widget_set_mapped (widget, TRUE); + + if (labeled_image_show_label (labeled_image)) + { + eel_gtk_container_child_map (GTK_CONTAINER (widget), labeled_image->details->label); + } + + if (labeled_image_show_image (labeled_image)) + { + eel_gtk_container_child_map (GTK_CONTAINER (widget), labeled_image->details->image); + } +} + +static void +eel_labeled_image_unmap (GtkWidget *widget) +{ + EelLabeledImage *labeled_image; + + g_assert (EEL_IS_LABELED_IMAGE (widget)); + + labeled_image = EEL_LABELED_IMAGE (widget); + + gtk_widget_set_mapped (widget, FALSE); + + eel_gtk_container_child_unmap (GTK_CONTAINER (widget), labeled_image->details->label); + eel_gtk_container_child_unmap (GTK_CONTAINER (widget), labeled_image->details->image); +} + +/* GtkContainerClass methods */ +static void +eel_labeled_image_add (GtkContainer *container, + GtkWidget *child) +{ + g_assert (GTK_IS_LABEL (child) || GTK_IS_IMAGE (child)); + + eel_gtk_container_child_add (container, child); +} + +static void +eel_labeled_image_remove (GtkContainer *container, + GtkWidget *child) +{ + EelLabeledImage *labeled_image; + + g_assert (GTK_IS_LABEL (child) || GTK_IS_IMAGE (child)); + + labeled_image = EEL_LABELED_IMAGE (container);; + + g_assert (child == labeled_image->details->image || child == labeled_image->details->label); + + eel_gtk_container_child_remove (container, child); + + if (labeled_image->details->image == child) + { + labeled_image->details->image = NULL; + } + + if (labeled_image->details->label == child) + { + labeled_image->details->label = NULL; + } +} + +static void +eel_labeled_image_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + EelLabeledImage *labeled_image; + + g_assert (EEL_IS_LABELED_IMAGE (container)); + g_assert (callback != NULL); + + labeled_image = EEL_LABELED_IMAGE (container); + + if (include_internals) + { + if (labeled_image->details->image != NULL) + { + (* callback) (labeled_image->details->image, callback_data); + } + + if (labeled_image->details->label != NULL) + { + (* callback) (labeled_image->details->label, callback_data); + } + } +} + +/* Private EelLabeledImage methods */ +static gboolean +is_fixed_height (const EelLabeledImage *labeled_image) +{ + return labeled_image->details->fixed_image_height > 0; +} + +static EelDimensions +labeled_image_get_image_dimensions (const EelLabeledImage *labeled_image) +{ + EelDimensions image_dimensions; + GtkRequisition image_requisition; + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (!labeled_image_show_image (labeled_image)) + { + return eel_dimensions_empty; + } + + gtk_widget_size_request (labeled_image->details->image, &image_requisition); + + image_dimensions.width = (int) image_requisition.width; + image_dimensions.height = (int) image_requisition.height; + + if (is_fixed_height (labeled_image)) + { + image_dimensions.height = labeled_image->details->fixed_image_height; + } + + return image_dimensions; +} + +static EelDimensions +labeled_image_get_label_dimensions (const EelLabeledImage *labeled_image) +{ + EelDimensions label_dimensions; + GtkRequisition label_requisition; + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (!labeled_image_show_label (labeled_image)) + { + return eel_dimensions_empty; + } + + gtk_widget_size_request (labeled_image->details->label, &label_requisition); + + label_dimensions.width = (int) label_requisition.width; + label_dimensions.height = (int) label_requisition.height; + + return label_dimensions; +} + +static EelIRect +labeled_image_get_image_bounds_fill (const EelLabeledImage *labeled_image) +{ + EelIRect image_bounds; + EelDimensions image_dimensions; + EelIRect content_bounds; + EelIRect bounds; + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + image_dimensions = labeled_image_get_image_dimensions (labeled_image); + + if (eel_dimensions_are_empty (image_dimensions)) + { + return eel_irect_empty; + } + + content_bounds = labeled_image_get_content_bounds (labeled_image); + bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (labeled_image)); + + if (!labeled_image_show_label (labeled_image)) + { + image_bounds = bounds; + } + else + { + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + image_bounds.y0 = bounds.y0; + image_bounds.x0 = content_bounds.x1 - image_dimensions.width; + image_bounds.y1 = bounds.y1; + image_bounds.x1 = bounds.x1; + break; + + case GTK_POS_RIGHT: + image_bounds.y0 = bounds.y0; + image_bounds.x0 = bounds.x0; + image_bounds.y1 = bounds.y1; + image_bounds.x1 = content_bounds.x0 + image_dimensions.width; + break; + + case GTK_POS_TOP: + image_bounds.x0 = bounds.x0; + image_bounds.y0 = content_bounds.y1 - image_dimensions.height; + image_bounds.x1 = bounds.x1; + image_bounds.y1 = bounds.y1; + break; + + case GTK_POS_BOTTOM: + image_bounds.x0 = bounds.x0; + image_bounds.y0 = bounds.y0; + image_bounds.x1 = bounds.x1; + image_bounds.y1 = content_bounds.y0 + image_dimensions.height; + break; + + default: + image_bounds.x0 = 0; + image_bounds.y0 = 0; + image_bounds.x1 = 0; + image_bounds.y1 = 0; + g_assert_not_reached (); + } + } + + return image_bounds; +} + +EelIRect +eel_labeled_image_get_image_bounds (const EelLabeledImage *labeled_image) +{ + EelDimensions image_dimensions; + EelDimensions label_dimensions; + GtkRequisition image_requisition; + EelIRect image_bounds; + EelIRect content_bounds; + + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), eel_irect_empty); + + if (labeled_image->details->fill) + { + return labeled_image_get_image_bounds_fill (labeled_image); + } + + /* get true real dimensions if we're in fixed height mode */ + if (is_fixed_height (labeled_image) && labeled_image_show_image (labeled_image)) + { + gtk_widget_size_request (labeled_image->details->image, &image_requisition); + image_dimensions.width = (int) image_requisition.width; + image_dimensions.height = (int) image_requisition.height; + } + else + { + image_dimensions = labeled_image_get_image_dimensions (labeled_image); + } + + label_dimensions = labeled_image_get_label_dimensions (labeled_image); + + if (eel_dimensions_are_empty (image_dimensions)) + { + return eel_irect_empty; + } + + content_bounds = labeled_image_get_content_bounds (labeled_image); + + if (!labeled_image_show_label (labeled_image)) + { + image_bounds.x0 = + content_bounds.x0 + + (eel_irect_get_width (content_bounds) - image_dimensions.width) / 2; + image_bounds.y0 = + content_bounds.y0 + + (eel_irect_get_height (content_bounds) - image_dimensions.height) / 2; + } + else + { + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + image_bounds.x0 = content_bounds.x1 - image_dimensions.width; + image_bounds.y0 = + content_bounds.y0 + + (eel_irect_get_height (content_bounds) - image_dimensions.height) / 2; + break; + + case GTK_POS_RIGHT: + image_bounds.x0 = content_bounds.x0; + image_bounds.y0 = + content_bounds.y0 + + (eel_irect_get_height (content_bounds) - image_dimensions.height) / 2; + break; + + case GTK_POS_TOP: + image_bounds.x0 = + content_bounds.x0 + + (eel_irect_get_width (content_bounds) - image_dimensions.width) / 2; + image_bounds.y0 = content_bounds.y1 - image_dimensions.height; + break; + + case GTK_POS_BOTTOM: + image_bounds.x0 = + content_bounds.x0 + + (eel_irect_get_width (content_bounds) - image_dimensions.width) / 2; + + if (is_fixed_height (labeled_image)) + { + image_bounds.y0 = content_bounds.y0 + eel_irect_get_height (content_bounds) + - image_dimensions.height + - label_dimensions.height + - labeled_image->details->spacing; + } + else + { + image_bounds.y0 = content_bounds.y0; + } + + break; + + default: + image_bounds.x0 = 0; + image_bounds.y0 = 0; + g_assert_not_reached (); + } + } + + image_bounds.x1 = image_bounds.x0 + image_dimensions.width; + image_bounds.y1 = image_bounds.y0 + image_dimensions.height; + + return image_bounds; +} + +static EelIRect +labeled_image_get_label_bounds_fill (const EelLabeledImage *labeled_image) +{ + EelIRect label_bounds; + EelDimensions label_dimensions; + EelIRect content_bounds; + EelIRect bounds; + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + label_dimensions = labeled_image_get_label_dimensions (labeled_image); + + if (eel_dimensions_are_empty (label_dimensions)) + { + return eel_irect_empty; + } + + content_bounds = labeled_image_get_content_bounds (labeled_image); + bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (labeled_image)); + + /* Only the label is shown */ + if (!labeled_image_show_image (labeled_image)) + { + label_bounds = bounds; + /* Both label and image are shown */ + } + else + { + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + label_bounds.y0 = bounds.y0; + label_bounds.x0 = bounds.x0; + label_bounds.y1 = bounds.y1; + label_bounds.x1 = content_bounds.x0 + label_dimensions.width; + break; + + case GTK_POS_RIGHT: + label_bounds.y0 = bounds.y0; + label_bounds.x0 = content_bounds.x1 - label_dimensions.width; + label_bounds.y1 = bounds.y1; + label_bounds.x1 = bounds.x1; + break; + + case GTK_POS_TOP: + label_bounds.x0 = bounds.x0; + label_bounds.y0 = bounds.y0; + label_bounds.x1 = bounds.x1; + label_bounds.y1 = content_bounds.y0 + label_dimensions.height; + break; + + case GTK_POS_BOTTOM: + label_bounds.x0 = bounds.x0; + label_bounds.y0 = content_bounds.y1 - label_dimensions.height; + label_bounds.x1 = bounds.x1; + label_bounds.y1 = bounds.y1; + break; + + default: + label_bounds.x0 = 0; + label_bounds.y0 = 0; + label_bounds.x1 = 0; + label_bounds.y1 = 0; + g_assert_not_reached (); + } + } + + return label_bounds; +} + +EelIRect +eel_labeled_image_get_label_bounds (const EelLabeledImage *labeled_image) +{ + EelIRect label_bounds; + EelDimensions label_dimensions; + EelIRect content_bounds; + + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), eel_irect_empty); + + if (labeled_image->details->fill) + { + return labeled_image_get_label_bounds_fill (labeled_image); + } + + label_dimensions = labeled_image_get_label_dimensions (labeled_image); + + if (eel_dimensions_are_empty (label_dimensions)) + { + return eel_irect_empty; + } + + content_bounds = labeled_image_get_content_bounds (labeled_image); + + /* Only the label is shown */ + if (!labeled_image_show_image (labeled_image)) + { + label_bounds.x0 = + content_bounds.x0 + + (eel_irect_get_width (content_bounds) - label_dimensions.width) / 2; + label_bounds.y0 = + content_bounds.y0 + + (eel_irect_get_height (content_bounds) - label_dimensions.height) / 2; + /* Both label and image are shown */ + } + else + { + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + label_bounds.x0 = content_bounds.x0; + label_bounds.y0 = + content_bounds.y0 + + (eel_irect_get_height (content_bounds) - label_dimensions.height) / 2; + break; + + case GTK_POS_RIGHT: + label_bounds.x0 = content_bounds.x1 - label_dimensions.width; + label_bounds.y0 = + content_bounds.y0 + + (eel_irect_get_height (content_bounds) - label_dimensions.height) / 2; + break; + + case GTK_POS_TOP: + label_bounds.x0 = + content_bounds.x0 + + (eel_irect_get_width (content_bounds) - label_dimensions.width) / 2; + label_bounds.y0 = content_bounds.y0; + break; + + case GTK_POS_BOTTOM: + label_bounds.x0 = + content_bounds.x0 + + (eel_irect_get_width (content_bounds) - label_dimensions.width) / 2; + label_bounds.y0 = content_bounds.y1 - label_dimensions.height; + break; + + default: + label_bounds.x0 = 0; + label_bounds.y0 = 0; + g_assert_not_reached (); + } + } + + label_bounds.x1 = label_bounds.x0 + label_dimensions.width; + label_bounds.y1 = label_bounds.y0 + label_dimensions.height; + + return label_bounds; +} + +static void +labeled_image_update_alignments (EelLabeledImage *labeled_image) +{ + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->label != NULL) + { + float x_alignment; + float y_alignment; + + if (labeled_image->details->fill) + { + gtk_misc_get_alignment (GTK_MISC (labeled_image->details->label), + &x_alignment, &y_alignment); + + /* Only the label is shown */ + if (!labeled_image_show_image (labeled_image)) + { + x_alignment = 0.5; + y_alignment = 0.5; + /* Both label and image are shown */ + } + else + { + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + x_alignment = 1.0; + y_alignment = 0.5; + break; + + case GTK_POS_RIGHT: + x_alignment = 0.0; + y_alignment = 0.5; + break; + + case GTK_POS_TOP: + x_alignment = 0.5; + y_alignment = 1.0; + break; + + case GTK_POS_BOTTOM: + x_alignment = 0.5; + y_alignment = 0.0; + break; + } + + } + + gtk_misc_set_alignment (GTK_MISC (labeled_image->details->label), + x_alignment, + y_alignment); + } + } + + if (labeled_image->details->image != NULL) + { + float x_alignment; + float y_alignment; + + if (labeled_image->details->fill) + { + gtk_misc_get_alignment (GTK_MISC (labeled_image->details->image), + &x_alignment, &y_alignment); + + /* Only the image is shown */ + if (!labeled_image_show_label (labeled_image)) + { + x_alignment = 0.5; + y_alignment = 0.5; + /* Both label and image are shown */ + } + else + { + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + x_alignment = 0.0; + y_alignment = 0.5; + break; + + case GTK_POS_RIGHT: + x_alignment = 1.0; + y_alignment = 0.5; + break; + + case GTK_POS_TOP: + x_alignment = 0.5; + y_alignment = 0.0; + break; + + case GTK_POS_BOTTOM: + x_alignment = 0.5; + y_alignment = 1.0; + break; + } + } + + gtk_misc_set_alignment (GTK_MISC (labeled_image->details->image), + x_alignment, + y_alignment); + } + } +} + +static EelDimensions +labeled_image_get_content_dimensions (const EelLabeledImage *labeled_image) +{ + EelDimensions image_dimensions; + EelDimensions label_dimensions; + EelDimensions content_dimensions; + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + image_dimensions = labeled_image_get_image_dimensions (labeled_image); + label_dimensions = labeled_image_get_label_dimensions (labeled_image); + + content_dimensions = eel_dimensions_empty; + + /* Both shown */ + if (!eel_dimensions_are_empty (image_dimensions) && !eel_dimensions_are_empty (label_dimensions)) + { + content_dimensions.width = + image_dimensions.width + labeled_image->details->spacing + label_dimensions.width; + switch (labeled_image->details->label_position) + { + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + content_dimensions.width = + image_dimensions.width + labeled_image->details->spacing + label_dimensions.width; + content_dimensions.height = MAX (image_dimensions.height, label_dimensions.height); + break; + + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + content_dimensions.width = MAX (image_dimensions.width, label_dimensions.width); + content_dimensions.height = + image_dimensions.height + labeled_image->details->spacing + label_dimensions.height; + break; + } + /* Only image shown */ + } + else if (!eel_dimensions_are_empty (image_dimensions)) + { + content_dimensions.width = image_dimensions.width; + content_dimensions.height = image_dimensions.height; + /* Only label shown */ + } + else + { + content_dimensions.width = label_dimensions.width; + content_dimensions.height = label_dimensions.height; + } + + return content_dimensions; +} + +static EelIRect +labeled_image_get_content_bounds (const EelLabeledImage *labeled_image) +{ + EelDimensions content_dimensions; + EelIRect content_bounds; + EelIRect bounds; + + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (labeled_image)); + + content_dimensions = labeled_image_get_content_dimensions (labeled_image); + content_bounds = eel_irect_align (bounds, + content_dimensions.width, + content_dimensions.height, + labeled_image->details->x_alignment, + labeled_image->details->y_alignment); + + return content_bounds; +} + +static void +labeled_image_ensure_label (EelLabeledImage *labeled_image) +{ + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->label != NULL) + { + return; + } + + labeled_image->details->label = gtk_label_new (NULL); + gtk_container_add (GTK_CONTAINER (labeled_image), labeled_image->details->label); + gtk_widget_show (labeled_image->details->label); +} + +static void +labeled_image_ensure_image (EelLabeledImage *labeled_image) +{ + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->image != NULL) + { + return; + } + + labeled_image->details->image = gtk_image_new (); + gtk_container_add (GTK_CONTAINER (labeled_image), labeled_image->details->image); + gtk_widget_show (labeled_image->details->image); +} + +static gboolean +labeled_image_show_image (const EelLabeledImage *labeled_image) +{ + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + return labeled_image->details->image != NULL && labeled_image->details->show_image; +} + +static gboolean +labeled_image_show_label (const EelLabeledImage *labeled_image) +{ + g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); + + return labeled_image->details->label != NULL && labeled_image->details->show_label; +} + +/** + * eel_labeled_image_new: + * @text: Text to use for label or NULL. + * @pixbuf: Pixbuf to use for image or NULL. + * + * Returns A newly allocated EelLabeledImage. If the &text parameter is not + * NULL then the LabeledImage will show a label. If the &pixbuf parameter is not + * NULL then the LabeledImage will show a pixbuf. Either of these can be NULL at + * creation time. + * + * Later in the lifetime of the widget you can invoke methods that affect the + * label and/or the image. If at creation time these were NULL, then they will + * be created as neeeded. + * + * Thus, using this widget in place of EelImage or EelLabel is "free" with + * only the GtkObject and function call overhead. + * + */ +GtkWidget* +eel_labeled_image_new (const char *text, + GdkPixbuf *pixbuf) +{ + EelLabeledImage *labeled_image; + + labeled_image = EEL_LABELED_IMAGE (gtk_widget_new (eel_labeled_image_get_type (), NULL)); + + if (text != NULL) + { + eel_labeled_image_set_text (labeled_image, text); + } + + if (pixbuf != NULL) + { + eel_labeled_image_set_pixbuf (labeled_image, pixbuf); + } + + labeled_image_update_alignments (labeled_image); + + return GTK_WIDGET (labeled_image); +} + +/** + * eel_labeled_image_new_from_file_name: + * @text: Text to use for label or NULL. + * @file_name: File name of picture to use for pixbuf. Cannot be NULL. + * + * Returns A newly allocated EelLabeledImage. If the &text parameter is not + * NULL then the LabeledImage will show a label. + * + */ +GtkWidget* +eel_labeled_image_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + EelLabeledImage *labeled_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + labeled_image = EEL_LABELED_IMAGE (eel_labeled_image_new (text, NULL)); + eel_labeled_image_set_pixbuf_from_file_name (labeled_image, pixbuf_file_name); + return GTK_WIDGET (labeled_image); +} + +/** + * eel_labeled_image_set_label_position: + * @labeled_image: A EelLabeledImage. + * @label_position: The position of the label with respect to the image. + * + * Set the position of the label with respect to the image as follows: + * + * GTK_POS_LEFT: + * [ <label> <image> ] + * + * GTK_POS_RIGHT: + * [ <image> <label> ] + * + * GTK_POS_TOP: + * [ <label> ] + * [ <image> ] + * + * GTK_POS_BOTTOM: + * [ <image> ] + * [ <label> ] + * + */ +void +eel_labeled_image_set_label_position (EelLabeledImage *labeled_image, + GtkPositionType label_position) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + g_return_if_fail (label_position >= GTK_POS_LEFT); + g_return_if_fail (label_position <= GTK_POS_BOTTOM); + + if (labeled_image->details->label_position == label_position) + { + return; + } + + labeled_image->details->label_position = label_position; + + labeled_image_update_alignments (labeled_image); + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_label_postiion: + * @labeled_image: A EelLabeledImage. + * + * Returns an enumeration indicating the position of the label with respect to the image. + */ +GtkPositionType +eel_labeled_image_get_label_position (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->label_position; +} + +/** + * eel_labeled_image_set_show_label: + * @labeled_image: A EelLabeledImage. + * @show_image: A boolean value indicating whether the label should be shown. + * + * Update the labeled image to either show or hide the internal label widget. + * This function doesnt have any effect if the LabeledImage doesnt already + * contain an label. + */ +void +eel_labeled_image_set_show_label (EelLabeledImage *labeled_image, + gboolean show_label) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->show_label == show_label) + { + return; + } + + labeled_image->details->show_label = show_label; + + if (labeled_image->details->label != NULL) + { + if (labeled_image->details->show_label) + { + gtk_widget_show (labeled_image->details->label); + } + else + { + gtk_widget_hide (labeled_image->details->label); + } + } + + labeled_image_update_alignments (labeled_image); + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_show_label: + * @labeled_image: A EelLabeledImage. + * + * Returns a boolean value indicating whether the internal label is shown. + */ +gboolean +eel_labeled_image_get_show_label (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->show_label; +} + +/** + * eel_labeled_image_set_show_image: + * @labeled_image: A EelLabeledImage. + * @show_image: A boolean value indicating whether the image should be shown. + * + * Update the labeled image to either show or hide the internal image widget. + * This function doesnt have any effect if the LabeledImage doesnt already + * contain an image. + */ +void +eel_labeled_image_set_show_image (EelLabeledImage *labeled_image, + gboolean show_image) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->show_image == show_image) + { + return; + } + + labeled_image->details->show_image = show_image; + + if (labeled_image->details->image != NULL) + { + if (labeled_image->details->show_image) + { + gtk_widget_show (labeled_image->details->image); + } + else + { + gtk_widget_hide (labeled_image->details->image); + } + } + + labeled_image_update_alignments (labeled_image); + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_show_image: + * @labeled_image: A EelLabeledImage. + * + * Returns a boolean value indicating whether the internal image is shown. + */ +gboolean +eel_labeled_image_get_show_image (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->show_image; +} + + +/** + * eel_labeled_image_set_fixed_image_height: + * @labeled_image: A EelLabeledImage. + * @fixed_image_height: The new fixed image height. + * + * Normally, we measure the height of images, but it's sometimes useful + * to use a fixed height for all the images. This routine sets the + * image height to the passed in value + * + */ +void +eel_labeled_image_set_fixed_image_height (EelLabeledImage *labeled_image, + int new_height) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->fixed_image_height == new_height) + { + return; + } + + labeled_image->details->fixed_image_height = new_height; + + labeled_image_update_alignments (labeled_image); + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_set_selected: + * @labeled_image: A EelLabeledImage. + * @selected: A boolean value indicating whether the labeled image + * should be selected. + * + * Selects or deselects the labeled image. + * + */ +void +eel_labeled_image_set_selected (EelLabeledImage *labeled_image, + gboolean selected) +{ + GtkStateType state; + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + state = selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL; + + gtk_widget_set_state (GTK_WIDGET (labeled_image), state); + gtk_widget_set_state (labeled_image->details->image, state); + gtk_widget_set_state (labeled_image->details->label, state); +} + +/** + * eel_labeled_image_get_selected: + * @labeled_image: A EelLabeledImage. + * + * Returns the selected state of the labeled image. + * + */ +gboolean +eel_labeled_image_get_selected (EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), FALSE); + + return gtk_widget_get_state (GTK_WIDGET (labeled_image)) == GTK_STATE_SELECTED; +} + +/** + * eel_labeled_image_set_spacing: + * @labeled_image: A EelLabeledImage. + * @spacing: The new spacing between label and image. + * + * Set the spacing between label and image. This will only affect + * the geometry of the widget if both a label and image are currently + * visible. + * + */ +void +eel_labeled_image_set_spacing (EelLabeledImage *labeled_image, + guint spacing) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->spacing == spacing) + { + return; + } + + labeled_image->details->spacing = spacing; + + labeled_image_update_alignments (labeled_image); + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_spacing: + * @labeled_image: A EelLabeledImage. + * + * Returns: The spacing between the label and image. + */ +guint +eel_labeled_image_get_spacing (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->spacing; +} + +/** + * eel_labeled_image_set_x_padding: + * @labeled_image: A EelLabeledImage. + * @x_padding: The new horizontal padding. + * + * Set horizontal padding for the EelLabeledImage. The padding + * attribute work just like that in GtkMisc. + */ +void +eel_labeled_image_set_x_padding (EelLabeledImage *labeled_image, + int x_padding) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + x_padding = MAX (0, x_padding); + + if (labeled_image->details->x_padding == x_padding) + { + return; + } + + labeled_image->details->x_padding = x_padding; + labeled_image_update_alignments (labeled_image); + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_x_padding: + * @labeled_image: A EelLabeledImage. + * + * Returns: The horizontal padding for the LabeledImage's content. + */ +int +eel_labeled_image_get_x_padding (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->x_padding; +} + +/** + * eel_labeled_image_set_y_padding: + * @labeled_image: A EelLabeledImage. + * @x_padding: The new vertical padding. + * + * Set vertical padding for the EelLabeledImage. The padding + * attribute work just like that in GtkMisc. + */ +void +eel_labeled_image_set_y_padding (EelLabeledImage *labeled_image, + int y_padding) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + y_padding = MAX (0, y_padding); + + if (labeled_image->details->y_padding == y_padding) + { + return; + } + + labeled_image->details->y_padding = y_padding; + labeled_image_update_alignments (labeled_image); + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_x_padding: + * @labeled_image: A EelLabeledImage. + * + * Returns: The vertical padding for the LabeledImage's content. + */ +int +eel_labeled_image_get_y_padding (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->y_padding; +} + +/** + * eel_labeled_image_set_x_alignment: + * @labeled_image: A EelLabeledImage. + * @x_alignment: The new horizontal alignment. + * + * Set horizontal alignment for the EelLabeledImage's content. + * The 'content' is the union of the image and label. The alignment + * attribute work just like that in GtkMisc. + */ +void +eel_labeled_image_set_x_alignment (EelLabeledImage *labeled_image, + float x_alignment) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + x_alignment = MAX (0, x_alignment); + x_alignment = MIN (1.0, x_alignment); + + if (labeled_image->details->x_alignment == x_alignment) + { + return; + } + + labeled_image->details->x_alignment = x_alignment; + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_x_alignment: + * @labeled_image: A EelLabeledImage. + * + * Returns: The horizontal alignment for the LabeledImage's content. + */ +float +eel_labeled_image_get_x_alignment (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->x_alignment; +} + +/** + * eel_labeled_image_set_y_alignment: + * @labeled_image: A EelLabeledImage. + * @y_alignment: The new vertical alignment. + * + * Set vertical alignment for the EelLabeledImage's content. + * The 'content' is the union of the image and label. The alignment + * attribute work just like that in GtkMisc. + */ +void +eel_labeled_image_set_y_alignment (EelLabeledImage *labeled_image, + float y_alignment) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + y_alignment = MAX (0, y_alignment); + y_alignment = MIN (1.0, y_alignment); + + if (labeled_image->details->y_alignment == y_alignment) + { + return; + } + + labeled_image->details->y_alignment = y_alignment; + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_y_alignment: + * @labeled_image: A EelLabeledImage. + * + * Returns: The vertical alignment for the LabeledImage's content. + */ +float +eel_labeled_image_get_y_alignment (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->y_alignment; +} + +/** + * eel_labeled_image_set_fill: + * @labeled_image: A EelLabeledImage. + * @fill: A boolean value indicating whether the internal image and label + * widgets should fill all the available allocation. + * + * By default the internal image and label wigets are sized to their natural + * preferred geometry. You can use the 'fill' attribute of LabeledImage + * to have the internal widgets fill as much of the LabeledImage allocation + * as is available. + */ +void +eel_labeled_image_set_fill (EelLabeledImage *labeled_image, + gboolean fill) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->fill == fill) + { + return; + } + + labeled_image->details->fill = fill; + + labeled_image_update_alignments (labeled_image); + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); +} + +/** + * eel_labeled_image_get_fill: + * @labeled_image: A EelLabeledImage. + * + * Retruns a boolean value indicating whether the internal widgets fill + * all the available allocation. + */ +gboolean +eel_labeled_image_get_fill (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), 0); + + return labeled_image->details->fill; +} + +static void +eel_labled_set_mnemonic_widget (GtkWidget *image_widget, + GtkWidget *mnemonic_widget) +{ + EelLabeledImage *image; + + g_assert (EEL_IS_LABELED_IMAGE (image_widget)); + + image = EEL_LABELED_IMAGE (image_widget); + + if (image->details->label) + gtk_label_set_mnemonic_widget + (GTK_LABEL (image->details->label), mnemonic_widget); +} + +/** + * eel_labeled_image_button_new: + * @text: Text to use for label or NULL. + * @pixbuf: Pixbuf to use for image or NULL. + * + * Create a stock GtkButton with a EelLabeledImage child. + * + */ +GtkWidget * +eel_labeled_image_button_new (const char *text, + GdkPixbuf *pixbuf) +{ + GtkWidget *button; + GtkWidget *labeled_image; + + button = g_object_new (eel_labeled_image_button_get_type (), NULL); + labeled_image = eel_labeled_image_new (text, pixbuf); + gtk_container_add (GTK_CONTAINER (button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, button); + gtk_widget_show (labeled_image); + + return button; +} + +/** + * eel_labeled_image_button_new_from_file_name: + * @text: Text to use for label or NULL. + * @pixbuf_file_name: Name of pixbuf to use for image. Cannot be NULL. + * + * Create a stock GtkToggleButton with a EelLabeledImage child. + * + */ +GtkWidget * +eel_labeled_image_button_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + GtkWidget *button; + GtkWidget *labeled_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + button = g_object_new (eel_labeled_image_button_get_type (), NULL); + labeled_image = eel_labeled_image_new_from_file_name (text, pixbuf_file_name); + gtk_container_add (GTK_CONTAINER (button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, button); + gtk_widget_show (labeled_image); + + return button; +} + +/** + * eel_labeled_image_toggle_button_new: + * @text: Text to use for label or NULL. + * @pixbuf: Pixbuf to use for image or NULL. + * + * Create a stock GtkToggleButton with a EelLabeledImage child. + * + */ +GtkWidget * +eel_labeled_image_toggle_button_new (const char *text, + GdkPixbuf *pixbuf) +{ + GtkWidget *toggle_button; + GtkWidget *labeled_image; + + toggle_button = g_object_new (eel_labeled_image_toggle_button_get_type (), NULL); + labeled_image = eel_labeled_image_new (text, pixbuf); + gtk_container_add (GTK_CONTAINER (toggle_button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, toggle_button); + gtk_widget_show (labeled_image); + + return toggle_button; +} + +/** + * eel_labeled_image_toggle_button_new_from_file_name: + * @text: Text to use for label or NULL. + * @pixbuf_file_name: Name of pixbuf to use for image. Cannot be NULL. + * + * Create a stock GtkToggleButton with a EelLabeledImage child. + * + */ +GtkWidget * +eel_labeled_image_toggle_button_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + GtkWidget *toggle_button; + GtkWidget *labeled_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + toggle_button = g_object_new (eel_labeled_image_toggle_button_get_type (), NULL); + labeled_image = eel_labeled_image_new_from_file_name (text, pixbuf_file_name); + gtk_container_add (GTK_CONTAINER (toggle_button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, toggle_button); + gtk_widget_show (labeled_image); + + return toggle_button; +} + +/** + * eel_labeled_image_toggle_button_new: + * @text: Text to use for label or NULL. + * @pixbuf: Pixbuf to use for image or NULL. + * + * Create a stock GtkToggleButton with a EelLabeledImage child. + * + * Returns: the new radio button. + */ +GtkWidget * +eel_labeled_image_radio_button_new (const char *text, + GdkPixbuf *pixbuf) +{ + GtkWidget *radio_button; + GtkWidget *labeled_image; + + radio_button = g_object_new (eel_labeled_image_radio_button_get_type (), NULL); + labeled_image = eel_labeled_image_new (text, pixbuf); + gtk_container_add (GTK_CONTAINER (radio_button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, radio_button); + gtk_widget_show (labeled_image); + + return radio_button; +} + +/** + * eel_labeled_image_radio_button_new_from_file_name: + * @text: Text to use for label or NULL. + * @pixbuf_file_name: Name of pixbuf to use for image. Cannot be NULL. + * + * Create a stock GtkRadioButton with a EelLabeledImage child. + * + * Returns: the new radio button. + */ +GtkWidget * +eel_labeled_image_radio_button_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + GtkWidget *radio_button; + GtkWidget *labeled_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + radio_button = g_object_new (eel_labeled_image_radio_button_get_type (), NULL); + labeled_image = eel_labeled_image_new_from_file_name (text, pixbuf_file_name); + gtk_container_add (GTK_CONTAINER (radio_button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, radio_button); + gtk_widget_show (labeled_image); + + return radio_button; +} + +/* + * Workaround some bugs in GtkCheckButton where the widget + * does not redraw properly after leave or focus out events + * + * The workaround is to draw a little bit more than the + * widget itself - 4 pixels worth. For some reason the + * widget does not properly redraw its edges. + */ +static void +button_leave_callback (GtkWidget *widget, + gpointer callback_data) +{ + g_assert (GTK_IS_WIDGET (widget)); + + if (gtk_widget_is_drawable (widget)) + { + const int fudge = 4; + EelIRect bounds; + + bounds = eel_gtk_widget_get_bounds (widget); + + bounds.x0 -= fudge; + bounds.y0 -= fudge; + bounds.x1 += fudge; + bounds.y1 += fudge; + + gtk_widget_queue_draw_area (gtk_widget_get_parent (widget), + bounds.x0, + bounds.y0, + eel_irect_get_width (bounds), + eel_irect_get_height (bounds)); + } +} + +static gint +button_focus_out_event_callback (GtkWidget *widget, + GdkEventFocus *event, + gpointer callback_data) +{ + g_assert (GTK_IS_WIDGET (widget)); + + button_leave_callback (widget, callback_data); + + return FALSE; +} + +/** + * eel_labeled_image_check_button_new: + * @text: Text to use for label or NULL. + * @pixbuf: Pixbuf to use for image or NULL. + * + * Create a stock GtkCheckButton with a EelLabeledImage child. + * + */ +GtkWidget * +eel_labeled_image_check_button_new (const char *text, + GdkPixbuf *pixbuf) +{ + GtkWidget *check_button; + GtkWidget *labeled_image; + + check_button = g_object_new (eel_labeled_image_check_button_get_type (), NULL); + labeled_image = eel_labeled_image_new (text, pixbuf); + gtk_container_add (GTK_CONTAINER (check_button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, check_button); + gtk_widget_show (labeled_image); + + /* + * Workaround some bugs in GtkCheckButton where the widget + * does not redraw properly after leave or focus out events + */ + g_signal_connect (check_button, "leave", + G_CALLBACK (button_leave_callback), NULL); + g_signal_connect (check_button, "focus_out_event", + G_CALLBACK (button_focus_out_event_callback), NULL); + + return check_button; +} + +/** + * eel_labeled_image_check_button_new_from_file_name: + * @text: Text to use for label or NULL. + * @pixbuf_file_name: Name of pixbuf to use for image. Cannot be NULL. + * + * Create a stock GtkCheckButton with a EelLabeledImage child. + * + */ +GtkWidget * +eel_labeled_image_check_button_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + GtkWidget *check_button; + GtkWidget *labeled_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + check_button = g_object_new (eel_labeled_image_check_button_get_type (), NULL); + labeled_image = eel_labeled_image_new_from_file_name (text, pixbuf_file_name); + gtk_container_add (GTK_CONTAINER (check_button), labeled_image); + eel_labled_set_mnemonic_widget (labeled_image, check_button); + gtk_widget_show (labeled_image); + + return check_button; +} + +/* + * The rest of the methods are proxies for those in EelImage and + * EelLabel. We have all these so that we dont have to expose + * our internal widgets at all. Probably more of these will be added + * as they are needed. + */ + +/** + * eel_labeled_image_set_pixbuf: + * @labaled_image: A EelLabeledImage. + * @pixbuf: New pixbuf to use or NULL. + * + * Change the pixbuf displayed by the LabeledImage. Note that the widget display + * is only updated if the show_image attribute is TRUE. + * + * If no internal image widget exists as of yet, a new one will be created. + * + * A NULL &pixbuf will cause the internal image widget (if alive) to be destroyed. + */ +void +eel_labeled_image_set_pixbuf (EelLabeledImage *labeled_image, + GdkPixbuf *pixbuf) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (pixbuf == NULL) + { + if (labeled_image->details->image != NULL) + { + gtk_widget_destroy (labeled_image->details->image); + labeled_image->details->image = NULL; + } + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); + } + else + { + labeled_image_ensure_image (labeled_image); + gtk_image_set_from_pixbuf (GTK_IMAGE (labeled_image->details->image), pixbuf); + } +} + +void +eel_labeled_image_set_pixbuf_from_file_name (EelLabeledImage *labeled_image, + const char *pixbuf_file_name) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + labeled_image_ensure_image (labeled_image); + gtk_image_set_from_file (GTK_IMAGE (labeled_image->details->image), pixbuf_file_name); +} + +/** + * eel_labeled_image_set_text: + * @labaled_image: A EelLabeledImage. + * @text: New text (with mnemnonic) to use or NULL. + * + * Change the text displayed by the LabeledImage. Note that the widget display + * is only updated if the show_label attribute is TRUE. + * + * If no internal label widget exists as of yet, a new one will be created. + * + * A NULL &text will cause the internal label widget (if alive) to be destroyed. + */ +void +eel_labeled_image_set_text (EelLabeledImage *labeled_image, + const char *text) +{ + g_return_if_fail (EEL_IS_LABELED_IMAGE (labeled_image)); + + if (text == NULL) + { + if (labeled_image->details->label) + { + gtk_widget_destroy (labeled_image->details->label); + labeled_image->details->label = NULL; + } + + gtk_widget_queue_resize (GTK_WIDGET (labeled_image)); + } + else + { + labeled_image_ensure_label (labeled_image); + gtk_label_set_text_with_mnemonic + (GTK_LABEL (labeled_image->details->label), text); + } +} + +char * +eel_labeled_image_get_text (const EelLabeledImage *labeled_image) +{ + g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), NULL); + + if (labeled_image->details->label == NULL) + { + return NULL; + } + + return g_strdup (gtk_label_get_text (GTK_LABEL (labeled_image->details->label))); +} + +void +eel_labeled_image_set_can_focus (EelLabeledImage *labeled_image, + gboolean can_focus) +{ + gtk_widget_set_can_focus (GTK_WIDGET (labeled_image), can_focus); +} + +static AtkObjectClass *a11y_parent_class = NULL; + +static void +eel_labeled_image_accessible_initialize (AtkObject *accessible, + gpointer widget) +{ + a11y_parent_class->initialize (accessible, widget); +} + +static EelLabeledImage * +get_image (gpointer object) +{ + GtkWidget *widget; + + if (!(widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (object)))) + { + return NULL; + } + + if (GTK_IS_BUTTON (widget)) + widget = gtk_bin_get_child (GTK_BIN (widget)); + + return EEL_LABELED_IMAGE (widget); +} + +static const gchar* eel_labeled_image_accessible_get_name(AtkObject* accessible) +{ + EelLabeledImage* labeled_image; + + labeled_image = get_image(accessible); + + if (labeled_image && labeled_image->details && labeled_image->details->label) + { + return gtk_label_get_text(GTK_LABEL(labeled_image->details->label)); + } + + g_warning("no label on '%p'", labeled_image); + + return NULL; +} + +static void +eel_labeled_image_accessible_image_get_size (AtkImage *image, + gint *width, + gint *height) +{ + EelLabeledImage *labeled_image; + GtkAllocation allocation; + + labeled_image = get_image (image); + + if (!labeled_image || !labeled_image->details->image) + { + *width = *height = 0; + return; + } + + gtk_widget_get_allocation (labeled_image->details->image, &allocation); + *width = allocation.width; + *height = allocation.height; +} + +static void +eel_labeled_image_accessible_image_interface_init (AtkImageIface *iface) +{ + iface->get_image_size = eel_labeled_image_accessible_image_get_size; +} + +static void +eel_labeled_image_accessible_class_init (AtkObjectClass *klass) +{ + a11y_parent_class = g_type_class_peek_parent (klass); + + klass->get_name = eel_labeled_image_accessible_get_name; + klass->initialize = eel_labeled_image_accessible_initialize; +} + +enum +{ + BUTTON, + CHECK, + TOGGLE, + RADIO, + PLAIN, + LAST_ONE +}; + +static AtkObject * +eel_labeled_image_get_accessible (GtkWidget *widget) +{ + int i; + static GType types[LAST_ONE] = { 0 }; + const char *tname; + AtkRole role; + AtkObject *accessible; + + if ((accessible = eel_accessibility_get_atk_object (widget))) + return accessible; + + if (GTK_IS_CHECK_BUTTON (widget)) + { + i = BUTTON; + role = ATK_ROLE_CHECK_BOX; + tname = "EelLabeledImageCheckButtonAccessible"; + + } + else if (GTK_IS_TOGGLE_BUTTON (widget)) + { + i = CHECK; + role = ATK_ROLE_TOGGLE_BUTTON; + tname = "EelLabeledImageToggleButtonAccessible"; + + } + else if (GTK_IS_RADIO_BUTTON (widget)) + { + i = RADIO; + role = ATK_ROLE_RADIO_BUTTON; + tname = "EelLabeledImageRadioButtonAccessible"; + + } + else if (GTK_IS_BUTTON (widget)) + { + i = TOGGLE; + role = ATK_ROLE_PUSH_BUTTON; + tname = "EelLabeledImagePushButtonAccessible"; + + } + else /* plain */ + { + i = PLAIN; + role = ATK_ROLE_IMAGE; + tname = "EelLabeledImagePlainAccessible"; + } + + if (!types [i]) + { + const GInterfaceInfo atk_image_info = + { + (GInterfaceInitFunc) eel_labeled_image_accessible_image_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + types [i] = eel_accessibility_create_derived_type + (tname, G_TYPE_FROM_INSTANCE (widget), + eel_labeled_image_accessible_class_init); + + if (!types [i]) + return NULL; + + g_type_add_interface_static ( + types [i], ATK_TYPE_IMAGE, &atk_image_info); + } + + accessible = g_object_new (types [i], NULL); + atk_object_set_role (accessible, role); + + return eel_accessibility_set_atk_object_return (widget, accessible); +} + +static void +eel_labeled_image_button_class_init (GtkWidgetClass *klass) +{ + klass->get_accessible = eel_labeled_image_get_accessible; +} + +static GType +eel_labeled_image_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + GTypeInfo info = + { + sizeof (GtkButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_labeled_image_button_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL + }; + + type = g_type_register_static + (GTK_TYPE_BUTTON, + "EelLabeledImageButton", &info, 0); + } + + return type; +} + +static GType +eel_labeled_image_check_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + GTypeInfo info = + { + sizeof (GtkCheckButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_labeled_image_button_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkCheckButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL + }; + + type = g_type_register_static + (GTK_TYPE_CHECK_BUTTON, + "EelLabeledImageCheckButton", &info, 0); + } + + return type; +} + +static GType +eel_labeled_image_toggle_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + GTypeInfo info = + { + sizeof (GtkToggleButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_labeled_image_button_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkToggleButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL + }; + + type = g_type_register_static + (GTK_TYPE_TOGGLE_BUTTON, + "EelLabeledImageToggleButton", &info, 0); + } + + return type; +} + + +static GType +eel_labeled_image_radio_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + GTypeInfo info = + { + sizeof (GtkRadioButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eel_labeled_image_button_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkRadioButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL + }; + + type = g_type_register_static + (GTK_TYPE_RADIO_BUTTON, + "EelLabeledImageRadioButton", &info, 0); + } + + return type; +} diff --git a/eel/eel-labeled-image.h b/eel/eel-labeled-image.h new file mode 100644 index 00000000..22058a0e --- /dev/null +++ b/eel/eel-labeled-image.h @@ -0,0 +1,166 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-labeled-image.h - A labeled image. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +/* EelLabeledImage is a container widget. It can only contain internal + * widgets. These internal widgets are can be a EelLabel and/or a + * EelImage. These internal widgets are created as needed. That means + * that EelLabeledImage can always be used for "free" instead of a + * EelLabel or EelImage. The only overhead is that of the GtkObject + * machinery. + * + * The position of the label with respect to the image is controlled by the + * 'label_positon' attribute. + * + * By default the internal image and label widgets are sized to their natural + * preferred geometry. You can use the 'fill' attribute of LabeledImage + * to have the internal widgets fill as much of the LabeledImage allocation + * as is available. + * + * LabeledImage also has x_padding/y_padding and x_alignment/y_alignment + * attributes that behave exaclty as those in the GtkMisc class. + * + * Note that the alignments are ignored if the fill attribute is TRUE. + */ + +#ifndef EEL_LABELED_IMAGE_H +#define EEL_LABELED_IMAGE_H + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtk.h> +#include <eel/eel-art-extensions.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_TYPE_LABELED_IMAGE eel_labeled_image_get_type() +#define EEL_LABELED_IMAGE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_LABELED_IMAGE, EelLabeledImage)) +#define EEL_LABELED_IMAGE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_LABELED_IMAGE, EelLabeledImageClass)) +#define EEL_IS_LABELED_IMAGE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_LABELED_IMAGE)) +#define EEL_IS_LABELED_IMAGE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_LABELED_IMAGE)) +#define EEL_LABELED_IMAGE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_LABELED_IMAGE, EelLabeledImageClass)) + + typedef struct EelLabeledImage EelLabeledImage; + typedef struct EelLabeledImageClass EelLabeledImageClass; + typedef struct EelLabeledImageDetails EelLabeledImageDetails; + + struct EelLabeledImage + { + /* Superclass */ + GtkContainer container; + + /* Private things */ + EelLabeledImageDetails *details; + }; + + struct EelLabeledImageClass + { + GtkContainerClass parent_class; + + void (*activate) (EelLabeledImage *image); + }; + + /* Public GtkLabeledImage methods */ + GType eel_labeled_image_get_type (void); + GtkWidget * eel_labeled_image_new (const char *text, + GdkPixbuf *pixbuf); + GtkWidget * eel_labeled_image_new_from_file_name (const char *text, + const char *pixbuf_file_name); + void eel_labeled_image_set_label_position (EelLabeledImage *labeled_image, + GtkPositionType label_position); + GtkPositionType eel_labeled_image_get_label_position (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_show_label (EelLabeledImage *labeled_image, + gboolean show_label); + gboolean eel_labeled_image_get_show_label (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_show_image (EelLabeledImage *labeled_image, + gboolean show_image); + gboolean eel_labeled_image_get_show_image (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_can_focus (EelLabeledImage *labeled_image, + gboolean can_focus); + void eel_labeled_image_set_spacing (EelLabeledImage *labeled_image, + guint spacing); + guint eel_labeled_image_get_spacing (const EelLabeledImage *labeled_image); + int eel_labeled_image_get_x_padding (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_x_padding (EelLabeledImage *labeled_image, + int x_padding); + int eel_labeled_image_get_y_padding (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_y_padding (EelLabeledImage *labeled_image, + int y_padding); + float eel_labeled_image_get_x_alignment (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_x_alignment (EelLabeledImage *labeled_image, + float x_alignment); + float eel_labeled_image_get_y_alignment (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_y_alignment (EelLabeledImage *labeled_image, + float y_alignment); + void eel_labeled_image_set_fill (EelLabeledImage *labeled_image, + gboolean fill); + gboolean eel_labeled_image_get_fill (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_fixed_image_height (EelLabeledImage *labeled_image, + int fixed_image_height); + void eel_labeled_image_set_selected (EelLabeledImage *labeled_image, + gboolean selected); + gboolean eel_labeled_image_get_selected (EelLabeledImage *labeled_image); + + /* Functions for creating stock GtkButtons with a labeled image child */ + GtkWidget * eel_labeled_image_button_new (const char *text, + GdkPixbuf *pixbuf); + GtkWidget * eel_labeled_image_button_new_from_file_name (const char *text, + const char *pixbuf_file_name); + GtkWidget * eel_labeled_image_toggle_button_new (const char *text, + GdkPixbuf *pixbuf); + GtkWidget * eel_labeled_image_toggle_button_new_from_file_name (const char *text, + const char *pixbuf_file_name); + GtkWidget * eel_labeled_image_check_button_new (const char *text, + GdkPixbuf *pixbuf); + GtkWidget * eel_labeled_image_check_button_new_from_file_name (const char *text, + const char *pixbuf_file_name); + GtkWidget * eel_labeled_image_radio_button_new (const char *text, + GdkPixbuf *pixbuf); + GtkWidget * eel_labeled_image_radio_button_new_from_file_name (const char *text, + const char *pixbuf_file_name); + + /* These are proxies for methods in EelImage and EelLabel */ + void eel_labeled_image_set_pixbuf (EelLabeledImage *labeled_image, + GdkPixbuf *pixbuf); + void eel_labeled_image_set_pixbuf_from_file_name (EelLabeledImage *labeled_image, + const char *pixbuf_file_name); + GdkPixbuf* eel_labeled_image_get_pixbuf (const EelLabeledImage *labeled_image); + void eel_labeled_image_set_text (EelLabeledImage *labeled_image, + const char *text); + char* eel_labeled_image_get_text (const EelLabeledImage *labeled_image); + EelIRect eel_labeled_image_get_image_bounds (const EelLabeledImage *labeled_image); + EelIRect eel_labeled_image_get_label_bounds (const EelLabeledImage *labeled_image); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_LABELED_IMAGE_H */ + + diff --git a/eel/eel-lib-self-check-functions.c b/eel/eel-lib-self-check-functions.c new file mode 100644 index 00000000..89ea2c7c --- /dev/null +++ b/eel/eel-lib-self-check-functions.c @@ -0,0 +1,38 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-lib-self-check-functions.c: Wrapper for all self check functions + in Eel proper. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#include <config.h> + +#if ! defined (EEL_OMIT_SELF_CHECK) + +#include "eel-lib-self-check-functions.h" + +void +eel_run_lib_self_checks (void) +{ + EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION (EEL_CALL_SELF_CHECK_FUNCTION) +} + +#endif /* ! EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-lib-self-check-functions.h b/eel/eel-lib-self-check-functions.h new file mode 100644 index 00000000..6a103171 --- /dev/null +++ b/eel/eel-lib-self-check-functions.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-lib-self-check-functions.h: Wrapper and prototypes for all + self-check functions in libeel. + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#include "eel-self-checks.h" + +void eel_run_lib_self_checks (void); + +/* Putting the prototypes for these self-check functions in each + header file for the files they are defined in would make compiling + the self-check framework take way too long (since one file would + have to include everything). + + So we put the list of functions here instead. + + Instead of just putting prototypes here, we put this macro that + can be used to do operations on the whole list of functions. +*/ + +#define EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \ + macro (eel_self_check_background) \ + macro (eel_self_check_enumeration) \ + macro (eel_self_check_gdk_extensions) \ + macro (eel_self_check_gdk_pixbuf_extensions) \ + macro (eel_self_check_glib_extensions) \ + macro (eel_self_check_pango_extensions) \ + macro (eel_self_check_preferences) \ + macro (eel_self_check_string) \ +/* Add new self-check functions to the list above this line. */ + +/* Generate prototypes for all the functions. */ +EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION (EEL_SELF_CHECK_FUNCTION_PROTOTYPE) diff --git a/eel/eel-mate-extensions.c b/eel/eel-mate-extensions.c new file mode 100644 index 00000000..212abefc --- /dev/null +++ b/eel/eel-mate-extensions.c @@ -0,0 +1,221 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-mate-extensions.c - implementation of new functions that operate on + mate classes. Perhaps some of these should be + rolled into mate someday. + + Copyright (C) 1999, 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#include <config.h> + +#define MATE_DESKTOP_USE_UNSTABLE_API + +#include "eel-mate-extensions.h" +#include "eel-art-extensions.h" +#include "eel-gdk-extensions.h" +#include "eel-glib-extensions.h" +#include "eel-gtk-extensions.h" +#include "eel-stock-dialogs.h" +#include "eel-i18n.h" +#include <X11/Xatom.h> +#include <errno.h> +#include <fcntl.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include <libmate/mate-desktop-utils.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> + +/* Return a command string containing the path to a terminal on this system. */ + +static char * +try_terminal_command (const char *program, + const char *args) +{ + char *program_in_path, *quoted, *result; + + if (program == NULL) + { + return NULL; + } + + program_in_path = g_find_program_in_path (program); + if (program_in_path == NULL) + { + return NULL; + } + + quoted = g_shell_quote (program_in_path); + if (args == NULL || args[0] == '\0') + { + return quoted; + } + result = g_strconcat (quoted, " ", args, NULL); + g_free (quoted); + return result; +} + +static char * +try_terminal_command_argv (int argc, + char **argv) +{ + GString *string; + int i; + char *quoted, *result; + + if (argc == 0) + { + return NULL; + } + + if (argc == 1) + { + return try_terminal_command (argv[0], NULL); + } + + string = g_string_new (argv[1]); + for (i = 2; i < argc; i++) + { + quoted = g_shell_quote (argv[i]); + g_string_append_c (string, ' '); + g_string_append (string, quoted); + g_free (quoted); + } + result = try_terminal_command (argv[0], string->str); + g_string_free (string, TRUE); + + return result; +} + +static char * +get_terminal_command_prefix (gboolean for_command) +{ + int argc; + char **argv; + char *command; + guint i; + static const char *const commands[][3] = + { + { "mate-terminal", "-x", "" }, + { "dtterm", "-e", "-ls" }, + { "nxterm", "-e", "-ls" }, + { "color-xterm", "-e", "-ls" }, + { "rxvt", "-e", "-ls" }, + { "xterm", "-e", "-ls" }, + }; + + /* Try the terminal from preferences. Use without any + * arguments if we are just doing a standalone terminal. + */ + argc = 0; + argv = g_new0 (char *, 1); + mate_desktop_prepend_terminal_to_vector (&argc, &argv); + + command = NULL; + if (argc != 0) + { + if (for_command) + { + command = try_terminal_command_argv (argc, argv); + } + else + { + /* Strip off the arguments in a lame attempt + * to make it be an interactive shell. + */ + command = try_terminal_command (argv[0], NULL); + } + } + + while (argc != 0) + { + g_free (argv[--argc]); + } + g_free (argv); + + if (command != NULL) + { + return command; + } + + /* Try well-known terminal applications in same order that gmc did. */ + for (i = 0; i < G_N_ELEMENTS (commands); i++) + { + command = try_terminal_command (commands[i][0], + commands[i][for_command ? 1 : 2]); + if (command != NULL) + { + break; + } + } + + return command; +} + +char * +eel_mate_make_terminal_command (const char *command) +{ + char *prefix, *quoted, *terminal_command; + + if (command == NULL) + { + return get_terminal_command_prefix (FALSE); + } + prefix = get_terminal_command_prefix (TRUE); + quoted = g_shell_quote (command); + terminal_command = g_strconcat (prefix, " /bin/sh -c ", quoted, NULL); + g_free (prefix); + g_free (quoted); + return terminal_command; +} + +void +eel_mate_open_terminal_on_screen (const char *command, + GdkScreen *screen) +{ + char *command_line; + + if (screen == NULL) + { + screen = gdk_screen_get_default (); + } + + command_line = eel_mate_make_terminal_command (command); + if (command_line == NULL) + { + g_message ("Could not start a terminal"); + return; + } + gdk_spawn_command_line_on_screen (screen, command_line, NULL); + g_free (command_line); +} + +void +eel_mate_open_terminal (const char *command) +{ + eel_mate_open_terminal_on_screen (command, NULL); +} diff --git a/eel/eel-mate-extensions.h b/eel/eel-mate-extensions.h new file mode 100644 index 00000000..4261c9da --- /dev/null +++ b/eel/eel-mate-extensions.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-mate-extensions.h - interface for new functions that operate on + mate classes. Perhaps some of these should be + rolled into mate someday. + + Copyright (C) 1999, 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#ifndef EEL_MATE_EXTENSIONS_H +#define EEL_MATE_EXTENSIONS_H + +#include <gtk/gtk.h> + +/* icon selection callback function. */ +typedef void (* EelIconSelectionFunction) (const char *icon_path, gpointer callback_data); + + +/* Return a command string containing the path to a terminal on this system. */ +char * eel_mate_make_terminal_command (const char *command); + +/* Open up a new terminal, optionally passing in a command to execute */ +void eel_mate_open_terminal (const char *command); +void eel_mate_open_terminal_on_screen (const char *command, + GdkScreen *screen); + +#endif /* EEL_MATE_EXTENSIONS_H */ diff --git a/eel/eel-mateconf-extensions.c b/eel/eel-mateconf-extensions.c new file mode 100644 index 00000000..518f0a3f --- /dev/null +++ b/eel/eel-mateconf-extensions.c @@ -0,0 +1,687 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-mateconf-extensions.c - Stuff to make MateConf easier to use. + + Copyright (C) 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-mateconf-extensions.h" + +#include "eel-debug.h" +#include "eel-glib-extensions.h" +#include "eel-stock-dialogs.h" +#include "eel-string.h" +#include "eel-i18n.h" + +#include <mateconf/mateconf-client.h> +#include <mateconf/mateconf.h> + +static MateConfClient *global_mateconf_client = NULL; + +static void +global_client_free (void) +{ + if (global_mateconf_client == NULL) + { + return; + } + + g_object_unref (global_mateconf_client); + global_mateconf_client = NULL; +} + +/* Public */ +MateConfClient * +eel_mateconf_client_get_global (void) +{ + /* Initialize mateconf if needed */ + if (!mateconf_is_initialized ()) + { + char *argv[] = { "eel-preferences", NULL }; + GError *error = NULL; + + if (!mateconf_init (1, argv, &error)) + { + if (eel_mateconf_handle_error (&error)) + { + return NULL; + } + } + } + + if (global_mateconf_client == NULL) + { + global_mateconf_client = mateconf_client_get_default (); + eel_debug_call_at_shutdown (global_client_free); + } + + return global_mateconf_client; +} + +gboolean +eel_mateconf_handle_error (GError **error) +{ + char *message; + static gboolean shown_dialog = FALSE; + + g_return_val_if_fail (error != NULL, FALSE); + + if (*error != NULL) + { + g_warning (_("MateConf error:\n %s"), (*error)->message); + if (! shown_dialog) + { + shown_dialog = TRUE; + + message = g_strdup_printf (_("MateConf error: %s"), + (*error)->message); + eel_show_error_dialog (message, + _("All further errors shown " + "only on terminal."), + NULL); + g_free (message); + } + g_error_free (*error); + *error = NULL; + + return TRUE; + } + + return FALSE; +} + +void +eel_mateconf_set_boolean (const char *key, + gboolean boolean_value) +{ + MateConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + mateconf_client_set_bool (client, key, boolean_value, &error); + eel_mateconf_handle_error (&error); +} + +gboolean +eel_mateconf_get_boolean (const char *key) +{ + gboolean result; + MateConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, FALSE); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, FALSE); + + result = mateconf_client_get_bool (client, key, &error); + + if (eel_mateconf_handle_error (&error)) + { + result = FALSE; + } + + return result; +} + +void +eel_mateconf_set_integer (const char *key, + int int_value) +{ + MateConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + mateconf_client_set_int (client, key, int_value, &error); + eel_mateconf_handle_error (&error); +} + +int +eel_mateconf_get_integer (const char *key) +{ + int result; + MateConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, 0); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, 0); + + result = mateconf_client_get_int (client, key, &error); + + if (eel_mateconf_handle_error (&error)) + { + result = 0; + } + + return result; +} + +void +eel_mateconf_set_string (const char *key, + const char *string_value) +{ + MateConfClient *client; + GError *error = NULL; + + g_return_if_fail (key != NULL); + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + mateconf_client_set_string (client, key, string_value, &error); + eel_mateconf_handle_error (&error); +} + +char * +eel_mateconf_get_string (const char *key) +{ + char *result; + MateConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + result = mateconf_client_get_string (client, key, &error); + + if (eel_mateconf_handle_error (&error)) + { + result = g_strdup (""); + } + + return result; +} + +void +eel_mateconf_set_string_list (const char *key, + const GSList *slist) +{ + MateConfClient *client; + GError *error; + + g_return_if_fail (key != NULL); + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + error = NULL; + mateconf_client_set_list (client, key, MATECONF_VALUE_STRING, + /* Need cast cause of MateConf api bug */ + (GSList *) slist, + &error); + eel_mateconf_handle_error (&error); +} + +GSList * +eel_mateconf_get_string_list (const char *key) +{ + GSList *slist; + MateConfClient *client; + GError *error; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + error = NULL; + slist = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, &error); + if (eel_mateconf_handle_error (&error)) + { + slist = NULL; + } + + return slist; +} + +void +eel_mateconf_unset (const char *key) +{ + MateConfClient *client; + GError *error; + + g_return_if_fail (key != NULL); + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + error = NULL; + mateconf_client_unset (client, key, &error); + eel_mateconf_handle_error (&error); +} + +gboolean +eel_mateconf_is_default (const char *key) +{ + gboolean result; + MateConfValue *value; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, FALSE); + + value = mateconf_client_get_without_default (eel_mateconf_client_get_global (), key, &error); + + if (eel_mateconf_handle_error (&error)) + { + if (value != NULL) + { + mateconf_value_free (value); + } + return FALSE; + } + + result = (value == NULL); + eel_mateconf_value_free (value); + return result; +} + +gboolean +eel_mateconf_key_is_writable (const char *key) +{ + gboolean result; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, FALSE); + + result = mateconf_client_key_is_writable (eel_mateconf_client_get_global (), key, &error); + + if (eel_mateconf_handle_error (&error)) + { + return result; + } + + return result; +} + +gboolean +eel_mateconf_monitor_add (const char *directory) +{ + GError *error = NULL; + MateConfClient *client; + + g_return_val_if_fail (directory != NULL, FALSE); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, FALSE); + + mateconf_client_add_dir (client, + directory, + MATECONF_CLIENT_PRELOAD_NONE, + &error); + + if (eel_mateconf_handle_error (&error)) + { + return FALSE; + } + + return TRUE; +} + +gboolean +eel_mateconf_monitor_remove (const char *directory) +{ + GError *error = NULL; + MateConfClient *client; + + if (directory == NULL) + { + return FALSE; + } + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, FALSE); + + mateconf_client_remove_dir (client, + directory, + &error); + + if (eel_mateconf_handle_error (&error)) + { + return FALSE; + } + + return TRUE; +} + +void +eel_mateconf_preload_cache (const char *directory, + MateConfClientPreloadType preload_type) +{ + GError *error = NULL; + MateConfClient *client; + + if (directory == NULL) + { + return; + } + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + mateconf_client_preload (client, + directory, + preload_type, + &error); + + eel_mateconf_handle_error (&error); +} + +void +eel_mateconf_suggest_sync (void) +{ + MateConfClient *client; + GError *error = NULL; + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + mateconf_client_suggest_sync (client, &error); + eel_mateconf_handle_error (&error); +} + +MateConfValue* +eel_mateconf_get_value (const char *key) +{ + MateConfValue *value = NULL; + MateConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + value = mateconf_client_get (client, key, &error); + + if (eel_mateconf_handle_error (&error)) + { + if (value != NULL) + { + mateconf_value_free (value); + value = NULL; + } + } + + return value; +} + +MateConfValue* +eel_mateconf_get_default_value (const char *key) +{ + MateConfValue *value = NULL; + MateConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, NULL); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, NULL); + + value = mateconf_client_get_default_from_schema (client, key, &error); + + if (eel_mateconf_handle_error (&error)) + { + if (value != NULL) + { + mateconf_value_free (value); + value = NULL; + } + } + + return value; +} + +static gboolean +simple_value_is_equal (const MateConfValue *a, + const MateConfValue *b) +{ + g_assert (a != NULL); + g_assert (b != NULL); + + switch (a->type) + { + case MATECONF_VALUE_STRING: + return eel_str_is_equal (mateconf_value_get_string (a), + mateconf_value_get_string (b)); + + case MATECONF_VALUE_INT: + return mateconf_value_get_int (a) == + mateconf_value_get_int (b); + + case MATECONF_VALUE_FLOAT: + return mateconf_value_get_float (a) == + mateconf_value_get_float (b); + + case MATECONF_VALUE_BOOL: + return mateconf_value_get_bool (a) == + mateconf_value_get_bool (b); + default: + g_assert_not_reached (); + } + + return FALSE; +} + +gboolean +eel_mateconf_value_is_equal (const MateConfValue *a, + const MateConfValue *b) +{ + GSList *node_a; + GSList *node_b; + + if (a == NULL && b == NULL) + { + return TRUE; + } + + if (a == NULL || b == NULL) + { + return FALSE; + } + + if (a->type != b->type) + { + return FALSE; + } + + switch (a->type) + { + case MATECONF_VALUE_STRING: + case MATECONF_VALUE_INT: + case MATECONF_VALUE_FLOAT: + case MATECONF_VALUE_BOOL: + return simple_value_is_equal (a, b); + break; + + case MATECONF_VALUE_LIST: + if (mateconf_value_get_list_type (a) != + mateconf_value_get_list_type (b)) + { + return FALSE; + } + + node_a = mateconf_value_get_list (a); + node_b = mateconf_value_get_list (b); + + if (node_a == NULL && node_b == NULL) + { + return TRUE; + } + + if (g_slist_length (node_a) != + g_slist_length (node_b)) + { + return FALSE; + } + + for (; + node_a != NULL && node_b != NULL; + node_a = node_a->next, node_b = node_b->next) + { + g_assert (node_a->data != NULL); + g_assert (node_b->data != NULL); + if (!simple_value_is_equal (node_a->data, node_b->data)) + { + return FALSE; + } + } + + return TRUE; + default: + /* FIXME: pair ? */ + g_assert (0); + } + + g_assert_not_reached (); + return FALSE; +} + +void +eel_mateconf_value_free (MateConfValue *value) +{ + if (value == NULL) + { + return; + } + + mateconf_value_free (value); +} + +guint +eel_mateconf_notification_add (const char *key, + MateConfClientNotifyFunc notification_callback, + gpointer callback_data) +{ + guint notification_id; + MateConfClient *client; + GError *error = NULL; + + g_return_val_if_fail (key != NULL, EEL_MATECONF_UNDEFINED_CONNECTION); + g_return_val_if_fail (notification_callback != NULL, EEL_MATECONF_UNDEFINED_CONNECTION); + + client = eel_mateconf_client_get_global (); + g_return_val_if_fail (client != NULL, EEL_MATECONF_UNDEFINED_CONNECTION); + + notification_id = mateconf_client_notify_add (client, + key, + notification_callback, + callback_data, + NULL, + &error); + + if (eel_mateconf_handle_error (&error)) + { + if (notification_id != EEL_MATECONF_UNDEFINED_CONNECTION) + { + mateconf_client_notify_remove (client, notification_id); + notification_id = EEL_MATECONF_UNDEFINED_CONNECTION; + } + } + + return notification_id; +} + +void +eel_mateconf_notification_remove (guint notification_id) +{ + MateConfClient *client; + + if (notification_id == EEL_MATECONF_UNDEFINED_CONNECTION) + { + return; + } + + client = eel_mateconf_client_get_global (); + g_return_if_fail (client != NULL); + + mateconf_client_notify_remove (client, notification_id); +} + +GSList * +eel_mateconf_value_get_string_list (const MateConfValue *value) +{ + GSList *result; + const GSList *slist; + const GSList *node; + const char *string; + const MateConfValue *next_value; + + if (value == NULL) + { + return NULL; + } + + g_return_val_if_fail (value->type == MATECONF_VALUE_LIST, NULL); + g_return_val_if_fail (mateconf_value_get_list_type (value) == MATECONF_VALUE_STRING, NULL); + + slist = mateconf_value_get_list (value); + result = NULL; + for (node = slist; node != NULL; node = node->next) + { + next_value = node->data; + g_return_val_if_fail (next_value != NULL, NULL); + g_return_val_if_fail (next_value->type == MATECONF_VALUE_STRING, NULL); + string = mateconf_value_get_string (next_value); + result = g_slist_prepend (result, g_strdup (string)); + } + return g_slist_reverse (result); +} + +void +eel_mateconf_value_set_string_list (MateConfValue *value, + const GSList *string_list) +{ + const GSList *node; + MateConfValue *next_value; + GSList *value_list; + + g_return_if_fail (value->type == MATECONF_VALUE_LIST); + g_return_if_fail (mateconf_value_get_list_type (value) == MATECONF_VALUE_STRING); + + value_list = NULL; + for (node = string_list; node != NULL; node = node->next) + { + next_value = mateconf_value_new (MATECONF_VALUE_STRING); + mateconf_value_set_string (next_value, node->data); + value_list = g_slist_append (value_list, next_value); + } + + mateconf_value_set_list (value, value_list); + + for (node = value_list; node != NULL; node = node->next) + { + mateconf_value_free (node->data); + } + g_slist_free (value_list); +} + diff --git a/eel/eel-mateconf-extensions.h b/eel/eel-mateconf-extensions.h new file mode 100644 index 00000000..5f1275da --- /dev/null +++ b/eel/eel-mateconf-extensions.h @@ -0,0 +1,78 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-mateconf-extensions.h - Stuff to make MateConf easier to use. + + Copyright (C) 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_MATECONF_EXTENSIONS_H +#define EEL_MATECONF_EXTENSIONS_H + +#include <glib.h> + +#include <mateconf/mateconf.h> +#include <mateconf/mateconf-client.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_MATECONF_UNDEFINED_CONNECTION 0 + + MateConfClient *eel_mateconf_client_get_global (void); + gboolean eel_mateconf_handle_error (GError **error); + void eel_mateconf_set_boolean (const char *key, + gboolean boolean_value); + gboolean eel_mateconf_get_boolean (const char *key); + int eel_mateconf_get_integer (const char *key); + void eel_mateconf_set_integer (const char *key, + int int_value); + char * eel_mateconf_get_string (const char *key); + void eel_mateconf_set_string (const char *key, + const char *string_value); + GSList * eel_mateconf_get_string_list (const char *key); + void eel_mateconf_set_string_list (const char *key, + const GSList *string_list_value); + void eel_mateconf_unset (const char *key); + gboolean eel_mateconf_key_is_writable (const char *key); + gboolean eel_mateconf_is_default (const char *key); + gboolean eel_mateconf_monitor_add (const char *directory); + gboolean eel_mateconf_monitor_remove (const char *directory); + void eel_mateconf_preload_cache (const char *directory, + MateConfClientPreloadType preload_type); + void eel_mateconf_suggest_sync (void); + MateConfValue* eel_mateconf_get_value (const char *key); + MateConfValue* eel_mateconf_get_default_value (const char *key); + gboolean eel_mateconf_value_is_equal (const MateConfValue *a, + const MateConfValue *b); + void eel_mateconf_value_free (MateConfValue *value); + guint eel_mateconf_notification_add (const char *key, + MateConfClientNotifyFunc notification_callback, + gpointer callback_data); + void eel_mateconf_notification_remove (guint notification_id); + GSList * eel_mateconf_value_get_string_list (const MateConfValue *value); + void eel_mateconf_value_set_string_list (MateConfValue *value, + const GSList *string_list); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_MATECONF_EXTENSIONS_H */ diff --git a/eel/eel-pango-extensions.c b/eel/eel-pango-extensions.c new file mode 100644 index 00000000..ec34c9c9 --- /dev/null +++ b/eel/eel-pango-extensions.c @@ -0,0 +1,615 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-pango-extensions.h - interface for new functions that conceptually + belong in pango. Perhaps some of these will be + actually rolled into pango someday. + + Copyright (C) 2001 Anders Carlsson + + The Eel Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Eel Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Eel Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Anders Carlsson <[email protected]> +*/ + +#include <config.h> +#include "eel-pango-extensions.h" + +#if !defined (EEL_OMIT_SELF_CHECK) +#include "eel-lib-self-check-functions.h" +#endif + +#include <gtk/gtk.h> +#include <pango/pango.h> +#include <string.h> + +PangoAttrList * +eel_pango_attr_list_copy_or_create (PangoAttrList *attr_list) +{ + if (attr_list != NULL) + { + return pango_attr_list_copy (attr_list); + } + return pango_attr_list_new (); +} + +PangoAttrList * +eel_pango_attr_list_apply_global_attribute (PangoAttrList *attr_list, + PangoAttribute *attr) +{ + PangoAttrList *new_attr_list; + + g_return_val_if_fail (attr != NULL, NULL); + + attr->start_index = 0; + attr->end_index = G_MAXINT; + + new_attr_list = eel_pango_attr_list_copy_or_create (attr_list); + pango_attr_list_change (new_attr_list, attr); + return new_attr_list; +} + +#define ELLIPSIS "..." + +/* Caution: this is an _expensive_ function */ +static int +measure_string_width (const char *string, + PangoLayout *layout) +{ + int width; + + pango_layout_set_text (layout, string, -1); + pango_layout_get_pixel_size (layout, &width, NULL); + + return width; +} + +/* this is also plenty slow */ +static void +compute_character_widths (const char *string, + PangoLayout *layout, + int *char_len_return, + int **widths_return, + int **cuts_return) +{ + int *widths; + int *offsets; + int *cuts; + int char_len; + int byte_len; + const char *p; + int i; + PangoLayoutIter *iter; + PangoLogAttr *attrs; + +#define BEGINS_UTF8_CHAR(x) (((x) & 0xc0) != 0x80) + + char_len = g_utf8_strlen (string, -1); + byte_len = strlen (string); + + widths = g_new (int, char_len); + offsets = g_new (int, byte_len); + + /* Create a translation table from byte index to char offset */ + p = string; + i = 0; + while (*p) + { + int byte_index = p - string; + + if (BEGINS_UTF8_CHAR (*p)) + { + offsets[byte_index] = i; + ++i; + } + else + { + offsets[byte_index] = G_MAXINT; /* segv if we try to use this */ + } + + ++p; + } + + /* Now fill in the widths array */ + pango_layout_set_text (layout, string, -1); + + iter = pango_layout_get_iter (layout); + + do + { + PangoRectangle extents; + int byte_index; + + byte_index = pango_layout_iter_get_index (iter); + + if (byte_index < byte_len) + { + pango_layout_iter_get_char_extents (iter, &extents); + + g_assert (BEGINS_UTF8_CHAR (string[byte_index])); + g_assert (offsets[byte_index] < char_len); + + widths[offsets[byte_index]] = PANGO_PIXELS (extents.width); + } + + } + while (pango_layout_iter_next_char (iter)); + + pango_layout_iter_free (iter); + + g_free (offsets); + + *widths_return = widths; + + /* Now compute character offsets that are legitimate places to + * chop the string + */ + attrs = g_new (PangoLogAttr, char_len + 1); + + pango_get_log_attrs (string, byte_len, -1, + pango_context_get_language ( + pango_layout_get_context (layout)), + attrs, + char_len + 1); + + cuts = g_new (int, char_len); + i = 0; + while (i < char_len) + { + cuts[i] = attrs[i].is_cursor_position; + + ++i; + } + + g_free (attrs); + + *cuts_return = cuts; + + *char_len_return = char_len; +} + + +static char * +eel_string_ellipsize_start (const char *string, PangoLayout *layout, int width) +{ + int resulting_width; + int *cuts; + int *widths; + int char_len; + const char *p; + int truncate_offset; + + /* Zero-length string can't get shorter - catch this here to + * avoid expensive calculations + */ + if (*string == '\0') + return g_strdup (""); + + /* I'm not sure if this short-circuit is a net win; it might be better + * to just dump this, and always do the compute_character_widths() etc. + * down below. + */ + resulting_width = measure_string_width (string, layout); + + if (resulting_width <= width) + { + /* String is already short enough. */ + return g_strdup (string); + } + + /* Remove width of an ellipsis */ + width -= measure_string_width (ELLIPSIS, layout); + + if (width < 0) + { + /* No room even for an ellipsis. */ + return g_strdup (""); + } + + /* Our algorithm involves removing enough chars from the string to bring + * the width to the required small size. However, due to ligatures, + * combining characters, etc., it's not guaranteed that the algorithm + * always works 100%. It's sort of a heuristic thing. It should work + * nearly all the time... but I wouldn't put in + * g_assert (width of resulting string < width). + * + * Hmm, another thing that this breaks with is explicit line breaks + * in "string" + */ + + compute_character_widths (string, layout, &char_len, &widths, &cuts); + + for (truncate_offset = 1; truncate_offset < char_len; truncate_offset++) + { + + resulting_width -= widths[truncate_offset]; + + if (resulting_width <= width && + cuts[truncate_offset]) + { + break; + } + } + + g_free (cuts); + g_free (widths); + + p = g_utf8_offset_to_pointer (string, truncate_offset); + + return g_strconcat (ELLIPSIS, p, NULL); +} + +static char * +eel_string_ellipsize_end (const char *string, PangoLayout *layout, int width) +{ + int resulting_width; + int *cuts; + int *widths; + int char_len; + const char *p; + int truncate_offset; + char *result; + + /* See explanatory comments in ellipsize_start */ + + if (*string == '\0') + return g_strdup (""); + + resulting_width = measure_string_width (string, layout); + + if (resulting_width <= width) + { + return g_strdup (string); + } + + width -= measure_string_width (ELLIPSIS, layout); + + if (width < 0) + { + return g_strdup (""); + } + + compute_character_widths (string, layout, &char_len, &widths, &cuts); + + for (truncate_offset = char_len - 1; truncate_offset > 0; truncate_offset--) + { + resulting_width -= widths[truncate_offset]; + if (resulting_width <= width && + cuts[truncate_offset]) + { + break; + } + } + + g_free (cuts); + g_free (widths); + + p = g_utf8_offset_to_pointer (string, truncate_offset); + + result = g_malloc ((p - string) + strlen (ELLIPSIS) + 1); + memcpy (result, string, (p - string)); + strcpy (result + (p - string), ELLIPSIS); + + return result; +} + +static char * +eel_string_ellipsize_middle (const char *string, PangoLayout *layout, int width) +{ + int resulting_width; + int *cuts; + int *widths; + int char_len; + int starting_fragment_byte_len; + int ending_fragment_byte_index; + int starting_fragment_length; + int ending_fragment_offset; + char *result; + + /* See explanatory comments in ellipsize_start */ + + if (*string == '\0') + return g_strdup (""); + + resulting_width = measure_string_width (string, layout); + + if (resulting_width <= width) + { + return g_strdup (string); + } + + width -= measure_string_width (ELLIPSIS, layout); + + if (width < 0) + { + return g_strdup (""); + } + + compute_character_widths (string, layout, &char_len, &widths, &cuts); + + starting_fragment_length = char_len / 2; + ending_fragment_offset = starting_fragment_length + 1; + + /* Shave off a character at a time from the first and the second half + * until we can fit + */ + resulting_width -= widths[ending_fragment_offset - 1]; + + /* depending on whether the original string length is odd or even, start by + * shaving off the characters from the starting or ending fragment + */ + if (char_len % 2) + { + goto shave_end; + } + + while (starting_fragment_length > 0 || ending_fragment_offset < char_len) + { + if (resulting_width <= width && + cuts[ending_fragment_offset] && + cuts[starting_fragment_length]) + { + break; + } + + if (starting_fragment_length > 0) + { + resulting_width -= widths[starting_fragment_length]; + starting_fragment_length--; + } + +shave_end: + if (resulting_width <= width && + cuts[ending_fragment_offset] && + cuts[starting_fragment_length]) + { + break; + } + + if (ending_fragment_offset < char_len) + { + resulting_width -= widths[ending_fragment_offset]; + ending_fragment_offset++; + } + } + + g_free (cuts); + g_free (widths); + + /* patch the two fragments together with an ellipsis */ + result = g_malloc (strlen (string) + strlen (ELLIPSIS) + 1); /* a bit wasteful, no biggie */ + + starting_fragment_byte_len = g_utf8_offset_to_pointer (string, starting_fragment_length) - string; + ending_fragment_byte_index = g_utf8_offset_to_pointer (string, ending_fragment_offset) - string; + + memcpy (result, string, starting_fragment_byte_len); + strcpy (result + starting_fragment_byte_len, ELLIPSIS); + strcpy (result + starting_fragment_byte_len + strlen (ELLIPSIS), string + ending_fragment_byte_index); + + return result; +} + + +/** + * eel_pango_layout_set_text_ellipsized + * + * @layout: a pango layout + * @string: A a string to be ellipsized. + * @width: Desired maximum width in points. + * @mode: The desired ellipsizing mode. + * + * Truncates a string if required to fit in @width and sets it on the + * layout. Truncation involves removing characters from the start, middle or end + * respectively and replacing them with "...". Algorithm is a bit + * fuzzy, won't work 100%. + * + */ +void +eel_pango_layout_set_text_ellipsized (PangoLayout *layout, + const char *string, + int width, + EelEllipsizeMode mode) +{ + char *s; + + g_return_if_fail (PANGO_IS_LAYOUT (layout)); + g_return_if_fail (string != NULL); + g_return_if_fail (width >= 0); + + switch (mode) + { + case EEL_ELLIPSIZE_START: + s = eel_string_ellipsize_start (string, layout, width); + break; + case EEL_ELLIPSIZE_MIDDLE: + s = eel_string_ellipsize_middle (string, layout, width); + break; + case EEL_ELLIPSIZE_END: + s = eel_string_ellipsize_end (string, layout, width); + break; + default: + g_return_if_reached (); + } + + pango_layout_set_text (layout, s, -1); + + g_free (s); +} + + +int +eel_pango_font_description_get_largest_fitting_font_size (const PangoFontDescription *font_desc, + PangoContext *context, + const char *text, + int available_width, + int minimum_acceptable_font_size, + int maximum_acceptable_font_size) +{ + int i; + int width; + PangoLayout *layout; + PangoFontDescription *font; + + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (text[0] != '\0', 0); + g_return_val_if_fail (available_width > 0, 0); + g_return_val_if_fail (minimum_acceptable_font_size > 0, 0); + g_return_val_if_fail (maximum_acceptable_font_size > 0, 0); + g_return_val_if_fail (maximum_acceptable_font_size > minimum_acceptable_font_size, 0); + + layout = pango_layout_new (context); + pango_layout_set_text (layout, text, -1); + pango_layout_set_font_description (layout, font_desc); + + font = pango_font_description_new (); + + for (i = maximum_acceptable_font_size; i >= minimum_acceptable_font_size; i--) + { + + pango_font_description_set_size (font, i * PANGO_SCALE); + pango_layout_set_font_description (layout, font); + pango_layout_get_pixel_size (layout, &width, NULL); + + if (width <= available_width) + { + pango_font_description_free (font); + g_object_unref (layout); + return i; + } + } + + pango_font_description_free (font); + g_object_unref (layout); + return i; +} + + +#if !defined (EEL_OMIT_SELF_CHECK) + +static PangoContext * +eel_create_bogus_test_pango_context (void) +{ + PangoContext *context; + + context = gdk_pango_context_get (); + pango_context_set_language (context, gtk_get_default_language ()); + + return context; +} + +/* Testing string truncation is tough because we do not know what font/ + * font metrics to expect on a given system. To work around this we use + * a substring of the original, measure it's length using the given font, + * add the length of the "..." string and use that for truncation. + * The result should then be the substring prepended with a "..." + */ +static char * +eel_self_check_ellipsize (const char *string, const char *truncate_to_length_string, EelEllipsizeMode mode) +{ + PangoContext *context; + int truncation_length; + char *result; + PangoLayout *layout; + + context = eel_create_bogus_test_pango_context (); + layout = pango_layout_new (context); + + /* measure the length we want to truncate to */ + truncation_length = measure_string_width (truncate_to_length_string, layout); + + eel_pango_layout_set_text_ellipsized (layout, string, truncation_length, mode); + + result = g_strdup (pango_layout_get_text (layout)); + + g_object_unref (G_OBJECT (context)); + g_object_unref (G_OBJECT (layout)); + + return result; +} + +static char * +eel_self_check_ellipsize_start (const char *string, const char *truncate_to_length_string) +{ + return eel_self_check_ellipsize (string, truncate_to_length_string, EEL_ELLIPSIZE_START); +} + +static char * +eel_self_check_ellipsize_middle (const char *string, const char *truncate_to_length_string) +{ + return eel_self_check_ellipsize (string, truncate_to_length_string, EEL_ELLIPSIZE_MIDDLE); +} + +static char * +eel_self_check_ellipsize_end (const char *string, const char *truncate_to_length_string) +{ + return eel_self_check_ellipsize (string, truncate_to_length_string, EEL_ELLIPSIZE_END); +} + +void +eel_self_check_pango_extensions (void) +{ + PangoContext *context; + + /* used to test ellipsize routines */ + context = eel_create_bogus_test_pango_context (); + + /* Turned off these tests because they are failing for me and I + * want the release to be able to pass "make check". We'll have + * to revisit this at some point. The failures started because + * I changed my default font and enabled Xft support. I presume + * this is simply the "fuzziness" Havoc mentions in his comments + * above. + * - Darin + */ + + if (0) + { + /* eel_string_ellipsize_start */ + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "0012345678"), "012345678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "012345678"), "012345678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "...45678"), "...45678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "...5678"), "...5678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "...678"), "...678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "...78"), "...78"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_start ("012345678", "...8"), "...8"); + + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "0123456789"), "012345678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "012345678"), "012345678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "012...78"), "012...78"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "01...78"), "01...78"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "01...8"), "01...8"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "0...8"), "0...8"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("012345678", "0..."), "0..."); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "0123456789"), "0123456789"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "012...789"), "012...789"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "012...89"), "012...89"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "01...89"), "01...89"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "01...9"), "01...9"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "0...9"), "0...9"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_middle ("0123456789", "0..."), "0..."); + + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "0123456789"), "012345678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "012345678"), "012345678"); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "01234..."), "01234..."); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "0123..."), "0123..."); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "012..."), "012..."); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "01..."), "01..."); + EEL_CHECK_STRING_RESULT (eel_self_check_ellipsize_end ("012345678", "0..."), "0..."); + } + + g_object_unref (context); +} + +#endif /* !EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-pango-extensions.h b/eel/eel-pango-extensions.h new file mode 100644 index 00000000..e788ffcc --- /dev/null +++ b/eel/eel-pango-extensions.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-pango-extensions.h - interface for new functions that conceptually + belong in pango. Perhaps some of these will be + actually rolled into pango someday. + + Copyright (C) 2001 Anders Carlsson + + The Eel Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Eel Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Eel Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Anders Carlsson <[email protected]> +*/ + +#ifndef EEL_PANGO_EXTENSIONS_H +#define EEL_PANGO_EXTENSIONS_H + +#include <pango/pango.h> + +typedef enum +{ + EEL_ELLIPSIZE_START, + EEL_ELLIPSIZE_MIDDLE, + EEL_ELLIPSIZE_END +} EelEllipsizeMode; + +PangoAttrList *eel_pango_attr_list_copy_or_create (PangoAttrList *attr_list); +PangoAttrList *eel_pango_attr_list_apply_global_attribute (PangoAttrList *attr_list, + PangoAttribute *attr); +int eel_pango_font_description_get_largest_fitting_font_size (const PangoFontDescription *font_desc, + PangoContext *context, + const char *text, + int available_width, + int minimum_acceptable_font_size, + int maximum_acceptable_font_size); + +/* caution: this function is expensive. */ +void eel_pango_layout_set_text_ellipsized (PangoLayout *layout, + const char *string, + int width, + EelEllipsizeMode mode); + +#endif /* EEL_PANGO_EXTENSIONS_H */ diff --git a/eel/eel-preferences-builder.c b/eel/eel-preferences-builder.c new file mode 100644 index 00000000..e02ca4df --- /dev/null +++ b/eel/eel-preferences-builder.c @@ -0,0 +1,646 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-preferences-glade.c - Some functions to connect a Glade-file to mateconf keys. + + Copyright (C) 2002 Jan Arne Petersen + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Jan Arne Petersen <[email protected]> +*/ + +#include <glib.h> + +#include <gtk/gtk.h> + +#include "eel-preferences.h" + +#define EEL_PREFERENCES_BUILDER_DATA_KEY "eel_preferences_builder_data_key" +#define EEL_PREFERENCES_BUILDER_DATA_VALUE "eel_preferences_builder_data_value" +#define EEL_PREFERENCES_BUILDER_DATA_MAP "eel_preferences_builder_data_map" +#define EEL_PREFERENCES_BUILDER_DATA_WIDGETS "eel_preferences_builder_data_widgets" + +/* helper */ + +static void +eel_preferences_builder_combo_box_update (GtkComboBox *combo_box, + gpointer value, + GCallback change_callback) +{ + GHashTable *map; + int active; + gpointer key; + + map = (GHashTable *) g_object_get_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_MAP); + active = GPOINTER_TO_INT (g_hash_table_lookup (map, value)); + + if (active == -1) + { + return; + } + + key = g_object_get_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_KEY); + + g_signal_handlers_block_by_func (combo_box, change_callback, key); + gtk_combo_box_set_active (combo_box, active); + g_signal_handlers_unblock_by_func (combo_box, change_callback, key); +} + +static void +eel_preference_glade_never_sensitive (GtkWidget *widget, GtkStateType state) +{ + gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE); +} + +static void +eel_preferences_builder_set_never_sensitive (GtkWidget *widget) +{ + gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE); + g_signal_connect (G_OBJECT (widget), "state_changed", + G_CALLBACK (eel_preference_glade_never_sensitive), + NULL); +} + +/* bool preference */ + +static void +eel_preferences_builder_bool_toggled (GtkToggleButton *toggle_button, + char *key) +{ + eel_preferences_set_boolean (key, gtk_toggle_button_get_active (toggle_button)); +} + +static void +eel_preferences_builder_bool_update (GtkToggleButton *toggle_button) +{ + gboolean value; + gpointer key; + + key = g_object_get_data (G_OBJECT (toggle_button), EEL_PREFERENCES_BUILDER_DATA_KEY); + + value = eel_preferences_get_boolean (key); + g_signal_handlers_block_by_func (toggle_button, eel_preferences_builder_bool_toggled, key); + gtk_toggle_button_set_active (toggle_button, value); + g_signal_handlers_unblock_by_func (toggle_button, eel_preferences_builder_bool_toggled, key); +} + +void +eel_preferences_builder_connect_bool (GtkBuilder *builder, + const char *component, + const char *key) +{ + GtkToggleButton *toggle_button; + + g_return_if_fail (builder != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); + + toggle_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, component)); + g_object_set_data_full (G_OBJECT (toggle_button), EEL_PREFERENCES_BUILDER_DATA_KEY, + g_strdup (key), (GDestroyNotify) g_free); + + eel_preferences_add_callback_while_alive (key, + (EelPreferencesCallback) eel_preferences_builder_bool_update, + toggle_button, G_OBJECT (toggle_button)); + + if (!eel_preferences_key_is_writable (key)) + { + eel_preferences_builder_set_never_sensitive (GTK_WIDGET (toggle_button)); + } + + g_signal_connect (G_OBJECT (toggle_button), "toggled", + G_CALLBACK (eel_preferences_builder_bool_toggled), + g_object_get_data (G_OBJECT (toggle_button), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + + eel_preferences_builder_bool_update (toggle_button); +} + +static void +eel_preferences_builder_inverted_bool_toggled (GtkToggleButton *toggle_button, + char *key) +{ + eel_preferences_set_boolean (key, !gtk_toggle_button_get_active (toggle_button)); +} + +static void +eel_preferences_builder_inverted_bool_update (GtkToggleButton *toggle_button) +{ + gboolean value; + gpointer key; + + key = g_object_get_data (G_OBJECT (toggle_button), EEL_PREFERENCES_BUILDER_DATA_KEY); + + value = eel_preferences_get_boolean (key); + g_signal_handlers_block_by_func (toggle_button, eel_preferences_builder_bool_toggled, key); + gtk_toggle_button_set_active (toggle_button, !value); + g_signal_handlers_unblock_by_func (toggle_button, eel_preferences_builder_bool_toggled, key); +} + +void +eel_preferences_builder_connect_inverted_bool (GtkBuilder *builder, + const char *component, + const char *key) +{ + GtkToggleButton *toggle_button; + + g_return_if_fail (builder != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); + + toggle_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, component)); + g_object_set_data_full (G_OBJECT (toggle_button), EEL_PREFERENCES_BUILDER_DATA_KEY, + g_strdup (key), (GDestroyNotify) g_free); + + eel_preferences_add_callback_while_alive (key, + (EelPreferencesCallback) eel_preferences_builder_inverted_bool_update, + toggle_button, G_OBJECT (toggle_button)); + + if (!eel_preferences_key_is_writable (key)) + { + eel_preferences_builder_set_never_sensitive (GTK_WIDGET (toggle_button)); + } + + g_signal_connect (G_OBJECT (toggle_button), "toggled", + G_CALLBACK (eel_preferences_builder_inverted_bool_toggled), + g_object_get_data (G_OBJECT (toggle_button), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + + eel_preferences_builder_inverted_bool_update (toggle_button); +} + +void +eel_preferences_builder_connect_bool_slave (GtkBuilder *builder, + const char *component, + const char *key) +{ + GtkToggleButton *toggle_button; + + g_return_if_fail (builder != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); + + toggle_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, component)); + + if (!eel_preferences_key_is_writable (key)) + { + eel_preferences_builder_set_never_sensitive (GTK_WIDGET (toggle_button)); + } + + g_signal_connect_data (G_OBJECT (toggle_button), "toggled", + G_CALLBACK (eel_preferences_builder_bool_toggled), + g_strdup (key), (GClosureNotify) g_free, 0); +} + +/* string enum (ComboBox) preference */ + +static void +eel_preferences_builder_string_enum_combo_box_changed (GtkComboBox *combo_box, + char *key) +{ + int active; + char **values; + int i; + + active = gtk_combo_box_get_active (combo_box); + values = g_object_get_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_VALUE); + + i = 0; + while (i < active && values[i] != NULL) + { + i++; + } + + if (values[i] == NULL) + { + return; + } + + eel_preferences_set (key, values[i]); +} + +static void +eel_preferences_builder_string_enum_combo_box_update (GtkComboBox *combo_box) +{ + char *value; + + value = eel_preferences_get (g_object_get_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + + eel_preferences_builder_combo_box_update (combo_box, value, + G_CALLBACK (eel_preferences_builder_string_enum_combo_box_changed)); + + g_free (value); +} + +void +eel_preferences_builder_connect_string_enum_combo_box (GtkBuilder *builder, + const char *component, + const char *key, + const char **values) +{ + GtkWidget *combo_box; + GHashTable *map; + int i; + + g_return_if_fail (builder != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (values != NULL); + + combo_box = GTK_WIDGET (gtk_builder_get_object (builder, component)); + + map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + + for (i = 0; values[i] != NULL; i++) + { + g_hash_table_insert (map, g_strdup (values[i]), GINT_TO_POINTER (i)); + } + + g_object_set_data_full (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_MAP, map, + (GDestroyNotify) g_hash_table_destroy); + g_object_set_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_VALUE, values); + g_object_set_data_full (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_KEY, + g_strdup (key), (GDestroyNotify) g_free); + + eel_preferences_add_callback_while_alive (key, + (EelPreferencesCallback) eel_preferences_builder_string_enum_combo_box_update, + combo_box, G_OBJECT (combo_box)); + + if (!eel_preferences_key_is_writable (key)) + { + eel_preferences_builder_set_never_sensitive (GTK_WIDGET (combo_box)); + } + + g_signal_connect (G_OBJECT (combo_box), "changed", + G_CALLBACK (eel_preferences_builder_string_enum_combo_box_changed), + g_object_get_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_KEY)); + + eel_preferences_builder_string_enum_combo_box_update (GTK_COMBO_BOX (combo_box)); +} + +void +eel_preferences_builder_connect_string_enum_combo_box_slave (GtkBuilder *builder, + const char *component, + const char *key) +{ + GtkWidget *combo_box; + + g_return_if_fail (builder != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); + + combo_box = GTK_WIDGET (gtk_builder_get_object (builder, component)); + + g_assert (g_object_get_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_MAP) != NULL); + + if (!eel_preferences_key_is_writable (key)) + { + eel_preferences_builder_set_never_sensitive (GTK_WIDGET (combo_box)); + } + + g_signal_connect_data (G_OBJECT (combo_box), "changed", + G_CALLBACK (eel_preferences_builder_string_enum_combo_box_changed), + g_strdup (key), (GClosureNotify) g_free, 0); +} + + +/* int enum preference */ + +static void +eel_preferences_builder_uint_enum_changed (GtkComboBox *combo_box, + char *key) +{ + int active; + GSList *value_list; + int i; + + active = gtk_combo_box_get_active (combo_box); + value_list = (GSList *) g_object_get_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_VALUE); + + i = 0; + while (i < active && value_list->next != NULL) + { + i++; + value_list = value_list->next; + } + + eel_preferences_set_uint (key, GPOINTER_TO_UINT (value_list->data)); +} + +static void +eel_preferences_builder_uint_enum_update (GtkComboBox *combo_box) +{ + guint value; + + value = eel_preferences_get_uint (g_object_get_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + + eel_preferences_builder_combo_box_update (combo_box, GUINT_TO_POINTER (value), + G_CALLBACK (eel_preferences_builder_uint_enum_changed)); +} + +void +eel_preferences_builder_connect_uint_enum (GtkBuilder *builder, + const char *component, + const char *key, + const guint *values, + int num_values) +{ + GHashTable *map; + int i; + guint value; + GtkComboBox *combo_box; + GSList *value_list; + + g_return_if_fail (builder != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (values != NULL); + + combo_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, component)); + + map = g_hash_table_new (g_direct_hash, g_direct_equal); + value_list = NULL; + + for (i = 0; i < num_values; i++) + { + value = values[i]; + value_list = g_slist_append (value_list, GUINT_TO_POINTER (value)); + g_hash_table_insert (map, GUINT_TO_POINTER (value), GINT_TO_POINTER (i)); + } + + g_object_set_data_full (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_MAP, map, + (GDestroyNotify) g_hash_table_destroy); + g_object_set_data_full (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_VALUE, value_list, + (GDestroyNotify) g_slist_free); + g_object_set_data_full (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_KEY, + g_strdup (key), (GDestroyNotify) g_free); + + if (!eel_preferences_key_is_writable (key)) + { + eel_preferences_builder_set_never_sensitive (GTK_WIDGET (combo_box)); + } + + g_signal_connect (G_OBJECT (combo_box), "changed", + G_CALLBACK (eel_preferences_builder_uint_enum_changed), + g_object_get_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_KEY)); + + eel_preferences_add_callback_while_alive (key, + (EelPreferencesCallback) eel_preferences_builder_uint_enum_update, + combo_box, G_OBJECT (combo_box)); + + eel_preferences_builder_uint_enum_update (combo_box); +} + + +/* String Enum (RadioButton) preference */ + +static void +eel_preferences_builder_string_enum_radio_button_toggled (GtkToggleButton *toggle_button, + char *key) +{ + if (gtk_toggle_button_get_active (toggle_button) == FALSE) + { + return; + } + + eel_preferences_set (key, + g_object_get_data (G_OBJECT (toggle_button), + EEL_PREFERENCES_BUILDER_DATA_VALUE)); +} + +static void +eel_preferences_builder_string_enum_radio_button_update (GtkWidget *widget) +{ + gpointer key; + char *value; + GHashTable *map; + gpointer object; + + key = g_object_get_data (G_OBJECT (widget), EEL_PREFERENCES_BUILDER_DATA_KEY); + value = eel_preferences_get (key); + map = g_object_get_data (G_OBJECT (widget), EEL_PREFERENCES_BUILDER_DATA_MAP); + object = g_hash_table_lookup (map, value); + g_free (value); + if (object == NULL) + { + return; + } + + g_signal_handlers_block_by_func (widget, + eel_preferences_builder_string_enum_radio_button_toggled, + key); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object), TRUE); + g_signal_handlers_unblock_by_func (widget, + eel_preferences_builder_string_enum_radio_button_toggled, + key); +} + +void +eel_preferences_builder_connect_string_enum_radio_button (GtkBuilder *builder, + const char **components, + const char *key, + const char **values) +{ + GHashTable *map; + int i; + GtkWidget *widget; + gboolean writable; + + g_return_if_fail (builder != NULL); + g_return_if_fail (components != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (values != NULL); + + map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + + writable = eel_preferences_key_is_writable (key); + + widget = NULL; + for (i = 0; components[i] != NULL && values[i] != NULL; i++) + { + widget = GTK_WIDGET (gtk_builder_get_object (builder, components[i])); + g_hash_table_insert (map, g_strdup (values[i]), widget); + if (i == 0) + { + g_object_set_data_full (G_OBJECT (widget), + EEL_PREFERENCES_BUILDER_DATA_MAP, map, + (GDestroyNotify) g_hash_table_destroy); + } + else + { + g_object_set_data (G_OBJECT (widget), + EEL_PREFERENCES_BUILDER_DATA_MAP, map); + } + g_object_set_data_full (G_OBJECT (widget), + EEL_PREFERENCES_BUILDER_DATA_VALUE, g_strdup (values[i]), + (GDestroyNotify) g_free); + g_object_set_data_full (G_OBJECT (widget), + EEL_PREFERENCES_BUILDER_DATA_KEY, g_strdup (key), + (GDestroyNotify) g_free); + + if (!writable) + { + eel_preferences_builder_set_never_sensitive (widget); + } + + g_signal_connect (G_OBJECT (widget), "toggled", + G_CALLBACK (eel_preferences_builder_string_enum_radio_button_toggled), + g_object_get_data (G_OBJECT (widget), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + } + + eel_preferences_add_callback_while_alive (key, + (EelPreferencesCallback) eel_preferences_builder_string_enum_radio_button_update, + widget, G_OBJECT (widget)); + + eel_preferences_builder_string_enum_radio_button_update (widget); +} + + +/* list enum preference */ + +static void +eel_preferences_builder_list_enum_changed (GtkComboBox *combo_box, + char *key) +{ + GSList *widgets; + int active; + char **values; + int i; + GPtrArray *v; + + widgets = g_object_get_data (G_OBJECT (combo_box), EEL_PREFERENCES_BUILDER_DATA_WIDGETS); + + v = g_ptr_array_new (); + for (; widgets != NULL; widgets = widgets->next) + { + active = gtk_combo_box_get_active (GTK_COMBO_BOX (widgets->data)); + values = g_object_get_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_VALUE); + + i = 0; + while (i < active && values[i] != NULL) + { + i++; + } + + if (values[i] != NULL) + { + g_ptr_array_add (v, values[i]); + } + } + g_ptr_array_add (v, NULL); + + eel_preferences_set_string_array (key, (char **) v->pdata); + g_ptr_array_free (v, TRUE); +} + +static void +eel_preferences_builder_list_enum_update (GtkWidget *widget) +{ + char **values; + GSList *components; + int i; + + values = eel_preferences_get_string_array (g_object_get_data (G_OBJECT (widget), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + components = g_object_get_data (G_OBJECT (widget), EEL_PREFERENCES_BUILDER_DATA_WIDGETS); + for (i = 0; values[i] != NULL && components != NULL; i++, components = components->next) + { + eel_preferences_builder_combo_box_update (GTK_COMBO_BOX (components->data), + values[i], + G_CALLBACK (eel_preferences_builder_list_enum_changed)); + } + + g_strfreev (values); +} + +void +eel_preferences_builder_connect_list_enum (GtkBuilder *builder, + const char **components, + const char *key, + const char **values) +{ + GtkWidget *combo_box; + GHashTable *map; + int i; + GSList *widgets; + gboolean writable; + + g_return_if_fail (builder != NULL); + g_return_if_fail (components != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (values != NULL); + + map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + + for (i = 0; values[i] != NULL; i++) + { + g_hash_table_insert (map, g_strdup (values[i]), GINT_TO_POINTER (i)); + } + + writable = eel_preferences_key_is_writable (key); + + combo_box = NULL; + widgets = NULL; + for (i = 0; components[i] != NULL; i++) + { + combo_box = GTK_WIDGET (gtk_builder_get_object (builder, components[i])); + widgets = g_slist_append (widgets, combo_box); + if (i == 0) + { + g_object_set_data_full (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_MAP, map, + (GDestroyNotify) g_hash_table_destroy); + g_object_set_data_full (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_WIDGETS, + widgets, (GDestroyNotify) g_slist_free); + } + else + { + g_object_set_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_MAP, map); + g_object_set_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_WIDGETS, widgets); + } + g_object_set_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_VALUE, values); + g_object_set_data_full (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_KEY, g_strdup (key), + (GDestroyNotify) g_free); + + if (!writable) + { + eel_preferences_builder_set_never_sensitive (combo_box); + } + + g_signal_connect (G_OBJECT (combo_box), "changed", + G_CALLBACK (eel_preferences_builder_list_enum_changed), + g_object_get_data (G_OBJECT (combo_box), + EEL_PREFERENCES_BUILDER_DATA_KEY)); + } + + eel_preferences_add_callback_while_alive (key, + (EelPreferencesCallback) eel_preferences_builder_list_enum_update, + combo_box, G_OBJECT (combo_box)); + + eel_preferences_builder_list_enum_update (combo_box); +} + diff --git a/eel/eel-preferences.c b/eel/eel-preferences.c new file mode 100644 index 00000000..7a24ed11 --- /dev/null +++ b/eel/eel-preferences.c @@ -0,0 +1,1764 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-preferences.c - Preference peek/poke/notify implementation. + + Copyright (C) 1999, 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-preferences.h" + +#include "eel-debug.h" +#include "eel-mateconf-extensions.h" +#include "eel-lib-self-check-functions.h" +#include "eel-enumeration.h" +#include "eel-glib-extensions.h" +#include "eel-string.h" +#include <mateconf/mateconf-client.h> +#include <mateconf/mateconf.h> +#include <gtk/gtk.h> + +/* An enumeration used for updating auto-storage variables in a type-specific way. + * FIXME: there is another enumeration like this in eel-global-preferences.c, + * used for different purposes but in a related way. Should we combine them? + */ +typedef enum +{ + PREFERENCE_BOOLEAN = 1, + PREFERENCE_INTEGER, + PREFERENCE_STRING, + PREFERENCE_STRING_ARRAY, + PREFERENCE_STRING_ARRAY_AS_QUARKS +} PreferenceType; + +/* + * PreferencesEntry: + * + * A structure to manage preference hash table nodes. + * Preferences are hash tables. The hash key is the preference name + * (a string). The hash value is a pointer of the following struct: + */ +typedef struct +{ + char *name; + char *description; + PreferenceType type; + gboolean invisible; + GList *callback_list; + GList *auto_storage_list; + int mateconf_connection_id; + char *enumeration_id; + MateConfValue *fallback; +} PreferencesEntry; + +/* + * PreferencesCallbackEntry: + * + * A structure to manage callback lists. A callback list is a GList. + * The callback_data in each list node is a pointer to the following + * struct: + */ +typedef struct +{ + EelPreferencesCallback callback; + gpointer callback_data; +} PreferencesCallbackEntry; + +static GHashTable *global_table = NULL; +static char *storage_path = NULL; +static gboolean initialized = FALSE; + +static void preferences_global_table_free (void); +static char * preferences_key_make (const char *name); +static void preferences_callback_entry_free (PreferencesCallbackEntry *callback_entry); +static void preferences_entry_update_auto_storage (PreferencesEntry *entry); +static PreferencesEntry *preferences_global_table_lookup_or_insert (const char *name); + +static int +preferences_mateconf_value_get_int (const MateConfValue *value) +{ + if (value == NULL) + { + return 0; + } + g_assert (value->type == MATECONF_VALUE_INT); + return mateconf_value_get_int (value); +} + +static gboolean +preferences_mateconf_value_get_bool (const MateConfValue *value) +{ + if (value == NULL) + { + return FALSE; + } + g_assert (value->type == MATECONF_VALUE_BOOL); + return mateconf_value_get_bool (value); +} + +static char * +preferences_mateconf_value_get_string (const MateConfValue *value) +{ + if (value == NULL) + { + return g_strdup (""); + } + g_assert (value->type == MATECONF_VALUE_STRING); + return g_strdup (mateconf_value_get_string (value)); +} + +static char ** +preferences_mateconf_value_get_string_array (const MateConfValue *value) +{ + GSList *slist, *l; + GPtrArray *result; + + if (value == NULL) + { + return NULL; + } + + g_assert (value->type == MATECONF_VALUE_LIST); + g_assert (mateconf_value_get_list_type (value) == MATECONF_VALUE_STRING); + + slist = eel_mateconf_value_get_string_list (value); + + result = g_ptr_array_new (); + for (l = slist; l != NULL; l = l->next) + { + g_ptr_array_add (result, l->data); + } + g_slist_free (slist); + g_ptr_array_add (result, NULL); + + return (char **) g_ptr_array_free (result, FALSE); +} + +static const char * +preferences_peek_storage_path (void) +{ + g_assert (storage_path != NULL); + + return storage_path; +} + +static void +preferences_set_storage_path (const char *new_storage_path) +{ + g_assert (eel_strlen (new_storage_path) > 0); + + /* Make sure the path is indeed different */ + if (eel_str_is_equal (new_storage_path, storage_path)) + { + return; + } + + /* Free the preference hash table */ + preferences_global_table_free (); + + /* Stop monitoring the old path */ + eel_mateconf_monitor_remove (storage_path); + + g_free (storage_path); + storage_path = g_strdup (new_storage_path); + + /* Start monitoring the new path */ + eel_mateconf_monitor_add (storage_path); +} + +static gboolean +preferences_is_initialized (void) +{ + return initialized; +} + +static MateConfValue * +preferences_get_value (const char *name) +{ + MateConfValue *result; + char *key; + PreferencesEntry *entry; + + g_assert (name != NULL); + g_assert (preferences_is_initialized ()); + + key = preferences_key_make (name); + result = eel_mateconf_get_value (key); + g_free (key); + + if (result == NULL) + { + entry = preferences_global_table_lookup_or_insert (name); + + if (entry->fallback) + result = mateconf_value_copy (entry->fallback); + } + + return result; +} + +/* If the preference name begind with a "/", we interpret + * it as a straight mateconf key. */ +static gboolean +preferences_preference_is_mateconf_key (const char *name) +{ + g_assert (name != NULL); + + if (eel_str_has_prefix (name, "/")) + { + return FALSE; + } + + return TRUE; +} + +static char * +preferences_key_make (const char *name) +{ + g_assert (name != NULL); + + if (!preferences_preference_is_mateconf_key (name)) + { + return g_strdup (name); + } + + /* Otherwise, we prefix it with the path */ + return g_strconcat (preferences_peek_storage_path (), "/", + name, NULL); +} + +/* Get default from schema or emergency fallback */ +static MateConfValue * +preferences_get_default_value (const char *name) +{ + MateConfValue *result; + PreferencesEntry *entry; + char *key; + + g_assert (name != NULL); + + key = preferences_key_make (name); + + result = eel_mateconf_get_default_value (key); + + g_free (key); + + if (result == NULL) + { + entry = preferences_global_table_lookup_or_insert (name); + if (entry && entry->fallback) + result = mateconf_value_copy (entry->fallback); + } + + return result; +} + +static int +preferences_callback_entry_compare (gconstpointer a, + gconstpointer b) +{ + const PreferencesCallbackEntry *a_entry = a; + const PreferencesCallbackEntry *b_entry = b; + + if (a_entry->callback < b_entry->callback) + { + return -1; + } + + if (a_entry->callback > b_entry->callback) + { + return +1; + } + + if (a_entry->callback_data < b_entry->callback_data) + { + return -1; + } + + if (a_entry->callback_data > b_entry->callback_data) + { + return +1; + } + + return 0; +} + +/* Public preferences functions */ + +gboolean +eel_preferences_get_is_invisible (const char *name) +{ + g_assert (name != NULL); + g_assert (preferences_is_initialized ()); + + return preferences_global_table_lookup_or_insert (name)->invisible; +} + +void +eel_preferences_set_is_invisible (const char *name, + gboolean is_invisible) +{ + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + preferences_global_table_lookup_or_insert (name)->invisible = is_invisible; +} + +void +eel_preferences_set_boolean (const char *name, + gboolean boolean_value) +{ + char *key; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + key = preferences_key_make (name); + eel_mateconf_set_boolean (key, boolean_value); + g_free (key); + + eel_mateconf_suggest_sync (); +} + +gboolean +eel_preferences_get_boolean (const char *name) +{ + gboolean result; + MateConfValue *value; + + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (preferences_is_initialized (), 0); + + value = preferences_get_value (name); + result = preferences_mateconf_value_get_bool (value); + eel_mateconf_value_free (value); + + return result; +} + +void +eel_preferences_set_integer (const char *name, + int int_value) +{ + char *key; + int old_value; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + key = preferences_key_make (name); + old_value = eel_preferences_get_integer (name); + + if (int_value != old_value) + { + eel_mateconf_set_integer (key, int_value); + } + g_free (key); +} + +int +eel_preferences_get_integer (const char *name) +{ + int result; + MateConfValue *value; + + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (preferences_is_initialized (), 0); + + value = preferences_get_value (name); + result = preferences_mateconf_value_get_int (value); + eel_mateconf_value_free (value); + + return result; +} + +/* MateConf has no unsigned store, save as signed and cast */ +guint +eel_preferences_get_uint (const char *name) +{ + return (guint)eel_preferences_get_integer (name); +} +void +eel_preferences_set_uint (const char *name, + guint uint_value) +{ + eel_preferences_set_integer (name, (int)uint_value); +} + +guint +eel_preferences_get_enum (const char *name) +{ + guint ret_val; + char *str_value; + MateConfValue *value; + const EelEnumeration *enumeration; + PreferencesEntry *entry; + + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (preferences_is_initialized (), 0); + + entry = preferences_global_table_lookup_or_insert (name); + g_return_val_if_fail (entry != NULL, 0); + + enumeration = eel_enumeration_lookup (entry->enumeration_id); + + if (!enumeration) + { + g_warning ("No enum entry for '%s' (%s)", + name, entry->enumeration_id); + return 0; + } + + value = preferences_get_value (name); + if (value->type == MATECONF_VALUE_INT) /* compatibility path */ + { + ret_val = (guint)preferences_mateconf_value_get_int (value); + eel_mateconf_value_free (value); + return ret_val; + } + + str_value = preferences_mateconf_value_get_string (value); + eel_mateconf_value_free (value); + + if (str_value == NULL) + { + g_warning ("No key for '%s' at %s", str_value, name); + return 0; + } + + ret_val = eel_enumeration_get_value_for_name (enumeration, str_value); + + g_free (str_value); + + return ret_val; +} + +void +eel_preferences_set_enum (const char *name, + guint int_value) +{ + const char *str_value; + const EelEnumeration *enumeration; + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_return_if_fail (entry != NULL); + + enumeration = eel_enumeration_lookup (entry->enumeration_id); + + if (!enumeration) + { + g_warning ("No enum entry for '%s' (%s)", + name, entry->enumeration_id); + return; + } + + str_value = eel_enumeration_get_name_for_value (enumeration, int_value); + + if (str_value == NULL) + { + g_warning ("No enum match for '%d'", int_value); + return; + } + + eel_preferences_set (name, str_value); +} + +void +eel_preferences_set (const char *name, + const char *string_value) +{ + char *key; + char *old_value; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + key = preferences_key_make (name); + old_value = eel_preferences_get (name); + + if (strcmp (string_value, old_value) != 0) + { + eel_mateconf_set_string (key, string_value); + } + g_free (key); + g_free (old_value); +} + +char * +eel_preferences_get (const char *name) +{ + char *result; + MateConfValue *value; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (preferences_is_initialized (), NULL); + + value = preferences_get_value (name); + result = preferences_mateconf_value_get_string (value); + eel_mateconf_value_free (value); + + return result; +} + +void +eel_preferences_set_string_array (const char *name, + char **strv_value) +{ + GSList *slist; + int i; + char *key; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + slist = NULL; + if (strv_value != NULL) + { + for (i = 0; strv_value[i] != NULL; i++) + { + slist = g_slist_prepend (slist, strv_value[i]); + } + slist = g_slist_reverse (slist); + } + + key = preferences_key_make (name); + eel_mateconf_set_string_list (key, slist); + g_free (key); + + g_slist_free (slist); +} + +static gboolean +string_array_is_valid (char **strv, const char *enumeration_id) +{ + guint i; + gboolean res; + + g_assert (strv != NULL); + g_assert (enumeration_id != NULL); + + res = TRUE; + for (i = 0; strv[i] != NULL; i++) + { + const EelEnumeration *enumeration; + + enumeration = eel_enumeration_lookup (enumeration_id); + if (!enumeration) + { + res = FALSE; + break; + } + + if (!eel_enumeration_contains_name (enumeration, strv[i])) + { + res = FALSE; + break; + } + } + + return res; +} + +char ** +eel_preferences_get_string_array (const char *name) +{ + char **result; + MateConfValue *value; + PreferencesEntry *entry; + MateConfValue *default_value; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (preferences_is_initialized (), NULL); + + value = preferences_get_value (name); + result = preferences_mateconf_value_get_string_array (value); + eel_mateconf_value_free (value); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + /* No enumeration_id so we're done */ + if (entry->enumeration_id == NULL) + { + return result; + } + + /* Do a sanity check on the validity of the values */ + if (string_array_is_valid (result, entry->enumeration_id)) + { + return result; + } + + /* Forget the bad value and use the default instead */ + g_strfreev (result); + + default_value = preferences_get_default_value (name); + if (default_value) + { + result = preferences_mateconf_value_get_string_array (default_value); + mateconf_value_free (default_value); + } + + return result; +} + +void +eel_preferences_unset (const char *name) +{ + char *key; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + key = preferences_key_make (name); + + eel_mateconf_unset (key); + + g_free (key); +} + +gboolean +eel_preferences_key_is_writable (const char *name) +{ + gboolean result; + char *key; + + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (preferences_is_initialized (), 0); + + key = preferences_key_make (name); + result = eel_mateconf_key_is_writable (key); + g_free (key); + + return result; +} + +/** + * preferences_callback_entry_invoke_function + * + * A function that invokes a callback from the given struct. It is meant to be fed to + * g_list_foreach () + * @data: The list data privately maintained by the GList. + * @callback_data: The callback_data privately maintained by the GList. + **/ +static void +preferences_callback_entry_invoke_function (gpointer data, + gpointer callback_data) +{ + PreferencesCallbackEntry *callback_entry; + + g_assert (data != NULL); + + callback_entry = data; + + (* callback_entry->callback) (callback_entry->callback_data); +} + +static void +preferences_entry_invoke_callbacks (PreferencesEntry *entry) +{ + g_assert (entry != NULL); + + /* Update the auto storage preferences */ + if (entry->auto_storage_list != NULL) + { + preferences_entry_update_auto_storage (entry); + } + + /* Invoke callbacks for this entry if any */ + if (entry->callback_list != NULL) + { + g_list_foreach (entry->callback_list, + preferences_callback_entry_invoke_function, + NULL); + } +} + +static void +update_auto_string (gpointer data, gpointer callback_data) +{ + char **storage; + const char *value; + + g_assert (data != NULL); + g_assert (callback_data != NULL); + + storage = (char **)data; + value = (const char *)callback_data; + + g_free (*storage); + *(char **)storage = g_strdup (value); +} + +static void +update_auto_string_array (gpointer data, gpointer callback_data) +{ + char ***storage; + char **value; + + g_assert (data != NULL); + g_assert (callback_data != NULL); + + storage = (char ***)data; + value = (char **)callback_data; + + g_strfreev (*storage); + *(char ***)storage = value ? g_strdupv (value) : NULL; +} + +static void +update_auto_string_array_as_quarks (gpointer data, gpointer callback_data) +{ + GQuark **storage; + char **value; + int i = 0; + + g_assert (data != NULL); + g_assert (callback_data != NULL); + + storage = (GQuark **)data; + value = (char **)callback_data; + + g_free (*storage); + *storage = g_new (GQuark, g_strv_length (value) + 1); + + if (value != NULL) + { + for (i = 0; value[i] != NULL; ++i) + { + (*storage)[i] = g_quark_from_string (value[i]); + } + } + (*storage)[i] = 0; +} + +static void +update_auto_integer_or_boolean (gpointer data, gpointer callback_data) +{ + g_assert (data != NULL); + + *(int *)data = GPOINTER_TO_INT (callback_data); +} + +static void +preferences_entry_update_auto_storage (PreferencesEntry *entry) +{ + char *new_string_value; + char **new_string_array_value; + int new_int_value; + guint new_uint_value; + gboolean new_boolean_value; + + switch (entry->type) + { + case PREFERENCE_STRING: + if (entry->enumeration_id != NULL) + { + new_uint_value = eel_preferences_get_enum (entry->name); + g_list_foreach (entry->auto_storage_list, + update_auto_integer_or_boolean, + GINT_TO_POINTER (new_uint_value)); + } + else + { + new_string_value = eel_preferences_get (entry->name); + g_list_foreach (entry->auto_storage_list, + update_auto_string, + new_string_value); + g_free (new_string_value); + } + break; + case PREFERENCE_STRING_ARRAY: + new_string_array_value = eel_preferences_get_string_array (entry->name); + g_list_foreach (entry->auto_storage_list, + update_auto_string_array, + new_string_array_value); + g_strfreev (new_string_array_value); + break; + case PREFERENCE_STRING_ARRAY_AS_QUARKS: + new_string_array_value = eel_preferences_get_string_array (entry->name); + g_list_foreach (entry->auto_storage_list, + update_auto_string_array_as_quarks, + new_string_array_value); + g_strfreev (new_string_array_value); + break; + case PREFERENCE_INTEGER: + new_int_value = eel_preferences_get_integer (entry->name); + g_list_foreach (entry->auto_storage_list, + update_auto_integer_or_boolean, + GINT_TO_POINTER (new_int_value)); + break; + case PREFERENCE_BOOLEAN: + new_boolean_value = eel_preferences_get_boolean (entry->name); + g_list_foreach (entry->auto_storage_list, + update_auto_integer_or_boolean, + GINT_TO_POINTER (new_boolean_value)); + break; + default: + g_warning ("unexpected preferences type %d in preferences_entry_update_auto_storage", entry->type); + } +} + +static void +preferences_something_changed_notice (MateConfClient *client, + guint connection_id, + MateConfEntry *entry, + gpointer notice_data) +{ + g_assert (entry != NULL); + g_assert (entry->key != NULL); + g_assert (notice_data != NULL); + + preferences_entry_invoke_callbacks (notice_data); +} + +static void +preferences_entry_ensure_mateconf_connection (PreferencesEntry *entry) +{ + char *key; + + /* + * We install only one mateconf notification for each preference entry. + * Otherwise, we would invoke the installed callbacks more than once + * per registered callback. + */ + if (entry->mateconf_connection_id != EEL_MATECONF_UNDEFINED_CONNECTION) + { + return; + } + + g_assert (entry->name != NULL); + + key = preferences_key_make (entry->name); + + entry->mateconf_connection_id = eel_mateconf_notification_add (key, + preferences_something_changed_notice, + entry); + g_free (key); + + g_assert (entry->mateconf_connection_id != EEL_MATECONF_UNDEFINED_CONNECTION); +} + +/** + * preferences_entry_add_callback + * + * Add a callback to a pref node. Callbacks are fired whenever + * the pref value changes. + * @preferences_entry: The hash node. + * @callback: The user-supplied callback. + * @callback_data: The user-supplied closure. + **/ +static void +preferences_entry_add_callback (PreferencesEntry *entry, + EelPreferencesCallback callback, + gpointer callback_data) +{ + PreferencesCallbackEntry *callback_entry; + GList *l; + + g_assert (entry != NULL); + g_assert (callback != NULL); + + callback_entry = g_new0 (PreferencesCallbackEntry, 1); + callback_entry->callback = callback; + callback_entry->callback_data = callback_data; + + l = g_list_find_custom (entry->callback_list, callback_entry, preferences_callback_entry_compare); + if (l == NULL) + { + entry->callback_list = g_list_append (entry->callback_list, callback_entry); + preferences_entry_ensure_mateconf_connection (entry); + } + else + { + g_warning ("Trying to add a callback for %s that already exists.", entry->name); + } +} + +/** + * preferences_entry_add_auto_storage + * + * Add an auto-storage variable to a pref node. The variable will + * be updated to match the pref value whenever the pref + * the pref value changes. + * @preferences_entry: The hash node. + * @storage: The user-supplied location at which to store the value. + * @type: Which type of variable this is. + **/ +static void +preferences_entry_add_auto_storage (PreferencesEntry *entry, + gpointer storage, + PreferenceType type) +{ + g_assert (entry != NULL); + g_assert (storage != NULL); + g_assert (entry->type == 0 || entry->type == type); + if (g_list_find (entry->auto_storage_list, storage) != NULL) + { + g_warning ("Trying to add an auto storage for %s that already exists.", entry->name); + return; + } + + entry->type = type; + + entry->auto_storage_list = g_list_append (entry->auto_storage_list, storage); + + preferences_entry_ensure_mateconf_connection (entry); +} + +static void +preferences_entry_check_remove_connection (PreferencesEntry *entry) +{ + /* + * If there are no callbacks or auto-storage variables left in the entry, + * remove the mateconf notification. + */ + if (entry->callback_list != NULL || entry->auto_storage_list != NULL) + { + return; + } + + eel_mateconf_notification_remove (entry->mateconf_connection_id); + entry->mateconf_connection_id = EEL_MATECONF_UNDEFINED_CONNECTION; +} + +/** + * preferences_entry_remove_callback + * + * remove a callback from a pref entry. Both the callback and the callback_data must + * match in order for a callback to be removed from the entry. + * @preferences_entry: The hash entry. + * @callback: The user-supplied callback. + * @callback_data: The user-supplied closure. + **/ +static void +preferences_entry_remove_callback (PreferencesEntry *entry, + EelPreferencesCallback callback, + gpointer callback_data) +{ + PreferencesCallbackEntry cb_entry; + GList *l; + + g_assert (entry != NULL); + g_assert (callback != NULL); + + cb_entry.callback = callback; + cb_entry.callback_data = callback_data; + + l = g_list_find_custom (entry->callback_list, &cb_entry, preferences_callback_entry_compare); + if (l != NULL) + { + preferences_callback_entry_free (l->data); + entry->callback_list = g_list_delete_link (entry->callback_list, l); + preferences_entry_check_remove_connection (entry); + } + else + { + g_warning ("Trying to remove a callback for %s without adding it first.", entry->name); + } + + g_assert (g_list_find_custom (entry->callback_list, &cb_entry, preferences_callback_entry_compare) == NULL); +} + +/** + * preferences_entry_remove_auto_storage + * + * remove an auto-storage variable from a pref entry. + * @preferences_entry: The hash entry. + * @storage: The user-supplied location. + **/ +static void +preferences_entry_remove_auto_storage (PreferencesEntry *entry, + gpointer storage) +{ + GList *new_list; + const GList *node; + gpointer storage_in_entry; + + g_assert (entry != NULL); + g_assert (storage != NULL); + g_assert (entry->auto_storage_list != NULL); + + new_list = g_list_copy (entry->auto_storage_list); + + for (node = new_list; node != NULL; node = node->next) + { + storage_in_entry = node->data; + + g_assert (storage_in_entry != NULL); + + if (storage_in_entry == storage) + { + entry->auto_storage_list = g_list_remove (entry->auto_storage_list, + storage); + + switch (entry->type) + { + case PREFERENCE_STRING: + update_auto_string (storage, NULL); + break; + case PREFERENCE_STRING_ARRAY: + update_auto_string_array (storage, NULL); + break; + case PREFERENCE_STRING_ARRAY_AS_QUARKS: + update_auto_string_array_as_quarks (storage, NULL); + break; + case PREFERENCE_BOOLEAN: + case PREFERENCE_INTEGER: + update_auto_integer_or_boolean (storage, NULL); + break; + default: + g_warning ("unexpected preference type %d in preferences_entry_remove_auto_storage", entry->type); + } + } + } + + g_list_free (new_list); + + preferences_entry_check_remove_connection (entry); +} + +/** + * preferences_callback_entry_free + * + * Free a callback info struct. + * @preferences_callback_entry: The struct to free. + **/ +static void +preferences_callback_entry_free (PreferencesCallbackEntry *callback_entry) +{ + g_assert (callback_entry != NULL); + + callback_entry->callback = NULL; + callback_entry->callback_data = NULL; + + g_free (callback_entry); +} + +/** + * preferences_callback_entry_free_func + * + * A function that frees a callback info struct. It is meant to be fed to + * g_list_foreach () + * @data: The list data privately maintained by the GList. + * @callback_data: The callback_data privately maintained by the GList. + **/ +static void +preferences_callback_entry_free_func (gpointer data, + gpointer callback_data) +{ + g_assert (data != NULL); + + preferences_callback_entry_free (data); +} + +/** + * preferences_entry_free + * + * Free a preference hash node's members along with the node itself. + * @preferences_hash_node: The node to free. + **/ +static void +preferences_entry_free (PreferencesEntry *entry) +{ + g_assert (entry != NULL); + + eel_mateconf_notification_remove (entry->mateconf_connection_id); + entry->mateconf_connection_id = EEL_MATECONF_UNDEFINED_CONNECTION; + + g_list_free (entry->auto_storage_list); + eel_g_list_free_deep_custom (entry->callback_list, + preferences_callback_entry_free_func, + NULL); + + entry->auto_storage_list = NULL; + entry->callback_list = NULL; + + g_free (entry->name); + g_free (entry->description); + g_free (entry->enumeration_id); + + eel_mateconf_value_free (entry->fallback); + + g_free (entry); +} + +/** + * preferences_entry_free_func + * + * A function that frees a pref hash node. It is meant to be fed to + * g_hash_table_foreach () + * @key: The hash key privately maintained by the GHashTable. + * @value: The hash value privately maintained by the GHashTable. + * @callback_data: The callback_data privately maintained by the GHashTable. + **/ +static void +preferences_entry_free_func (gpointer key, + gpointer value, + gpointer callback_data) +{ + g_assert (value != NULL); + + preferences_entry_free (value); +} + +static void +preferences_global_table_free (void) +{ + if (global_table == NULL) + { + return; + } + + g_hash_table_foreach (global_table, preferences_entry_free_func, NULL); + g_hash_table_destroy (global_table); + global_table = NULL; + + g_free (storage_path); + storage_path = NULL; +} + +static void +preferences_uninitialize (void) +{ + initialized = FALSE; +} + +static GHashTable * +preferences_global_table_get_global (void) +{ + static gboolean at_exit_handler_added = FALSE; + + if (global_table == NULL) + { + global_table = g_hash_table_new (g_str_hash, g_str_equal); + + if (!at_exit_handler_added) + { + at_exit_handler_added = TRUE; + eel_debug_call_at_shutdown (preferences_global_table_free); + /* ensure that we catch calls to preferences functions after eel shutdown */ + eel_debug_call_at_shutdown (preferences_uninitialize); + } + } + + return global_table; +} + +static PreferencesEntry * +preferences_global_table_lookup (const char *name) +{ + g_assert (name != NULL); + g_assert (preferences_global_table_get_global () != NULL); + + return g_hash_table_lookup (preferences_global_table_get_global (), name); +} + +static PreferencesEntry * +preferences_global_table_insert (const char *name) +{ + PreferencesEntry *entry; + + g_assert (name != NULL); + g_assert (preferences_global_table_get_global () != NULL); + g_assert (preferences_global_table_lookup (name) == NULL); + + entry = g_new0 (PreferencesEntry, 1); + entry->name = g_strdup (name); + + g_hash_table_insert (preferences_global_table_get_global (), entry->name, entry); + + g_assert (entry == preferences_global_table_lookup (name)); + + return entry; +} + +static PreferencesEntry * +preferences_global_table_lookup_or_insert (const char *name) +{ + PreferencesEntry *entry; + + g_assert (name != NULL); + + entry = preferences_global_table_lookup (name); + + if (entry != NULL) + { + return entry; + } + + entry = preferences_global_table_insert (name); + g_assert (entry != NULL); + + return entry; +} + +void +eel_preferences_add_callback (const char *name, + EelPreferencesCallback callback, + gpointer callback_data) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (callback != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + preferences_entry_add_callback (entry, callback, callback_data); +} + +void +eel_preferences_add_auto_string (const char *name, + const char **storage) +{ + PreferencesEntry *entry; + char *value; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING); + + value = eel_preferences_get (entry->name); + update_auto_string (storage, value); + g_free (value); +} + +void +eel_preferences_add_auto_string_array (const char *name, + char ***storage) +{ + PreferencesEntry *entry; + char **value; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING_ARRAY); + + value = eel_preferences_get_string_array (entry->name); + update_auto_string_array (storage, value); + g_strfreev (value); +} + +void +eel_preferences_add_auto_string_array_as_quarks (const char *name, + GQuark **storage) +{ + PreferencesEntry *entry; + char **value; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING_ARRAY_AS_QUARKS); + + value = eel_preferences_get_string_array (entry->name); + update_auto_string_array_as_quarks (storage, value); + g_strfreev (value); +} + +void +eel_preferences_add_auto_integer (const char *name, + int *storage) +{ + PreferencesEntry *entry; + int value; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + preferences_entry_add_auto_storage (entry, storage, PREFERENCE_INTEGER); + + value = eel_preferences_get_integer (entry->name); + update_auto_integer_or_boolean (storage, GINT_TO_POINTER (value)); +} + + +void +eel_preferences_add_auto_enum (const char *name, + guint *storage) +{ + PreferencesEntry *entry; + guint value; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + g_assert (entry->enumeration_id != NULL); + + preferences_entry_add_auto_storage (entry, storage, PREFERENCE_STRING); + + value = eel_preferences_get_enum (entry->name); + update_auto_integer_or_boolean (storage, GINT_TO_POINTER (value)); +} + +void +eel_preferences_add_auto_boolean (const char *name, + gboolean *storage) +{ + PreferencesEntry *entry; + gboolean value; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + preferences_entry_add_auto_storage (entry, storage, PREFERENCE_BOOLEAN); + + value = eel_preferences_get_boolean (entry->name); + update_auto_integer_or_boolean (storage, GINT_TO_POINTER (value)); +} + +void +eel_preferences_remove_auto_string (const char *name, + const char **storage) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup (name); + if (entry == NULL) + { + g_warning ("Trying to remove auto-string for %s without adding it first.", name); + return; + } + + preferences_entry_remove_auto_storage (entry, storage); +} + +void +eel_preferences_remove_auto_string_array (const char *name, + char ***storage) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup (name); + if (entry == NULL) + { + g_warning ("Trying to remove auto-string for %s without adding it first.", name); + return; + } + + preferences_entry_remove_auto_storage (entry, storage); +} + +void +eel_preferences_remove_auto_integer (const char *name, + int *storage) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup (name); + if (entry == NULL) + { + g_warning ("Trying to remove auto-integer for %s without adding it first.", name); + return; + } + + preferences_entry_remove_auto_storage (entry, storage); +} + +void +eel_preferences_remove_auto_boolean (const char *name, + gboolean *storage) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (storage != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup (name); + if (entry == NULL) + { + g_warning ("Trying to remove auto-boolean for %s without adding it first.", name); + return; + } + + preferences_entry_remove_auto_storage (entry, storage); +} + +typedef struct +{ + char *name; + EelPreferencesCallback callback; + gpointer callback_data; +} WhileAliveData; + +static void +preferences_while_alive_disconnector (gpointer callback_data, GObject *where_object_was) +{ + WhileAliveData *data; + + g_assert (callback_data != NULL); + + data = callback_data; + + /* we might have survived an eel shutdown, which + * already cleared all the callbacks */ + if (preferences_is_initialized ()) + { + eel_preferences_remove_callback (data->name, + data->callback, + data->callback_data); + } + + g_free (data->name); + g_free (data); +} + +void +eel_preferences_add_callback_while_alive (const char *name, + EelPreferencesCallback callback, + gpointer callback_data, + GObject *alive_object) +{ + WhileAliveData *data; + + g_return_if_fail (name != NULL); + g_return_if_fail (callback != NULL); + g_return_if_fail (G_IS_OBJECT (alive_object)); + g_return_if_fail (preferences_is_initialized ()); + + data = g_new (WhileAliveData, 1); + data->name = g_strdup (name); + data->callback = callback; + data->callback_data = callback_data; + + eel_preferences_add_callback (name, callback, callback_data); + + g_object_weak_ref (alive_object, + preferences_while_alive_disconnector, + data); +} + +void +eel_preferences_remove_callback (const char *name, + EelPreferencesCallback callback, + gpointer callback_data) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (callback != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup (name); + + if (entry == NULL) + { + g_warning ("Trying to remove a callback for %s without adding it first.", name); + return; + } + + preferences_entry_remove_callback (entry, callback, callback_data); +} + +void +eel_preferences_set_description (const char *name, + const char *description) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (description != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + g_free (entry->description); + entry->description = g_strdup (description); +} + +char * +eel_preferences_get_description (const char *name) +{ + PreferencesEntry *entry; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (preferences_is_initialized (), NULL); + + entry = preferences_global_table_lookup_or_insert (name); + + return g_strdup (entry->description ? entry->description : ""); +} + +void +eel_preferences_set_enumeration_id (const char *name, + const char *enumeration_id) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (enumeration_id != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + g_free (entry->enumeration_id); + entry->enumeration_id = g_strdup (enumeration_id); +} + +char * +eel_preferences_get_enumeration_id (const char *name) +{ + PreferencesEntry *entry; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (preferences_is_initialized (), NULL); + + entry = preferences_global_table_lookup_or_insert (name); + + return g_strdup (entry->enumeration_id); +} + +static void +preferences_set_emergency_fallback_stealing_value (const char *name, + MateConfValue *value) +{ + PreferencesEntry *entry; + + g_assert (name != NULL); + g_assert (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + if (entry->fallback) + mateconf_value_free (entry->fallback); + entry->fallback = value; /* steal ownership of value */ +} + +void +eel_preferences_set_emergency_fallback_string (const char *name, + const char *value) +{ + MateConfValue *mateconf_value; + + g_return_if_fail (name != NULL); + g_return_if_fail (value != NULL); + + mateconf_value = mateconf_value_new (MATECONF_VALUE_STRING); + + mateconf_value_set_string (mateconf_value, value); + + preferences_set_emergency_fallback_stealing_value (name, mateconf_value); +} + +void +eel_preferences_set_emergency_fallback_integer (const char *name, + int value) +{ + MateConfValue *mateconf_value; + + g_return_if_fail (name != NULL); + + mateconf_value = mateconf_value_new (MATECONF_VALUE_INT); + + mateconf_value_set_int (mateconf_value, value); + + preferences_set_emergency_fallback_stealing_value (name, mateconf_value); +} + +void +eel_preferences_set_emergency_fallback_boolean (const char *name, + gboolean value) +{ + MateConfValue *mateconf_value; + + g_return_if_fail (name != NULL); + + mateconf_value = mateconf_value_new (MATECONF_VALUE_BOOL); + + mateconf_value_set_bool (mateconf_value, value); + + preferences_set_emergency_fallback_stealing_value (name, mateconf_value); +} + + +void +eel_preferences_set_emergency_fallback_string_array (const char *name, + char **value) +{ + MateConfValue *mateconf_value; + GSList *list; + int i; + + g_return_if_fail (name != NULL); + g_return_if_fail (value != NULL); + + mateconf_value = mateconf_value_new (MATECONF_VALUE_LIST); + mateconf_value_set_list_type (mateconf_value, MATECONF_VALUE_STRING); + + list = NULL; + for (i = 0; value[i] != NULL; ++i) + { + MateConfValue *v; + + v = mateconf_value_new (MATECONF_VALUE_STRING); + mateconf_value_set_string (v, value[i]); + + list = g_slist_prepend (list, v); + } + + mateconf_value_set_list_nocopy (mateconf_value, g_slist_reverse (list)); + + preferences_set_emergency_fallback_stealing_value (name, mateconf_value); +} + +MateConfValue* +eel_preferences_get_emergency_fallback (const char *name) +{ + PreferencesEntry *entry; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (preferences_is_initialized (), NULL); + + entry = preferences_global_table_lookup_or_insert (name); + + return entry->fallback ? mateconf_value_copy (entry->fallback) : NULL; +} + +gboolean +eel_preferences_monitor_directory (const char *directory) +{ + g_return_val_if_fail (preferences_is_initialized (), FALSE); + + return eel_mateconf_monitor_add (directory); +} + +gboolean +eel_preferences_is_visible (const char *name) +{ + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (preferences_is_initialized (), FALSE); + + return !preferences_global_table_lookup_or_insert (name)->invisible; +} + +void +eel_preferences_init (const char *path) +{ + g_return_if_fail (eel_strlen (path) > 0); + + if (initialized) + { + return; + } + + initialized = TRUE; + + preferences_set_storage_path (path); +} + +#if !defined (EEL_OMIT_SELF_CHECK) + +#define CHECK_BOOLEAN(name__, value__) \ +G_STMT_START { \ + eel_preferences_set_boolean ((name__), (value__)); \ + EEL_CHECK_BOOLEAN_RESULT (eel_preferences_get_boolean (name__), (value__)); \ +} G_STMT_END + +#define CHECK_INTEGER(name__, value__) \ +G_STMT_START { \ + eel_preferences_set_integer ((name__), (value__)); \ + EEL_CHECK_INTEGER_RESULT (eel_preferences_get_integer (name__), (value__)); \ +} G_STMT_END + +#define CHECK_STRING(name__, value__) \ +G_STMT_START { \ + eel_preferences_set ((name__), (value__)); \ + EEL_CHECK_STRING_RESULT (eel_preferences_get (name__), (value__)); \ +} G_STMT_END + +void +eel_self_check_preferences (void) +{ + /* Disabled until I can debug why these seemingly harmless tests + * dont work. -re + */ +#if 0 + int original_user_level; + + original_user_level = eel_preferences_get_user_level (); + + EEL_CHECK_INTEGER_RESULT (eel_preferences_get_integer ("self-check/neverset/i"), 0); + EEL_CHECK_STRING_RESULT (eel_preferences_get ("self-check/neverset/s"), ""); + EEL_CHECK_BOOLEAN_RESULT (eel_preferences_get_boolean ("self-check/neverset/b"), FALSE); + + eel_preferences_set_user_level (0); + + /* FIXME: Fails if you add the commented-out lines. */ + /* CHECK_INTEGER ("self-check/i", 0); */ + CHECK_INTEGER ("self-check/i", 666); + /* CHECK_BOOLEAN ("self-check/b", FALSE); */ + CHECK_BOOLEAN ("self-check/b", TRUE); + /* CHECK_STRING ("self-check/s", ""); */ + CHECK_STRING ("self-check/s", "foo"); + + /* Restore the original user level */ + eel_preferences_set_user_level (original_user_level); +#endif +} + +#endif /* !EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-preferences.h b/eel/eel-preferences.h new file mode 100644 index 00000000..ecbd7704 --- /dev/null +++ b/eel/eel-preferences.h @@ -0,0 +1,165 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-preferences.c - Preference peek/poke/notify interface. + + Copyright (C) 1999, 2000, 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_PREFERENCES_H +#define EEL_PREFERENCES_H + +#include <glib.h> + +#include <eel/eel-mateconf-extensions.h> +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * A callback which you can register to to be notified when a particular + * preference changes. + */ + typedef void (*EelPreferencesCallback) (gpointer callback_data); + + /* Preferences getters and setters */ + gboolean eel_preferences_get_boolean (const char *name); + void eel_preferences_set_boolean (const char *name, + gboolean boolean_value); + int eel_preferences_get_integer (const char *name); + void eel_preferences_set_integer (const char *name, + int int_value); + guint eel_preferences_get_uint (const char *name); + void eel_preferences_set_uint (const char *name, + guint uint_value); + guint eel_preferences_get_enum (const char *name); + void eel_preferences_set_enum (const char *name, + guint int_value); + char * eel_preferences_get (const char *name); + void eel_preferences_set (const char *name, + const char *string_value); + char ** eel_preferences_get_string_array (const char *name); + void eel_preferences_set_string_array (const char *name, + char **strv_value); + + void eel_preferences_unset (const char *name); + + /* Writability of a key */ + gboolean eel_preferences_key_is_writable (const char *name); + + /* Callbacks */ + void eel_preferences_add_callback (const char *name, + EelPreferencesCallback callback, + gpointer callback_data); + void eel_preferences_add_callback_while_alive (const char *name, + EelPreferencesCallback callback, + gpointer callback_data, + GObject *alive_object); + void eel_preferences_remove_callback (const char *name, + EelPreferencesCallback callback, + gpointer callback_data); + + /* Variables that are automatically updated (lightweight "callbacks") */ + void eel_preferences_add_auto_string (const char *name, + const char **storage); + void eel_preferences_add_auto_string_array (const char *name, + char ***storage); + void eel_preferences_add_auto_string_array_as_quarks (const char *name, + GQuark **storage); + void eel_preferences_add_auto_integer (const char *name, + int *storage); + void eel_preferences_add_auto_enum (const char *name, + guint *storage); + void eel_preferences_add_auto_boolean (const char *name, + gboolean *storage); + void eel_preferences_remove_auto_string (const char *name, + const char **storage); + void eel_preferences_remove_auto_string_array (const char *name, + char ***storage); + void eel_preferences_remove_auto_integer (const char *name, + int *storage); + void eel_preferences_remove_auto_boolean (const char *name, + int *storage); + + /* Preferences attributes */ + + gboolean eel_preferences_get_is_invisible (const char *name); + void eel_preferences_set_is_invisible (const char *name, + gboolean invisible); + char * eel_preferences_get_description (const char *name); + void eel_preferences_set_description (const char *name, + const char *description); + char * eel_preferences_get_enumeration_id (const char *name); + void eel_preferences_set_enumeration_id (const char *name, + const char *enumeration_id); + + void eel_preferences_set_emergency_fallback_string (const char *name, + const char *value); + void eel_preferences_set_emergency_fallback_integer (const char *name, + int value); + void eel_preferences_set_emergency_fallback_boolean (const char *name, + gboolean value); + void eel_preferences_set_emergency_fallback_string_array(const char *name, + char **value); + MateConfValue *eel_preferences_get_emergency_fallback (const char *name); + + + gboolean eel_preferences_monitor_directory (const char *directory); + gboolean eel_preferences_is_visible (const char *name); + void eel_preferences_init (const char *storage_path); + + void eel_preferences_builder_connect_bool (GtkBuilder *builder, + const char *component, + const char *key); + void eel_preferences_builder_connect_inverted_bool (GtkBuilder *builder, + const char *component, + const char *key); + void eel_preferences_builder_connect_bool_slave (GtkBuilder *builder, + const char *component, + const char *key); + void eel_preferences_builder_connect_string_enum_combo_box (GtkBuilder *builder, + const char *component, + const char *key, + const char **values); + void eel_preferences_builder_connect_string_enum_combo_box_slave (GtkBuilder *builder, + const char *component, + const char *key); + + void eel_preferences_builder_connect_uint_enum (GtkBuilder *builder, + const char *component, + const char *key, + const guint *values, + int num_values); + void eel_preferences_builder_connect_string_enum_radio_button (GtkBuilder *builder, + const char **components, + const char *key, + const char **values); + void eel_preferences_builder_connect_list_enum (GtkBuilder *builder, + const char **components, + const char *key, + const char **values); + + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_PREFERENCES_H */ diff --git a/eel/eel-self-checks.c b/eel/eel-self-checks.c new file mode 100644 index 00000000..c1fa425f --- /dev/null +++ b/eel/eel-self-checks.c @@ -0,0 +1,237 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-self-checks.c: The self-check framework. + + Copyright (C) 1999 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#include <config.h> + +#if ! defined (EEL_OMIT_SELF_CHECK) + +#include "eel-self-checks.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static gboolean failed; + +static const char *current_expression; +static const char *current_file_name; +static int current_line_number; + +void +eel_exit_if_self_checks_failed (void) +{ + if (!failed) + { + return; + } + + printf ("\n"); + + exit (EXIT_FAILURE); +} + +void +eel_report_check_failure (char *result, char *expected) +{ + if (!failed) + { + fprintf (stderr, "\n"); + } + + fprintf (stderr, "FAIL: check failed in %s, line %d\n", current_file_name, current_line_number); + fprintf (stderr, " evaluated: %s\n", current_expression); + fprintf (stderr, " expected: %s\n", expected == NULL ? "NULL" : expected); + fprintf (stderr, " got: %s\n", result == NULL ? "NULL" : result); + + failed = TRUE; + + g_free (result); + g_free (expected); +} + +static char * +eel_strdup_boolean (gboolean boolean) +{ + if (boolean == FALSE) + { + return g_strdup ("FALSE"); + } + if (boolean == TRUE) + { + return g_strdup ("TRUE"); + } + return g_strdup_printf ("gboolean(%d)", boolean); +} + +void +eel_before_check (const char *expression, + const char *file_name, + int line_number) +{ + current_expression = expression; + current_file_name = file_name; + current_line_number = line_number; +} + +void +eel_after_check (void) +{ + /* It would be good to check here if there was a memory leak. */ +} + +void +eel_check_boolean_result (gboolean result, gboolean expected) +{ + if (result != expected) + { + eel_report_check_failure (eel_strdup_boolean (result), + eel_strdup_boolean (expected)); + } + eel_after_check (); +} + +void +eel_check_rectangle_result (EelIRect result, + int expected_x0, + int expected_y0, + int expected_x1, + int expected_y1) +{ + if (result.x0 != expected_x0 + || result.y0 != expected_y0 + || result.x1 != expected_x1 + || result.y1 != expected_y1) + { + eel_report_check_failure (g_strdup_printf ("x0=%d, y0=%d, x1=%d, y1=%d", + result.x0, + result.y0, + result.x1, + result.y1), + g_strdup_printf ("x0=%d, y0=%d, x1=%d, y1=%d", + expected_x0, + expected_y0, + expected_x1, + expected_y1)); + } + eel_after_check (); +} + +void +eel_check_dimensions_result (EelDimensions result, + int expected_width, + int expected_height) +{ + if (result.width != expected_width + || result.height != expected_height) + { + eel_report_check_failure (g_strdup_printf ("width=%d, height=%d", + result.width, + result.height), + g_strdup_printf ("width=%d, height=%d", + expected_width, + expected_height)); + } + eel_after_check (); +} + +void +eel_check_point_result (EelIPoint result, + int expected_x, + int expected_y) +{ + if (result.x != expected_x + || result.y != expected_y) + { + eel_report_check_failure (g_strdup_printf ("x=%d, y=%d", + result.x, + result.y), + g_strdup_printf ("x=%d, y=%d", + expected_x, + expected_y)); + } + eel_after_check (); +} + +void +eel_check_integer_result (long result, long expected) +{ + if (result != expected) + { + eel_report_check_failure (g_strdup_printf ("%ld", result), + g_strdup_printf ("%ld", expected)); + } + eel_after_check (); +} + +void +eel_check_double_result (double result, double expected) +{ + if (result != expected) + { + eel_report_check_failure (g_strdup_printf ("%f", result), + g_strdup_printf ("%f", expected)); + } + eel_after_check (); +} + +void +eel_check_string_result (char *result, const char *expected) +{ + gboolean match; + + /* Stricter than eel_strcmp. + * NULL does not match "" in this test. + */ + if (expected == NULL) + { + match = result == NULL; + } + else + { + match = result != NULL && strcmp (result, expected) == 0; + } + + if (!match) + { + eel_report_check_failure (result, g_strdup (expected)); + } + else + { + g_free (result); + } + eel_after_check (); +} + +void +eel_before_check_function (const char *name) +{ + fprintf (stderr, "running %s\n", name); +} + +void +eel_after_check_function (void) +{ +} + +#endif /* ! EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-self-checks.h b/eel/eel-self-checks.h new file mode 100644 index 00000000..778a2be2 --- /dev/null +++ b/eel/eel-self-checks.h @@ -0,0 +1,101 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-self-checks.h: The self-check framework. + + Copyright (C) 1999 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <[email protected]> +*/ + +#ifndef EEL_SELF_CHECKS_H +#define EEL_SELF_CHECKS_H + +#include <glib.h> + +#include <eel/eel-art-extensions.h> + +#define EEL_CHECK_RESULT(type, expression, expected_value) \ +G_STMT_START { \ + eel_before_check (#expression, __FILE__, __LINE__); \ + eel_check_##type##_result (expression, expected_value); \ +} G_STMT_END + +#define EEL_CHECK_BOOLEAN_RESULT(expression, expected_value) \ + EEL_CHECK_RESULT(boolean, expression, expected_value) +#define EEL_CHECK_INTEGER_RESULT(expression, expected_value) \ + EEL_CHECK_RESULT(integer, expression, expected_value) +#define EEL_CHECK_DOUBLE_RESULT(expression, expected_value) \ + EEL_CHECK_RESULT(double, expression, expected_value) +#define EEL_CHECK_STRING_RESULT(expression, expected_value) \ + EEL_CHECK_RESULT(string, expression, expected_value) +#define EEL_CHECK_RECTANGLE_RESULT(expression, expected_x0, expected_y0, expected_x1, expected_y1) \ +G_STMT_START { \ + eel_before_check (#expression, __FILE__, __LINE__); \ + eel_check_rectangle_result (expression, expected_x0, expected_y0, expected_x1, expected_y1); \ +} G_STMT_END +#define EEL_CHECK_DIMENSIONS_RESULT(expression, expected_width, expected_height) \ +G_STMT_START { \ + eel_before_check (#expression, __FILE__, __LINE__); \ + eel_check_dimensions_result (expression, expected_width, expected_height); \ +} G_STMT_END +#define EEL_CHECK_POINT_RESULT(expression, expected_x, expected_y) \ +G_STMT_START { \ + eel_before_check (#expression, __FILE__, __LINE__); \ + eel_check_point_result (expression, expected_x, expected_y); \ +} G_STMT_END + +void eel_exit_if_self_checks_failed (void); +void eel_before_check_function (const char *name); +void eel_after_check_function (void); +void eel_before_check (const char *expression, + const char *file_name, + int line_number); +void eel_after_check (void); + +/* Both 'result' and 'expected' get freed with g_free */ +void eel_report_check_failure (char *result, + char *expected); +void eel_check_boolean_result (gboolean result, + gboolean expected_value); +void eel_check_integer_result (long result, + long expected_value); +void eel_check_double_result (double result, + double expected_value); +void eel_check_rectangle_result (EelIRect result, + int expected_x0, + int expected_y0, + int expected_x1, + int expected_y1); +void eel_check_dimensions_result (EelDimensions result, + int expected_width, + int expected_height); +void eel_check_point_result (EelIPoint result, + int expected_x, + int expected_y); +void eel_check_string_result (char *result, + const char *expected_value); + +#define EEL_SELF_CHECK_FUNCTION_PROTOTYPE(function) \ + void function (void); + +#define EEL_CALL_SELF_CHECK_FUNCTION(function) \ + eel_before_check_function (#function); \ + function (); \ + eel_after_check_function (); + +#endif /* EEL_SELF_CHECKS_H */ diff --git a/eel/eel-stock-dialogs.c b/eel/eel-stock-dialogs.c new file mode 100644 index 00000000..c538971c --- /dev/null +++ b/eel/eel-stock-dialogs.c @@ -0,0 +1,588 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-stock-dialogs.c: Various standard dialogs for Eel. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-stock-dialogs.h" + +#include "eel-alert-dialog.h" +#include "eel-glib-extensions.h" +#include "eel-mate-extensions.h" +#include "eel-string.h" +#include "eel-i18n.h" +#include <gtk/gtk.h> + +#define TIMED_WAIT_STANDARD_DURATION 2000 +#define TIMED_WAIT_MIN_TIME_UP 3000 + +#define TIMED_WAIT_MINIMUM_DIALOG_WIDTH 300 + +#define RESPONSE_DETAILS 1000 + +typedef struct +{ + EelCancelCallback cancel_callback; + gpointer callback_data; + + /* Parameters for creation of the window. */ + char *wait_message; + GtkWindow *parent_window; + + /* Timer to determine when we need to create the window. */ + guint timeout_handler_id; + + /* Window, once it's created. */ + GtkDialog *dialog; + + /* system time (microseconds) when dialog was created */ + gint64 dialog_creation_time; + +} TimedWait; + +static GHashTable *timed_wait_hash_table; + +static void timed_wait_dialog_destroy_callback (GtkObject *object, gpointer callback_data); + +static guint +timed_wait_hash (gconstpointer value) +{ + const TimedWait *wait; + + wait = value; + + return GPOINTER_TO_UINT (wait->cancel_callback) + ^ GPOINTER_TO_UINT (wait->callback_data); +} + +static gboolean +timed_wait_hash_equal (gconstpointer value1, gconstpointer value2) +{ + const TimedWait *wait1, *wait2; + + wait1 = value1; + wait2 = value2; + + return wait1->cancel_callback == wait2->cancel_callback + && wait1->callback_data == wait2->callback_data; +} + +static void +timed_wait_delayed_close_destroy_dialog_callback (GtkObject *object, gpointer callback_data) +{ + g_source_remove (GPOINTER_TO_UINT (callback_data)); +} + +static gboolean +timed_wait_delayed_close_timeout_callback (gpointer callback_data) +{ + guint handler_id; + + handler_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (callback_data), + "eel-stock-dialogs/delayed_close_handler_timeout_id")); + + g_signal_handlers_disconnect_by_func (G_OBJECT (callback_data), + G_CALLBACK (timed_wait_delayed_close_destroy_dialog_callback), + GUINT_TO_POINTER (handler_id)); + + gtk_object_destroy (GTK_OBJECT (callback_data)); + + return FALSE; +} + +static void +timed_wait_free (TimedWait *wait) +{ + guint delayed_close_handler_id; + guint64 time_up; + + g_assert (g_hash_table_lookup (timed_wait_hash_table, wait) != NULL); + + g_hash_table_remove (timed_wait_hash_table, wait); + + g_free (wait->wait_message); + if (wait->parent_window != NULL) + { + g_object_unref (wait->parent_window); + } + if (wait->timeout_handler_id != 0) + { + g_source_remove (wait->timeout_handler_id); + } + if (wait->dialog != NULL) + { + /* Make sure to detach from the "destroy" signal, or we'll + * double-free. + */ + g_signal_handlers_disconnect_by_func (G_OBJECT (wait->dialog), + G_CALLBACK (timed_wait_dialog_destroy_callback), + wait); + + /* compute time up in milliseconds */ + time_up = (eel_get_system_time () - wait->dialog_creation_time) / 1000; + + if (time_up < TIMED_WAIT_MIN_TIME_UP) + { + delayed_close_handler_id = g_timeout_add (TIMED_WAIT_MIN_TIME_UP - time_up, + timed_wait_delayed_close_timeout_callback, + wait->dialog); + g_object_set_data (G_OBJECT (wait->dialog), + "eel-stock-dialogs/delayed_close_handler_timeout_id", + GUINT_TO_POINTER (delayed_close_handler_id)); + g_signal_connect (wait->dialog, "destroy", + G_CALLBACK (timed_wait_delayed_close_destroy_dialog_callback), + GUINT_TO_POINTER (delayed_close_handler_id)); + } + else + { + gtk_object_destroy (GTK_OBJECT (wait->dialog)); + } + } + + /* And the wait object itself. */ + g_free (wait); +} + +static void +timed_wait_dialog_destroy_callback (GtkObject *object, gpointer callback_data) +{ + TimedWait *wait; + + wait = callback_data; + + g_assert (GTK_DIALOG (object) == wait->dialog); + + wait->dialog = NULL; + + /* When there's no cancel_callback, the originator will/must + * call eel_timed_wait_stop which will call timed_wait_free. + */ + + if (wait->cancel_callback != NULL) + { + (* wait->cancel_callback) (wait->callback_data); + timed_wait_free (wait); + } +} + +static void +trash_dialog_response_callback (GtkDialog *dialog, + int response_id, + TimedWait *wait) +{ + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static gboolean +timed_wait_callback (gpointer callback_data) +{ + TimedWait *wait; + GtkDialog *dialog; + const char *button; + + wait = callback_data; + + /* Put up the timed wait window. */ + button = wait->cancel_callback != NULL ? GTK_STOCK_CANCEL : GTK_STOCK_OK; + dialog = GTK_DIALOG (eel_alert_dialog_new (wait->parent_window, + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_NONE, + wait->wait_message, + _("You can stop this operation by clicking cancel."))); + + gtk_dialog_add_button (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + /* The contents are often very small, causing tiny little + * dialogs with their titles clipped if you just let gtk + * sizing do its thing. This enforces a minimum width to + * make it more likely that the title won't be clipped. + */ + gtk_window_set_default_size (GTK_WINDOW (dialog), + TIMED_WAIT_MINIMUM_DIALOG_WIDTH, + -1); + wait->dialog_creation_time = eel_get_system_time (); + gtk_widget_show (GTK_WIDGET (dialog)); + + /* FIXME bugzilla.eazel.com 2441: + * Could parent here, but it's complicated because we + * don't want this window to go away just because the parent + * would go away first. + */ + + /* Make the dialog cancel the timed wait when it goes away. + * Connect to "destroy" instead of "response" since we want + * to be called no matter how the dialog goes away. + */ + g_signal_connect (dialog, "destroy", + G_CALLBACK (timed_wait_dialog_destroy_callback), + wait); + g_signal_connect (dialog, "response", + G_CALLBACK (trash_dialog_response_callback), + wait); + + wait->timeout_handler_id = 0; + wait->dialog = dialog; + + return FALSE; +} + +void +eel_timed_wait_start_with_duration (int duration, + EelCancelCallback cancel_callback, + gpointer callback_data, + const char *wait_message, + GtkWindow *parent_window) +{ + TimedWait *wait; + + g_return_if_fail (callback_data != NULL); + g_return_if_fail (wait_message != NULL); + g_return_if_fail (parent_window == NULL || GTK_IS_WINDOW (parent_window)); + + /* Create the timed wait record. */ + wait = g_new0 (TimedWait, 1); + wait->wait_message = g_strdup (wait_message); + wait->cancel_callback = cancel_callback; + wait->callback_data = callback_data; + wait->parent_window = parent_window; + + if (parent_window != NULL) + { + g_object_ref (parent_window); + } + + /* Start the timer. */ + wait->timeout_handler_id = g_timeout_add (duration, timed_wait_callback, wait); + + /* Put in the hash table so we can find it later. */ + if (timed_wait_hash_table == NULL) + { + timed_wait_hash_table = eel_g_hash_table_new_free_at_exit + (timed_wait_hash, timed_wait_hash_equal, __FILE__ ": timed wait"); + } + g_assert (g_hash_table_lookup (timed_wait_hash_table, wait) == NULL); + g_hash_table_insert (timed_wait_hash_table, wait, wait); + g_assert (g_hash_table_lookup (timed_wait_hash_table, wait) == wait); +} + +void +eel_timed_wait_start (EelCancelCallback cancel_callback, + gpointer callback_data, + const char *wait_message, + GtkWindow *parent_window) +{ + eel_timed_wait_start_with_duration + (TIMED_WAIT_STANDARD_DURATION, + cancel_callback, callback_data, + wait_message, parent_window); +} + +void +eel_timed_wait_stop (EelCancelCallback cancel_callback, + gpointer callback_data) +{ + TimedWait key; + TimedWait *wait; + + g_return_if_fail (callback_data != NULL); + + key.cancel_callback = cancel_callback; + key.callback_data = callback_data; + wait = g_hash_table_lookup (timed_wait_hash_table, &key); + + g_return_if_fail (wait != NULL); + + timed_wait_free (wait); +} + +int +eel_run_simple_dialog (GtkWidget *parent, gboolean ignore_close_box, + GtkMessageType message_type, const char *primary_text, + const char *secondary_text, ...) +{ + va_list button_title_args; + const char *button_title; + GtkWidget *dialog; + GtkWidget *top_widget, *chosen_parent; + int result; + int response_id; + + /* Parent it if asked to. */ + chosen_parent = NULL; + if (parent != NULL) + { + top_widget = gtk_widget_get_toplevel (parent); + if (GTK_IS_WINDOW (top_widget)) + { + chosen_parent = top_widget; + } + } + + /* Create the dialog. */ + dialog = eel_alert_dialog_new (GTK_WINDOW (chosen_parent), + 0, + message_type, + GTK_BUTTONS_NONE, + primary_text, + secondary_text); + + va_start (button_title_args, secondary_text); + response_id = 0; + while (1) + { + button_title = va_arg (button_title_args, const char *); + if (button_title == NULL) + { + break; + } + gtk_dialog_add_button (GTK_DIALOG (dialog), button_title, response_id); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), response_id); + response_id++; + } + va_end (button_title_args); + + /* Run it. */ + gtk_widget_show (dialog); + result = gtk_dialog_run (GTK_DIALOG (dialog)); + while ((result == GTK_RESPONSE_NONE || result == GTK_RESPONSE_DELETE_EVENT) && ignore_close_box) + { + gtk_widget_show (GTK_WIDGET (dialog)); + result = gtk_dialog_run (GTK_DIALOG (dialog)); + } + gtk_object_destroy (GTK_OBJECT (dialog)); + + return result; +} + +static GtkDialog * +create_message_dialog (const char *primary_text, + const char *secondary_text, + GtkMessageType type, + GtkButtonsType buttons_type, + GtkWindow *parent) +{ + GtkWidget *dialog; + + dialog = eel_alert_dialog_new (parent, + 0, + type, + buttons_type, + primary_text, + secondary_text); + return GTK_DIALOG (dialog); +} + +static GtkDialog * +show_message_dialog (const char *primary_text, + const char *secondary_text, + GtkMessageType type, + GtkButtonsType buttons_type, + const char *details_text, + GtkWindow *parent) +{ + GtkDialog *dialog; + + dialog = create_message_dialog (primary_text, secondary_text, type, + buttons_type, parent); + if (details_text != NULL) + { + eel_alert_dialog_set_details_label (EEL_ALERT_DIALOG (dialog), details_text); + } + gtk_widget_show (GTK_WIDGET (dialog)); + + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_object_destroy), NULL); + + return dialog; +} + +static GtkDialog * +show_ok_dialog (const char *primary_text, + const char *secondary_text, + GtkMessageType type, + GtkWindow *parent) +{ + GtkDialog *dialog; + + dialog = show_message_dialog (primary_text, secondary_text, type, + GTK_BUTTONS_OK, NULL, parent); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + return dialog; +} + +GtkDialog * +eel_create_info_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent) +{ + return create_message_dialog (primary_text, secondary_text, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + parent); +} + +GtkDialog * +eel_show_info_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent) +{ + return show_ok_dialog (primary_text, + secondary_text, + GTK_MESSAGE_INFO, parent); +} + +GtkDialog * +eel_show_info_dialog_with_details (const char *primary_text, + const char *secondary_text, + const char *detailed_info, + GtkWindow *parent) +{ + GtkDialog *dialog; + + if (detailed_info == NULL + || strcmp (primary_text, detailed_info) == 0) + { + return eel_show_info_dialog (primary_text, secondary_text, parent); + } + + dialog = show_message_dialog (primary_text, + secondary_text, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + detailed_info, + parent); + + return dialog; + +} + + +GtkDialog * +eel_show_warning_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent) +{ + return show_ok_dialog (primary_text, + secondary_text, + GTK_MESSAGE_WARNING, parent); +} + + +GtkDialog * +eel_show_error_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent) +{ + return show_ok_dialog (primary_text, + secondary_text, + GTK_MESSAGE_ERROR, parent); +} + +GtkDialog * +eel_show_error_dialog_with_details (const char *primary_text, + const char *secondary_text, + const char *detailed_error_message, + GtkWindow *parent) +{ + GtkDialog *dialog; + + g_return_val_if_fail (primary_text != NULL, NULL); + g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); + + if (detailed_error_message == NULL + || strcmp (primary_text, detailed_error_message) == 0) + { + return eel_show_error_dialog (primary_text, secondary_text, parent); + } + + dialog = show_message_dialog (primary_text, + secondary_text, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, detailed_error_message, + parent); + return dialog; +} + +/** + * eel_show_yes_no_dialog: + * + * Create and show a dialog asking a question with two choices. + * The caller needs to set up any necessary callbacks + * for the buttons. Use eel_create_question_dialog instead + * if any visual changes need to be made, to avoid flashiness. + * @question: The text of the question. + * @yes_label: The label of the "yes" button. + * @no_label: The label of the "no" button. + * @parent: The parent window for this dialog. + */ +GtkDialog * +eel_show_yes_no_dialog (const char *primary_text, + const char *secondary_text, + const char *yes_label, + const char *no_label, + GtkWindow *parent) +{ + GtkDialog *dialog = NULL; + dialog = eel_create_question_dialog (primary_text, + secondary_text, + no_label, GTK_RESPONSE_CANCEL, + yes_label, GTK_RESPONSE_YES, + GTK_WINDOW (parent)); + gtk_widget_show (GTK_WIDGET (dialog)); + return dialog; +} + +/** + * eel_create_question_dialog: + * + * Create a dialog asking a question with at least two choices. + * The caller needs to set up any necessary callbacks + * for the buttons. The dialog is not yet shown, so that the + * caller can add additional buttons or make other visual changes + * without causing flashiness. + * @question: The text of the question. + * @answer_0: The label of the leftmost button (index 0) + * @answer_1: The label of the 2nd-to-leftmost button (index 1) + * @parent: The parent window for this dialog. + */ +GtkDialog * +eel_create_question_dialog (const char *primary_text, + const char *secondary_text, + const char *answer_1, + int response_1, + const char *answer_2, + int response_2, + GtkWindow *parent) +{ + GtkDialog *dialog; + + dialog = create_message_dialog (primary_text, + secondary_text, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + parent); + gtk_dialog_add_buttons (dialog, answer_1, response_1, answer_2, response_2, NULL); + return dialog; +} diff --git a/eel/eel-stock-dialogs.h b/eel/eel-stock-dialogs.h new file mode 100644 index 00000000..8e4f105f --- /dev/null +++ b/eel/eel-stock-dialogs.h @@ -0,0 +1,91 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-stock-dialogs.h: Various standard dialogs for Eel. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#ifndef EEL_STOCK_DIALOGS_H +#define EEL_STOCK_DIALOGS_H + +#include <gtk/gtk.h> + +typedef void (* EelCancelCallback) (gpointer callback_data); + +/* Dialog for cancelling something that normally is fast enough not to need a dialog. */ +void eel_timed_wait_start (EelCancelCallback cancel_callback, + gpointer callback_data, + const char *wait_message, + GtkWindow *parent_window); +void eel_timed_wait_start_with_duration (int duration, + EelCancelCallback cancel_callback, + gpointer callback_data, + const char *wait_message, + GtkWindow *parent_window); +void eel_timed_wait_stop (EelCancelCallback cancel_callback, + gpointer callback_data); + +/* Basic dialog with buttons. */ +int eel_run_simple_dialog (GtkWidget *parent, + gboolean ignore_close_box, + GtkMessageType message_type, + const char *primary_text, + const char *secondary_text, + ...); + +/* Variations on mate stock dialogs; these do line wrapping, we don't + * bother with non-parented versions, we allow setting the title, + * primary, and secondary messages, and we return GtkDialog pointers + * instead of GtkWidget pointers. + */ +GtkDialog *eel_show_info_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent); +GtkDialog *eel_show_info_dialog_with_details (const char *primary_text, + const char *secondary_text, + const char *detailed_informative_message, + GtkWindow *parent); +GtkDialog *eel_show_warning_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent); +GtkDialog *eel_show_error_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent); +GtkDialog *eel_show_error_dialog_with_details (const char *primary_text, + const char *secondary_text, + const char *detailed_error_message, + GtkWindow *parent); +GtkDialog *eel_show_yes_no_dialog (const char *primary_text, + const char *secondary_text, + const char *yes_label, + const char *no_label, + GtkWindow *parent); +GtkDialog *eel_create_question_dialog (const char *primary_text, + const char *secondary_text, + const char *answer_one, + int response_one, + const char *answer_two, + int response_two, + GtkWindow *parent); +GtkDialog *eel_create_info_dialog (const char *primary_text, + const char *secondary_text, + GtkWindow *parent); + +#endif /* EEL_STOCK_DIALOGS_H */ diff --git a/eel/eel-string.c b/eel/eel-string.c new file mode 100644 index 00000000..f554b91c --- /dev/null +++ b/eel/eel-string.c @@ -0,0 +1,1275 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-string.c: String routines to augment <string.h>. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-string.h" + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <eel-glib-extensions.h> + +#if !defined (EEL_OMIT_SELF_CHECK) +#include "eel-lib-self-check-functions.h" +#endif + +size_t +eel_strlen (const char *string) +{ + return string == NULL ? 0 : strlen (string); +} + +char * +eel_strchr (const char *haystack, char needle) +{ + return haystack == NULL ? NULL : strchr (haystack, needle); +} + +int +eel_strcmp (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL < ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return strcmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + +int +eel_strcasecmp (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL < ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return g_ascii_strcasecmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + +int +eel_strcmp_case_breaks_ties (const char *string_a, const char *string_b) +{ + int casecmp_result; + + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL < ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + casecmp_result = eel_strcasecmp (string_a, string_b); + if (casecmp_result != 0) + { + return casecmp_result; + } + return eel_strcmp (string_a, string_b); +} + +gboolean +eel_str_is_empty (const char *string_or_null) +{ + return eel_strcmp (string_or_null, NULL) == 0; +} + +gboolean +eel_str_is_equal (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL != ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return eel_strcmp (string_a, string_b) == 0; +} + +gboolean +eel_istr_is_equal (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL != ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return eel_strcasecmp (string_a, string_b) == 0; +} + +gboolean +eel_str_has_prefix (const char *haystack, const char *needle) +{ + return g_str_has_prefix (haystack == NULL ? "" : haystack, + needle == NULL ? "" : needle); +} + +gboolean +eel_str_has_suffix (const char *haystack, const char *needle) +{ + if (needle == NULL) + { + return TRUE; + } + if (haystack == NULL) + { + return needle[0] == '\0'; + } + + return g_str_has_suffix (haystack, needle); +} + +gboolean +eel_istr_has_prefix (const char *haystack, const char *needle) +{ + const char *h, *n; + char hc, nc; + + /* Eat one character at a time. */ + h = haystack == NULL ? "" : haystack; + n = needle == NULL ? "" : needle; + do + { + if (*n == '\0') + { + return TRUE; + } + if (*h == '\0') + { + return FALSE; + } + hc = *h++; + nc = *n++; + hc = g_ascii_tolower (hc); + nc = g_ascii_tolower (nc); + } + while (hc == nc); + return FALSE; +} + +gboolean +eel_istr_has_suffix (const char *haystack, const char *needle) +{ + const char *h, *n; + char hc, nc; + + if (needle == NULL) + { + return TRUE; + } + if (haystack == NULL) + { + return needle[0] == '\0'; + } + + /* Eat one character at a time. */ + h = haystack + strlen (haystack); + n = needle + strlen (needle); + do + { + if (n == needle) + { + return TRUE; + } + if (h == haystack) + { + return FALSE; + } + hc = *--h; + nc = *--n; + hc = g_ascii_tolower (hc); + nc = g_ascii_tolower (nc); + } + while (hc == nc); + return FALSE; +} + +/** + * eel_str_get_prefix: + * Get a new string containing the first part of an existing string. + * + * @source: The string whose prefix should be extracted. + * @delimiter: The string that marks the end of the prefix. + * + * Return value: A newly-allocated string that that matches the first part + * of @source, up to but not including the first occurrence of + * @delimiter. If @source is NULL, returns NULL. If + * @delimiter is NULL, returns a copy of @source. + * If @delimiter does not occur in @source, returns + * a copy of @source. + **/ +char * +eel_str_get_prefix (const char *source, + const char *delimiter) +{ + char *prefix_start; + + if (source == NULL) + { + return NULL; + } + + if (delimiter == NULL) + { + return g_strdup (source); + } + + prefix_start = strstr (source, delimiter); + + if (prefix_start == NULL) + { + return g_strdup (""); + } + + return g_strndup (source, prefix_start - source); +} + +gboolean +eel_str_to_int (const char *string, int *integer) +{ + long result; + char *parse_end; + + /* Check for the case of an empty string. */ + if (string == NULL || *string == '\0') + { + return FALSE; + } + + /* Call the standard library routine to do the conversion. */ + errno = 0; + result = strtol (string, &parse_end, 0); + + /* Check that the result is in range. */ + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) + { + return FALSE; + } + if (result < G_MININT || result > G_MAXINT) + { + return FALSE; + } + + /* Check that all the trailing characters are spaces. */ + while (*parse_end != '\0') + { + if (!g_ascii_isspace (*parse_end++)) + { + return FALSE; + } + } + + /* Return the result. */ + *integer = result; + return TRUE; +} + +char * +eel_str_double_underscores (const char *string) +{ + int underscores; + const char *p; + char *q; + char *escaped; + + if (string == NULL) + { + return NULL; + } + + underscores = 0; + for (p = string; *p != '\0'; p++) + { + underscores += (*p == '_'); + } + + if (underscores == 0) + { + return g_strdup (string); + } + + escaped = g_new (char, strlen (string) + underscores + 1); + for (p = string, q = escaped; *p != '\0'; p++, q++) + { + /* Add an extra underscore. */ + if (*p == '_') + { + *q++ = '_'; + } + *q = *p; + } + *q = '\0'; + + return escaped; +} + +char * +eel_str_capitalize (const char *string) +{ + char *capitalized; + + if (string == NULL) + { + return NULL; + } + + capitalized = g_strdup (string); + + capitalized[0] = g_ascii_toupper (capitalized[0]); + + return capitalized; +} + +/* Note: eel_string_ellipsize_* that use a length in pixels + * rather than characters can be found in eel_gdk_extensions.h + * + * FIXME bugzilla.eazel.com 5089: + * we should coordinate the names of eel_string_ellipsize_* + * and eel_str_*_truncate so that they match better and reflect + * their different behavior. + */ +char * +eel_str_middle_truncate (const char *string, + guint truncate_length) +{ + char *truncated; + guint length; + guint num_left_chars; + guint num_right_chars; + + const char delimter[] = "..."; + const guint delimter_length = strlen (delimter); + const guint min_truncate_length = delimter_length + 2; + + if (string == NULL) + { + return NULL; + } + + /* It doesnt make sense to truncate strings to less than + * the size of the delimiter plus 2 characters (one on each + * side) + */ + if (truncate_length < min_truncate_length) + { + return g_strdup (string); + } + + length = g_utf8_strlen (string, -1); + + /* Make sure the string is not already small enough. */ + if (length <= truncate_length) + { + return g_strdup (string); + } + + /* Find the 'middle' where the truncation will occur. */ + num_left_chars = (truncate_length - delimter_length) / 2; + num_right_chars = truncate_length - num_left_chars - delimter_length; + + truncated = g_new (char, strlen (string) + 1); + + g_utf8_strncpy (truncated, string, num_left_chars); + strcat (truncated, delimter); + strcat (truncated, g_utf8_offset_to_pointer (string, length - num_right_chars)); + + return truncated; +} + +char * +eel_str_strip_substring_and_after (const char *string, + const char *substring) +{ + const char *substring_position; + + g_return_val_if_fail (substring != NULL, g_strdup (string)); + g_return_val_if_fail (substring[0] != '\0', g_strdup (string)); + + if (string == NULL) + { + return NULL; + } + + substring_position = strstr (string, substring); + if (substring_position == NULL) + { + return g_strdup (string); + } + + return g_strndup (string, + substring_position - string); +} + +char * +eel_str_replace_substring (const char *string, + const char *substring, + const char *replacement) +{ + int substring_length, replacement_length, result_length, remaining_length; + const char *p, *substring_position; + char *result, *result_position; + + g_return_val_if_fail (substring != NULL, g_strdup (string)); + g_return_val_if_fail (substring[0] != '\0', g_strdup (string)); + + if (string == NULL) + { + return NULL; + } + + substring_length = strlen (substring); + replacement_length = eel_strlen (replacement); + + result_length = strlen (string); + for (p = string; ; p = substring_position + substring_length) + { + substring_position = strstr (p, substring); + if (substring_position == NULL) + { + break; + } + result_length += replacement_length - substring_length; + } + + result = g_malloc (result_length + 1); + + result_position = result; + for (p = string; ; p = substring_position + substring_length) + { + substring_position = strstr (p, substring); + if (substring_position == NULL) + { + remaining_length = strlen (p); + memcpy (result_position, p, remaining_length); + result_position += remaining_length; + break; + } + memcpy (result_position, p, substring_position - p); + result_position += substring_position - p; + memcpy (result_position, replacement, replacement_length); + result_position += replacement_length; + } + g_assert (result_position - result == result_length); + result_position[0] = '\0'; + + return result; +} + +/**************** Custom printf ***********/ + +typedef struct +{ + const char *start; + const char *end; + GString *format; + int arg_pos; + int width_pos; + int width_format_index; + int precision_pos; + int precision_format_index; +} ConversionInfo; + +enum +{ + ARG_TYPE_INVALID, + ARG_TYPE_INT, + ARG_TYPE_LONG, + ARG_TYPE_LONG_LONG, + ARG_TYPE_SIZE, + ARG_TYPE_LONG_DOUBLE, + ARG_TYPE_DOUBLE, + ARG_TYPE_POINTER +}; + +typedef int ArgType; /* An int, because custom are < 0 */ + + +static const char * +get_position (const char *format, int *i) +{ + const char *p; + + p = format; + + if (g_ascii_isdigit (*p)) + { + p++; + + while (g_ascii_isdigit (*p)) + { + p++; + } + + if (*p == '$') + { + if (i != NULL) + { + *i = atoi (format) - 1; + } + return p + 1; + } + } + + return format; +} + +static gboolean +is_flag (char c) +{ + return strchr ("#0- +'I", c) != NULL; +} + +static gboolean +is_length_modifier (char c) +{ + return strchr ("hlLjzt", c) != NULL; +} + + +static ArgType +get_arg_type_from_format (EelPrintfHandler *custom_handlers, + const char *format, + int len) +{ + int i; + char c; + + c = format[len-1]; + + if (custom_handlers != NULL) + { + for (i = 0; custom_handlers[i].character != 0; i++) + { + if (custom_handlers[i].character == c) + { + return -(i + 1); + } + } + } + + switch (c) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (g_str_has_prefix (format, "ll")) + { + return ARG_TYPE_LONG_LONG; + } + if (g_str_has_prefix (format, "l")) + { + return ARG_TYPE_LONG; + } + if (g_str_has_prefix (format, "l")) + { + return ARG_TYPE_LONG; + } + if (g_str_has_prefix (format, "z")) + { + return ARG_TYPE_SIZE; + } + return ARG_TYPE_INT; + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + if (g_str_has_prefix (format, "L")) + { + return ARG_TYPE_LONG_DOUBLE; + } + return ARG_TYPE_DOUBLE; + case 'c': + return ARG_TYPE_INT; + case 's': + case 'p': + case 'n': + return ARG_TYPE_POINTER; + } + return ARG_TYPE_INVALID; +} + +static void +skip_argv (va_list *va, + ArgType type, + EelPrintfHandler *custom_handlers) +{ + if (type < 0) + { + custom_handlers[-type - 1].skip (va); + return; + } + + switch (type) + { + default: + case ARG_TYPE_INVALID: + return; + + case ARG_TYPE_INT: + (void) va_arg (*va, int); + break; + case ARG_TYPE_LONG: + (void) va_arg (*va, long int); + break; + case ARG_TYPE_LONG_LONG: + (void) va_arg (*va, long long int); + break; + case ARG_TYPE_SIZE: + (void) va_arg (*va, gsize); + break; + case ARG_TYPE_LONG_DOUBLE: + (void) va_arg (*va, long double); + break; + case ARG_TYPE_DOUBLE: + (void) va_arg (*va, double); + break; + case ARG_TYPE_POINTER: + (void) va_arg (*va, void *); + break; + } +} + +static void +skip_to_arg (va_list *va, + ArgType *types, + EelPrintfHandler *custom_handlers, + int n) +{ + int i; + for (i = 0; i < n; i++) + { + skip_argv (va, types[i], custom_handlers); + } +} + +char * +eel_strdup_vprintf_with_custom (EelPrintfHandler *custom, + const char *format, + va_list va_orig) +{ + va_list va; + const char *p; + int num_args, i, j; + ArgType *args; + ArgType type; + ConversionInfo *conversions; + GString *f, *str; + const char *flags, *width, *prec, *mod, *pos; + char *s; + + num_args = 0; + for (p = format; *p != 0; p++) + { + if (*p == '%') + { + p++; + if (*p != '%') + { + num_args++; + } + } + } + + args = g_new0 (ArgType, num_args * 3 + 1); + conversions = g_new0 (ConversionInfo, num_args); + + /* i indexes conversions, j indexes args */ + i = 0; + j = 0; + p = format; + while (*p != 0) + { + if (*p != '%') + { + p++; + continue; + } + p++; + if (*p == '%') + { + p++; + continue; + } + + /* We got a real conversion: */ + f = g_string_new ("%"); + conversions[i].start = p - 1; + + /* First comes the positional arg */ + + pos = p; + p = get_position (p, NULL); + + /* Then flags */ + flags = p; + while (is_flag (*p)) + { + p++; + } + g_string_append_len (f, flags, p - flags); + + /* Field width */ + + if (*p == '*') + { + p++; + p = get_position (p, &j); + args[j] = ARG_TYPE_INT; + conversions[i].width_pos = j++; + conversions[i].width_format_index = f->len; + } + else + { + conversions[i].width_pos = -1; + conversions[i].width_format_index = -1; + width = p; + while (g_ascii_isdigit (*p)) + { + p++; + } + g_string_append_len (f, width, p - width); + } + + /* Precision */ + conversions[i].precision_pos = -1; + conversions[i].precision_format_index = -1; + if (*p == '.') + { + g_string_append_c (f, '.'); + p++; + + if (*p == '*') + { + p++; + p = get_position (p, &j); + args[j] = ARG_TYPE_INT; + conversions[i].precision_pos = j++; + conversions[i].precision_format_index = f->len; + } + else + { + prec = p; + while (g_ascii_isdigit (*p) || *p == '-') + { + p++; + } + g_string_append_len (f, prec, p - prec); + } + } + + /* length modifier */ + + mod = p; + + while (is_length_modifier (*p)) + { + p++; + } + + /* conversion specifier */ + if (*p != 0) + p++; + + g_string_append_len (f, mod, p - mod); + + get_position (pos, &j); + args[j] = get_arg_type_from_format (custom, mod, p - mod); + conversions[i].arg_pos = j++; + conversions[i].format = f; + conversions[i].end = p; + + i++; + } + + g_assert (i == num_args); + + str = g_string_new (""); + + p = format; + for (i = 0; i < num_args; i++) + { + g_string_append_len (str, p, conversions[i].start - p); + p = conversions[i].end; + + if (conversions[i].precision_pos != -1) + { + char *val; + + G_VA_COPY(va, va_orig); + skip_to_arg (&va, args, custom, conversions[i].precision_pos); + val = g_strdup_vprintf ("%d", va); + va_end (va); + + g_string_insert (conversions[i].format, + conversions[i].precision_format_index, + val); + + g_free (val); + } + + if (conversions[i].width_pos != -1) + { + char *val; + + G_VA_COPY(va, va_orig); + skip_to_arg (&va, args, custom, conversions[i].width_pos); + val = g_strdup_vprintf ("%d", va); + va_end (va); + + g_string_insert (conversions[i].format, + conversions[i].width_format_index, + val); + + g_free (val); + } + + G_VA_COPY(va, va_orig); + skip_to_arg (&va, args, custom, conversions[i].arg_pos); + type = args[conversions[i].arg_pos]; + if (type < 0) + { + s = custom[-type - 1].to_string (conversions[i].format->str, va); + g_string_append (str, s); + g_free (s); + } + else + { + g_string_append_vprintf (str, conversions[i].format->str, va); + } + va_end (va); + + g_string_free (conversions[i].format, TRUE); + } + g_string_append (str, p); + + g_free (args); + g_free (conversions); + + return g_string_free (str, FALSE); +} + +char * +eel_strdup_printf_with_custom (EelPrintfHandler *handlers, + const char *format, + ...) +{ + va_list va; + char *res; + + va_start (va, format); + res = eel_strdup_vprintf_with_custom (handlers, format, va); + va_end (va); + + return res; +} + +/*********** refcounted strings ****************/ + +G_LOCK_DEFINE_STATIC (unique_ref_strs); +static GHashTable *unique_ref_strs = NULL; + +static eel_ref_str +eel_ref_str_new_internal (const char *string, int start_count) +{ + char *res; + volatile gint *count; + gsize len; + + len = strlen (string); + res = g_malloc (sizeof (gint) + len + 1); + count = (volatile gint *)res; + *count = start_count; + res += sizeof(gint); + memcpy (res, string, len + 1); + return res; +} + +eel_ref_str +eel_ref_str_new (const char *string) +{ + if (string == NULL) + { + return NULL; + } + + return eel_ref_str_new_internal (string, 1); +} + +eel_ref_str +eel_ref_str_get_unique (const char *string) +{ + eel_ref_str res; + + if (string == NULL) + { + return NULL; + } + + G_LOCK (unique_ref_strs); + if (unique_ref_strs == NULL) + { + unique_ref_strs = + eel_g_hash_table_new_free_at_exit (g_str_hash, g_str_equal, + "unique eel_ref_str"); + } + + res = g_hash_table_lookup (unique_ref_strs, string); + if (res != NULL) + { + eel_ref_str_ref (res); + } + else + { + res = eel_ref_str_new_internal (string, 0x80000001); + g_hash_table_insert (unique_ref_strs, res, res); + } + + G_UNLOCK (unique_ref_strs); + + return res; +} + +eel_ref_str +eel_ref_str_ref (eel_ref_str str) +{ + volatile gint *count; + + count = (volatile gint *)((char *)str - sizeof (gint)); + g_atomic_int_add (count, 1); + + return str; +} + +void +eel_ref_str_unref (eel_ref_str str) +{ + volatile gint *count; + gint old_ref; + + if (str == NULL) + return; + + count = (volatile gint *)((char *)str - sizeof (gint)); + +retry_atomic_decrement: + old_ref = g_atomic_int_get (count); + if (old_ref == 1) + { + g_free ((char *)count); + } + else if (old_ref == 0x80000001) + { + G_LOCK (unique_ref_strs); + /* Need to recheck after taking lock to avoid races with _get_unique() */ + if (g_atomic_int_exchange_and_add (count, -1) == 0x80000001) + { + g_hash_table_remove (unique_ref_strs, (char *)str); + g_free ((char *)count); + } + G_UNLOCK (unique_ref_strs); + } + else if (!g_atomic_int_compare_and_exchange (count, + old_ref, old_ref - 1)) + { + goto retry_atomic_decrement; + } +} + + +#if !defined (EEL_OMIT_SELF_CHECK) + +static int +call_str_to_int (const char *string) +{ + int integer; + + integer = 9999; + eel_str_to_int (string, &integer); + return integer; +} + +static void +verify_printf (const char *format, ...) +{ + va_list va; + char *orig, *new; + + va_start (va, format); + orig = g_strdup_vprintf (format, va); + va_end (va); + + va_start (va, format); + new = eel_strdup_vprintf_with_custom (NULL, format, va); + va_end (va); + + EEL_CHECK_STRING_RESULT (new, orig); + + g_free (orig); +} + +static char * +custom1_to_string (char *format, va_list va) +{ + int i; + + i = va_arg (va, int); + + return g_strdup_printf ("c1-%d-", i); +} + +static void +custom1_skip (va_list *va) +{ + (void) va_arg (*va, int); +} + +static char * +custom2_to_string (char *format, va_list va) +{ + char *s; + + s = va_arg (va, char *); + + return g_strdup_printf ("c2-%s-", s); +} + +static void +custom2_skip (va_list *va) +{ + (void) va_arg (*va, char *); +} + +static EelPrintfHandler handlers[] = +{ + { 'N', custom1_to_string, custom1_skip }, + { 'Y', custom2_to_string, custom2_skip }, + { 0 } +}; + +static void +verify_custom (const char *orig, const char *format, ...) +{ + char *new; + va_list va; + + va_start (va, format); + new = eel_strdup_vprintf_with_custom (handlers, format, va); + va_end (va); + + EEL_CHECK_STRING_RESULT (new, orig); +} + +void +eel_self_check_string (void) +{ + int integer; + + EEL_CHECK_INTEGER_RESULT (eel_strlen (NULL), 0); + EEL_CHECK_INTEGER_RESULT (eel_strlen (""), 0); + EEL_CHECK_INTEGER_RESULT (eel_strlen ("abc"), 3); + + EEL_CHECK_INTEGER_RESULT (eel_strcmp (NULL, NULL), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp (NULL, ""), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp ("", NULL), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp ("a", "a"), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp ("aaab", "aaab"), 0); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp (NULL, "a") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", NULL) > 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("", "a") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "") > 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "b") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "ab") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("ab", "a") > 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("aaa", "aaab") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("aaab", "aaa") > 0, TRUE); + + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "a"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaab", "aaab"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "b"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "ab"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("ab", "a"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaa", "aaab"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaab", "aaa"), TRUE); + + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", "a"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("aaab", "aaab"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix (NULL, "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", "b"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", "ab"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("ab", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("ab", "b"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("aaa", "baaa"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("baaa", "aaa"), TRUE); + + EEL_CHECK_STRING_RESULT (eel_str_get_prefix (NULL, NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix (NULL, "foo"), NULL); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", NULL), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("", ""), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("", "foo"), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", ""), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", "foo"), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo:", ":"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo:bar", ":"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("footle:bar", "tle:"), "foo"); + + EEL_CHECK_STRING_RESULT (eel_str_double_underscores (NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores (""), ""); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_"), "__"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar"), "foo__bar"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar_2"), "foo__bar__2"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_foo"), "__foo"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_"), "foo__"); + + EEL_CHECK_STRING_RESULT (eel_str_capitalize (NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_capitalize (""), ""); + EEL_CHECK_STRING_RESULT (eel_str_capitalize ("foo"), "Foo"); + EEL_CHECK_STRING_RESULT (eel_str_capitalize ("Foo"), "Foo"); + + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 0), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 1), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 3), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 4), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 5), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 6), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 7), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 0), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 1), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 2), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 3), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 4), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 5), "a...o"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 6), "a...oo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 7), "a_...oo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 8), "a_...foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 9), "a_m...foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 8), "so...ven"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 8), "so...odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 9), "som...ven"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 9), "som...odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 10), "som...even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 10), "som..._odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 11), "some...even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 11), "some..._odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 12), "some..._even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 12), "some...g_odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 13), "somet..._even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 14), "something_even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd"); + +#define TEST_INTEGER_CONVERSION_FUNCTIONS(string, boolean_result, integer_result) \ + EEL_CHECK_BOOLEAN_RESULT (eel_str_to_int (string, &integer), boolean_result); \ + EEL_CHECK_INTEGER_RESULT (call_str_to_int (string), integer_result); + + TEST_INTEGER_CONVERSION_FUNCTIONS (NULL, FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("a", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS (".", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("0", TRUE, 0) + TEST_INTEGER_CONVERSION_FUNCTIONS ("1", TRUE, 1) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+1", TRUE, 1) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-1", TRUE, -1) + TEST_INTEGER_CONVERSION_FUNCTIONS ("2147483647", TRUE, 2147483647) + TEST_INTEGER_CONVERSION_FUNCTIONS ("2147483648", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+2147483647", TRUE, 2147483647) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+2147483648", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-2147483648", TRUE, INT_MIN) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-2147483649", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("1a", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("0.0", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("1e1", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("21474836470", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+21474836470", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-21474836480", FALSE, 9999) + + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("foo", "foo"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("foo", "bar"), FALSE); + + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("foo", "foo"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("foo", "bar"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("Foo", "foo"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("foo", "Foo"), TRUE); + + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after (NULL, "bar"), NULL); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("", "bar"), ""); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo", "bar"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar", "bar"), "foo "); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar xxx", "bar"), "foo "); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("bar", "bar"), ""); + + EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", "bar"), NULL); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", NULL), "bar"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", ""), ""); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", "bar"), ""); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", ""), "bar"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("xxx", "x", "foo"), "foofoofoo"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("fff", "f", "foo"), "foofoofoo"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "foo", "f"), "fff"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "f", ""), "oooooo"); + + verify_printf ("%.*s", 2, "foo"); + verify_printf ("%*.*s", 2, 4, "foo"); + verify_printf ("before %5$*1$.*2$s between %6$*3$.*4$d after", + 4, 5, 6, 7, "foo", G_PI); + verify_custom ("c1-42- c2-foo-","%N %Y", 42 ,"foo"); + verify_custom ("c1-42- bar c2-foo-","%N %s %Y", 42, "bar" ,"foo"); + verify_custom ("c1-42- bar c2-foo-","%3$N %2$s %1$Y","foo", "bar", 42); + +} + +#endif /* !EEL_OMIT_SELF_CHECK */ diff --git a/eel/eel-string.h b/eel/eel-string.h new file mode 100644 index 00000000..ffd5c647 --- /dev/null +++ b/eel/eel-string.h @@ -0,0 +1,122 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-string.h: String routines to augment <string.h>. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#ifndef EEL_STRING_H +#define EEL_STRING_H + +#include <glib.h> + +#include <string.h> +#include <stdarg.h> + +/* We use the "str" abbrevation to mean char * string, since + * "string" usually means g_string instead. We use the "istr" + * abbreviation to mean a case-insensitive char *. + */ + + +/* NULL is allowed for all the str parameters to these functions. */ + +/* Versions of basic string functions that allow NULL, and handle + * cases that the standard ones get a bit wrong for our purposes. + */ +size_t eel_strlen (const char *str); +char * eel_strchr (const char *haystack, + char needle); +int eel_strcmp (const char *str_a, + const char *str_b); +int eel_strcasecmp (const char *str_a, + const char *str_b); +int eel_strcmp_case_breaks_ties (const char *str_a, + const char *str_b); + +/* Other basic string operations. */ +gboolean eel_str_is_empty (const char *str_or_null); +gboolean eel_str_is_equal (const char *str_a, + const char *str_b); +gboolean eel_istr_is_equal (const char *str_a, + const char *str_b); +gboolean eel_str_has_prefix (const char *target, + const char *prefix); +char * eel_str_get_prefix (const char *source, + const char *delimiter); +gboolean eel_istr_has_prefix (const char *target, + const char *prefix); +gboolean eel_str_has_suffix (const char *target, + const char *suffix); +gboolean eel_istr_has_suffix (const char *target, + const char *suffix); + +/* Conversions to and from strings. */ +gboolean eel_str_to_int (const char *str, + int *integer); + +/* Escape function for '_' character. */ +char * eel_str_double_underscores (const char *str); + +/* Capitalize a string */ +char * eel_str_capitalize (const char *str); + +/* Middle truncate a string to a maximum of truncate_length characters. + * The resulting string will be truncated in the middle with a "..." + * delimiter. + */ +char * eel_str_middle_truncate (const char *str, + guint truncate_length); + + +/* Remove all characters after the passed-in substring. */ +char * eel_str_strip_substring_and_after (const char *str, + const char *substring); + +/* Replace all occurrences of substring with replacement. */ +char * eel_str_replace_substring (const char *str, + const char *substring, + const char *replacement); + +typedef char * eel_ref_str; + +eel_ref_str eel_ref_str_new (const char *string); +eel_ref_str eel_ref_str_get_unique (const char *string); +eel_ref_str eel_ref_str_ref (eel_ref_str str); +void eel_ref_str_unref (eel_ref_str str); + +#define eel_ref_str_peek(__str) ((const char *)(__str)) + + +typedef struct +{ + char character; + char *(*to_string) (char *format, va_list va); + void (*skip) (va_list *va); +} EelPrintfHandler; + +char *eel_strdup_printf_with_custom (EelPrintfHandler *handlers, + const char *format, + ...); +char *eel_strdup_vprintf_with_custom (EelPrintfHandler *custom, + const char *format, + va_list va); + +#endif /* EEL_STRING_H */ diff --git a/eel/eel-types.c b/eel/eel-types.c new file mode 100644 index 00000000..3b93817e --- /dev/null +++ b/eel/eel-types.c @@ -0,0 +1,82 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* eel-types.h - + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Maciej Stachowiak <[email protected]> +*/ + + +#include <config.h> +#include <gtk/gtk.h> + +#define EEL_COMPILATION 1 +#include <eel/eel.h> + +#include "eel-type-builtins-vars.c" +#include "eel-type-builtins-evals.c" + +void +eel_type_init (void) +{ + int i; + GType type_id; + static gboolean initialized = FALSE; + + static struct + { + const gchar *type_name; + GType *type_id; + GType parent; + gconstpointer pointer1; + gpointer pointer2; + } builtin_info[EEL_TYPE_N_BUILTINS] = + { +#include "eel-type-builtins-ids.c" + }; + + if (initialized) + { + return; + } + initialized = TRUE; + + for (i = 0; i < EEL_TYPE_N_BUILTINS; i++) + { + type_id = G_TYPE_INVALID; + + if (builtin_info[i].parent == G_TYPE_ENUM) + { + type_id = g_enum_register_static (builtin_info[i].type_name, + builtin_info[i].pointer1); + } + else if (builtin_info[i].parent == G_TYPE_FLAGS) + { + type_id = g_flags_register_static (builtin_info[i].type_name, + builtin_info[i].pointer1); + } + else + { + g_assert_not_reached (); + } + + g_assert (type_id != G_TYPE_INVALID); + *builtin_info[i].type_id = type_id; + } +} + diff --git a/eel/eel-types.h b/eel/eel-types.h new file mode 100644 index 00000000..cf18f3f1 --- /dev/null +++ b/eel/eel-types.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* eel-types.h - + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Maciej Stachowiak <[email protected]> +*/ + +#ifndef EEL_TYPES_H +#define EEL_TYPES_H + +#include <eel/eel-type-builtins.h> + +void eel_type_init (void); + +#endif /* EEL_TYPES_H */ + diff --git a/eel/eel-vfs-extensions.c b/eel/eel-vfs-extensions.c new file mode 100644 index 00000000..0ddea688 --- /dev/null +++ b/eel/eel-vfs-extensions.c @@ -0,0 +1,187 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-vfs-extensions.c - mate-vfs extensions. Its likely some of these will + be part of mate-vfs in the future. + + Copyright (C) 1999, 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Pavel Cisler <[email protected]> + Mike Fleming <[email protected]> + John Sullivan <[email protected]> +*/ + +#include <config.h> +#include "eel-i18n.h" +#include "eel-vfs-extensions.h" +#include "eel-glib-extensions.h" +#include "eel-lib-self-check-functions.h" +#include <glib.h> +#include <gio/gio.h> + +#include "eel-string.h" + +#include <string.h> +#include <stdlib.h> + +gboolean +eel_uri_is_trash (const char *uri) +{ + return eel_istr_has_prefix (uri, "trash:"); +} + +gboolean +eel_uri_is_search (const char *uri) +{ + return eel_istr_has_prefix (uri, EEL_SEARCH_URI); +} + +gboolean +eel_uri_is_desktop (const char *uri) +{ + return eel_istr_has_prefix (uri, EEL_DESKTOP_URI); +} + +char * +eel_make_valid_utf8 (const char *name) +{ + GString *string; + const char *remainder, *invalid; + int remaining_bytes, valid_bytes; + + string = NULL; + remainder = name; + remaining_bytes = strlen (name); + + while (remaining_bytes != 0) + { + if (g_utf8_validate (remainder, remaining_bytes, &invalid)) + { + break; + } + valid_bytes = invalid - remainder; + + if (string == NULL) + { + string = g_string_sized_new (remaining_bytes); + } + g_string_append_len (string, remainder, valid_bytes); + g_string_append_c (string, '?'); + + remaining_bytes -= valid_bytes + 1; + remainder = invalid + 1; + } + + if (string == NULL) + { + return g_strdup (name); + } + + g_string_append (string, remainder); + g_string_append (string, _(" (invalid Unicode)")); + g_assert (g_utf8_validate (string->str, -1, NULL)); + + return g_string_free (string, FALSE); +} + +/** + * eel_format_uri_for_display: + * + * Filter, modify, unescape and change URIs to make them appropriate + * to display to users. The conversion is done such that the roundtrip + * to UTf8 is reversible. + * + * Rules: + * file: URI's without fragments should appear as local paths + * file: URI's with fragments should appear as file: URI's + * All other URI's appear as expected + * + * @uri: a URI + * + * returns a g_malloc'd UTF8 string + **/ +char * +eel_format_uri_for_display (const char *uri) +{ + GFile *file; + char *res; + + file = g_file_new_for_uri (uri); + res = g_file_get_parse_name (file); + g_object_unref (file); + return res; +} + +char * +eel_filename_strip_extension (const char * filename_with_extension) +{ + char *filename, *end, *end2; + + if (filename_with_extension == NULL) + { + return NULL; + } + + filename = g_strdup (filename_with_extension); + + end = strrchr (filename, '.'); + + if (end && end != filename) + { + if (strcmp (end, ".gz") == 0 || + strcmp (end, ".bz2") == 0 || + strcmp (end, ".sit") == 0 || + strcmp (end, ".Z") == 0) + { + end2 = end - 1; + while (end2 > filename && + *end2 != '.') + { + end2--; + } + if (end2 != filename) + { + end = end2; + } + } + *end = '\0'; + } + + return filename; +} + +void +eel_filename_get_rename_region (const char *filename, + int *start_offset, + int *end_offset) +{ + char *filename_without_extension; + + g_return_if_fail (start_offset != NULL); + g_return_if_fail (end_offset != NULL); + + *start_offset = 0; + *end_offset = 0; + + g_return_if_fail (filename != NULL); + + filename_without_extension = eel_filename_strip_extension (filename); + *end_offset = g_utf8_strlen (filename_without_extension, -1); + + g_free (filename_without_extension); +} diff --git a/eel/eel-vfs-extensions.h b/eel/eel-vfs-extensions.h new file mode 100644 index 00000000..596da8c3 --- /dev/null +++ b/eel/eel-vfs-extensions.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-vfs-extensions.h - mate-vfs extensions. Its likely some of these will + be part of mate-vfs in the future. + + Copyright (C) 1999, 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> + Pavel Cisler <[email protected]> + Mike Fleming <[email protected]> + John Sullivan <[email protected]> +*/ + +#ifndef EEL_VFS_EXTENSIONS_H +#define EEL_VFS_EXTENSIONS_H + +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_TRASH_URI "trash:" +#define EEL_DESKTOP_URI "x-caja-desktop:" +#define EEL_SEARCH_URI "x-caja-search:" + + gboolean eel_uri_is_trash(const char* uri); + gboolean eel_uri_is_trash_folder(const char* uri); + gboolean eel_uri_is_in_trash(const char* uri); + gboolean eel_uri_is_desktop(const char* uri); + gboolean eel_uri_is_search(const char* uri); + + + char* eel_format_uri_for_display(const char* uri); + char* eel_make_valid_utf8(const char* name); + + char* eel_filename_strip_extension(const char* filename); + void eel_filename_get_rename_region(const char* filename, int* start_offset, int* end_offset); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_VFS_EXTENSIONS_H */ diff --git a/eel/eel-wrap-table.c b/eel/eel-wrap-table.c new file mode 100644 index 00000000..12325a14 --- /dev/null +++ b/eel/eel-wrap-table.c @@ -0,0 +1,1108 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-wrap-box.c - A table that can wrap its contents as needed. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-wrap-table.h" + +#include "eel-art-extensions.h" +#include "eel-art-gtk-extensions.h" +#include "eel-gtk-extensions.h" +#include "eel-gtk-macros.h" +#include "eel-types.h" +#include <gtk/gtk.h> + +/* Arguments */ +enum +{ + PROP_0, + PROP_X_SPACING, + PROP_Y_SPACING, + PROP_X_JUSTIFICATION, + PROP_Y_JUSTIFICATION, + PROP_HOMOGENEOUS +}; + +/* Detail member struct */ +struct EelWrapTableDetails +{ + guint x_spacing; + guint y_spacing; + EelJustification x_justification; + EelJustification y_justification; + gboolean homogeneous; + GList *children; + + guint is_scrolled : 1; + guint cols; +}; + +static void eel_wrap_table_class_init (EelWrapTableClass *wrap_table_class); +static void eel_wrap_table_init (EelWrapTable *wrap); +/* GObjectClass methods */ +static void eel_wrap_table_finalize (GObject *object); +static void eel_wrap_table_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void eel_wrap_table_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +/* GtkWidgetClass methods */ +static void eel_wrap_table_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static int eel_wrap_table_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static void eel_wrap_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void eel_wrap_table_map (GtkWidget *widget); +static void eel_wrap_table_unmap (GtkWidget *widget); +static void eel_wrap_table_realize (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void eel_wrap_table_add (GtkContainer *container, + GtkWidget *widget); +static void eel_wrap_table_remove (GtkContainer *container, + GtkWidget *widget); +static void eel_wrap_table_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GType eel_wrap_table_child_type (GtkContainer *container); + + +/* Private EelWrapTable methods */ +static EelDimensions wrap_table_irect_max_dimensions (const EelDimensions *one, + const EelDimensions *two); +static EelDimensions wrap_table_get_max_child_dimensions (const EelWrapTable *wrap_table); +static EelDimensions wrap_table_get_content_dimensions (const EelWrapTable *wrap_table); +static EelIRect wrap_table_get_content_bounds (const EelWrapTable *wrap_table); +static gboolean wrap_table_child_focus_in (GtkWidget *widget, + GdkEventFocus *event, + gpointer data); +static void wrap_table_layout (EelWrapTable *wrap_table); + + +EEL_CLASS_BOILERPLATE (EelWrapTable, eel_wrap_table, GTK_TYPE_CONTAINER) + +/* Class init methods */ +static void +eel_wrap_table_class_init (EelWrapTableClass *wrap_table_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (wrap_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (wrap_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (wrap_table_class); + + /* GObjectClass */ + gobject_class->finalize = eel_wrap_table_finalize; + gobject_class->set_property = eel_wrap_table_set_property; + gobject_class->get_property = eel_wrap_table_get_property; + + /* GtkWidgetClass */ + widget_class->size_request = eel_wrap_table_size_request; + widget_class->size_allocate = eel_wrap_table_size_allocate; + widget_class->expose_event = eel_wrap_table_expose_event; + widget_class->map = eel_wrap_table_map; + widget_class->unmap = eel_wrap_table_unmap; + widget_class->realize = eel_wrap_table_realize; + + /* GtkContainerClass */ + container_class->add = eel_wrap_table_add; + container_class->remove = eel_wrap_table_remove; + container_class->forall = eel_wrap_table_forall; + container_class->child_type = eel_wrap_table_child_type; + + /* Register some the enum types we need */ + eel_type_init (); + + /* Arguments */ + g_object_class_install_property + (gobject_class, + PROP_X_SPACING, + g_param_spec_uint ("x_spacing", NULL, NULL, + 0, G_MAXINT, 0, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, + PROP_Y_SPACING, + g_param_spec_uint ("y_spacing", NULL, NULL, + 0, G_MAXINT, 0, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, + PROP_X_JUSTIFICATION, + g_param_spec_enum ("x_justification", NULL, NULL, + EEL_TYPE_JUSTIFICATION, + EEL_JUSTIFICATION_BEGINNING, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, + PROP_Y_JUSTIFICATION, + g_param_spec_enum ("y_justification", NULL, NULL, + EEL_TYPE_JUSTIFICATION, + EEL_JUSTIFICATION_BEGINNING, + G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, + PROP_HOMOGENEOUS, + g_param_spec_boolean ("homogenous", NULL, NULL, + FALSE, G_PARAM_READWRITE)); +} + +static void +eel_wrap_table_init (EelWrapTable *wrap_table) +{ + gtk_widget_set_has_window (GTK_WIDGET (wrap_table), FALSE); + + wrap_table->details = g_new0 (EelWrapTableDetails, 1); + wrap_table->details->x_justification = EEL_JUSTIFICATION_BEGINNING; + wrap_table->details->y_justification = EEL_JUSTIFICATION_END; + wrap_table->details->cols = 1; +} + +static void +eel_wrap_table_finalize (GObject *object) +{ + EelWrapTable *wrap_table; + + wrap_table = EEL_WRAP_TABLE (object); + + g_list_free (wrap_table->details->children); + g_free (wrap_table->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +/* GObjectClass methods */ + +static void +eel_wrap_table_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EelWrapTable *wrap_table; + + g_assert (EEL_IS_WRAP_TABLE (object)); + + wrap_table = EEL_WRAP_TABLE (object); + + switch (property_id) + { + case PROP_X_SPACING: + eel_wrap_table_set_x_spacing (wrap_table, g_value_get_uint (value)); + break; + + case PROP_Y_SPACING: + eel_wrap_table_set_y_spacing (wrap_table, g_value_get_uint (value)); + break; + + case PROP_X_JUSTIFICATION: + eel_wrap_table_set_x_justification (wrap_table, g_value_get_enum (value)); + break; + + case PROP_Y_JUSTIFICATION: + eel_wrap_table_set_y_justification (wrap_table, g_value_get_enum (value)); + break; + + case PROP_HOMOGENEOUS: + eel_wrap_table_set_homogeneous (wrap_table, g_value_get_boolean (value)); + break; + + default: + g_assert_not_reached (); + } +} + +static void +eel_wrap_table_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EelWrapTable *wrap_table; + + g_assert (EEL_IS_WRAP_TABLE (object)); + + wrap_table = EEL_WRAP_TABLE (object); + + switch (property_id) + { + case PROP_X_SPACING: + g_value_set_uint (value, eel_wrap_table_get_x_spacing (wrap_table)); + break; + + case PROP_Y_SPACING: + g_value_set_uint (value, eel_wrap_table_get_y_spacing (wrap_table)); + break; + + case PROP_X_JUSTIFICATION: + g_value_set_enum (value, eel_wrap_table_get_x_justification (wrap_table)); + break; + + case PROP_Y_JUSTIFICATION: + g_value_set_enum (value, eel_wrap_table_get_y_justification (wrap_table)); + break; + + case PROP_HOMOGENEOUS: + g_value_set_boolean (value, eel_wrap_table_get_homogeneous (wrap_table)); + break; + + default: + g_assert_not_reached (); + } +} + +/* GtkWidgetClass methods */ +static void +eel_wrap_table_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EelWrapTable *wrap_table; + EelDimensions content_dimensions; + + g_assert (EEL_IS_WRAP_TABLE (widget)); + g_assert (requisition != NULL); + + wrap_table = EEL_WRAP_TABLE (widget); + + content_dimensions = wrap_table_get_content_dimensions (wrap_table); + + /* The -1 tells Satan to use as much space as is available */ + requisition->width = -1; + requisition->height = content_dimensions.height + gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2; +} + +static void +eel_wrap_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + EelWrapTable *wrap_table; + + g_assert (EEL_IS_WRAP_TABLE (widget)); + g_assert (allocation != NULL); + + wrap_table = EEL_WRAP_TABLE (widget); + + gtk_widget_set_allocation (widget, allocation); + + wrap_table_layout (wrap_table); +} + +static int +eel_wrap_table_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + EelWrapTable *wrap_table; + GList *iterator; + + g_assert (EEL_IS_WRAP_TABLE (widget)); + g_assert (gtk_widget_get_realized (widget)); + g_assert (event != NULL); + + wrap_table = EEL_WRAP_TABLE (widget); + + for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) + { + g_assert (GTK_IS_WIDGET (iterator->data)); + gtk_container_propagate_expose (GTK_CONTAINER (widget), + GTK_WIDGET (iterator->data), + event); + } + + return FALSE; +} + +static void +eel_wrap_table_map (GtkWidget *widget) +{ + EelWrapTable *wrap_table; + GList *iterator; + + g_assert (EEL_IS_WRAP_TABLE (widget)); + + wrap_table = EEL_WRAP_TABLE (widget); + + gtk_widget_set_mapped (widget, TRUE); + + for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) + { + GtkWidget *item; + + item = iterator->data; + + if (gtk_widget_get_visible (item) && !gtk_widget_get_mapped (item)) + { + gtk_widget_map (item); + } + } +} + +static void +eel_wrap_table_unmap (GtkWidget *widget) +{ + EelWrapTable *wrap_table; + GList *iterator; + + g_assert (EEL_IS_WRAP_TABLE (widget)); + + wrap_table = EEL_WRAP_TABLE (widget); + + gtk_widget_set_mapped (widget, FALSE); + + for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) + { + GtkWidget *item; + + item = iterator->data; + + if (gtk_widget_get_visible (item) && gtk_widget_get_mapped (item)) + { + gtk_widget_unmap (item); + } + } +} + +static void +eel_wrap_table_realize (GtkWidget *widget) +{ + g_assert (EEL_IS_WRAP_TABLE (widget)); + + GTK_WIDGET_CLASS (parent_class)->realize (widget); + + gtk_widget_queue_resize (widget); +} + +/* GtkContainerClass methods */ +static void +eel_wrap_table_add (GtkContainer *container, + GtkWidget *child) +{ + EelWrapTable *wrap_table; + GtkWidget *widget; + + g_assert (container != NULL); + g_assert (EEL_IS_WRAP_TABLE (container)); + g_assert (GTK_IS_WIDGET (child)); + + widget = GTK_WIDGET (container); + wrap_table = EEL_WRAP_TABLE (container); + + gtk_widget_set_parent (child, GTK_WIDGET (container)); + + wrap_table->details->children = g_list_append (wrap_table->details->children, child); + + if (gtk_widget_get_realized (widget)) + { + gtk_widget_realize (child); + } + + if (gtk_widget_get_visible (widget) && gtk_widget_get_visible (child)) + { + if (gtk_widget_get_mapped (widget)) + { + gtk_widget_map (child); + } + + gtk_widget_queue_resize (child); + } + + if (wrap_table->details->is_scrolled) + { + g_signal_connect (child, "focus_in_event", + G_CALLBACK (wrap_table_child_focus_in), + wrap_table); + } +} + +static void +eel_wrap_table_remove (GtkContainer *container, + GtkWidget *child) +{ + EelWrapTable *wrap_table; + gboolean child_was_visible; + + g_assert (EEL_IS_WRAP_TABLE (container)); + g_assert (GTK_IS_WIDGET (child)); + + wrap_table = EEL_WRAP_TABLE (container);; + + child_was_visible = gtk_widget_get_visible (child); + gtk_widget_unparent (child); + wrap_table->details->children = g_list_remove (wrap_table->details->children, child); + + if (child_was_visible) + { + gtk_widget_queue_resize (GTK_WIDGET (container)); + } + + if (wrap_table->details->is_scrolled) + { + g_signal_handlers_disconnect_by_func ( + child, + G_CALLBACK (wrap_table_child_focus_in), + wrap_table); + } +} + +static void +eel_wrap_table_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + EelWrapTable *wrap_table; + GList *node; + GList *next; + + g_assert (EEL_IS_WRAP_TABLE (container)); + g_assert (callback != NULL); + + wrap_table = EEL_WRAP_TABLE (container);; + + for (node = wrap_table->details->children; node != NULL; node = next) + { + g_assert (GTK_IS_WIDGET (node->data)); + next = node->next; + (* callback) (GTK_WIDGET (node->data), callback_data); + } +} + +static GType +eel_wrap_table_child_type (GtkContainer *container) +{ + return GTK_TYPE_WIDGET; +} + +/* Private EelWrapTable methods */ +static int +wrap_table_get_num_fitting (int available, + int spacing, + int max_child_size) +{ + int num; + + g_assert (max_child_size > 0); + g_assert (spacing >= 0); + + available = MAX (available, 0); + + num = (available + spacing) / (max_child_size + spacing); + num = MAX (num, 1); + + return num; +} + +static void +wrap_table_layout (EelWrapTable *wrap_table) +{ + GList *iterator; + EelIPoint pos; + EelDimensions max_child_dimensions; + EelIRect content_bounds; + guint num_cols; + GtkAllocation allocation; + + g_assert (EEL_IS_WRAP_TABLE (wrap_table)); + + max_child_dimensions = wrap_table_get_max_child_dimensions (wrap_table); + content_bounds = wrap_table_get_content_bounds (wrap_table); + pos.x = content_bounds.x0; + pos.y = content_bounds.y0; + + gtk_widget_get_allocation (GTK_WIDGET (wrap_table), &allocation); + num_cols = wrap_table_get_num_fitting (allocation.width - + gtk_container_get_border_width (GTK_CONTAINER (wrap_table)) * 2, + wrap_table->details->x_spacing, + max_child_dimensions.width); + if (num_cols != wrap_table->details->cols) + { + wrap_table->details->cols = num_cols; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); + return; + } + + for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) + { + GtkWidget *item; + + item = iterator->data; + + if (gtk_widget_get_visible (item)) + { + GtkAllocation item_allocation; + + if (wrap_table->details->homogeneous) + { + item_allocation.x = pos.x; + item_allocation.y = pos.y; + item_allocation.width = max_child_dimensions.width; + item_allocation.height = max_child_dimensions.height; + + if ((pos.x + max_child_dimensions.width) > content_bounds.x1) + { + pos.x = content_bounds.x0 + wrap_table->details->x_spacing + max_child_dimensions.width; + pos.y += (max_child_dimensions.height + wrap_table->details->y_spacing); + item_allocation.x = content_bounds.x0; + item_allocation.y = pos.y; + } + else + { + pos.x += (wrap_table->details->x_spacing + max_child_dimensions.width); + } + } + else + { + GtkRequisition item_requisition; + + gtk_widget_size_request (item, &item_requisition); + + item_allocation.x = pos.x; + item_allocation.y = pos.y; + item_allocation.width = item_requisition.width; + item_allocation.height = item_requisition.height; + + g_assert (item_allocation.width <= max_child_dimensions.width); + g_assert (item_allocation.height <= max_child_dimensions.height); + + if ((pos.x + max_child_dimensions.width) > content_bounds.x1) + { + pos.x = content_bounds.x0 + wrap_table->details->x_spacing + max_child_dimensions.width; + pos.y += (max_child_dimensions.height + wrap_table->details->y_spacing); + item_allocation.x = content_bounds.x0; + item_allocation.y = pos.y; + } + else + { + pos.x += (wrap_table->details->x_spacing + max_child_dimensions.width); + } + + switch (wrap_table->details->x_justification) + { + case EEL_JUSTIFICATION_MIDDLE: + item_allocation.x += (max_child_dimensions.width - (int) item_allocation.width) / 2; + break; + case EEL_JUSTIFICATION_END: + item_allocation.x += (max_child_dimensions.width - (int) item_allocation.width); + break; + default: + break; + } + + switch (wrap_table->details->y_justification) + { + case EEL_JUSTIFICATION_MIDDLE: + item_allocation.y += (max_child_dimensions.height - (int) item_allocation.height) / 2; + break; + case EEL_JUSTIFICATION_END: + item_allocation.y += (max_child_dimensions.height - (int) item_allocation.height); + break; + default: + break; + } + } + + gtk_widget_size_allocate (item, &item_allocation); + } + } +} + +static EelDimensions +wrap_table_irect_max_dimensions (const EelDimensions *one, + const EelDimensions *two) +{ + EelDimensions max_dimensions; + + g_assert (one != NULL); + g_assert (two != NULL); + + max_dimensions.width = MAX (one->width, two->width); + max_dimensions.height = MAX (one->height, two->height); + + return max_dimensions; +} + +static EelDimensions +wrap_table_get_max_child_dimensions (const EelWrapTable *wrap_table) +{ + EelDimensions max_dimensions; + GList *iterator; + + g_assert (EEL_IS_WRAP_TABLE (wrap_table)); + + max_dimensions = eel_dimensions_empty; + + for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) + { + GtkWidget *child; + + child = iterator->data; + + if (gtk_widget_get_visible (child)) + { + GtkRequisition child_requisition; + EelDimensions child_dimensions; + + gtk_widget_size_request (child, &child_requisition); + + child_dimensions.width = (int) child_requisition.width; + child_dimensions.height = (int) child_requisition.height; + + max_dimensions = wrap_table_irect_max_dimensions (&child_dimensions, &max_dimensions); + } + } + + return max_dimensions; +} + +static EelDimensions +wrap_table_get_content_dimensions (const EelWrapTable *wrap_table) +{ + EelDimensions content_dimensions; + guint num_children; + + g_assert (EEL_IS_WRAP_TABLE (wrap_table)); + + content_dimensions = eel_dimensions_empty; + + num_children = g_list_length (wrap_table->details->children); + + if (num_children > 0) + { + EelDimensions max_child_dimensions; + EelDimensions dimensions; + int num_cols; + int num_rows; + + dimensions = eel_gtk_widget_get_dimensions (GTK_WIDGET (wrap_table)); + max_child_dimensions = wrap_table_get_max_child_dimensions (wrap_table); + + max_child_dimensions.width = MAX (max_child_dimensions.width, 1); + max_child_dimensions.height = MAX (max_child_dimensions.height, 1); + + num_cols = wrap_table_get_num_fitting (dimensions.width - + gtk_container_get_border_width (GTK_CONTAINER (wrap_table)) * 2, + wrap_table->details->x_spacing, + max_child_dimensions.width); + num_rows = num_children / num_cols; + num_rows = MAX (num_rows, 1); + + if ((num_children % num_rows) > 0) + { + num_rows++; + } + + content_dimensions.width = dimensions.width; + content_dimensions.height = num_rows * max_child_dimensions.height; + + content_dimensions.width += (num_cols - 1) * wrap_table->details->x_spacing; + content_dimensions.height += (num_rows - 1) * wrap_table->details->y_spacing; + } + + return content_dimensions; +} + +static EelIRect +wrap_table_get_content_bounds (const EelWrapTable *wrap_table) +{ + EelIRect content_bounds; + guint border; + + g_assert (EEL_IS_WRAP_TABLE (wrap_table)); + + content_bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (wrap_table)); + + border = gtk_container_get_border_width (GTK_CONTAINER (wrap_table)); + content_bounds.x0 += border; + content_bounds.y0 += border; + content_bounds.x1 -= border; + content_bounds.y1 -= border; + + return content_bounds; +} + +static gboolean +wrap_table_child_focus_in (GtkWidget *widget, + GdkEventFocus *event, + gpointer data) +{ + GtkWidget *parent, *pparent; + GtkAllocation allocation; + + parent = gtk_widget_get_parent (widget); + if (parent) + pparent = gtk_widget_get_parent (parent); + g_assert (parent && pparent); + g_assert (GTK_IS_VIEWPORT (pparent)); + + gtk_widget_get_allocation (widget, &allocation); + eel_gtk_viewport_scroll_to_rect (GTK_VIEWPORT (pparent), + &allocation); + + return FALSE; +} + +/** + * eel_wrap_table_new: + * + */ +GtkWidget* +eel_wrap_table_new (gboolean homogeneous) +{ + EelWrapTable *wrap_table; + + wrap_table = EEL_WRAP_TABLE (gtk_widget_new (eel_wrap_table_get_type (), NULL)); + + eel_wrap_table_set_homogeneous (wrap_table, homogeneous); + + return GTK_WIDGET (wrap_table); +} + +/** + * eel_wrap_table_set_x_spacing: + * @wrap_table: A EelWrapTable. + * @x_spacing: The new horizontal spacing between wraps. + * + */ +void +eel_wrap_table_set_x_spacing (EelWrapTable *wrap_table, + guint x_spacing) +{ + g_return_if_fail (EEL_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->x_spacing == x_spacing) + { + return; + } + + wrap_table->details->x_spacing = x_spacing; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * eel_wrap_table_get_item_spacing: + * @wrap_table: A EelWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +guint +eel_wrap_table_get_x_spacing (const EelWrapTable *wrap_table) +{ + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->x_spacing; +} + +/** + * eel_wrap_table_set_y_spacing: + * @wrap_table: A EelWrapTable. + * @y_spacing: The new horizontal spacing between wraps. + * + */ +void +eel_wrap_table_set_y_spacing (EelWrapTable *wrap_table, + guint y_spacing) +{ + g_return_if_fail (EEL_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->y_spacing == y_spacing) + { + return; + } + + wrap_table->details->y_spacing = y_spacing; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * eel_wrap_table_get_item_spacing: + * @wrap_table: A EelWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +guint +eel_wrap_table_get_y_spacing (const EelWrapTable *wrap_table) +{ + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->y_spacing; +} + + +/** + * eel_wrap_table_find_child_at_event_point: + * @wrap_table: A EelWrapTable. + * @x: Event x; + * @y: Event y; + * + * Returns: Child found at given coordinates or NULL of no child is found. + */ +GtkWidget * +eel_wrap_table_find_child_at_event_point (const EelWrapTable *wrap_table, + int x, + int y) +{ + GList *iterator; + + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), NULL); + + for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) + { + GtkWidget *child; + + child = iterator->data; + + if (gtk_widget_get_visible (child)) + { + EelIRect child_bounds; + + child_bounds = eel_gtk_widget_get_bounds (child); + + if (eel_irect_contains_point (child_bounds, x, y)) + { + return child; + } + } + } + + return NULL; +} + +/** + * eel_wrap_table_set_x_justification: + * @wrap_table: A EelWrapTable. + * @x_justification: The new horizontal justification between wraps. + * + */ +void +eel_wrap_table_set_x_justification (EelWrapTable *wrap_table, + EelJustification x_justification) +{ + g_return_if_fail (EEL_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (x_justification >= EEL_JUSTIFICATION_BEGINNING); + g_return_if_fail (x_justification <= EEL_JUSTIFICATION_END); + + if (wrap_table->details->x_justification == x_justification) + { + return; + } + + wrap_table->details->x_justification = x_justification; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * eel_wrap_table_get_item_justification: + * @wrap_table: A EelWrapTable. + * + * Returns: The horizontal justification between wraps. + */ +EelJustification +eel_wrap_table_get_x_justification (const EelWrapTable *wrap_table) +{ + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->x_justification; +} + +/** + * eel_wrap_table_set_y_justification: + * @wrap_table: A EelWrapTable. + * @y_justification: The new horizontal justification between wraps. + * + */ +void +eel_wrap_table_set_y_justification (EelWrapTable *wrap_table, + EelJustification y_justification) +{ + g_return_if_fail (EEL_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (y_justification >= EEL_JUSTIFICATION_BEGINNING); + g_return_if_fail (y_justification <= EEL_JUSTIFICATION_END); + + if (wrap_table->details->y_justification == y_justification) + { + return; + } + + wrap_table->details->y_justification = y_justification; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * eel_wrap_table_get_item_justification: + * @wrap_table: A EelWrapTable. + * + * Returns: The horizontal justification between wraps. + */ +EelJustification +eel_wrap_table_get_y_justification (const EelWrapTable *wrap_table) +{ + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->y_justification; +} + +/** + * eel_wrap_table_set_homogeneous: + * @wrap_table: A EelWrapTable. + * @homogeneous: The new horizontal spacing between wraps. + * + */ +void +eel_wrap_table_set_homogeneous (EelWrapTable *wrap_table, + gboolean homogeneous) +{ + g_return_if_fail (EEL_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->homogeneous == homogeneous) + { + return; + } + + wrap_table->details->homogeneous = homogeneous; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * eel_wrap_table_get_item_spacing: + * @wrap_table: A EelWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +gboolean +eel_wrap_table_get_homogeneous (const EelWrapTable *wrap_table) +{ + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), FALSE); + + return wrap_table->details->homogeneous; +} + +/** + * eel_wrap_table_reorder_child: + * @wrap_table: A EelWrapTable. + * @child: Child to reorder. + * @position: New position to put child at. + * + * Reorder the given chilren into the given position. + * + * Position is interpreted as follows: + * + * 0 - Place child at start of table. + * -1 - Place child at end of table. + * n - Place child at nth position. Count starts at 0. + */ +void +eel_wrap_table_reorder_child (EelWrapTable *wrap_table, + GtkWidget *child, + int position) +{ + GList *node; + gboolean found_child = FALSE; + + g_return_if_fail (EEL_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (g_list_length (wrap_table->details->children) > 0); + + if (position == -1) + { + position = g_list_length (wrap_table->details->children) - 1; + } + + g_return_if_fail (position >= 0); + g_return_if_fail ((guint) position < g_list_length (wrap_table->details->children)); + + for (node = wrap_table->details->children; node != NULL; node = node->next) + { + GtkWidget *next_child; + next_child = node->data; + + if (next_child == child) + { + g_assert (found_child == FALSE); + found_child = TRUE; + } + } + + g_return_if_fail (found_child); + + wrap_table->details->children = g_list_remove (wrap_table->details->children, child); + wrap_table->details->children = g_list_insert (wrap_table->details->children, child, position); + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * eel_wrap_table_get_num_children: + * @wrap_table: A EelWrapTable. + * + * Returns: The number of children being managed by the wrap table. + */ +guint +eel_wrap_table_get_num_children (const EelWrapTable *wrap_table) +{ + g_return_val_if_fail (EEL_IS_WRAP_TABLE (wrap_table), 0); + + return g_list_length (wrap_table->details->children); +} + +GtkWidget * +eel_scrolled_wrap_table_new (gboolean homogenous, + GtkShadowType shadow_type, + GtkWidget **wrap_table_out) +{ + GtkWidget *scrolled_window; + GtkWidget *wrap_table; + GtkWidget *viewport; + + g_return_val_if_fail (wrap_table_out != NULL, NULL); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + + viewport = gtk_viewport_new (gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled_window)), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window))); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), + shadow_type); + + gtk_container_add (GTK_CONTAINER (scrolled_window), + viewport); + + wrap_table = eel_wrap_table_new (homogenous); + gtk_container_add (GTK_CONTAINER (viewport), + wrap_table); + + gtk_widget_show (wrap_table); + gtk_widget_show (viewport); + + EEL_WRAP_TABLE (wrap_table)->details->is_scrolled = 1; + + *wrap_table_out = wrap_table; + return scrolled_window; +} diff --git a/eel/eel-wrap-table.h b/eel/eel-wrap-table.h new file mode 100644 index 00000000..0353b19c --- /dev/null +++ b/eel/eel-wrap-table.h @@ -0,0 +1,108 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-wrap-table.h - A table that can wrap its contents as needed. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#ifndef EEL_WRAP_TABLE_H +#define EEL_WRAP_TABLE_H + +#include <glib.h> +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define EEL_TYPE_WRAP_TABLE eel_wrap_table_get_type() +#define EEL_WRAP_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_WRAP_TABLE, EelWrapTable)) +#define EEL_WRAP_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_WRAP_TABLE, EelWrapTableClass)) +#define EEL_IS_WRAP_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_WRAP_TABLE)) +#define EEL_IS_WRAP_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_WRAP_TABLE)) +#define EEL_WRAP_TABLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_WRAP_TABLE, EelWrapTableClass)) + + typedef struct EelWrapTable EelWrapTable; + typedef struct EelWrapTableClass EelWrapTableClass; + typedef struct EelWrapTableDetails EelWrapTableDetails; + + struct EelWrapTable + { + /* Superclass */ + GtkContainer container; + + /* Private things */ + EelWrapTableDetails *details; + }; + + struct EelWrapTableClass + { + GtkContainerClass parent_class; + }; + + typedef enum + { + EEL_JUSTIFICATION_BEGINNING, + EEL_JUSTIFICATION_MIDDLE, + EEL_JUSTIFICATION_END + } EelJustification; + + /* Public GtkWrapTable methods */ + GType eel_wrap_table_get_type (void); + GtkWidget * eel_wrap_table_new (gboolean homogeneous); + void eel_wrap_table_set_x_spacing (EelWrapTable *wrap_table, + guint x_spacing); + guint eel_wrap_table_get_x_spacing (const EelWrapTable *wrap_table); + void eel_wrap_table_set_y_spacing (EelWrapTable *wrap_table, + guint y_spacing); + guint eel_wrap_table_get_y_spacing (const EelWrapTable *wrap_table); + GtkWidget * eel_wrap_table_find_child_at_event_point (const EelWrapTable *wrap_table, + int x, + int y); + void eel_wrap_table_set_x_justification (EelWrapTable *wrap_table, + EelJustification justification); + EelJustification eel_wrap_table_get_x_justification (const EelWrapTable *wrap_table); + void eel_wrap_table_set_y_justification (EelWrapTable *wrap_table, + EelJustification justification); + EelJustification eel_wrap_table_get_y_justification (const EelWrapTable *wrap_table); + void eel_wrap_table_set_homogeneous (EelWrapTable *wrap_table, + gboolean homogeneous); + gboolean eel_wrap_table_get_homogeneous (const EelWrapTable *wrap_table); + void eel_wrap_table_reorder_child (EelWrapTable *wrap_table, + GtkWidget *child, + int position); + guint eel_wrap_table_get_num_children (const EelWrapTable *wrap_table); + + GtkWidget * eel_scrolled_wrap_table_new (gboolean homogenous, + GtkShadowType shadow_type, + GtkWidget **wrap_table_out); + +#ifdef __cplusplus +} +#endif + +#endif /* EEL_WRAP_TABLE_H */ + + diff --git a/eel/eel-xml-extensions.c b/eel/eel-xml-extensions.c new file mode 100644 index 00000000..a2d3a3a2 --- /dev/null +++ b/eel/eel-xml-extensions.c @@ -0,0 +1,199 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-xml-extensions.c - functions that extend mate-xml + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-xml-extensions.h" + +#include "eel-string.h" +#include "eel-i18n.h" +#include <glib.h> + +#include <libxml/parser.h> +#include <stdlib.h> + +xmlNodePtr +eel_xml_get_children (xmlNodePtr parent) +{ + if (parent == NULL) + { + return NULL; + } + return parent->children; +} + +xmlNodePtr +eel_xml_get_root_children (xmlDocPtr document) +{ + return eel_xml_get_children (xmlDocGetRootElement (document)); +} + +xmlNodePtr +eel_xml_get_child_by_name_and_property (xmlNodePtr parent, + const char *child_name, + const char *property_name, + const char *property_value) +{ + xmlNodePtr child; + xmlChar *property; + gboolean match; + + if (parent == NULL) + { + return NULL; + } + for (child = eel_xml_get_children (parent); child != NULL; child = child->next) + { + if (strcmp (child->name, child_name) == 0) + { + property = xmlGetProp (child, property_name); + match = eel_strcmp (property, property_value) == 0; + xmlFree (property); + if (match) + { + return child; + } + } + } + return NULL; +} + +/* return a child of the passed-in node with a matching name */ + +xmlNodePtr +eel_xml_get_child_by_name (xmlNodePtr parent, + const char *child_name) +{ + xmlNodePtr child; + + if (parent == NULL) + { + return NULL; + } + for (child = eel_xml_get_children (parent); child != NULL; child = child->next) + { + if (strcmp (child->name, child_name) == 0) + { + return child; + } + } + return NULL; +} + + +xmlNodePtr +eel_xml_get_root_child_by_name_and_property (xmlDocPtr document, + const char *child_name, + const char *property_name, + const char *property_value) +{ + return eel_xml_get_child_by_name_and_property + (xmlDocGetRootElement (document), + child_name, + property_name, + property_value); +} + +/** + * eel_xml_get_property_for_children + * + * Returns a list of the values for the specified property for all + * children of the node that have the specified name. + * + * @parent: xmlNodePtr representing the node in question. + * @child_name: child element name to look for + * @property: name of propety to reutnr for matching children that have the property + * + * Returns: A list of keywords. + * + **/ +GList * +eel_xml_get_property_for_children (xmlNodePtr parent, + const char *child_name, + const char *property_name) +{ + GList *properties; + xmlNode *child; + xmlChar *property; + + properties = NULL; + + for (child = eel_xml_get_children (parent); + child != NULL; + child = child->next) + { + if (strcmp (child->name, child_name) == 0) + { + property = xmlGetProp (child, property_name); + if (property != NULL) + { + properties = g_list_prepend (properties, + g_strdup (property)); + xmlFree (property); + } + } + } + + /* Reverse so you get them in the same order as the XML file. */ + return g_list_reverse (properties); +} + +xmlChar * +eel_xml_get_property_translated (xmlNodePtr parent, + const char *property_name) +{ + xmlChar *property, *untranslated_property; + char *untranslated_property_name; + const char *translated_property; + + /* Try for the already-translated version. */ + property = xmlGetProp (parent, property_name); + if (property != NULL) + { + return property; + } + + /* Try for the untranslated version. */ + untranslated_property_name = g_strconcat ("_", property_name, NULL); + untranslated_property = xmlGetProp (parent, untranslated_property_name); + g_free (untranslated_property_name); + if (untranslated_property == NULL) + { + return NULL; + } + + /* Try to translate. */ + translated_property = gettext (untranslated_property); + + /* If not translation is found, return untranslated property as-is. */ + if (translated_property == (char *) untranslated_property) + { + return untranslated_property; + } + + /* If a translation happened, make a copy to match the normal + * behavior of this function (returning a string you xmlFree). + */ + xmlFree (untranslated_property); + return xmlStrdup (translated_property); +} diff --git a/eel/eel-xml-extensions.h b/eel/eel-xml-extensions.h new file mode 100644 index 00000000..76ad4b84 --- /dev/null +++ b/eel/eel-xml-extensions.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-xml-extensions.h - functions that extend mate-xml + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#ifndef EEL_XML_EXTENSIONS_H +#define EEL_XML_EXTENSIONS_H + +#include <libxml/tree.h> +#include <glib.h> + +xmlNodePtr eel_xml_get_children (xmlNodePtr parent); +xmlNodePtr eel_xml_get_root_children (xmlDocPtr document); +xmlNodePtr eel_xml_get_child_by_name (xmlNodePtr parent, + const char *child_name); +xmlNodePtr eel_xml_get_child_by_name_and_property (xmlNodePtr parent, + const char *child_name, + const char *property_name, + const char *property_value); +xmlNodePtr eel_xml_get_root_child_by_name_and_property (xmlDocPtr document, + const char *child_name, + const char *property_name, + const char *property_value); +GList *eel_xml_get_property_for_children (xmlNodePtr parent, + const char *child_name, + const char *property_name); +xmlChar *eel_xml_get_property_translated (xmlNodePtr parent, + const char *property_name); + +#endif /* EEL_XML_EXTENSIONS_H */ diff --git a/eel/eel.h b/eel/eel.h new file mode 100644 index 00000000..80c848cc --- /dev/null +++ b/eel/eel.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel.h + + Copyright (C) 2001 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Maciej Stachowiak <[email protected]> +*/ + +#ifndef EEL_H +#define EEL_H + +#include <eel/eel-art-extensions.h> +#include <eel/eel-art-gtk-extensions.h> +#include <eel/eel-background.h> +#include <eel/eel-enumeration.h> +#include <eel/eel-mateconf-extensions.h> +#include <eel/eel-gdk-extensions.h> +#include <eel/eel-gdk-pixbuf-extensions.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-mate-extensions.h> +#include <eel/eel-graphic-effects.h> +#include <eel/eel-gtk-container.h> +#include <eel/eel-gtk-extensions.h> +#include <eel/eel-gtk-macros.h> +#include <eel/eel-image-table.h> +#include <eel/eel-labeled-image.h> +#include <eel/eel-pango-extensions.h> +#include <eel/eel-preferences.h> +#include <eel/eel-self-checks.h> +#include <eel/eel-stock-dialogs.h> +#include <eel/eel-string.h> +#include <eel/eel-types.h> +#include <eel/eel-vfs-extensions.h> +#include <eel/eel-wrap-table.h> +#include <eel/eel-xml-extensions.h> + +#endif /* EEL_H */ diff --git a/eel/eelmarshal.list b/eel/eelmarshal.list new file mode 100644 index 00000000..3974c4b7 --- /dev/null +++ b/eel/eelmarshal.list @@ -0,0 +1,13 @@ +BOOLEAN:BOOLEAN +BOOLEAN:BOXED +BOOLEAN:POINTER,POINTER +BOOLEAN:VOID +ENUM:INT,INT +INT:INT +INT:POINTER,STRING +STRING:POINTER +STRING:VOID +VOID:ENUM,INT +VOID:ENUM,INT,BOOLEAN +VOID:INT,INT,INT,INT +VOID:OBJECT,POINTER diff --git a/eel/makeenums.pl b/eel/makeenums.pl new file mode 100755 index 00000000..50402ed2 --- /dev/null +++ b/eel/makeenums.pl @@ -0,0 +1,220 @@ +#!/usr/bin/perl -w + +# This script snarfs the enums from header files and writes them out into +# a .defs file (mate.defs, for example). From there, the sister script +# maketypes.awk converts the defs into a *typebuiltins.h, as well as +# *typebuiltins_vals.c, *typebuiltins_ids.c and *typebuiltins_evals.c. + +# Information about the current enumeration + +my $flags; # Is enumeration a bitmask +my $seenbitshift; # Have we seen bitshift operators? +my $prefix; # Prefix for this enumeration +my $enumname; # Name for this enumeration +my $firstenum = 1; # Is this the first enumeration in file? +my @entries; # [ $name, $val ] for each entry + +sub parse_options { + my $opts = shift; + my @opts; + + for $opt (split /\s*,\s*/, $opts) { + my ($key,$val) = $opt =~ /\s*(\w+)(?:=(\S+))?/; + defined $val or $val = 1; + push @opts, $key, $val; + } + @opts; +} +sub parse_entries { + my $file = shift; + + while (<$file>) { + # Read lines until we have no open comments + while (m@/\* + ([^*]|\*(?!/))*$ + @x) { + my $new; + defined ($new = <$file>) || die "Unmatched comment"; + $_ .= $new; + } + # Now strip comments + s@/\*(?!<) + ([^*]+|\*(?!/))* + \*/@@gx; + + s@\n@ @; + + next if m@^\s*$@; + + # Handle include files + if (/^\#include\s*<([^>]*)>/ ) { + my $file= "../$1"; + open NEWFILE, $file or die "Cannot open include file $file: $!\n"; + + if (parse_entries (\*NEWFILE)) { + return 1; + } else { + next; + } + } + + if (/^\s*\}\s*(\w+)/) { + $enumname = $1; + return 1; + } + + if (m@^\s* + (\w+)\s* # name + (?:=( # value + (?:[^,/]|/(?!\*))* + ))?,?\s* + (?:/\*< # options + (([^*]|\*(?!/))*) + >\*/)? + \s*$ + @x) { + my ($name, $value, $options) = ($1,$2,$3); + + if (!defined $flags && defined $value && $value =~ /<</) { + $seenbitshift = 1; + } + if (defined $options) { + my %options = parse_options($options); + if (!defined $options{skip}) { + push @entries, [ $name, $options{nick} ]; + } + } else { + push @entries, [ $name ]; + } + } else { + print STDERR "Can't understand: $_\n"; + } + } + return 0; +} + + +my $gen_arrays = 0; +my $gen_defs = 0; + +# Parse arguments + +if (@ARGV) { + if ($ARGV[0] eq "arrays") { + shift @ARGV; + $gen_arrays = 1; + } elsif ($ARGV[0] eq "defs") { + shift @ARGV; + $gen_defs = 1; + } else { + $gen_defs = 1; + } + +} + +if ($gen_defs) { + print ";; generated by makeenums.pl ; -*- scheme -*-\n\n"; +} else { + print "/* Generated by makeenums.pl */\n\n"; +} + +ENUMERATION: +while (<>) { + if (eof) { + close (ARGV); # reset line numbering + $firstenum = 1; # Flag to print filename at next enum + } + + if (m@^\s*typedef\s+enum\s* + ({)?\s* + (?:/\*< + (([^*]|\*(?!/))*) + >\*/)? + @x) { + if (defined $2) { + my %options = parse_options($2); + $prefix = $options{prefix}; + $flags = $options{flags}; + } else { + $prefix = undef; + $flags = undef; + } + # Didn't have trailing '{' look on next lines + if (!defined $1) { + while (<>) { + if (s/^\s*\{//) { + last; + } + } + } + + $seenbitshift = 0; + @entries = (); + + # Now parse the entries + parse_entries (\*ARGV); + + # figure out if this was a flags or enums enumeration + + if (!defined $flags) { + $flags = $seenbitshift; + } + + # Autogenerate a prefix + + if (!defined $prefix) { + for (@entries) { + my $name = $_->[0]; + if (defined $prefix) { + my $tmp = ~ ($name ^ $prefix); + ($tmp) = $tmp =~ /(^\xff*)/; + $prefix = $prefix & $tmp; + } else { + $prefix = $name; + } + } + # Trim so that it ends in an underscore + $prefix =~ s/_[^_]*$/_/; + } + + for $entry (@entries) { + my ($name,$nick) = @{$entry}; + if (!defined $nick) { + ($nick = $name) =~ s/^$prefix//; + $nick =~ tr/_/-/; + $nick = lc($nick); + @{$entry} = ($name, $nick); + } + } + + # Spit out the output + + if ($gen_defs) { + if ($firstenum) { + print qq(\n; enumerations from "$ARGV"\n); + $firstenum = 0; + } + + print "\n(define-".($flags ? "flags" : "enum")." $enumname"; + + for (@entries) { + my ($name,$nick) = @{$_}; + print "\n ($nick $name)"; + } + print ")\n"; + + } else { + ($valuename = $enumname) =~ s/([A-Z][a-z])/_$1/g; + $valuename =~ s/([a-z])([A-Z])/$1_$2/g; + $valuename = lc($valuename); + + print "static const GEnumValue $ {valuename}_values[] = {\n"; + for (@entries) { + my ($name,$nick) = @{$_}; + print qq( { $name, "$name", "$nick" },\n); + } + print " { 0, NULL, NULL }\n"; + print "};\n"; + } + } +} diff --git a/eel/maketypes.awk b/eel/maketypes.awk new file mode 100755 index 00000000..4284eddd --- /dev/null +++ b/eel/maketypes.awk @@ -0,0 +1,155 @@ + +BEGIN { + type_name = ""; # GtkEnumType + type_macro = ""; # GTK_TYPE_ENUM_TYPE + type_ident = ""; # _gtk_enum_type + type_counter = 0; + gen_macros = 0; + gen_entries = 0; + gen_vars = 0; + boxed_copy = ""; + boxed_free = ""; + + for (i = 2; i < ARGC; i++) + { + if (ARGV[i] == "macros") + gen_macros = 1; + else if (ARGV[i] == "entries") + gen_entries = 1; + else if (ARGV[i] == "variables") + gen_vars = 1; + ARGV[i] = ""; + } + + if (gen_macros) + { + printf ("/* type macros, generated by maketypes.awk */\n"); + printf ("\n"); + printf ("#ifdef G_OS_WIN32\n"); + printf ("# ifdef EEL_COMPILATION\n"); + printf ("# define EELTYPEBUILTINS_VAR __declspec(dllexport)\n"); + printf ("# else\n"); + printf ("# define EELTYPEBUILTINS_VAR extern __declspec(dllimport)\n"); + printf ("# endif\n"); + printf ("#else\n"); + printf ("# ifdef EEL_COMPILATION\n"); + printf ("# define EELTYPEBUILTINS_VAR\n"); + printf ("# else\n"); + printf ("# define EELTYPEBUILTINS_VAR extern\n"); + printf ("# endif\n"); + printf ("#endif\n"); + printf ("\n"); + } + else if (gen_entries) + printf ("/* type entries, generated by maketypes.awk */\n\n"); + else if (gen_vars) + printf ("/* type variables, generated by maketypes.awk */\n\n"); + else + { + printf ("hm? what do you want me to do?\n") > "/dev/stderr"; + exit 1; + } +} + +function set_type (set_type_1) +{ + type_counter += 1; + type_name = set_type_1; + type_macro = "EEL_TYPE_"; + + tmp = type_name; +# OK, the following is ridiculous, and sed s///g would be far easier + gsub ("[A-Z]", "@&", tmp); + gsub ("[^A-Z]@", "&_", tmp); + gsub ("@", "", tmp); + gsub ("[A-Z][A-Z][A-Z][0-9a-z]", "@&", tmp); + gsub ("@..", "&_", tmp); + gsub ("@", "", tmp); + type_macro = type_macro toupper (tmp); + type_ident = "_" tolower (tmp); + + sub ("^EEL_TYPE_EEL_", "EEL_TYPE_", type_macro); +} + +function generate (generate_what) +{ + if (gen_macros) + { + printf ("EELTYPEBUILTINS_VAR GType %s;\n", type_macro); + } + if (gen_entries) + { + printf (" { \"%s\", &%s,\n", type_name, type_macro); + if (generate_what == "BOXED") + printf (" G_TYPE_%s, %s, %s, },\n", generate_what, boxed_copy, boxed_free); + else + printf (" G_TYPE_%s, %s_values },\n", generate_what, type_ident); + } + if (gen_vars) + { + printf ("EELTYPEBUILTINS_VAR GType %s = 0;\n", type_macro); + } +} + +# skip scheme comments +";" { + sub (";.*", ""); +} + +# parse keywords + +/\(define-enum/ { + if ($2 == "") + printf ("huh? define-enum keyword without arg?\n") > "/dev/stderr"; + else + { + set_type($2); + generate("ENUM"); + } +} + +/\(define-flags/ { + if ($2 == "") + printf ("huh? define-flags keyword without arg?\n") > "/dev/stderr"; + else + { + set_type($2); + generate("FLAGS"); + } +} + +/\(define-boxed/ { + if ($2 == "") + printf ("huh? define-boxed keyword without arg?\n") > "/dev/stderr"; + else + { + boxed_copy = "NULL"; + boxed_free = "NULL"; + set_type($2); + do { + getline; + sub (";.*", "", $0); + } while ($0 ~ /^[ \t]*$/); + tmp_var1 = $1; + if ($0 ~ /\)/) { generate("BOXED"); next; } + do { + getline; + sub (";.*", "", $0); + } while ($0 ~ /^[ \t]*$/); + tmp_var2 = $1; + sub (/\).*/, "", tmp_var2); + if (tmp_var1 ~ /^[_A-Za-z][_A-Za-z0-9]*$/ && + tmp_var2 ~ /^[_A-Za-z][_A-Za-z0-9]*$/) + { + boxed_copy = tmp_var1; + boxed_free = tmp_var2; + # printf ("read boxed funcs: %s %s\n", boxed_copy, boxed_free) > "/dev/stderr"; + } + generate("BOXED"); + } +} + +END { + if (gen_macros) + printf("\n#define\tEEL_TYPE_N_BUILTINS\t(%u)\n", type_counter); +} |