summaryrefslogtreecommitdiff
path: root/eel
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2008-12-15 15:56:41 +0000
committerAlexander Larsson <alexl@src.gnome.org>2008-12-15 15:56:41 +0000
commit7e668edf204ea9a8c72565e7cabaced11be86caa (patch)
tree7baed8654034492f54d4de730a13ad2c4f8a7050 /eel
parentd4b4c188e1a89a268af33ff0381eeca04e5528dc (diff)
downloadnautilus-7e668edf204ea9a8c72565e7cabaced11be86caa.tar.gz
eel/ Import eel into nautilus.
2008-12-15 Alexander Larsson <alexl@redhat.com> * Makefile.am: * acconfig.h: * configure.in: * eel/ * libnautilus-private/Makefile.am: Import eel into nautilus. svn path=/trunk/; revision=14815
Diffstat (limited to 'eel')
-rw-r--r--eel/ChangeLog10652
-rw-r--r--eel/Makefile.am188
-rw-r--r--eel/README4
-rw-r--r--eel/README.canvas25
-rwxr-xr-xeel/check-eel3
-rw-r--r--eel/check-program.c60
-rw-r--r--eel/eel-accessibility.c413
-rw-r--r--eel/eel-accessibility.h152
-rw-r--r--eel/eel-alert-dialog.c467
-rw-r--r--eel/eel-alert-dialog.h60
-rw-r--r--eel/eel-art-extensions.c308
-rw-r--r--eel/eel-art-extensions.h111
-rw-r--r--eel/eel-art-gtk-extensions.c313
-rw-r--r--eel/eel-art-gtk-extensions.h70
-rw-r--r--eel/eel-background-box.c70
-rw-r--r--eel/eel-background-box.h61
-rw-r--r--eel/eel-background.c933
-rw-r--r--eel/eel-background.h155
-rw-r--r--eel/eel-canvas-rect-ellipse.c1489
-rw-r--r--eel/eel-canvas-rect-ellipse.h174
-rw-r--r--eel/eel-canvas-util.c396
-rw-r--r--eel/eel-canvas-util.h105
-rw-r--r--eel/eel-canvas.c3979
-rw-r--r--eel/eel-canvas.h530
-rw-r--r--eel/eel-debug-drawing.c527
-rw-r--r--eel/eel-debug-drawing.h72
-rw-r--r--eel/eel-debug.c129
-rw-r--r--eel/eel-debug.h48
-rw-r--r--eel/eel-editable-label.c4410
-rw-r--r--eel/eel-editable-label.h142
-rw-r--r--eel/eel-enumeration.c533
-rw-r--r--eel/eel-enumeration.h63
-rw-r--r--eel/eel-gconf-extensions.c647
-rw-r--r--eel/eel-gconf-extensions.h73
-rw-r--r--eel/eel-gdk-extensions.c947
-rw-r--r--eel/eel-gdk-extensions.h163
-rw-r--r--eel/eel-gdk-pixbuf-extensions.c1305
-rw-r--r--eel/eel-gdk-pixbuf-extensions.h155
-rw-r--r--eel/eel-glib-extensions.c1159
-rw-r--r--eel/eel-glib-extensions.h126
-rw-r--r--eel/eel-gnome-extensions.c203
-rw-r--r--eel/eel-gnome-extensions.h44
-rw-r--r--eel/eel-graphic-effects.c399
-rw-r--r--eel/eel-graphic-effects.h66
-rw-r--r--eel/eel-gtk-container.c209
-rw-r--r--eel/eel-gtk-container.h47
-rw-r--r--eel/eel-gtk-extensions.c1174
-rw-r--r--eel/eel-gtk-extensions.h141
-rw-r--r--eel/eel-gtk-macros.h178
-rw-r--r--eel/eel-i18n.c51
-rw-r--r--eel/eel-i18n.h53
-rw-r--r--eel/eel-image-table.c579
-rw-r--r--eel/eel-image-table.h89
-rw-r--r--eel/eel-labeled-image.c2376
-rw-r--r--eel/eel-labeled-image.h156
-rw-r--r--eel/eel-lib-self-check-functions.c38
-rw-r--r--eel/eel-lib-self-check-functions.h53
-rw-r--r--eel/eel-pango-extensions.c586
-rw-r--r--eel/eel-pango-extensions.h54
-rw-r--r--eel/eel-preferences-builder.c564
-rw-r--r--eel/eel-preferences.c1701
-rw-r--r--eel/eel-preferences.h157
-rw-r--r--eel/eel-self-checks.c221
-rw-r--r--eel/eel-self-checks.h100
-rw-r--r--eel/eel-stock-dialogs.c571
-rw-r--r--eel/eel-stock-dialogs.h91
-rw-r--r--eel/eel-string.c1178
-rw-r--r--eel/eel-string.h120
-rw-r--r--eel/eel-types.c73
-rw-r--r--eel/eel-types.h32
-rw-r--r--eel/eel-vfs-extensions.c178
-rw-r--r--eel/eel-vfs-extensions.h57
-rw-r--r--eel/eel-wrap-table.c1053
-rw-r--r--eel/eel-wrap-table.h97
-rw-r--r--eel/eel-xml-extensions.c184
-rw-r--r--eel/eel-xml-extensions.h49
-rw-r--r--eel/eel.h53
-rw-r--r--eel/eelmarshal.list13
-rwxr-xr-xeel/makeenums.pl220
-rwxr-xr-xeel/maketypes.awk155
-rwxr-xr-xeel/update-from-egg.sh25
81 files changed, 44605 insertions, 0 deletions
diff --git a/eel/ChangeLog b/eel/ChangeLog
new file mode 100644
index 000000000..0d22d7ce4
--- /dev/null
+++ b/eel/ChangeLog
@@ -0,0 +1,10652 @@
+2008-12-15 Alexander Larsson <alexl@redhat.com>
+
+ Reviewed by NOBODY (OOPS!).
+
+ * ChangeLog: Added.
+ * Makefile.am: Added.
+ * README: Added.
+ * README.canvas: Added.
+ * check-eel: Added.
+ * check-program.c: Added.
+ (main):
+ * eel-accessibility.c: Added.
+ (eel_accessibility_set_up_label_widget_relation):
+ (eel_accessibility_create_derived_type):
+ (get_quark_accessible):
+ (get_quark_gobject):
+ (eel_accessibility_get_atk_object):
+ (eel_accessibility_for_object):
+ (eel_accessibility_get_gobject):
+ (eel_accessibility_destroy):
+ (eel_accessibility_set_atk_object_return):
+ (get_simple_text):
+ (eel_accessibility_text_get_text):
+ (eel_accessibility_text_get_character_at_offset):
+ (eel_accessibility_text_get_text_before_offset):
+ (eel_accessibility_text_get_text_at_offset):
+ (eel_accessibility_text_get_text_after_offset):
+ (eel_accessibility_text_get_character_count):
+ (eel_accessibility_simple_text_interface_init):
+ (eel_accessibility_add_simple_text):
+ (eel_accessible_text_get_type):
+ (eel_accessibility_set_name):
+ (eel_accessibility_set_description):
+ * eel-accessibility.h: Added.
+ * eel-alert-dialog.c: Added.
+ (eel_alert_dialog_get_type):
+ (eel_alert_dialog_class_init):
+ (eel_alert_dialog_finalize):
+ (eel_alert_dialog_init):
+ (setup_type):
+ (eel_alert_dialog_set_property):
+ (eel_alert_dialog_get_property):
+ (eel_alert_dialog_set_primary_label):
+ (eel_alert_dialog_set_secondary_label):
+ (eel_alert_dialog_set_details_label):
+ (eel_alert_dialog_new):
+ (eel_alert_dialog_add_buttons):
+ (eel_alert_dialog_style_set):
+ * eel-alert-dialog.h: Added.
+ * eel-art-extensions.c: Added.
+ (eel_irect_copy):
+ (eel_irect_union):
+ (eel_irect_intersect):
+ (eel_irect_is_empty):
+ (eel_irect_assign):
+ (eel_irect_assign_dimensions):
+ (eel_irect_get_width):
+ (eel_irect_get_height):
+ (eel_drect_copy):
+ (eel_drect_is_empty):
+ (eel_drect_union):
+ (eel_irect_contains_point):
+ (eel_irect_hits_irect):
+ (eel_irect_equal):
+ (eel_irect_align):
+ (eel_dimensions_are_empty):
+ (eel_irect_offset_by):
+ (eel_irect_scale_by):
+ * eel-art-extensions.h: Added.
+ * eel-art-gtk-extensions.c: Added.
+ (eel_gdk_rectangle_to_eel_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_irect_to_gdk_rectangle):
+ (eel_gdk_window_get_dimensions):
+ (eel_gdk_get_pointer_position):
+ * eel-art-gtk-extensions.h: Added.
+ * eel-background-box.c: Added.
+ (eel_background_box_expose_event):
+ (eel_background_box_class_init):
+ (eel_background_box_init):
+ (eel_background_box_new):
+ * eel-background-box.h: Added.
+ * eel-background.c: Added.
+ (eel_background_class_init):
+ (on_bg_changed):
+ (eel_background_init):
+ (eel_background_remove_current_image):
+ (eel_background_finalize):
+ (placement_gnome_to_eel):
+ (placement_eel_to_gnome):
+ (eel_background_get_image_placement):
+ (eel_background_set_image_placement):
+ (eel_background_new):
+ (eel_background_unrealize):
+ (drawable_get_adjusted_size):
+ (eel_background_ensure_realized):
+ (eel_background_get_pixmap_and_color):
+ (eel_background_expose):
+ (set_image_properties):
+ (eel_background_get_color):
+ (eel_background_get_image_uri):
+ (eel_background_set_use_base):
+ (eel_background_set_color):
+ (eel_background_set_image_uri_helper):
+ (eel_background_set_image_uri):
+ (eel_background_set_image_uri_and_color):
+ (eel_background_receive_dropped_background_image):
+ (eel_background_is_set):
+ (eel_background_reset):
+ (eel_background_set_up_widget):
+ (eel_widget_background_changed):
+ (widget_style_set_cb):
+ (screen_size_changed):
+ (widget_realized_setup):
+ (widget_realize_cb):
+ (widget_unrealize_cb):
+ (eel_background_set_desktop):
+ (eel_background_is_desktop):
+ (eel_get_widget_background):
+ (eel_background_is_dark):
+ (eel_background_receive_dropped_color):
+ (eel_background_save_to_gconf):
+ (eel_self_check_background):
+ * eel-background.h: Added.
+ * eel-canvas-rect-ellipse.c: Added.
+ (eel_canvas_re_get_type):
+ (eel_canvas_re_class_init):
+ (eel_canvas_re_init):
+ (eel_canvas_re_destroy):
+ (get_bounds):
+ (set_gc_foreground):
+ (set_stipple):
+ (set_outline_gc_width):
+ (eel_canvas_re_set_fill):
+ (eel_canvas_re_set_outline):
+ (eel_canvas_re_set_property):
+ (get_color_value):
+ (eel_canvas_re_get_property):
+ (set_colors_and_stipples):
+ (eel_canvas_re_update_shared):
+ (eel_canvas_re_realize):
+ (eel_canvas_re_unrealize):
+ (eel_canvas_re_translate):
+ (eel_canvas_re_bounds):
+ (eel_canvas_rect_get_type):
+ (eel_canvas_rect_class_init):
+ (eel_canvas_rect_init):
+ (eel_canvas_rect_finalize):
+ (eel_canvas_rect_realize):
+ (render_rect_alpha):
+ (eel_canvas_rect_draw):
+ (eel_canvas_rect_point):
+ (request_redraw_borders):
+ (eel_canvas_rect_update):
+ (eel_canvas_ellipse_get_type):
+ (eel_canvas_ellipse_class_init):
+ (eel_canvas_ellipse_draw):
+ (eel_canvas_ellipse_point):
+ (eel_canvas_ellipse_update):
+ (rect_empty):
+ (make_rect):
+ (rects_intersect):
+ (diff_rects_guts):
+ (diff_rects):
+ * eel-canvas-rect-ellipse.h: Added.
+ * eel-canvas-util.c: Added.
+ (eel_canvas_points_new):
+ (eel_canvas_points_ref):
+ (eel_canvas_points_free):
+ (eel_canvas_get_miter_points):
+ (eel_canvas_get_butt_points):
+ (eel_canvas_polygon_to_point):
+ (eel_canvas_item_reset_bounds):
+ (eel_canvas_update_bbox):
+ * eel-canvas-util.h: Added.
+ * eel-canvas.c: Added.
+ (eel_canvas_item_get_type):
+ (eel_canvas_item_init):
+ (eel_canvas_item_new):
+ (item_post_create_setup):
+ (eel_canvas_item_set_property):
+ (eel_canvas_item_get_property):
+ (eel_canvas_item_construct):
+ (redraw_and_repick_if_mapped):
+ (eel_canvas_item_dispose):
+ (eel_canvas_item_realize):
+ (eel_canvas_item_unrealize):
+ (eel_canvas_item_map):
+ (eel_canvas_item_unmap):
+ (eel_canvas_item_update):
+ (eel_canvas_item_invoke_update):
+ (eel_canvas_item_invoke_point):
+ (eel_canvas_item_set):
+ (eel_canvas_item_set_valist):
+ (eel_canvas_item_move):
+ (put_item_after):
+ (eel_canvas_item_raise):
+ (eel_canvas_item_lower):
+ (eel_canvas_item_raise_to_top):
+ (eel_canvas_item_lower_to_bottom):
+ (eel_canvas_item_send_behind):
+ (eel_canvas_item_show):
+ (eel_canvas_item_hide):
+ (eel_canvas_item_grab):
+ (eel_canvas_item_ungrab):
+ (eel_canvas_item_w2i):
+ (eel_canvas_item_i2w):
+ (is_descendant):
+ (eel_canvas_item_reparent):
+ (eel_canvas_item_grab_focus):
+ (eel_canvas_item_get_bounds):
+ (eel_canvas_item_request_update):
+ (eel_canvas_item_request_redraw):
+ (eel_canvas_group_get_type):
+ (eel_canvas_group_class_init):
+ (eel_canvas_group_init):
+ (eel_canvas_group_set_property):
+ (eel_canvas_group_get_property):
+ (eel_canvas_group_destroy):
+ (eel_canvas_group_update):
+ (eel_canvas_group_unrealize):
+ (eel_canvas_group_map):
+ (eel_canvas_group_unmap):
+ (eel_canvas_group_draw):
+ (eel_canvas_group_point):
+ (eel_canvas_group_translate):
+ (eel_canvas_group_bounds):
+ (group_add):
+ (group_remove):
+ (eel_canvas_get_type):
+ (eel_canvas_get_property):
+ (eel_canvas_set_property):
+ (eel_canvas_accessible_adjustment_changed):
+ (eel_canvas_accessible_initialize):
+ (eel_canvas_accessible_get_n_children):
+ (eel_canvas_accessible_ref_child):
+ (eel_canvas_accessible_class_init):
+ (eel_canvas_accessible_get_type):
+ (eel_canvas_accessible_create):
+ (eel_canvas_accessible_factory_get_accessible_type):
+ (eel_canvas_accessible_factory_create_accessible):
+ (eel_canvas_accessible_factory_class_init):
+ (eel_canvas_accessible_factory_get_type):
+ (eel_canvas_class_init):
+ (panic_root_destroyed):
+ (eel_canvas_init):
+ (remove_idle):
+ (shutdown_transients):
+ (eel_canvas_destroy):
+ (eel_canvas_new):
+ (eel_canvas_map):
+ (eel_canvas_unmap):
+ (eel_canvas_realize):
+ (eel_canvas_unrealize):
+ (scroll_to):
+ (eel_canvas_size_allocate):
+ (emit_event):
+ (pick_current_item):
+ (eel_canvas_button):
+ (eel_canvas_motion):
+ (eel_canvas_key):
+ (eel_canvas_crossing):
+ (eel_canvas_focus_in):
+ (eel_canvas_focus_out):
+ (eel_canvas_expose):
+ (eel_canvas_draw_background):
+ (do_update):
+ (idle_handler):
+ (add_idle):
+ (eel_canvas_root):
+ (eel_canvas_set_scroll_region):
+ (eel_canvas_get_scroll_region):
+ (eel_canvas_set_center_scroll_region):
+ (eel_canvas_set_pixels_per_unit):
+ (eel_canvas_scroll_to):
+ (eel_canvas_get_scroll_offsets):
+ (eel_canvas_update_now):
+ (eel_canvas_get_item_at):
+ (eel_canvas_request_update):
+ (eel_canvas_request_update_real):
+ (eel_canvas_request_redraw):
+ (eel_canvas_w2c):
+ (eel_canvas_w2c_rect_d):
+ (eel_canvas_w2c_d):
+ (eel_canvas_c2w):
+ (eel_canvas_window_to_world):
+ (eel_canvas_world_to_window):
+ (eel_canvas_get_color):
+ (eel_canvas_get_color_pixel):
+ (eel_canvas_set_stipple_origin):
+ (boolean_handled_accumulator):
+ (eel_canvas_item_accessible_add_focus_handler):
+ (eel_canvas_item_accessible_get_item_extents):
+ (eel_canvas_item_accessible_is_item_in_window):
+ (eel_canvas_item_accessible_get_extents):
+ (eel_canvas_item_accessible_get_mdi_zorder):
+ (eel_canvas_item_accessible_grab_focus):
+ (eel_canvas_item_accessible_remove_focus_handler):
+ (eel_canvas_item_accessible_component_interface_init):
+ (eel_canvas_item_accessible_is_item_on_screen):
+ (eel_canvas_item_accessible_initialize):
+ (eel_canvas_item_accessible_ref_state_set):
+ (eel_canvas_item_accessible_class_init):
+ (eel_canvas_item_accessible_get_type):
+ (eel_canvas_item_accessible_create):
+ (eel_canvas_item_accessible_factory_get_accessible_type):
+ (eel_canvas_item_accessible_factory_create_accessible):
+ (eel_canvas_item_accessible_factory_class_init):
+ (eel_canvas_item_accessible_factory_get_type):
+ (eel_canvas_item_class_init):
+ * eel-canvas.h: Added.
+ * eel-debug-drawing.c: Added.
+ (debug_pixbuf_viewer_class_init):
+ (debug_pixbuf_viewer_init):
+ (debug_pixbuf_viewer_finalize):
+ (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_external_viewer):
+ (debug_delete_event):
+ (destroy_debug_window):
+ (eel_debug_show_pixbuf):
+ (eel_debug_pixbuf_draw_point):
+ (eel_debug_pixbuf_draw_rectangle):
+ (eel_debug_pixbuf_draw_rectangle_inset):
+ * eel-debug-drawing.h: Added.
+ * eel-debug.c: Added.
+ (eel_stop_in_debugger):
+ (log_handler):
+ (eel_make_warnings_and_criticals_stop_in_debugger):
+ (eel_get_available_file_descriptor_count):
+ (eel_debug_shut_down):
+ (eel_debug_call_at_shutdown):
+ (eel_debug_call_at_shutdown_with_data):
+ * eel-debug.h: Added.
+ * eel-editable-label.c: Added.
+ (eel_editable_label_get_type):
+ (add_move_binding):
+ (eel_editable_label_class_init):
+ (eel_editable_label_editable_init):
+ (eel_editable_label_set_property):
+ (eel_editable_label_get_property):
+ (eel_editable_label_init):
+ (eel_editable_label_new):
+ (eel_editable_label_set_text):
+ (eel_editable_label_get_text):
+ (eel_editable_label_set_justify):
+ (eel_editable_label_get_justify):
+ (eel_editable_label_set_draw_outline):
+ (eel_editable_label_set_line_wrap):
+ (eel_editable_label_set_line_wrap_mode):
+ (eel_editable_label_get_line_wrap):
+ (eel_editable_label_get_font_description):
+ (eel_editable_label_set_font_description):
+ (eel_editable_label_finalize):
+ (eel_editable_label_clear_layout):
+ (eel_editable_label_recompute):
+ (label_wrap_width_free):
+ (get_label_wrap_width):
+ (eel_editable_label_ensure_layout):
+ (eel_editable_label_size_request):
+ (eel_editable_label_size_allocate):
+ (eel_editable_label_state_changed):
+ (eel_editable_label_style_set):
+ (eel_editable_label_direction_changed):
+ (get_layout_location):
+ (eel_editable_label_get_cursor_pos):
+ (eel_editable_label_get_block_cursor_location):
+ (make_cursor_gc):
+ (_eel_draw_insertion_cursor):
+ (eel_editable_label_draw_cursor):
+ (eel_editable_label_expose):
+ (eel_editable_label_realize):
+ (eel_editable_label_unrealize):
+ (eel_editable_label_map):
+ (eel_editable_label_unmap):
+ (window_to_layout_coords):
+ (get_layout_index):
+ (eel_editable_label_select_word):
+ (eel_editable_label_button_press):
+ (eel_editable_label_button_release):
+ (eel_editable_label_motion):
+ (get_text_callback):
+ (clear_text_callback):
+ (eel_editable_label_select_region_index):
+ (eel_editable_label_select_region):
+ (eel_editable_label_get_selection_bounds):
+ (eel_editable_label_get_layout):
+ (eel_editable_label_get_layout_offsets):
+ (eel_editable_label_pend_cursor_blink):
+ (eel_editable_label_check_cursor_blink):
+ (eel_editable_label_key_press):
+ (eel_editable_label_key_release):
+ (eel_editable_label_keymap_direction_changed):
+ (eel_editable_label_focus_in):
+ (eel_editable_label_focus_out):
+ (eel_editable_label_delete_text):
+ (eel_editable_label_insert_text):
+ (eel_editable_label_enter_text):
+ (eel_editable_label_commit_cb):
+ (eel_editable_label_preedit_changed_cb):
+ (eel_editable_label_retrieve_surrounding_cb):
+ (eel_editable_label_delete_surrounding_cb):
+ (eel_editable_label_focus):
+ (get_better_cursor):
+ (eel_editable_label_move_logically):
+ (eel_editable_label_move_visually):
+ (eel_editable_label_move_line):
+ (eel_editable_label_move_forward_word):
+ (eel_editable_label_move_backward_word):
+ (eel_editable_label_move_cursor):
+ (eel_editable_label_reset_im_context):
+ (eel_editable_label_delete_from_cursor):
+ (eel_editable_label_copy_clipboard):
+ (eel_editable_label_cut_clipboard):
+ (paste_received):
+ (eel_editable_label_paste):
+ (eel_editable_label_paste_clipboard):
+ (eel_editable_label_select_all):
+ (activate_cb):
+ (append_action_signal):
+ (popup_menu_detach):
+ (popup_position_func):
+ (eel_editable_label_toggle_overwrite):
+ (popup_targets_received):
+ (eel_editable_label_do_popup):
+ (editable_insert_text_emit):
+ (editable_delete_text_emit):
+ (editable_insert_text):
+ (editable_delete_text):
+ (editable_get_chars):
+ (editable_set_selection_bounds):
+ (editable_get_selection_bounds):
+ (editable_real_set_position):
+ (editable_get_position):
+ (eel_editable_label_accessible_get_text):
+ (eel_editable_label_accessible_get_character_at_offset):
+ (eel_editable_label_accessible_get_text_before_offset):
+ (eel_editable_label_accessible_get_text_at_offset):
+ (eel_editable_label_accessible_get_text_after_offset):
+ (eel_editable_label_accessible_get_caret_offset):
+ (eel_editable_label_accessible_set_caret_offset):
+ (eel_editable_label_accessible_get_character_count):
+ (eel_editable_label_accessible_get_n_selections):
+ (eel_editable_label_accessible_get_selection):
+ (eel_editable_label_accessible_add_selection):
+ (eel_editable_label_accessible_remove_selection):
+ (eel_editable_label_accessible_set_selection):
+ (eel_editable_label_accessible_get_run_attributes):
+ (eel_editable_label_accessible_get_default_attributes):
+ (eel_editable_label_accessible_get_character_extents):
+ (eel_editable_label_accessible_get_offset_at_point):
+ (atk_text_interface_init):
+ (eel_editable_label_accessible_set_text_contents):
+ (eel_editable_label_accessible_insert_text):
+ (eel_editable_label_accessible_copy_text):
+ (eel_editable_label_accessible_cut_text):
+ (eel_editable_label_accessible_delete_text):
+ (eel_editable_label_accessible_paste_received):
+ (eel_editable_label_accessible_paste_text):
+ (atk_editable_text_interface_init):
+ (eel_editable_label_accessible_notify_insert):
+ (eel_editable_label_accessible_idle_notify_insert):
+ (eel_editable_label_accessible_insert_text_cb):
+ (eel_editable_label_accessible_delete_text_cb):
+ (eel_editable_label_accessible_changed_cb):
+ (check_for_selection_change):
+ (eel_editable_label_accessible_notify_gtk):
+ (eel_editable_label_accessible_initialize):
+ (eel_editable_label_accessible_get_name):
+ (eel_editable_label_accessible_ref_state_set):
+ (eel_editable_label_accessible_finalize):
+ (eel_editable_label_accessible_class_init):
+ (eel_editable_label_get_accessible):
+ * eel-editable-label.h: Added.
+ * eel-enumeration.c: Added.
+ (eel_enumeration_new):
+ (free_entry):
+ (eel_enumeration_free):
+ (eel_enumeration_get_id):
+ (eel_enumeration_get_length):
+ (eel_enumeration_get_nth_entry):
+ (eel_enumeration_get_name_position):
+ (eel_enumeration_contains_name):
+ (eel_enumeration_get_value_for_name):
+ (eel_enumeration_get_name_for_value):
+ (eel_enumeration_get_names):
+ (eel_enumeration_new_from_tokens):
+ (dup_entry):
+ (eel_enumeration_new_from_entries):
+ (enumeration_table_free):
+ (enumeration_table_get):
+ (eel_enumeration_lookup):
+ (eel_enumeration_register):
+ (eel_self_check_enumeration):
+ * eel-enumeration.h: Added.
+ * eel-gconf-extensions.c: Added.
+ (global_client_free):
+ (eel_gconf_client_get_global):
+ (eel_gconf_handle_error):
+ (eel_gconf_set_boolean):
+ (eel_gconf_get_boolean):
+ (eel_gconf_set_integer):
+ (eel_gconf_get_integer):
+ (eel_gconf_set_string):
+ (eel_gconf_get_string):
+ (eel_gconf_set_string_list):
+ (eel_gconf_get_string_list):
+ (eel_gconf_unset):
+ (eel_gconf_is_default):
+ (eel_gconf_key_is_writable):
+ (eel_gconf_monitor_add):
+ (eel_gconf_monitor_remove):
+ (eel_gconf_preload_cache):
+ (eel_gconf_suggest_sync):
+ (eel_gconf_get_value):
+ (eel_gconf_get_default_value):
+ (simple_value_is_equal):
+ (eel_gconf_value_is_equal):
+ (eel_gconf_value_free):
+ (eel_gconf_notification_add):
+ (eel_gconf_notification_remove):
+ (eel_gconf_value_get_string_list):
+ (eel_gconf_value_set_string_list):
+ * eel-gconf-extensions.h: Added.
+ * eel-gdk-extensions.c: Added.
+ (eel_gdk_rectangle_contains_rectangle):
+ (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_stipple_bitmap_for_screen):
+ (eel_stipple_bitmap):
+ (eel_gdk_window_bring_to_front):
+ (eel_gdk_window_focus):
+ (eel_gdk_window_set_wm_protocols):
+ (eel_gdk_window_set_wm_hints_input):
+ (eel_gdk_window_set_invisible_cursor):
+ (eel_gdk_parse_geometry):
+ (eel_gdk_draw_layout_with_drop_shadow):
+ (eel_gdk_color_as_hex_string):
+ (eel_self_check_parse):
+ (eel_self_check_gdk_rgb_to_color):
+ (eel_self_check_gdk_extensions):
+ * eel-gdk-extensions.h: Added.
+ * eel-gdk-pixbuf-extensions.c: Added.
+ (eel_gdk_pixbuf_list_ref):
+ (eel_gdk_pixbuf_list_free):
+ (eel_gdk_pixbuf_load):
+ (eel_gdk_pixbuf_load_from_stream):
+ (pixbuf_loader_size_prepared):
+ (eel_gdk_pixbuf_load_from_stream_at_size):
+ (free_pixbuf_load_handle):
+ (load_done):
+ (file_read_callback):
+ (file_opened_callback):
+ (eel_gdk_pixbuf_load_async):
+ (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_scale_to_min_factor):
+ (eel_gdk_pixbuf_scale_to_min):
+ (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):
+ (pixbuf_destroy_callback):
+ (eel_gdk_pixbuf_new_from_pixbuf_sub_area):
+ (eel_gdk_pixbuf_new_from_existing_buffer):
+ (eel_gdk_pixbuf_intersect):
+ (eel_gdk_pixbuf_scale_down):
+ (check_average_value):
+ (eel_self_check_gdk_pixbuf_extensions):
+ * eel-gdk-pixbuf-extensions.h: Added.
+ * eel-glib-extensions.c: Added.
+ (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_str_list_equal):
+ (eel_g_str_list_copy):
+ (eel_g_str_list_alphabetize):
+ (eel_g_str_list_index):
+ (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):
+ (compare_pointers):
+ (eel_g_lists_sort_and_check_for_intersection):
+ (eel_g_list_partition):
+ (eel_get_system_time):
+ (print_key_string):
+ (free_hash_tables_at_exit):
+ (eel_g_hash_table_new_free_at_exit):
+ (flatten_hash_table_element):
+ (eel_g_hash_table_safe_for_each):
+ (eel_round):
+ (eel_g_list_from_g_slist):
+ (eel_g_slist_from_g_list):
+ (eel_get_operating_system_name):
+ (eel_compare_integer):
+ (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):
+ (filename_charset_cache_free):
+ (eel_get_filename_charset):
+ (check_tm_to_g_date):
+ (eel_test_predicate):
+ (test_strftime):
+ (eel_self_check_glib_extensions):
+ * eel-glib-extensions.h: Added.
+ * eel-gnome-extensions.c: Added.
+ (try_terminal_command):
+ (try_terminal_command_argv):
+ (get_terminal_command_prefix):
+ (eel_gnome_make_terminal_command):
+ (eel_gnome_open_terminal_on_screen):
+ (eel_gnome_open_terminal):
+ * eel-gnome-extensions.h: Added.
+ * eel-graphic-effects.c: Added.
+ (create_new_pixbuf):
+ (create_new_pixbuf_with_alpha):
+ (lighten_component):
+ (eel_create_spotlight_pixbuf):
+ (eel_create_darkened_pixbuf):
+ (eel_create_colorized_pixbuf):
+ (draw_frame_row):
+ (draw_frame_column):
+ (eel_stretch_frame_image):
+ (eel_embed_image_in_frame):
+ (eel_make_semi_transparent):
+ * eel-graphic-effects.h: Added.
+ * eel-gtk-container.c: Added.
+ (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):
+ * eel-gtk-container.h: Added.
+ * eel-gtk-extensions.c: Added.
+ (eel_gtk_window_get_geometry_string):
+ (send_delete_event):
+ (handle_standard_close_accelerator):
+ (eel_gtk_window_event_is_close_accelerator):
+ (eel_gtk_window_set_up_close_accelerator):
+ (sanity_check_window_position):
+ (sanity_check_window_dimensions):
+ (eel_gtk_window_set_initial_geometry):
+ (eel_gtk_window_set_initial_geometry_from_string):
+ (eel_pop_up_context_menu):
+ (eel_gtk_menu_append_separator):
+ (eel_gtk_menu_insert_separator):
+ (eel_gtk_menu_set_item_visibility):
+ (eel_point_in_allocation):
+ (eel_point_in_widget):
+ (eel_gtk_widget_set_shown):
+ (alive_disconnecter):
+ (eel_gtk_signal_connect_full_while_alive):
+ (while_realized_disconnecter):
+ (eel_gtk_signal_connect_while_realized):
+ (get_first_callback):
+ (eel_gtk_container_get_first_child):
+ (container_foreach_deep_callback):
+ (eel_gtk_container_foreach_deep):
+ (eel_gtk_adjustment_set_value):
+ (eel_gtk_adjustment_clamp_value):
+ (eel_gtk_label_make_bold):
+ (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_gtk_widget_set_background_color):
+ (eel_gtk_widget_set_foreground_color):
+ (eel_gtk_widget_find_windowed_ancestor):
+ (eel_gtk_get_system_font):
+ (eel_gtk_widget_get_button_event_location):
+ (eel_gtk_widget_get_motion_event_location):
+ (eel_gtk_tree_view_cell_is_completely_visible):
+ (tree_view_button_press_callback):
+ (eel_gtk_tree_view_set_activate_on_single_click):
+ (eel_gtk_viewport_get_visible_rect):
+ (eel_gtk_viewport_scroll_to_rect):
+ * eel-gtk-extensions.h: Added.
+ * eel-gtk-macros.h: Added.
+ * eel-i18n.c: Added.
+ (_eel_gettext):
+ * eel-i18n.h: Added.
+ * eel-image-table.c: Added.
+ (eel_image_table_class_init):
+ (eel_image_table_init):
+ (eel_image_table_finalize):
+ (eel_image_table_realize):
+ (eel_image_table_unrealize):
+ (eel_image_table_remove):
+ (eel_image_table_child_type):
+ (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_add_empty_image):
+ * eel-image-table.h: Added.
+ * eel-labeled-image.c: Added.
+ (eel_labeled_image_class_init):
+ (eel_labeled_image_init):
+ (eel_labeled_image_finalize):
+ (eel_labeled_image_destroy):
+ (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):
+ (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_selected):
+ (eel_labeled_image_get_selected):
+ (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_labled_set_mnemonic_widget):
+ (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):
+ (eel_labeled_image_radio_button_new):
+ (eel_labeled_image_radio_button_new_from_file_name):
+ (button_leave_callback):
+ (button_focus_out_event_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_text):
+ (eel_labeled_image_get_text):
+ (eel_labeled_image_set_can_focus):
+ (eel_labeled_image_accessible_initialize):
+ (get_image):
+ (eel_labeled_image_accessible_get_name):
+ (eel_labeled_image_accessible_image_get_size):
+ (eel_labeled_image_accessible_image_interface_init):
+ (eel_labeled_image_accessible_class_init):
+ (eel_labeled_image_get_accessible):
+ (eel_labeled_image_button_class_init):
+ (eel_labeled_image_button_get_type):
+ (eel_labeled_image_check_button_get_type):
+ (eel_labeled_image_toggle_button_get_type):
+ (eel_labeled_image_radio_button_get_type):
+ * eel-labeled-image.h: Added.
+ * eel-lib-self-check-functions.c: Added.
+ (eel_run_lib_self_checks):
+ * eel-lib-self-check-functions.h: Added.
+ * eel-pango-extensions.c: Added.
+ (eel_pango_attr_list_copy_or_create):
+ (eel_pango_attr_list_apply_global_attribute):
+ (measure_string_width):
+ (compute_character_widths):
+ (eel_string_ellipsize_start):
+ (eel_string_ellipsize_end):
+ (eel_string_ellipsize_middle):
+ (eel_pango_layout_set_text_ellipsized):
+ (eel_pango_font_description_get_largest_fitting_font_size):
+ (eel_create_bogus_test_pango_context):
+ (eel_self_check_ellipsize):
+ (eel_self_check_ellipsize_start):
+ (eel_self_check_ellipsize_middle):
+ (eel_self_check_ellipsize_end):
+ (eel_self_check_pango_extensions):
+ * eel-pango-extensions.h: Added.
+ * eel-preferences-builder.c: Added.
+ (eel_preferences_builder_combo_box_update):
+ (eel_preference_glade_never_sensitive):
+ (eel_preferences_builder_set_never_sensitive):
+ (eel_preferences_builder_bool_toggled):
+ (eel_preferences_builder_bool_update):
+ (eel_preferences_builder_connect_bool):
+ (eel_preferences_builder_connect_bool_slave):
+ (eel_preferences_builder_string_enum_combo_box_changed):
+ (eel_preferences_builder_string_enum_combo_box_update):
+ (eel_preferences_builder_connect_string_enum_combo_box):
+ (eel_preferences_builder_connect_string_enum_combo_box_slave):
+ (eel_preferences_builder_uint_enum_changed):
+ (eel_preferences_builder_uint_enum_update):
+ (eel_preferences_builder_connect_uint_enum):
+ (eel_preferences_builder_string_enum_radio_button_toggled):
+ (eel_preferences_builder_string_enum_radio_button_update):
+ (eel_preferences_builder_connect_string_enum_radio_button):
+ (eel_preferences_builder_list_enum_changed):
+ (eel_preferences_builder_list_enum_update):
+ (eel_preferences_builder_connect_list_enum):
+ * eel-preferences.c: Added.
+ (preferences_gconf_value_get_int):
+ (preferences_gconf_value_get_bool):
+ (preferences_gconf_value_get_string):
+ (preferences_gconf_value_get_string_array):
+ (preferences_peek_storage_path):
+ (preferences_set_storage_path):
+ (preferences_is_initialized):
+ (preferences_get_value):
+ (preferences_preference_is_gconf_key):
+ (preferences_key_make):
+ (preferences_get_default_value):
+ (preferences_callback_entry_compare):
+ (eel_preferences_get_is_invisible):
+ (eel_preferences_set_is_invisible):
+ (eel_preferences_set_boolean):
+ (eel_preferences_get_boolean):
+ (eel_preferences_set_integer):
+ (eel_preferences_get_integer):
+ (eel_preferences_get_uint):
+ (eel_preferences_set_uint):
+ (eel_preferences_get_enum):
+ (eel_preferences_set_enum):
+ (eel_preferences_set):
+ (eel_preferences_get):
+ (eel_preferences_set_string_array):
+ (string_array_is_valid):
+ (eel_preferences_get_string_array):
+ (eel_preferences_unset):
+ (eel_preferences_key_is_writable):
+ (preferences_callback_entry_invoke_function):
+ (preferences_entry_invoke_callbacks):
+ (update_auto_string):
+ (update_auto_string_array):
+ (update_auto_string_array_as_quarks):
+ (update_auto_integer_or_boolean):
+ (preferences_entry_update_auto_storage):
+ (preferences_something_changed_notice):
+ (preferences_entry_ensure_gconf_connection):
+ (preferences_entry_add_callback):
+ (preferences_entry_add_auto_storage):
+ (preferences_entry_check_remove_connection):
+ (preferences_entry_remove_callback):
+ (preferences_entry_remove_auto_storage):
+ (preferences_callback_entry_free):
+ (preferences_callback_entry_free_func):
+ (preferences_entry_free):
+ (preferences_entry_free_func):
+ (preferences_global_table_free):
+ (preferences_uninitialize):
+ (preferences_global_table_get_global):
+ (preferences_global_table_lookup):
+ (preferences_global_table_insert):
+ (preferences_global_table_lookup_or_insert):
+ (eel_preferences_add_callback):
+ (eel_preferences_add_auto_string):
+ (eel_preferences_add_auto_string_array):
+ (eel_preferences_add_auto_string_array_as_quarks):
+ (eel_preferences_add_auto_integer):
+ (eel_preferences_add_auto_enum):
+ (eel_preferences_add_auto_boolean):
+ (eel_preferences_remove_auto_string):
+ (eel_preferences_remove_auto_string_array):
+ (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_get_description):
+ (eel_preferences_set_enumeration_id):
+ (eel_preferences_get_enumeration_id):
+ (preferences_set_emergency_fallback_stealing_value):
+ (eel_preferences_set_emergency_fallback_string):
+ (eel_preferences_set_emergency_fallback_integer):
+ (eel_preferences_set_emergency_fallback_boolean):
+ (eel_preferences_set_emergency_fallback_string_array):
+ (eel_preferences_get_emergency_fallback):
+ (eel_preferences_monitor_directory):
+ (eel_preferences_is_visible):
+ (eel_preferences_init):
+ (eel_self_check_preferences):
+ * eel-preferences.h: Added.
+ * eel-self-checks.c: Added.
+ (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_point_result):
+ (eel_check_integer_result):
+ (eel_check_double_result):
+ (eel_check_string_result):
+ (eel_before_check_function):
+ (eel_after_check_function):
+ * eel-self-checks.h: Added.
+ * eel-stock-dialogs.c: Added.
+ (timed_wait_hash):
+ (timed_wait_hash_equal):
+ (timed_wait_delayed_close_destroy_dialog_callback):
+ (timed_wait_delayed_close_timeout_callback):
+ (timed_wait_free):
+ (timed_wait_dialog_destroy_callback):
+ (trash_dialog_response_callback):
+ (timed_wait_callback):
+ (eel_timed_wait_start_with_duration):
+ (eel_timed_wait_start):
+ (eel_timed_wait_stop):
+ (eel_run_simple_dialog):
+ (create_message_dialog):
+ (show_message_dialog):
+ (show_ok_dialog):
+ (eel_create_info_dialog):
+ (eel_show_info_dialog):
+ (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-stock-dialogs.h: Added.
+ * eel-string.c: Added.
+ (eel_strlen):
+ (eel_strchr):
+ (eel_strcmp):
+ (eel_strcasecmp):
+ (eel_strcmp_case_breaks_ties):
+ (eel_str_is_empty):
+ (eel_str_is_equal):
+ (eel_istr_is_equal):
+ (eel_str_has_prefix):
+ (eel_str_has_suffix):
+ (eel_istr_has_prefix):
+ (eel_istr_has_suffix):
+ (eel_str_get_prefix):
+ (eel_str_to_int):
+ (eel_str_double_underscores):
+ (eel_str_capitalize):
+ (eel_str_middle_truncate):
+ (eel_str_strip_substring_and_after):
+ (eel_str_replace_substring):
+ (get_position):
+ (is_flag):
+ (is_length_modifier):
+ (get_arg_type_from_format):
+ (skip_argv):
+ (skip_to_arg):
+ (eel_strdup_vprintf_with_custom):
+ (eel_strdup_printf_with_custom):
+ (eel_ref_str_new_internal):
+ (eel_ref_str_new):
+ (eel_ref_str_get_unique):
+ (eel_ref_str_ref):
+ (eel_ref_str_unref):
+ (call_str_to_int):
+ (verify_printf):
+ (custom1_to_string):
+ (custom1_skip):
+ (custom2_to_string):
+ (custom2_skip):
+ (verify_custom):
+ (eel_self_check_string):
+ * eel-string.h: Added.
+ * eel-types.c: Added.
+ (eel_type_init):
+ * eel-types.h: Added.
+ * eel-vfs-extensions.c: Added.
+ (eel_uri_is_trash):
+ (eel_uri_is_search):
+ (eel_uri_is_desktop):
+ (eel_make_valid_utf8):
+ (eel_format_uri_for_display):
+ (eel_filename_strip_extension):
+ (eel_filename_get_rename_region):
+ * eel-vfs-extensions.h: Added.
+ * eel-wrap-table.c: Added.
+ (eel_wrap_table_class_init):
+ (eel_wrap_table_init):
+ (eel_wrap_table_finalize):
+ (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):
+ (eel_wrap_table_child_type):
+ (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):
+ (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_scrolled_wrap_table_new):
+ * eel-wrap-table.h: Added.
+ * eel-xml-extensions.c: Added.
+ (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-extensions.h: Added.
+ * eel.h: Added.
+ * eelmarshal.list: Added.
+ * makeenums.pl: Added.
+ * maketypes.awk: Added.
+ * update-from-egg.sh: Added.
+
+2008-12-10 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <cosimoc@gnome.org>
+
+ * test/test.h:
+ Flip include orders to fix the build (#563731).
+
+2008-12-07 Cosimo Cecchi <cosimoc@gnome.org>
+
+ * eel/eel-background.c:
+ * test/test.h:
+ Remove more useless includes.
+ Thanks to Luis Menina (#563569).
+
+2008-12-07 Cosimo Cecchi <cosimoc@gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+==================== 2.25.1 ====================
+
+2008-12-01 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2008-11-18 Cosimo Cecchi <cosimoc@gnome.org>
+
+ * eel/eel-preferences.c:
+ (eel_preferences_add_auto_string_array_as_quarks):
+ Plug a leak.
+
+2008-10-09 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gdk-extensions.[ch]:
+ Remove old now unused function eel_gdk_color_parse()
+
+2008-10-07 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * eel-2.0-uninstalled.pc.in:
+ * eel-2.0.pc.in:
+ Remove deps on startup-notify, libgnome* and libglade
+
+ * eel/eel-gnome-extensions.[ch]:
+ Remove GnomeIconSelector 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 libgnome headers.
+
+2008-10-07 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gnome-extensions.[ch]:
+ Remove gnome_icon_selector code
+
+2008-10-06 Alexander Larsson <alexl@redhat.com>
+
+ * eel/check-program.c:
+ * test/test-eel-widgets.c:
+ * test/test.c:
+ Don't use GnomeProgram
+
+2008-10-06 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-stock-dialogs.c (timed_wait_callback):
+ Don't call gnome_authentication_manager_dialog_is_visible()
+ anymore, not needed with no gnome-vfs.
+
+2008-10-06 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * eel/eel-mount-operation.[ch]:
+ Remove EelMountOperation
+
+2008-10-01 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.25.1.
+ Stable version lives on the gnome-2-24 branch.
+
+2008-09-22 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.24.1
+
+==================== 2.24.0 ====================
+
+2008-09-22 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS:
+ Update for release.
+
+2008-09-15 Christian Neumair <cneumair@gnome.org>
+
+ * eel/eel-mount-operation.c (ask_password):
+ Do not make password dialog modal. Fixes #539966.
+
+2008-09-13 Cosimo Cecchi <cosimoc@gnome.org>
+
+ * 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 <cneumair@gnome.org>
+
+ * 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 <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.40.0
+
+==================== 2.23.92 ====================
+
+2008-09-08 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS:
+ Update for release.
+
+2008-09-08 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <cneumair@gnome.org>
+
+ * 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 <cosimoc@gnome.org>
+
+ * eel/*.[ch]: use single headers GTK/GDK/Pango includes.
+
+2008-09-01 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.23.92.
+
+==================== 2.23.91 ====================
+
+2008-09-01 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS:
+ Update for release.
+
+2008-09-01 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <pborelli@katamail.com> and Jared Moore <jaredm@gmx.com>.
+
+2008-09-01 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.23.91.
+
+==================== 2.23.90 ====================
+
+2008-08-03 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.23.90.
+
+==================== 2.23.6 ====================
+
+2008-07-21 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.23.6.
+
+==================== 2.23.5 ====================
+
+2008-06-16 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in: post-release bump to 2.23.5.
+
+==================== 2.23.4 ====================
+
+2008-06-16 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in: actually pre-release bump to 2.23.4.
+
+2008-06-16 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS: Update for release.
+ * configure.in: pre-release bump to 2.23.4.
+
+2008-06-10 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <vuntz@gnome.org>
+
+ * configure.in: post-release bump to 2.23.3
+
+==================== 2.23.2 ====================
+
+2008-06-03 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS:
+ * configure.in:
+ Require libgnome 2.23.0.
+
+2008-06-03 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS:
+ Update for release.
+
+Sun Jun 1 21:04:04 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * eel/eel-background.c (struct EelBackgroundDetails): Remove
+ unused image_mtime
+
+Sun Jun 1 21:02:00 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * eel/eel-background.c: Don't store the image_uri - instead rely
+ on getting it from GnomeBG.
+
+Sun Jun 1 20:39:03 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * eel/eel-background.c: Don't monitor the file anymore; this is
+ done by GnomeBG.
+
+Sun Jun 1 20:24:12 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * eel/eel-background.c (struct EelBackgroundDetails): Don't store
+ an EelBackgroundPlacement; instead compute it from the GnomeBG.
+
+Sun Jun 1 19:30:16 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * eel/eel-background.c (eel_background_save_to_gconf): New function.
+
+Sat May 31 02:23:16 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * 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 <sandmann@redhat.com>
+
+ * eel/eel-background.c (eel_background_reload_image): Use
+ gnome_bg_set_filename().
+
+ * configure.in: Require new gnome-desktop
+
+Fri May 30 23:23:53 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * Revert last commit, since we still need to deal with file uris.
+
+Fri May 30 22:13:51 2008 Søren Sandmann <sandmann@redhat.com>
+
+ * 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 <sandmann@redhat.com>
+
+ * eel/eel-background.h: Remove unused
+ eel_background_set_image_uri_sync() function.
+
+2008-04-21 Christian Neumair <cneumair@gnome.org>
+
+ * configure.in:
+ post release version bump
+
+=== eel 2.23.1 ===
+
+2008-04-21 Christian Neumair <cneumair@gnome.org>
+
+ * NEWS:
+ Update for release.
+
+2008-03-29 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <lool@dooz.org>.
+
+2008-03-29 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.23.1
+ Gnome 2.22 work continues on gnome-2-22 branch
+
+2008-03-28 Christian Neumair <cneumair@gnome.org>
+
+ * 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-gconf-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_gconf_value_get_int),
+ (preferences_gconf_value_get_bool),
+ (preferences_gconf_value_get_string),
+ (preferences_gconf_value_get_string_array),
+ (preferences_peek_storage_path), (preferences_set_storage_path),
+ (preferences_get_value), (preferences_preference_is_gconf_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_gconf_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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.22.1 ===
+
+2008-03-28 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2008-03-24 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <cneumair@gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Post release version bump
+
+=== eel 2.22.0 ===
+
+2008-03-10 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Bump version to 2.22.0
+
+2008-02-25 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.21.92 ===
+
+2008-02-25 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2008-02-22 Carlos Garcia Campos <carlosgc@gnome.org>
+
+ * 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 <cosimoc@gnome.org>
+
+ * eel/eel-background.c: (eel_background_ensure_realized):
+ Better fix for bug #517681.
+
+2008-02-21 Cosimo Cecchi <cosimoc@gnome.org>
+
+ * eel/eel-background.c: (eel_background_ensure_realized):
+ Fix compilation warning. (#517681)
+ Patch from Rodrigo Moya.
+
+2008-02-21 Cosimo Cecchi <cosimoc@gnome.org>
+
+ * eel-2.0-uninstalled.pc.in:
+ * eel-2.0.pc.in:
+ Update dependencies (#505831).
+
+2008-02-18 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mount-operation.c:
+ Handle the save-password flags (#516997)
+ Patch from Carlos Garcia Campos
+
+2008-02-13 Christian Persch <chpe@gnome.org>
+
+ * eel/eel-editable-label.c:
+ (eel_editable_label_select_region_index): Update text targets list.
+ Bug #516230.
+
+2008-02-13 Christian Persch <chpe@gnome.org>
+
+ * configure.in:
+ * eel/eel-string.c: (eel_strdup_vprintf_with_custom): Use G_VA_COPY.
+ Bug #516232.
+
+2008-02-13 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Check for va_copy and define a replacement if not availible (#513199)
+ Patch from Jens Granseuer
+
+2008-02-11 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.21.91 ===
+
+2008-02-11 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2008-01-28 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.21.90 ===
+
+2008-01-28 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+ * configure.in:
+ Bump version to 2.21.90
+
+2008-01-28 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <sandmann@redhat.com>
+
+ * eel/eel-background.c: Add #define GNOME_DESKTOP_USE_UNSTABLE_API
+ before including gnome-bg.h
+
+ * eel/eel-background.c: Delete eel_background_set_is_constant_size().
+
+2008-01-22 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Post release version bump
+
+=== eel 2.21.5 ===
+
+2008-01-14 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Bump version to 2.21.5
+
+ * NEWS:
+ Updated for release
+
+2008-01-09 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mount-operation.c:
+ Update for gio API changes
+
+2007-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.21.1 ===
+
+2007-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+ * configure.in:
+ Require glib 2.15.0
+
+2007-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-app-launch-context.c:
+ Update to new file attribute names
+
+2007-12-14 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mount-operation.c:
+ Update to new flag enum names and values
+
+2007-12-14 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-mount-operation.c:
+ (ask_password):
+ G_PASSWORD_FLAGS_ANON_SUPPORTED -> G_PASSWORD_FLAGS_ANONYMOUS_SUPPORTED
+
+2007-12-10 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-app-launch-context.c (add_startup_timeout):
+ Correct set_data name
+
+2007-11-30 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Bump version to 2.21.1
+ Remove extraversion
+
+2007-11-29 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-app-launch-context.c:
+ * eel/eel-vfs-extensions.c:
+ Update code to handle glib version of gio
+
+2007-11-22 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-string.c (handlers):
+ Make handlers static
+
+2007-11-22 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-string.[ch]:
+ Added eel_strdup_vprintf_with_custom and
+ eel_strdup_printf_with_custom
+
+2007-11-06 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mount-operation.c:
+ Fix build for new gio
+
+2007-11-06 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Look for libstartupnotify
+
+ * eel/Makefile.am:
+ * eel/eel-app-launch-context.[ch]:
+ Add EelAppLaunchContext
+
+2007-11-02 Paolo Borelli <pborelli@katamail.com>
+
+ * eel/eel-string.c:
+ * eel/eel-string.h:
+ Remove two functions that were just used in eel-string-list.
+
+2007-11-02 Paolo Borelli <pborelli@katamail.com>
+
+ * eel/eel-preferences-glade.c:
+ * eel/eel-gconf-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 <alexl@redhat.com>
+
+ * eel/eel-string.c (eel_str_middle_truncate):
+ Fix off by one bug
+
+2007-11-01 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-string.c:
+ Make eel_str_middle_truncate handle utf8 strings
+ correctly.
+
+2007-10-24 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mount-operation.[ch]:
+ Add active_changed signal
+
+2007-10-24 Alexander Larsson <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * eel/eel-mount-operation.[ch]:
+ Add GMountOperation version with gtk+ dialogs
+
+2007-10-24 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gdk-pixbuf-extensions.[ch]:
+ * eel/eel-background.c:
+ Convert gnome_vfs use to gio
+
+ * configure.in:
+ * eel/check-program.c:
+ * test/test-eel-background.c:
+ * test/test.[ch]:
+ Remove dependencies on gnome-vfs, libgnomedesktop, etc
+
+2007-10-24 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-editable-label.c:
+ * eel/eelmarshal.list:
+ Remove unused marshallers
+
+2007-10-24 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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-gnome-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 <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * eel/eel-dateedit-extensions.[ch]: Removed.
+ * eel/eel-gnome-extensions.[ch]:
+ * eel/eel.h:
+ Remove unneeded eel functions
+
+2007-10-23 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-lib-self-check-functions.h:
+ * eel/eel-vfs-extensions.[ch]:
+ Remove a bunch of unnecessary gnome-vfs functions
+
+2007-10-11 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gdk-pixbuf-extensions.[ch]:
+ Added eel_gdk_pixbuf_load_from_stream
+
+2007-10-01 Alexander Larsson <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * eel/eel-mime-application-chooser.[ch]:
+ * eel/eel-open-with-dialog.[ch]:
+ Move these to nautilus
+
+2007-10-01 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-string.h:
+ Fix up macro definition.
+ It can't have a space before the param list
+
+2007-09-26 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-string.[ch];
+ Add eel_ref_str, a set of refcounted and optionally uniquified
+ string functions.
+
+2007-09-26 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-vfs-extensions.[ch]:
+ Remove more unused code
+
+2007-09-26 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-vfs-extensions.c:
+ Remove code not used by nautilus anymore
+
+2007-11-28 Soren Sandmann <sandmann@redhat.com>
+
+ * configure.in: Require libgnomedesktop 2.21.3
+
+ * eel/eel-background.[ch]: Make EelBackground a thin wrapper
+ around GnomeBG from libgnomedesktop.
+
+2007-10-12 Christian Kirbach <Christian.Kirbach@googlemail.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Add gio as extraversion
+
+ * eel/eel-gdk-pixbuf-extensions.c:
+ * eel/eel-vfs-extensions.[ch]:
+ Use goffset instead of GnomeVFSFileSize
+
+=== gio-branch starts here ===
+
+2007-09-18 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.20.0 ===
+
+2007-09-18 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.20.0
+
+2007-08-14 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.19.90 ===
+
+2007-08-14 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2007-07-31 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.19.6 ===
+
+2007-07-31 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2007-07-28 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <pascal.terjan@free.fr>
+
+2007-07-10 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.19.5 ===
+
+2007-07-10 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2007-07-10 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <martin.wehner@gmail.com>
+
+ * 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 <martin.wehner@gmail.com>
+
+ * 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 <martin.wehner@gmail.com>
+
+ * configure.in:
+ Don't set extra warning flags in the user environment CFLAGS.
+ Fixes 'make distcheck'.
+
+2007-06-19 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.19.4 ===
+
+2006-06-18 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2007-06-12 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <bjourne@gmail.com>
+
+2006-06-05 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.19.3 ===
+
+2006-06-05 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2007-06-01 Christian Neumair <cneumair@gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ * NEWS:
+ Update for 2.19.2
+
+2007-04-10 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gconf-extensions.c:
+ (eel_gconf_monitor_add):
+ (eel_gconf_monitor_remove):
+ (eel_gconf_preload_cache):
+ Avoid leaked refcounts on default gconf client. (#235657)
+ Patch from Matthias Clasen
+
+2007-03-19 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.19.1
+ Gnome 2.18 work continues on gnome-2-18 branch
+
+2007-03-12 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.18.0 ===
+
+2007-03-12 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+ * configure.in:
+ Bump version to 2.18.0
+
+2007-03-02 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <chpe@svn.gnome.org>
+
+ * eel/eel.h: Remove eel-ellipsizing-label.h inclusion.
+
+2007-02-20 Christian Persch <chpe@svn.gnome.org>
+
+ * 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 <chpe@svn.gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.17.90 ===
+
+2007-01-22 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.17.90
+
+2007-01-18 Christian Persch <chpe@svn.gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ post release version bump
+
+=== eel 2.17.1 ===
+
+2006-12-18 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2006-12-08 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.17.1
+ Gnome 2.16 work continues on gnome-2-16 branch
+
+2006-11-20 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.16.3 ===
+
+2006-11-20 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Call it 2.16.3 to match nautilus release
+
+ * NEWS:
+ Update for release.
+
+2006-11-07 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ post release version bump
+
+=== eel 2.16.1 ===
+
+2006-11-07 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * NEWS:
+ Update for release.
+
+2006-10-19 Christian Neumair <chris@gnome-de.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.16.0
+
+ * NEWS:
+ Update for release
+
+2006-09-01 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.c: (eel_editable_label_enter_text):
+ Don't reset im context when commiting text.
+
+2006-08-25 Alexander Larsson <alexl@redhat.com>
+
+ * eel/check-program.c: (main):
+ Fix build with EEL_OMIT_SELF_CHECK.
+
+2006-08-23 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-vfs-extensions.c: (eel_vfs_has_capability):
+ Fix crash that happened on DnD from firefox in nautilus.
+
+2006-08-21 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.15.92 ===
+
+2006-08-21 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2006-08-15 Kjartan Maraas <kmaraas@gnome.org>
+
+ * configure.in: Fix intltool req.
+
+2006-08-08 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.15.91 ===
+
+2006-08-08 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2006-08-08 Kjartan Maraas <kmaraas@gnome.org>
+
+ * configure.in: Really depend on a newer libgnome-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 <alexl@redhat.com>
+
+ * eel/eel-background.c:
+ Fix crash in previous fix.
+
+2006-08-08 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-background.c:
+ Check mtime for background uri changes. (#349962)
+ Patch from Matthias Clasen
+
+2006-07-25 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post-release version bump
+
+=== eel 2.15.90 ===
+
+2006-07-25 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2006-07-24 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <jensgr@gmx.net>
+
+2006-07-11 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post-release version bump
+
+=== eel 2.15.4 ===
+
+2006-07-11 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+ * configure.in:
+ Bump version to 2.15.4
+
+2006-07-11 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <mquiros@ugr.es>
+
+2006-07-11 Martin Wehner <martin.wehner@gmail.com>
+
+ * eel/eel-accessibility.c:
+ (eel_accessibility_set_up_label_widget_relation):
+ Set up the atk widget/label relationship correctly. (#341420)
+
+ Patch from Willie Walker <william.walker@sun.com>
+
+2006-06-19 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ post release version bump
+
+=== eel 2.15.2 ===
+
+2006-06-12 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2006-05-24 Paolo Borelli <pborelli@katamail.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * eel/eel-cell-renderer-pixbuf-list.[ch]:
+ Remove
+
+2006-05-24 Paolo Borelli <pborelli@katamail.com>
+
+ * 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 gnome-vfs itself for a long time and they
+ are not used anymore in nautilus. (bug #342237)
+
+2006-05-16 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post-release version bump.
+
+=== eel 2.15.1 ===
+
+2006-05-16 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2006-05-07 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <martin.wehner@gmail.com>
+
+ * 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 <josep.puigdemont@gmail.com>
+
+2006-05-01 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <ruben@lambda1.be>
+
+2006-04-28 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ * po/LINGUAS:
+ Update po/LINGUAS support to new guidelines. (#338017)
+
+ Patch from Przemyslaw Grzegorczyk <pgrzegorczyk@gmail.com>
+
+2006-04-25 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.15.1
+ 2.14 development continues on gnome-2-14 branch.
+
+2006-04-15 Martin Wehner <martin.wehner@gmail.com>
+
+ * po/LINGUAS:
+ Remove newlines to fix build with CVS intltool. (#338423)
+
+2006-04-11 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post-release version bump.
+
+=== eel 2.14.1 ===
+
+2006-04-11 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release
+
+2006-04-10 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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/GnomeGoals/PoLinguas
+
+ Patch from Przemyslaw Grzegorczyk <pgrzegorczyk@gmail.com>
+
+2006-04-08 Martin Wehner <martin.wehner@gmail.com>
+
+ * 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 <tonyarnold@users.sourceforge.net>
+
+2006-03-26 Sebastien Bacher <seb128@debian.org>
+
+ * configure.in: popt is not used by eel no need to require it
+
+2006-03-22 Tommi Vainikainen <thv@iki.fi>
+
+ * configure.in (ALL_LINGUAS): Added Dzongkha (dz).
+
+2006-03-22 Paolo Borelli <pborelli@katamail.com>
+
+ * eel/eel-enumeration.c: remove inefficient use of glist.
+ Fixes bug #335349.
+
+2006-03-20 Christian Neumair <chris@gnome-de.org>
+
+ * configure.in:
+ Depend on libgnome-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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.14.0 ===
+
+2006-03-13 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.14.0
+
+ * NEWS:
+ Update for release
+
+2006-03-01 Vladimer SIchinava <vlsichinava@gmail.com>
+
+ * configure.in: Added ka (Georgian) to ALL_LINGUAS
+
+2006-02-28 Bill Haneman <billh@gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.13.92 ===
+
+2006-02-27 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2006-02-19 Erdal Ronahi <erdal.ronahi@gmail.com>
+
+ * configure.in: Added ku (Kurdish) to ALL_LINGUAS
+
+2006-02-16 Martin Wehner <martin.wehner@gmail.com>
+
+ * eel/eel-editable-label.c:
+ Include config.h to fix i18n of the context menu.
+ Fixes bug #331377.
+ Patch from Takao Fujiwara <takao.fujiwara@sun.com>
+
+2006-02-16 Martin Wehner <martin.wehner@gmail.com>
+
+ * test/test.c: (test_window_set_title_with_pid):
+ Add a cast to fix build on Solaris. (#117825)
+ Patch from Fredrik Jonsson <fjo@nada.kth.se>
+
+2006-02-13 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.13.91 ===
+
+2006-02-13 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2006-02-07 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mime-extensions.c (eel_mime_add_application):
+ Add %f to exec line when creating open-with desktop files.
+ Patch from Christian Persch <chpe@gnome.org>
+ Bug #169202
+
+2006-01-31 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.13.90 ===
+
+2006-01-31 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release.
+
+ * configure.in:
+ Bump version to 2.13.90
+
+2006-01-21 Luca Ferretti <elle.uca@libero.it>
+
+ * .cvsignore:
+ Added missing files to ignore.
+ * eel/.cvsignore:
+ Ditto.
+
+2006-01-16 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.13.4 ===
+
+2006-01-16 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2006-01-12 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <maddog@linuxhall.org>
+
+ * configure.in: Added "zh_HK" to ALL_LINGUAS.
+
+2005-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Actuallu bump version.
+
+2005-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mime-extensions.[ch]:
+ Add eel_mime_get_availible_mime_types
+
+2005-12-17 Dennis Cranston <dennis_cranston@yahoo.com>
+
+ * eel/eel-alert-dialog.c: Hide dialog from taskbar, so it
+ does not display "untitled window".
+
+2005-12-13 Dennis Cranston <dennis_cranston@yahoo.com>
+
+ * eel/eel-open-with-dialog.c: (eel_open_with_dialog_instance_init):
+ HIG fixes.
+
+2005-12-12 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.13.3 ===
+
+2005-12-12 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2005-12-09 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-alert-dialog.[ch]:
+ * eel/eel-gconf-extensions.c:
+ * eel/eel-gnome-extensions.c:
+ * eel/eel-open-with-dialog.c:
+ * eel/eel-stock-dialogs.[ch]:
+ Remove title from alerts. (#323134)
+
+ Patch from jaap@haitsma.org
+
+2005-12-08 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-preferences-glade.[ch]:
+ Use GtkComboBox, not GtkOptionMenu
+ Patch from jaap@haitsma.org
+
+2005-11-14 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.13.2 ===
+
+2005-11-14 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2005-11-14 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-alert-dialog.c:
+ Include config.h so we get translations.
+ Patch from Yang Hong <yanghong@ccoss.com.cn>
+
+2005-10-28 Simos Xenitellis <simos@gnome.org>
+
+ * configure.in: Added ky (Kirghiz) to ALL_LINGUAS.
+
+2005-10-27 Kjartan Maraas <kmaraas@gnome.org>
+
+ * 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-gconf-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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.13.1 ===
+
+2005-10-24 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2005-10-19 Christian Neumair <chris@gnome-de.org>
+
+ * eel/eel-mime-application-chooser.c: (create_tree_view):
+ Sort applications by display name, filed as part of #310038.
+
+2005-10-03 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.13.1. Further 2.12.x work is on
+ gnome-2-12 branch.
+
+2005-10-03 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.12.1 ===
+
+2005-10-03 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for 2.12.1.
+
+2005-10-03 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-accessibility.c:
+ (eel_accessibility_set_up_label_widget_relation):
+ Slight cleanup. Patch from Christian Neumair.
+
+2005-09-05 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.12.0 ===
+
+2005-09-05 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS: Update for release.
+
+2005-08-23 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.11.92 ===
+
+2005-08-23 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release.
+
+2005-08-09 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.11.91 ===
+
+2005-08-09 Martin Wehner <martin.wehner@gmail.com>
+
+ * NEWS:
+ Update for release.
+
+2005-08-05 Christian Neumair <chris@gnome-de.org>
+
+ * src/eel-wrap-table.c: Get rid of broken scrolled window viewport
+ code. Fixes #308996.
+
+2005-08-01 Christian Persch <chpe@cvs.gnome.org>
+
+ * 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 <martin.wehner@gmail.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.11.90 ===
+
+2005-07-25 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Bump version to 2.11.90
+
+ * NEWS:
+ Update for release.
+
+2005-07-20 Mikael Hallendal <micke@imendio.com>
+
+ * eel/eel-vfs-extensions.[ch] (eel_uri_is_search):
+ Add x-nautilus-search URI.
+
+2005-07-19 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-wrap-table.c:
+ Take border width into account when wrapping (#155642)
+ Patch from Christian Neumair.
+
+2005-07-11 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.11.4 ===
+
+2005-07-11 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2005-07-06 Kjartan Maraas <kmaraas@gnome.org>
+
+ * eel/eel-open-with-dialog.c: (add_or_find_application):
+ Fix a small leak.
+
+2005-07-01 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.11.3 ===
+
+2005-07-01 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2005-06-11 Kjartan Maraas <kmaraas@gnome.org>
+
+ * eel/eel-mime-application-chooser.c: (remove_clicked_cb): Remove
+ const qualifier now that we free the application id.
+
+2005-06-11 Kjartan Maraas <kmaraas@gnome.org>
+
+ * 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 <martin.wehner@gmail.com>
+
+ * 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 <kmaraas@gnome.org> and
+ James M. Cape <jcape@ignore-your.tv>
+
+2005-06-08 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Post release version bump.
+
+=== eel 2.11.2 ===
+
+2005-06-08 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-open-with-dialog.c:
+ Fix const warning.
+
+ * NEWS:
+ Update for release.
+
+2005-06-07 Kjartan Maraas <kmaraas@gnome.org>
+
+ * eel/eel-open-with-dialog.c: (program_list_selection_changed):
+ Plug a couple of leaks. Closes bug #306767.
+
+2005-05-22 Sebastien Bacher <seb128@debian.org>
+
+ * configure.in:
+ Update of glib and gtk requirements to 2.6.0 (Closes: #304875).
+
+2005-05-17 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.11.1 ===
+
+2005-05-17 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for 2.11.1 release
+
+2005-04-12 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <mark@skynet.ie>
+
+ * eel/Makefile.am, eel/eel-open-with-dialog.c: update
+ for libgnome-menu API renaming.
+
+2005-04-11 Abduxukur Abdurixit <abduxukur.abdurixit@t-systems.ch>
+
+ * configure.in: Added 'ug' to ALL_LINGUAS.
+
+2005-04-08 Sebastien Bacher <seb128@debian.org>
+
+ * configure.in:
+ Update gnomevfs requirement to 2.9.1.
+
+2005-04-06 Mark McLoughlin <mark@skynet.ie>
+
+ * eel/eel-open-with-dialog.c: (get_all_applications):
+ Update for slight change in menu_tree_lookup() API.
+
+2005-03-31 Steve Murphy <murf@e-tools.com>
+
+ * configure.in: Added "rw" to ALL_LINGUAS.
+
+2005-03-28 Martin Wehner <martin.wehner@gmail.com>
+
+ * eel/eel-accessibility.c: (get_simple_text):
+ Return NULL if the gobject is no longer valid.
+ Fixes bug #168161.
+
+ Patch from Muktha <muktha.narayan@wipro.com>
+
+2005-03-27 Martin Wehner <martin.wehner@gmail.com>
+
+ * configure.in:
+ Require libgnome-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 libgnome-menu API.
+
+ Patch from Christian Neumair <chris@gnome-de.org>
+
+2005-03-24 Adi Attar <aattar@cvs.gnome.org>
+
+ * configure.in: Added 'xh' to ALL_LINGUAS.
+
+2005-03-22 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.11.1
+ Gnome 2.10 versions are now on the gnome-2-10 branch.
+
+2005-03-16 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.10.0 ===
+
+2005-03-07 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Update for 2.10 release
+
+2005-03-01 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Post release version bump
+
+=== eel 2.9.92 ===
+
+2005-03-01 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2005-03-01 James Henstridge <james@jamesh.id.au>
+
+ 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 <alexl@redhat.com>
+
+ * eel/eel-vfs-extensions.c (eel_read_entire_file):
+ Just use gnome_vfs_read_entire_file().
+ We should remove this function eventually.
+
+2005-02-11 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mime-application-chooser.c (refresh_model):
+ Handle the case with no existing applications better.
+
+2005-02-10 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Post release version bump.
+
+=== eel 2.9.91 ===
+
+2005-02-10 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2005-01-26 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-open-with-dialog.c (eel_open_with_dialog_finalize):
+ Remove idle handlers when closing window. (#165208)
+
+2005-01-25 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.9.90 ===
+
+2005-01-25 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+ * configure.in:
+ Bump version to 2.9.90
+
+2005-01-25 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-open-with-dialog.c (eel_open_with_dialog_add_icon_idle):
+ Don't crash if no icon .
+
+2005-01-24 Kjartan Maraas <kmaraas@gnome.org>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-open-with-dialog.c: (eel_open_with_dialog_instance_init):
+ Mark string for translation.
+ Patch from Yang Hong <yanghong@ccoss.com.cn>
+
+2005-01-23 Martin Wehner <martin.wehner@epost.de>
+
+ * eel/eel-mime-application-chooser.c: (create_tree_view),
+ (refresh_model): Show application icon in the selector.
+
+ Patch from Fernando Herrera <fernando.herrera@tecsidel.es>
+
+2005-01-21 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * eel/Makefile.am:
+ require libgnome-desktop and libgnome-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 <fernando.herrera@tecsidel.es>
+
+2005-01-13 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-alert-dialog.c (eel_alert_dialog_set_primary_label):
+ Escape the text put in the markup string.
+
+2005-01-11 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.9.2 ===
+
+2005-01-11 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release.
+
+2004-11-25 Marco Pesenti Gritti <marco@gnome.org>
+
+ reviewed by: Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release bump
+
+=== eel 2.9.1 ===
+
+2004-11-24 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2004-11-19 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eelmarshal.list:
+ Add some new needed marshallers.
+
+2004-10-29 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Update version to 2.9.1.
+ Gnome 2.8 versions are now on the gnome-2-8 branch.
+
+==== gnome-2-8 branched from here ===
+
+2004-10-28 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release bump
+
+=== eel 2.8.2 ===
+
+2004-10-28 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for release
+
+2004-10-28 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-canvas.c: (eel_canvas_group_draw), (eel_canvas_expose):
+ Update to latest foocanvas, fix expose returning TRUE.
+
+2004-10-15 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.8.1 ===
+
+2004-10-11 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for 2.8.1
+
+2004-09-28 Gora Mohanty <gmohanty@cvs.gnome.org>
+
+ * configure.in: Added 'or' to ALL_LINGUAS.
+
+2004-09-13 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump.
+
+=== eel 2.8.0 ===
+
+2004-09-13 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Update for 2.8.0
+
+2004-09-11 Abel Cheung <maddog@linuxhall.org>
+
+ * configure.in: Added "ang" to ALL_LINGUAS.
+
+2004-09-06 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mime-extensions.c: (eel_mime_set_default_application):
+ Create ~/.local/share/applications as needed.
+
+2004-08-31 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.7.92 ===
+
+2004-08-30 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for 2.7.92
+
+ * configure.in:
+ Require new libgnomeui
+
+2004-08-25 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-stock-dialogs.c (timed_wait_callback):
+ Don't pop up cancel dialog if password dialog is visible.
+
+2004-08-16 Kjartan Maraas <kmaraas@gnome.org>
+
+ * configure.in: Added nb to ALL_LINGUAS.
+
+2004-08-16 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release bump to 2.7.92
+
+=== eel 2.7.4 ===
+
+2004-08-16 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update for 2.7.4
+
+ * eel/eel-canvas.c:
+ Update from foocanvas.
+
+ * configure.in:
+ Require new gnome-vfs (for default application file
+ type change).
+
+2004-08-12 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-canvas-rect-ellipse.c:
+ * eel/eel-canvas.c: (eel_canvas_key):
+ Update to latest foocanvas.
+
+2004-08-12 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-mime-extensions.c (eel_mime_set_default_application):
+ Use new name for default.list toplevel section.
+
+2004-08-09 Ray Strode <rstrode@redhat.com>
+
+ * 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 <chris@gnome-de.org>
+
+ * 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 <chris@gnome-de.org>
+
+ * configure.in: Require GNOME-VFS 2.7.5 (HEAD).
+
+2004-07-23 Tomasz KÅ‚oczko <kloczek@pld.org.pl>
+
+ * configure.in: better looking PKG_CHECK_MODULES() output.
+
+2004-07-22 Dave Camp <dave@novell.com>
+
+ * configure.in: Post-release version bump
+
+=== eel 2.7.3 ===
+
+2004-07-22 Dave Camp <dave@novell.com>
+
+ * configure.in:
+ * NEWS: 2.7.3
+
+2004-07-21 Dave Camp <dave@novell.com>
+
+ * Merged the eel-new-mime branch.
+
+2004-07-21 Dave Camp <dave@novell.com>
+
+ * 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 <jrb@redhat.com>
+
+ * 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 gnome-run
+ stock image.
+
+Wed Jul 21 02:54:32 2004 Jonathan Blandford <jrb@gnome.org>
+
+ * 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 <jrb@gnome.org>
+
+ * eel/eel-open-with-dialog.c (eel_open_with_dialog_new): make
+ function have no return value.
+
+2004-07-19 Dave Camp <dave@novell.com>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ Update for 2.7.2
+
+2004-06-01 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release bump
+
+=== eel 2.7.1 ===
+
+ * NEWS:
+ Update for 2.7.1
+
+2004-05-14 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in (LIBGLADE_REQUIRED):
+ Bump to 2.7.1 on HEAD, 2.6.3 is on gnome-2-6 branch
+
+2004-05-13 Dave Camp <dave@novell.com>
+
+ * configure.in: Post-release version bump.
+
+=== eel 2.6.2 ===
+
+2004-05-13 Dave Camp <dave@novell.com>
+
+ * NEWS: Updated for 2.6.2.
+
+2004-04-19 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Post release version bump
+
+=== eel 2.6.1 ===
+
+2004-04-19 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Updates for 2.6.1
+
+2004-04-09 Guntupalli Karunakar <karunakar@freedomink.org>
+
+ * configure.in: Added "gu" (Gujarati) to ALL_LINGUAS.
+
+2004-03-22 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.6.1
+
+=== eel 2.6.0 ===
+
+2004-03-22 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Update to 2.6.0
+
+2004-03-20 Guntupalli Karunakar <karunakar@freedomink.org>
+
+ * configure.in: Added "pa" (Punjabi) to ALL_LINGUAS.
+
+=== eel 2.5.91.1 ===
+
+2004-03-16 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Update to 2.5.91
+
+=== eel 2.5.90 ===
+
+2004-03-08 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Update to 2.5.90
+
+2004-03-02 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gnome-extensions.c (eel_gnome_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 <garnacho@tuxerver.net>
+
+ * eel/eel-gnome-extensions.c: (eel_gnome_icon_selector_new)
+ made it to use the new GtkFileChooser
+
+2004-03-02 Alexander Larsson <alexl@redhat.com>
+
+ * 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 bugzilla-gnome@thewrittenword.com.
+ Fixes #131647.
+
+2004-03-01 Alexander Larsson <alexl@redhat.com>
+
+ 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.5.8
+
+2004-02-21 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "en_CA" to ALL_LINGUAS.
+
+=== eel 2.5.7 ===
+
+2004-02-11 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.5.7
+
+2004-02-06 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-glib-extensions.c (eel_strdup_strftime):
+ Fix check
+
+2004-02-06 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * eel/eel-glib-extensions.c (eel_strdup_strftime):
+ Check for and support SUS modifiers.
+
+2004-02-05 Padraig O'Briain <padraig.obriain@sun.com>
+
+ * 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 <kloczek@pld.org.pl>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.5.6
+
+2004-01-27 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-canvas-util.c: (eel_canvas_get_miter_points):
+ * eel/eel-canvas.c: (emit_event):
+ Update from foocanvas. May fix nautilus event crash.
+
+2004-01-19 Narayana Pattipati <narayana.pattipati@wipro.com>
+
+ * 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 <dave@ximian.com>
+
+ * NEWS:
+ * configure.in: 2.5.5
+
+2004-01-11 Dave Camp <dave@ximian.com>
+
+ * eel/eel-glib-extensions.h:
+ * eel/eel-glib-extensions.c: (eel_g_str_list_index): New function.
+ * eel/eel-gconf-extensions.h:
+ * eel/eel-gconf-extensions.c: (eel_gconf_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 <andersca@gnome.org>
+
+ * eel/eel-input-event-box.c:
+ * eel/eel-input-event-box.h:
+ Remove these too.
+
+2004-01-03 Anders Carlsson <andersca@gnome.org>
+
+ * 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 <robert.sedak@sk.htnet.hr>
+
+ * configure.in: Added "hr" in ALL_LINGUAS.
+
+=== eel 2.5.4 ===
+
+2003-12-29 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ 2.5.4
+
+2003-12-11 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-stock-dialogs.c (show_message_dialog):
+ Connect to response in the right place
+
+2003-12-11 Alexander Larsson <alexl@redhat.com>
+
+ * 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-gconf-extensions.c:
+ * eel/eel-gnome-extensions.c:
+ * test/test-eel-widgets.c:
+ Use new API
+
+ Patch from dennis_cranston@yahoo.com (with some changes)
+
+=== eel 2.5.3 ===
+
+2003-12-08 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ 2.5.3
+
+2003-11-25 Padraig O'Briain <padraig.obriain@sun.com>
+
+ 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.5.2
+
+2003-11-21 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.c:
+ Accessibility support, and better support
+ for GtkEditable signals.
+ Patch by padraig o'briain <Padraig.Obriain@Sun.COM>
+
+=== eel 2.5.1 ===
+
+2003-11-10 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ 2.5.1
+
+2003-10-27 Gregory Merchan <merchan@phys.lsu.edu>
+
+ * 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-gnome-extensions.c (eel_gnome_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 <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * test/Makefile.am:
+ Disable GNOME_DISABLE_DEPRECATED for now
+
+2003-10-21 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-preferences.c:
+ Fix leaks.
+ Patch from Martin Wehner <martin.wehner@epost.de>
+
+=== eel 2.5.0 ===
+
+2003-10-20 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.5.0
+
+2003-10-15 Alexander Larsson <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * test/Makefile.am:
+ Disable GTK_DISABLE_DEPRECATED for now, since gtk 2.4
+ deprecated various widgets.
+
+2003-10-06 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "mr" to ALL_LINGUAS.
+
+2003-10-02 Padraig O'Briain <padraig.obriain@sun.com>
+
+ 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 <jody@gnome.org>
+
+ (do_update):
+ Loop do_update if picking caused need_update to be set again.
+ (Thanks to George <jirka@5z.com> for noticing this)
+ Fix from Alexander Larsson <alexl@redhat.com>
+
+2003-09-24 Dave Camp <dave@ximian.com>
+
+ * eel/eelmarshal.list: Added VOID:STRING,LONG,LONG,POINTER.
+
+2003-09-19 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "br" to ALL_LINGUAS.
+
+=== eel 2.4.0 ===
+
+2003-09-08 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ 2.4.0
+
+2003-09-04 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-gdk-extensions.c (eel_gdk_window_focus):
+ Don't use RevertToNone
+
+=== eel 2.3.90 ===
+
+2003-09-02 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in: 2.3.90
+
+2003-08-28 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "ne" to ALL_LINGUAS.
+
+=== eel 2.3.9 ===
+
+2003-08-25 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ 2.3.9
+
+=== eel 2.3.8 ===
+
+2003-08-08 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in: 2.3.8
+
+Tue Jul 22 16:18:26 2003 George Lebl <jirka@5z.com>
+
+ * eel/eel-gconf-extensions.[ch]: add eel_gconf_key_is_writable,
+ which calls gconf_client_key_is_writable
+
+ * eel/eel-preferences.[ch]: add eel_preferences_key_is_writable,
+ which in turn calls eel_gconf_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 <dave@ximian.com>
+
+ * NEWS:
+ * configure.in:
+ Bumped to 2.3.7.
+
+2003-07-08 Balamurali Viswanathan <balamurali.viswanathan@wipro.com>
+
+ * configure.in: Checking for X Development libraries explicitly.
+ * eel/Makefile.am: Added X_LIBS to libeel_2_la_LDFLAGS
+
+2003-07-07 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-canvas-rect-ellipse.c (render_rect_alpha):
+ Update from foocanvas, fixes #116752
+
+=== eel 2.3.6 ===
+
+2003-06-27 Dave Camp <dave@ximian.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.3.6.
+
+=== eel 2.3.5 ===
+
+2003-06-23 Dave Camp <dave@ximian.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.3.5.
+
+2003-06-15 Frederic Crozat <fcrozat@mandrakesoft.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <dave@ximian.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.3.4.
+
+2003-06-05 Kenneth Rohde Christiansen <kenneth@gnu.org>
+
+ * configure.in: Added li to ALL_LINGUAS.
+
+2003-06-04 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.3.3.
+
+2003-05-26 Anders Carlsson <andersca@codefactory.se>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.3.2.
+
+2003-05-15 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <hobbit@aloss.ukuu.org.uk>
+
+ * configure.in: Added cy to ALL_LINGUAS
+ * po/cy.po: Added
+
+2003-05-05 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Update
+
+ * configure.in:
+ Bump version
+
+2003-05-04 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added sr and sr@Latn to ALL_LINGUAS.
+
+2003-04-23 Masahiro Sakai <sakai@tom.sfc.keio.ac.jp>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-canvas.c:
+ Update foocanvas.
+
+=== eel 2.2.3 ===
+
+2003-03-31 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.2.3
+
+2003-03-27 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-accessibility.c (eel_accessibility_set_atk_object_return):
+ Fix warning.
+
+2003-03-19 Padraig O'Briain <padraig.obriain@sun.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-editable-label.c (eel_editable_label_expose):
+ Draw frame even if text is "".
+
+2003-03-13 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "ml" to ALL_LINGUAS.
+
+2003-03-12 Balamurali Viswanathan <balamurali.viswanathan@wipro.com>
+
+ *eel/eel-stock-dialogs.c
+ connect the "response" signal of the trash dialog
+
+=== eel 2.2.2 ===
+
+2003-03-10 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.2.2.
+
+2003-03-04 Alexander Larsson <alexl@redhat.com>
+
+ * eel/Makefile.am:
+ * eel/eel-input-event-box.[ch]:
+ New widget. Basically GtkEventBox with a INPUT_ONLY window.
+
+2003-03-04 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-canvas.c:
+ Update foocanvas. Fix a11y crash.
+
+2003-03-04 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-accessibility.[ch]:
+ Publicaly export some utility functions.
+ Patch from padraig.obriain@sun.com
+
+2003-03-04 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-canvas.c:
+ Update foocanvas. Gets a11y support from padraig.
+
+2003-03-03 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-canvas.c:
+ Update from foo-canvas. Fixes group movement,
+ removes silly warning.
+
+2003-02-28 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.[ch]:
+ Add eel_editable_label_get_font_description and
+ eel_editable_label_set_font_description.
+
+2003-02-27 Taneem Ahmed <taneem@eyetap.org>
+
+ * configur.in: Added "bn" to ALL_LINGUAS
+
+2003-02-25 Samúel Jón Gunnarsson <sammi@techattack.nu>
+
+ * configur.in: Added is to ALL_LINGUAS
+
+2003-02-21 Paisa Seeluangsawat <paisa@colorado.edu>
+
+ * configure.in (ALL_LINGUAS): Added "th".
+
+2003-02-18 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "ga" to ALL_LINGUAS.
+
+2003-02-14 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-glib-extensions.c (eel_unsetenv):
+ Fix bug. Patch from hidetoshi.tajima@sun.com.
+
+=== eel 2.2.1 ===
+
+2003-02-11 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.2.1
+
+2003-02-09 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "kn" to ALL_LINGUAS.
+
+2003-02-07 Abel Cheung <maddog@linux.org.hk>
+
+ * configure.in: Removed "ga" from ALL_LINGUAS. Empty translation file.
+
+2003-02-06 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "id" to ALL_LINGUAS.
+
+2003-02-05 James M. Cape <jcape@ignore-your.tv>
+
+ * 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-gnome-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 <dave@ximian.com>
+
+ * NEWS:
+ * configure.in: 2.2.0.2
+
+=== eel 2.2.0.1 ===
+
+2003-01-22 Dave Camp <dave@ximian.com>
+
+ * NEWS:
+ * configure.in: 2.2.0.1
+
+2003-01-21 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "mn" to ALL_LINGUAS.
+
+=== eel 2.2.0 ===
+
+2003-01-20 Dave Camp <dave@ximian.com>
+
+ * NEWS:
+ * configure.in: 2.2.0.
+
+2003-01-17 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-preferences-glade.c:
+ Correct previous fix.
+
+2003-01-17 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.1.91.
+
+2003-01-13 Alexander Larsson <alexl@redhat.com>
+
+ * 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 bonoboplug 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 <pablo@mandrakesoft.com>
+
+ * configure.in: Added Amharic (am) and Farsi (fa) to ALL_LINGUAS
+
+=== eel 2.1.6 ===
+
+2003-01-06 Dave Camp <dave@ximian.com>
+
+ * NEWS:
+ * configure.in: 2.1.6.
+
+2002-12-17 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * eel/Makefile.am:
+ * test/Makefile.am:
+ -pthread build fixes
+
+=== eel 2.1.5 ===
+
+2002-12-16 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump to 2.1.5
+
+2002-12-13 Alex Duggan <aldug@gnome.org>
+
+ * configure.in:
+ * eel-2.0.pc.in:
+ * eel.spec.in:
+ remove libgnomecanvas deps
+
+=== eel 2.1.4 ===
+
+2002-12-09 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * NEWS:
+ Bump to 2.1.4
+
+2002-12-05 Dave Camp <dave@ximian.com>
+
+ * eel/eel-gnome-extensions.c: (list_icon_selected_callback): Free
+ the return value of gnome_icon_selection_get_icon(). Patch from
+ Jörgen Viksell <jorgen.viksell@telia.com>
+
+Wed Dec 4 12:50:35 2002 HideToshi Tajima <hidetoshi.tajima@sun.com>
+
+ * 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 <alexl@redhat.com>
+
+ * eel/eel-vfs-extensions.c:
+ Fix checks so we distcheck.
+
+2002-11-25 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ * NEWS:
+ Bump to 2.1.3.
+
+2002-11-21 Alexander Larsson <alexl@redhat.com>
+
+ * 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 Brian.Cameron@sun.com
+
+2002-11-19 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.[ch]:
+ Don't use private gtk functions.
+
+2002-11-05 Dave Camp <dave@ximian.com>
+
+ * 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 <diego@pemas.net>
+
+ * 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 <diego@pemas.net>
+
+ * eel/eel-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c: (get_set_value_imethod),
+ (do_nothing_cb), (eel_bonobo_pbclient_set_value_async):
+ remove these functions since they are now in libbonobo
+
+2002-11-04 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <jpetersen@gnome-de.org>
+
+2002-11-03 Dmitry G. Mastrukov <dmitry@taurussoft.org>
+
+ * configure.in: Added Belarusian to ALL_LINGUAS
+
+=== eel 2.1.2 ===
+
+2002-10-31 Dave Camp <dave@ximian.com>
+
+ * MAINTAINERS: Updated.
+
+ * configure.in:
+ * NEWS: 2.1.2
+
+2002-10-31 Dave Camp <dave@ximian.com>
+
+ * 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 <dave@ximian.com>
+
+ * 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 <jpetersen@uni-bonn.de>.
+
+2002-10-25 Dave Camp <dave@ximian.com>
+
+ * eel/Makefile.am: Oops. Removed extra \ at the end of a
+ commented out line.
+
+2002-10-19 Dave Camp <dave@ximian.com>
+
+ * eel/Makefile.am: Take out -DBONOBO_DISABLE_DEPRECATED while the
+ make_registration_id() api is being worked out.
+
+=== eel 2.1.1 ===
+
+2002-10-14 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Added news items
+
+ * configure.in:
+ Bump version to 2.1.1
+
+2002-10-02 Mark McLoughlin <mark@skynet.ie>
+
+ * 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-gnome-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 <mark@skynet.ie>
+
+ * eel/eel-gdk-extensions.c:
+ (eel_stipple_bitmap_for_screen): use gdk_screen_get_display
+ instead of assuming the default display.
+
+ * eel/eel-gnome-extensions.c:
+ (eel_gnome_shell_execute_on_screen): use the default screen
+ if screen == NULL.
+
+2002-10-02 Mark McLoughlin <mark@skynet.ie>
+
+ * eel/eel-gnome-extensions.[ch]:
+ (eel_gnome_shell_execute_on_screen): rename from
+ eel_gnome_screen_shell_execute.
+ (eel_gnome_shell_execute): update.
+ (eel_gnome_open_terminal_on_screen): rename from
+ eel_gnome_screen_open_terminal.
+ (eel_gnome_open_terminal): update.
+
+2002-10-02 Mark McLoughlin <mark@skynet.ie>
+
+ * 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 <mark@skynet.ie>
+
+ * 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-gnome-extensions.[ch]:
+ (eel_gnome_screen_shell_execute): implement.
+ (eel_gnome_screen_open_terminal): implement.
+ (eel_gnome_open_terminal):
+
+ * eel/eel-gtk-extensions.c:
+ (eel_gtk_window_set_initial_geometry):
+ use gdk_screen_get_(width|height).
+
+2002-10-01 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.[ch]:
+ Added eel_editable_label_set_line_wrap_mode.
+
+2002-09-30 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.c:
+ Implement GtkEditable
+
+2002-09-30 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.c:
+ Finish cut/paste and other stuff.
+
+=== eel 2.1.0 ===
+
+2002-09-27 Dave Camp <dave@ximian.com>
+
+ * NEWS: Updated.
+
+2002-09-27 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Bump version to 2.1.0.
+
+2002-09-26 Alexander Larsson <alexl@redhat.com>
+
+ * eel/eel-editable-label.c:
+ Remove leftover debug spew.
+
+2002-09-26 Alexander Larsson <alexl@redhat.com>
+
+ * test/Makefile.am:
+ * test/test-eel-canvas-items.c:
+ Remove canvas item test.
+
+2002-09-26 Alexander Larsson <alexl@redhat.com>
+
+ * 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-gnome-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 <dave@ximian.com>
+
+ * 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 <jacob@ximian.com>
+
+ * 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 <dave@ximian.com>
+
+ * 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 <menthos@menthos.com>
+
+ * configure.in: Added "he" to ALL_LINGUAS.
+
+2002-09-03 Michael Meeks <michael@ximian.com>
+
+ * eel/eel-background.c
+ (eel_background_load_image_callback): disable,
+ until the nautilus side is re-thunk.
+
+2002-09-03 Michael Meeks <michael@ximian.com>
+
+ * 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 <alexl@redhat.com>
+
+ branched of gnome 2.0.x development to gnome-2-0 branch.
+
+=== eel 2.0.6 ===
+
+2002-08-28 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bumped to 2.0.6.
+
+=== eel 2.0.5 ===
+
+2002-08-23 Alexander Larsson <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Version bumped to 2.0.5.
+
+=== eel 2.0.4 ===
+
+2002-08-14 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Version bumped to 2.0.4
+
+2002-08-12 Dave Camp <dave@ximian.com>
+
+ * 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 <dave@ximian.com>
+
+ * NEWS: Updated.
+ * configure.in: 2.0.3.
+
+2002-07-28 Christian Rose <menthos@menthos.com>
+
+ * configure.in: Added "sq" to ALL_LINGUAS.
+
+2002-07-27 Dave Camp <dave@ximian.com>
+
+ * eel/eel-background.c: (widget_realize_cb),
+ (eel_get_widget_background): Set up the widget background on
+ realize.
+
+2002-07-27 Dave Camp <dave@ximian.com>
+
+ * 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 <dave@ximian.com>
+
+ * NEWS: Add a list of changes.
+ * configure.in: Bump version to 2.0.2.
+
+2002-07-25 Pablo Saratxaga <pablo@mandrakesoft.com>
+
+ * configure.in: Added Bosnian (bs) to ALL_LINGUAS
+
+2002-07-24 Dave Camp <dave@ximian.com>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 2.0.01.
+ Add list of changes.
+
+2002-07-18 Federico Mena Quintero <federico@ximian.com>
+
+ Fixes the eel part of #46238; see Nautilus 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 <fworsley@shaw.ca>
+
+ * 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 <damon@ximian.com>
+
+ * 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 <dave@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <damon@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-labeled-image.c
+ (eel_labeled_image_get_accessible): cope better
+ with the no a11y scenario.
+
+2002-07-08 Michael Meeks <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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-gnome-extensions.c (eel_glade_get_file): impl.
+
+2002-06-28 Marco Pesenti Gritti <marco@it.gnome.org>
+
+ * eel/eel-gtk-extensions.c (eel_popup_menu_position_func):
+ Remove context menus custom positioning code to be consistent
+ with other gnome applications.
+
+2002-06-27 Frank Worsley <fworsley@shaw.ca>
+
+ * 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 <dave@ximian.com>
+
+ * 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 <fcrozat@mandrakesoft.com>
+
+ * acconfig.h:
+ * configure.in:
+ * eel/Makefile.am:
+ * eel/check-program.c: (main):
+ * eel/eel-enumeration.c:
+ * eel/eel-gconf-extensions.c:
+ * eel/eel-glib-extensions.c:
+ * eel/eel-gnome-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 <satyajit.kanungo@wipro.com>
+
+ * 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 <dave@ximian.com>
+
+ * 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 <damon@ximian.com>
+
+ * eel/eel-gnome-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 <alla@lysator.liu.se>
+
+ * eel/eel-preferences-box.c: change treeview shadow type
+ to GTK_SHADOW_IN and add some spacing for consistency with
+ the rest of gnome.
+
+ Patch from Jorn Baayen <jorn@nl.linux.org>
+
+2002-06-10 Alexander Larsson <alla@lysator.liu.se>
+
+ * NEWS:
+ Update version nr.
+
+ * configure.in:
+ Update requirements to latest versions of everything.
+
+2002-06-10 Naba Kumar <kh_naba@users.sourceforge.net>
+
+ * configure.in: Added hi in ALL_LINGUAS.
+
+2002-06-09 Abel Cheung <maddog@linux.org.hk>
+
+ * eel/eel-glib-extension.c: Clarify the comment about
+ strftime check.
+
+2002-06-07 Damon Chaplin <damon@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-vfs-extensions.c
+ (eel_vfs_test_capabilities): impl.
+
+2002-06-06 Michael Meeks <michael@ximian.com>
+
+ * Version 2.0.0
+
+2002-06-06 Jacob Berkman <jacob@ximian.com>
+
+ * 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 <yaneti@declera.com>
+
+ * configure.in: (ALL_LINGUAS) Added Bulgarian (bg).
+
+=== eel 1.1.17 ===
+
+2002-06-03 Alex Larsson <alexl@redhat.com>
+
+ * NEWS:
+ Add some actual changes.
+
+2002-06-03 Alexander Larsson <alla@lysator.liu.se>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 1.1.17
+
+2002-05-31 Alex Larsson <alexl@redhat.com>
+
+ * eel/eel-gdk-extensions.[ch] (eel_gdk_draw_layout_with_drop_shadow):
+ Add new function.
+
+2002-05-28 Havoc Pennington <hp@redhat.com>
+
+ * eel/eel-gdk-pixbuf-extensions.c: remove bogus #include <png.h>,
+ we no longer use libpng
+
+2002-05-27 Michael Meeks <michael@ximian.com>
+
+ * eel/eel-vfs-extensions.c
+ (eel_make_valid_utf8): copy from nautilus
+ (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 <alla@lysator.liu.se>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 1.1.16
+
+2002-05-23 Michael Meeks <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-vfs-extensions.c (eel_is_valid_uri): impl.
+
+2002-05-21 Damon Chaplin <damon@ximian.com>
+
+ * eel/eel-gnome-extensions.c (eel_gnome_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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 1.15.
+
+2002-05-18 Kjartan Maraas <kmaraas@gnome.org>
+
+ * configure.in: Added "mk" to ALL_LINGUAS.
+
+2002-05-16 Michael Meeks <michael@ximian.com>
+
+ * 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 <mark@skynet.ie>
+
+ * 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 <federico@ximian.com>
+
+ * 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 <alexl@redhat.com>
+
+ * NEWS:
+ * configure.in:
+ Update to 1.1.14
+
+2002-05-12 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <alla@lysator.liu.se>
+
+ * 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 <damon@ximian.com>
+
+ * eel/eel-gnome-extensions.c (eel_gnome_icon_selector_new): connect
+ the dialog signals up before calling gnome_icon_selection_show_icons()
+ and also add a weak pointer to the dialog. We need to do this as
+ GnomeIconSelection 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 <dwatson@cs.ucr.edu>
+
+ 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 <alla@lysator.liu.se>
+
+ * 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 <pablo@mandrakesoft.com>
+
+ * 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 <alla@lysator.liu.se>
+
+ * configure.in:
+ * NEWS:
+ Bump version to 1.1.12.
+
+2002-04-28 Alexander Larsson <alla@lysator.liu.se>
+
+ * 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 <murrayc@usa.net>
+
+ * 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 <gustavo.giraldez@gmx.net>
+
+ * eel/eel-ellipsizing-label.c (real_finalize): chain call to
+ parent class' finalize.
+
+2002-04-22 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <alla@lysator.liu.se>
+
+ * configure.in:
+ * NEWS:
+ Bump version to 1.1.11.
+
+2002-04-21 Alexander Larsson <alla@lysator.liu.se>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-gnome-extensions.c
+ (do_nothing_cb, get_set_value_imethod),
+ (eel_bonobo_pbclient_set_value_async): impl.
+ async property setter to cut throbber
+ latency.
+
+2002-04-17 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <alla@lysator.liu.se>
+
+ * NEWS:
+ * configure.in:
+ Bump version to 1.1.10
+
+2002-04-14 Alexander Larsson <alla@lysator.liu.se>
+
+ * eel/eel-gnome-extensions.c (eel_gnome_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 <alla@lysator.liu.se>
+
+ * eel/eel-gnome-extensions.c (eel_gnome_shell_execute):
+ Print a warning on failure. For debugging purposes.
+
+2002-04-12 Jody Goldberg <jody@gnome.org>
+
+ * eel/eel-gnome-extensions.c (eel_gnome_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 <padraig.obriain@sun.com>
+
+ * 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 <alla@lysator.liu.se>
+
+ * 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 Nautilus thumbnail size limit.
+
+2002-04-04 Dave Camp <dave@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-accessibility.c
+ (eel_accessibility_set_description),
+ (eel_accessibility_set_name): impl.
+
+2002-04-03 Michael Meeks <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <alla@lysator.liu.se>
+
+ * test/test-eel-pixbuf-scale.c:
+ Don't double define DEST_WIDTH and DEST_HEIGHT.
+
+2002-03-29 Havoc Pennington <hp@pobox.com>
+
+ * eel/eel-gconf-extensions.c (eel_gconf_value_is_equal): don't use
+ private gconf fields, and fix a bug in comparison of equality
+ of list values (if (a != NULL || b != NULL) return FALSE)
+
+2002-03-28 Michael Meeks <michael@ximian.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <dave@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-accessibility.c
+ [ cut & paste helpers from bonobo 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 <alla@lysator.liu.se>
+
+ * configure.in: Bump version to 1.1.9
+
+ * NEWS: bump version.
+
+2002-03-22 Dave Camp <dave@ximian.com>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * configure.in: Bump required versions.
+
+=== eel 1.1.8 ===
+
+2002-03-17 Alexander Larsson <alexl@redhat.com>
+
+ * 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 <gleblanc@linuxweasel.com>
+
+ * eel.spec.in: New one, from Chris Chabot
+
+2002-03-11 Michael Meeks <michael@ximian.com>
+
+ * eel/eel-gnome-extensions.c
+ (eel_bonobo_make_registration_id): impl.
+
+2002-03-11 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * NEWS: Bump version.
+
+2002-03-09 Alexander Larsson <alexl@redhat.com>
+
+ * 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 nautilus.)
+
+2002-03-08 Darin Adler <darin@bentspoon.com>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-preferences-box.c: (eel_preferences_dialog_new): Make the
+ button say "Close" instead of "OK".
+
+2002-03-06 Darin Adler <darin@bentspoon.com>
+
+ * 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 gnome-i18n.h include. Not sure why
+ this wasn't needed before.
+
+ * eel/eel-preferences.c: Remove unneeded gnome-i18n.h include.
+
+2002-03-06 Darin Adler <darin@bentspoon.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <alla@lysator.liu.se>
+
+ * 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 nautilus 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-image-chooser.c: (eel_image_chooser_set_selected_row):
+ Handle -1 by deselecting all rows.
+
+2002-02-28 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gnome-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_gnome_icon_selector_new): Store a pointer to the dialog that we
+ can use later to close it.
+
+2002-02-27 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-glib-extensions.h:
+ * eel/eel-glib-extensions.c:
+ Remove unused eel_g_ptr_array_* functions.
+
+ * eel/eel-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c:
+ Remove unused eel_gnome_canvas_world_to_window_rectangle.
+ (eel_gnome_canvas_world_to_widget_rectangle),
+ (eel_gnome_canvas_widget_to_world),
+ (eel_gnome_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 <darin@bentspoon.com>
+
+ * 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 <dwatson@cs.ucr.edu>
+
+ eel/eel-preferences-box.c:
+ (eel_preferences_box_init): Remove connect.
+ (user_level_changed_callback): Removed.
+
+2002-02-20 Michael Meeks <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <jacob@ximian.com>
+
+ * eel/eel-gnome-extensions.c (get_terminal_command_prefix):
+ gnome-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 <michael@ximian.com>
+
+ * 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 <menesis@delfi.lt>
+
+ * configure.in: remove GNOME_COMMON_INIT, GNOME_PLATFORM_GNOME_2
+
+2002-02-16 Alexander Larsson <alla@lysator.liu.se>
+
+ * 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 <dwatson@cs.ucr.edu>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <michael@ximian.com>
+
+ * eel/eel-stock-dialogs.h (eel_create_info_dialog):
+ fix header comment.
+
+2002-02-12 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-wrap-table.c: (eel_wrap_table_class_init):
+ Register enums in here. This gets rid of the last place
+ we had GNOME2_CONVERSION_COMPLETE.
+
+ * eel/maketypes.awk: Fix to make EEL_TYPE_X instead of
+ EEL_TYPE_EEL_X.
+
+2002-02-12 Tõivo Leedjärv <leedjarv@interest.ee>
+
+ * configure.in: Added et to ALL_LINGUAS.
+
+2002-02-12 Michael Meeks <michael@ximian.com>
+
+ * 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 <andersca@gnu.org>
+
+ * eel/eel-canvas-rect.c (eel_canvas_rect_realize): Surround
+ variable declarations with HAVE_RENDER.
+
+2002-02-10 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * NEWS: Bump version.
+ * configure.in: Bump version.
+
+ * eel/eel-debug.c:
+ (eel_make_warnings_and_criticals_stop_in_debugger):
+ Add gnome-vfs-modules to list of domains.
+
+2002-02-08 Anders Carlsson <andersca@gnu.org>
+
+ * eel/eel-canvas-rect.c: (eel_canvas_rect_realize),
+ (eel_canvas_rect_unrealize):
+ Chain to parent implementations.
+
+2002-02-06 Darin Adler <darin@bentspoon.com>
+
+ * eel/Makefile.am: Turn on GNOME_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-gnome-extensions.c: (eel_gnome_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, GNOME_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 <michael@ximian.com>
+
+ * 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-gnome-extensions.c
+ (eel_gnome_icon_selector_new): remove all
+ deprecated bits.
+
+ * eel/eel-dateedit-extensions.c
+ (eel_gnome_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 <michael@ximian.com>
+
+ * eel/eel-dateedit-extensions.c
+ (eel_gnome_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-gnome-extensions.c
+ (try_terminal_command),
+ (eel_gnome_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 <darin@bentspoon.com>
+
+ * 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 Nautilus.
+ * eel/eel-dnd.h: Move back into Nautilus.
+ * 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 <darin@bentspoon.com>
+
+ * 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
+ <nothin2chance@yahoo.com>.
+
+2002-02-04 Laszlo Peter <laca@ireland.sun.com>
+
+ * 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 <otaylor@redhat.com>
+
+ * eel/eel-gnome-extensions.c (dialog_response_callback):
+ Labels need a statement after them. (Fixes -Werror problem
+ with recent GCC.)
+
+2002-01-30 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c:
+ (eel_gnome_canvas_world_to_canvas_window_rectangle): New.
+ (eel_gnome_canvas_canvas_window_to_world): New.
+ (eel_gnome_canvas_world_to_canvas_window): New.
+
+==== eel 1.1.2 ====
+
+2002-01-29 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * NEWS: Update for 1.1.2 release.
+
+2002-01-28 Gediminas Paulauskas <menesis@delfi.lt>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/Makefile.am: Use LC_ALL instead of LC_COLLATE.
+ * eel/eel-gnome-extensions.c: (eel_gnome_canvas_item_send_behind):
+ Oops, it was sending things in front.
+
+2002-01-27 Anders Carlsson <andersca@gnu.org>
+
+ * eel/eel-stock-dialogs.c (eel_run_simple_dialog): Start with
+ a response id that is 0.
+
+2002-01-27 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c: (eel_gnome_canvas_item_send_behind): New.
+
+2002-01-27 Alexander Larsson <alla@lysator.liu.se>
+
+ * 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 Nautilus
+ 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 <darin@bentspoon.com>
+
+ * 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 <peteris.krisjanis@ttc.lv>
+
+ * eel/configure.in: added lv to ALL_LINGUAS
+
+2002-01-22 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-font-picker.c: (font_picker_get_index_for_font):
+ Handle NULL family_name.
+
+2002-01-21 Darin Adler <darin@bentspoon.com>
+
+ * 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 <menesis@delfi.lt>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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-gconf-extensions.c: (eel_gconf_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 <darin@bentspoon.com>
+
+ * eel/eel-pango-extensions.c:
+ (eel_pango_layout_set_text_ellipsized): Soften an assert to
+ a g_return.
+
+2002-01-17 Darin Adler <darin@bentspoon.com>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * configure.in: Bump version to 1.1.2.
+
+2002-01-16 Darin Adler <darin@bentspoon.com>
+
+ * 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 <hp@redhat.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <alla@lysator.liu.se>
+
+ * 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 <otaylor@redhat.com>
+
+ * eel/eel-gnome-extensions.c
+ (eel_gnome_canvas_world_to_window_rectangle): Remove
+ unused variable so things compile.
+
+2002-01-09 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c:
+ Remove gnome_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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-gdk-font-extensions.c: Remove.
+ * eel/eel-gdk-font-extensions.h: Remove.
+
+2002-01-08 Darin Adler <darin@bentspoon.com>
+
+ * 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 <menthos@menthos.com>
+
+ * configure.in: Added "ms" to ALL_LINGUAS.
+
+2002-01-04 Havoc Pennington <hp@pobox.com>
+
+ * eel/eel-gconf-extensions.c (eel_gconf_monitor_add): don't do the
+ recursive preload here, too much stuff in /apps/nautilus it seems
+ like. Rely on explicit preloads in other code.
+
+ * eel/eel-font-picker.c (font_picker_get_selected_style_entry):
+ add FIXME and GNOME2_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-gconf-extensions.c
+ (eel_gconf_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 gconf
+ database (as we did when a list of enum values was invalid), don't
+ bother to cache values since GConfClient does already, remove
+ callbacks_blocked which incorrectly relied on
+ synchronicity/non-reentrancy of gconf, 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-gconf-extensions.c (eel_gconf_preload_cache): New
+ function to allow us to get a bunch of GConf data in a single
+ round trip
+ (eel_gconf_get_default_value): new function to get the default
+ from the schema
+
+2002-01-04 Darin Adler <darin@bentspoon.com>
+
+ * 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 bonobo-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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * test/Makefile.am:
+ * test/test-eel-font-picker.c: (main):
+ Loose ends from removing EelFontManager.
+
+2002-01-03 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gnome-extensions.c: (get_terminal_command_prefix):
+ Port to use libgnome to get terminal choice from GConf.
+
+ * 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 <darin@bentspoon.com>
+
+ * 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-gnome-extensions.c:
+ (eel_gnome_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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 libgnomecanvas 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 <darin@bentspoon.com>
+
+ * 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 <michael@ximian.com>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * configure.in: Remove unused libpng code.
+ * eel.spec.in: Remove libpng, fonts, and librsvg.
+
+2002-01-02 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-gnome-extensions.c: (eel_gnome_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 <fcrozat@mandrakesoft.com>
+
+ * 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 Nautilus desktop)
+
+2002-01-02 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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-gnome-extensions.c: (create_pango_context_for_aa_canvas):
+ Remove some unneeded casts.
+
+2001-12-21 Duarte Loreto <happyguy_pt@hotmail.com>
+
+ * configure.in: Added new pt translation to ALL_LINGUAS
+
+2001-12-18 Michael Meeks <michael@ximian.com>
+
+ * eel/eel-gconf-extensions.c (eel_gconf_monitor_add):
+ recursively cache the GConf keys to reduce CORBA traffic.
+
+2001-12-17 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c: (create_pango_context_for_aa_canvas),
+ (eel_gnome_canvas_get_pango_context): Helper function for getting
+ the appropriate context when drawing to an anti-aliased GnomeCanvas.
+
+ * eel/eel-gtk-extensions.c: Add an include that's needed now that
+ I removed excess includes from eel-gnome-extensions.h.
+
+2001-12-12 Michael Meeks <michael@ximian.com>
+
+ * eel/eel-list-column-title.c (eel_list_column_title_paint):
+ remove erroneous style unref.
+
+2001-12-11 Laszlo Peter <laca@ireland.sun.com>
+
+ * eel/Makefile.am: add dependencies to fix building with make -j
+
+2001-12-09 Anders Carlsson <andersca@gnu.org>
+
+ * eel/eel-caption-table.c: (eel_caption_table_resize),
+ (eel_caption_table_set_row_info): Use gtk+ mnemonics.
+
+ * eel/eel-gnome-extensions.c: (icon_selected_callback),
+ (icon_cancel_pressed), (dialog_response_callback),
+ (entry_activated), (eel_gnome_icon_selector_new):
+ * eel/eel-gnome-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 <michael@ximian.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-art-extensions.c: (eel_art_irect_union): Add missing return.
+
+2001-12-07 Laszlo Peter <laca@ireland.sun.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * lots of files
+ Get rid of unneeded casts in calls to g_object_ref/unref.
+
+2001-12-06 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <otaylor@redhat.com>
+
+ * configure.in: Add [quoting] around AC_CHECK_HEADER
+ needed by some autoconf versions.
+
+Mon Nov 19 17:34:16 2001 Jonathan Blandford <jrb@webwynk.net>
+
+ * eel/eel-stock-dialogs.c (eel_run_simple_dialog): remove uneeded
+ GTK_OBJECT_DESTROYED check.
+
+ Patch from Gediminas Paulauskas <menesis@delfi.lt>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * Tons of files.
+ Removed many unneeded G_OBJECT casts.
+
+2001-11-08 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-stock-dialogs.h:
+ * eel/eel-stock-dialogs.c:
+ A cut at porting this all to GtkDialog.
+
+2001-11-08 jacob berkman <jacob@ximian.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * Lots of files.
+ More GtkObject -> GObject.
+
+2001-11-06 Michael Meeks <michael@ximian.com>
+
+ * eel/eel-gdk-pixbuf-extensions.c
+ (free_pixbuf_load_handle): do a g_object_unref not an
+ unref.
+
+2001-11-03 Darin Adler <darin@bentspoon.com>
+
+ * Tons of files:
+ A bit more GtkObject -> GObject conversion.
+
+2001-11-03 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gtk-macros.h: Ref the parent class instead of just
+ peeking at it.
+
+2001-11-03 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <hp@pobox.com>
+
+ * eel/eel-gtk-extensions.c (eel_gtk_window_get_geometry_string):
+ new function to replace gnome_geometry_string
+
+2001-11-01 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gtk-macros.h: When I fixed the comma in my copy, I
+ made some formatting changes.
+
+2001-11-01 Havoc Pennington <hp@pobox.com>
+
+ * eel/eel-gtk-macros.h (EEL_DEFINE_BONOBO_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 <darin@bentspoon.com>
+
+ * eel/eel-gtk-macros.h: Oops, need to pass init and fini functions
+ in to bonobo_type_unique.
+
+2001-11-01 Darin Adler <darin@bentspoon.com>
+
+ * configure.in: Remove some unused stuff.
+ * eel/eel-gtk-macros.h: Fix boilerplate to work with GObject, not
+ just GtkObject. Share code with the BonoboObject case too.
+
+2001-10-29 Darin Adler <darin@bentspoon.com>
+
+ * eel-2.0.pc.in: Add some Requires.
+
+2001-10-29 Darin Adler <darin@bentspoon.com>
+
+ * eel/Makefile.am: Fix typo.
+
+2001-10-28 Darin Adler <darin@bentspoon.com>
+
+ * configure.in: Fix comment, remove unnecessary direct pkgconfig
+ macro since GNOME_PLATFORM_GNOME_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_BONOBO_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 <jacob@ximian.com>
+
+ * eel/eel-background.c (eel_background_start_loading_image):
+ update to new vfs priority macro name
+
+2001-10-22 Darin Adler <darin@bentspoon.com>
+
+ * 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 <andersca@gnu.org>
+
+ * 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 gnome-vfs
+ to take a priority argument because of the recent priority changes in
+ gnome-vfs.
+
+2001-10-11 Ramiro Estrugo <ramiro@fateware.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * .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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ 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 gnome_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 gnome-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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/Makefile.am:
+ Another pass. The last one was too simplistic.
+
+2001-09-26 Darin Adler <darin@bentspoon.com>
+
+ * 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 <mandreiana@yahoo.com>
+
+ * configure.in: Added ro (Romanian) to ALL_LINGUAS
+
+2001-09-18 Darin Adler <darin@bentspoon.com>
+
+ * 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 gnome 2 conversion work that will
+ be needed.
+
+2001-09-17 Darin Adler <darin@bentspoon.com>
+
+ * 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
+ Nautilus 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 <lark@linux.net.cn>
+
+ * configure.in(ALL_LINGUAS): Added zh_CN for Simplified Chinese.
+
+2001-09-07 Darin Adler <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * configure.in: Got rid of dependency on libgnomesupport.
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/check-program.c: (main):
+ * test/test-eel-password-dialog.c: (main):
+ * test/test-eel-widgets.c: (main):
+ * test/test.c: (test_init):
+ Use libgnomeui_module_info_get () instead of
+ libgnomeui_module_info.
+
+2001-09-01 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gtk-extensions.c: Remove include.
+
+2001-09-01 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-dnd.c:
+ (is_path_that_gnome_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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ 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 <darin@bentspoon.com>
+
+ * eel/eel-gtk-extensions.c: (eel_gtk_window_present):
+ Get things compiling again by getting rid of code that uses
+ gnome_win_hints (for now).
+
+2001-08-31 Abel Cheung <maddog@linux.org.hk>
+
+ * configure.in (ALL_LINGUAS): zh_TW.Big5 -> zh_TW
+
+2001-08-27 Darin Adler <darin@bentspoon.com>
+
+ Rolled change from stable eel-1-0 branch:
+
+ 2001-08-27 Alex Larsson <alexl@redhat.com>
+
+ * eel/eel-list-column-title.c (truncate_string):
+ Fix elipsis truncation on multibyte locales.
+
+2001-08-27 Anders Carlsson <andersca@gnu.org>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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 <ramiro@fateware.com>
+
+ Change from the stable eel-1-0 branch.
+
+ * eel/eel-gconf-extensions.c: (eel_gconf_value_set_string_list):
+ Fix leaks introduced in last checkin.
+
+2001-08-22 Ramiro Estrugo <ramiro@fateware.com>
+
+ Change from the stable eel-1-0 branch.
+
+ * eel/eel-gconf-extensions.h:
+ * eel/eel-gconf-extensions.c: (eel_gconf_is_default): Use value
+ free cover that does its own not NULL checking.
+ (eel_gconf_value_get_string_list),
+ (eel_gconf_value_set_string_list): New function to deal with
+ GConfValue lists of GNONF_VALUE_STRING type.
+
+ * eel/eel-preferences.c: (preferences_gconf_value_get_int),
+ (preferences_gconf_value_get_bool),
+ (preferences_gconf_value_get_string),
+ (preferences_gconf_value_get_string_list), (preferences_get_value),
+ (preferences_preference_is_gconf_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_gconf_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 gconf. 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 GConfValue safely and with some extra checking the
+ the types are right.
+
+2001-08-21 Maciej Stachowiak <mjs@anarchy.noisehavoc.org>
+
+ Merge from stable branch:
+
+ 2001-08-20 Maciej Stachowiak <mjs@noisehavoc.org>
+
+ * 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 <mjs@noisehavoc.org>
+
+ * eel/eel-font-manager.c (collect_fonts_from_directory): Adjust to
+ recent removal of filtering from gnome-vfs.
+
+2001-08-21 Maciej Stachowiak <mjs@eazel.com>
+
+ Merge from eel-1-0 branch:
+
+ 2001-07-20 Maciej Stachowiak <mjs@eazel.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * eel/eel-gtk-extensions.c: Remove include of obsolete header.
+
+2001-08-17 Ramiro Estrugo <ramiro@fateware.com>
+
+ Change from the stable eel-1-0 branch.
+
+ Make these widgets more useful outside Nautilus 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 Nautilus.
+
+ * 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 <darin@bentspoon.com>
+
+ 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-gnome-extensions.c: (try_terminal_command),
+ (try_terminal_command_argv), (get_terminal_command_prefix),
+ (eel_gnome_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 <jrb@redhat.com>
+
+ * eel/eel-dnd.c (eel_drag_default_drop_action_for_icons): make the
+ trash directory.
+
+2001-08-15 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-gdk-pixbuf-extensions.c: Use a 64K buffer instead of
+ a 4K one.
+
+2001-08-14 Darin Adler <darin@bentspoon.com>
+
+ * 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 <alexl@redhat.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * 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
+ GnomeCanvas.
+
+ * 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 <ramiro@fateware.com>
+
+ 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 <darin@bentspoon.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * autogen.sh: No need to gettextize, xml-i18n-toolize, and
+ libtoolize twice.
+ * configure.in: Switch from lots of GNOME_PKGCONFIG_CHECK_MODULES
+ calls to a lot fewer PKG_CHECK_MODULES calls. More oaf ->
+ bonobo-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:
+ <libgnomeui/gnome-init.h> -> <libgnomeui/gnome-ui-init.h>.
+
+2001-07-26 Darin Adler <darin@bentspoon.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ 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 <ramiro@fateware.com>
+
+ * eel/Makefile.am:
+ Add missing eelmarshal.list to EXTRA_DIST and use a sophisticated
+ alphabetized order on the list.
+
+2001-07-25 Ramiro Estrugo <ramiro@fateware.com>
+
+ * eel-2.0.pc.in:
+ Change link flags to '-leel-2' instead of '-leel'
+
+2001-07-25 Ramiro Estrugo <ramiro@fateware.com>
+
+ * 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 GNOME1 and GNOME2 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 (GNOME1 and GNOME2 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 gnome_program_init() thing for now.
+ Currently the gnome_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 gnome_program_init ()
+ function is fixed or we learn how to use it properly.
+
+2001-07-24 Ramiro Estrugo <ramiro@fateware.com>
+
+ 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 Nautilus or Eel since neither used
+ this function.
+
+2001-07-18 Darin Adler <darin@bentspoon.com>
+
+ * acconfig.h: Also need to add GNOME_EXPLICIT_TRANSLATION_DOMAIN
+ here for autoheader.
+
+2001-07-17 Darin Adler <darin@bentspoon.com>
+
+ * configure.in: Add GNOME_EXPLICIT_TRANSLATION_DOMAIN so messages
+ withing eel get translated properly.
+
+2001-07-17 Darin Adler <darin@bentspoon.com>
+
+ * 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 gnome_program_init correctly.
+ * test/test-eel-password-dialog.c: (main): Use gnome_program_init
+ correctly.
+ * test/test-eel-widgets.c: (main): Use gnome_program_init
+ correctly.
+
+2001-07-16 Darin Adler <darin@bentspoon.com>
+
+ * eel/eel-self-checks.c: (eel_check_string_list_result):
+ Fix place where I called the wrong function.
+
+2001-07-15 Darin Adler <darin@bentspoon.com>
+
+ * eel/check-program.c: (main): Fix up init calls. I am still quite
+ confused about how to use gnome_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 <darin@bentspoon.com>
+
+ * eel/check-program.c:
+ * eel/eel-xml-extensions.c:
+ * eel/eel-xml-extensions.h:
+ Fix gnome-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 <darin@bentspoon.com>
+
+ 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 <darin@bentspoon.com>
+
+ 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 <darin@bentspoon.com>
+
+ A cut at making things compile with GNOME 2.
+ Some things are inside #ifdef GNOME2_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-gnome-extensions.c: (eel_dialog_get_button_by_index),
+ (get_terminal_command_prefix), (eel_gnome_icon_selector_new),
+ (eel_gnome_stock_set_icon_or_register):
+ * eel/eel-gnome-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 <darin@bentspoon.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * .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-gconf-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 GNOME2, part 1. Make configure work in the GNOME2
+ universe and also a few simple s/BEGIN_GNOME_DECLS/G_BEGIN_DECLS/
+
+2001-07-09 Ramiro Estrugo <ramiro@fateware.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * configure.in: Bumped version to 1.0.1
+ * NEWS: Some notes about recent changes.
+
+2001-06-26 Alexander Larsson <alla@lysator.liu.se>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ Patch from Frederic Devernay <Frederic.Devernay@sophia.inria.fr>
+ (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 <darin@bentspoon.com>
+
+ Integrated a revised version of a patch by Eungkyu Song
+ <eungkyu@sparcs.org> 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 <alexl@redhat.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 <ramiro@fateware.com>
+
+ * 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 Nautilus 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 <darin@bentspoon.com>
+
+ * 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 gnome_vfs_get_uri_from_local_path instead.
+
+2001-06-01 Alex Larsson <alexl@redhat.com>
+
+ * 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 <darin@bentspoon.com>
+
+ * configure.in: Bump version number to 1.0.0.1
+ * NEWS: Mention the plans to release 1.0.1
+
+2001-06-01 Darin Adler <darin@bentspoon.com>
+
+ * 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 Nautilus list view. Also did some other
+ cleanups to behavior when multiple buttons are pressed at once.
+
+2001-05-22 John Harper <jsh@pixelslut.com>
+
+ 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 <darin@eazel.com>
+
+ Checked in change for Miguel Rodríguez Pérez
+ <migras@atlas.uvigo.es>.
+
+ * 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 <jirka@5z.com>
+
+ * configure.in, po/cs.po: Add czech translations
+
+2001-05-17 Darin Adler <darin@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * RENAMING: Refine the renaming ideas.
+
+==== eel 1.0 ====
+
+2001-05-04 Robin * Slomkowski <rslomkow@rslomkow.org>
+
+ * configure.in: fixed lirsvg test for 1.0.x
+
+2001-05-04 Robin * Slomkowski <rslomkow@rslomkow.org>
+
+ * configure.in: upped version to 1.0 and changed upped
+ dependance too librsvg 1.0.0
+
+2001-05-04 Robin * Slomkowski <rslomkow@rslomkow.org>
+
+ * configure.in: upped version to 0.1
+
+2001-05-04 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel/eel-preferences-item.c:
+ (preferences_item_create_editable_string):
+ Restore a silly hack for the sake of Nautilus. Id like to
+ properly fix this, but not so close to a release.
+
+2001-05-04 Ramiro Estrugo <ramiro@eazel.com>
+
+ * configure.in:
+ Add GConf and OAF dependency.
+
+ * eel.spec.in:
+ Add GConf 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-gconf-extensions.c:
+ * eel/eel-gconf-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 Nautilus.
+
+2001-05-03 Darin Adler <darin@eazel.com>
+
+ * RENAMING: Some renaming ideas.
+
+2001-05-03 Darin Adler <darin@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 Nautilus.
+
+ * 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 <darin@eazel.com>
+
+ 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * test/Makefile.am:
+ Add include flag for test directory.
+
+2001-05-01 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * eel/Makefile.am:
+ Remove some garbage that apparently satan tried to sneak in.
+
+2001-04-30 Darin Adler <darin@eazel.com>
+
+ reviewed by: John Sullivan <sullivan@eazel.com>
+
+ Fixed bug 8198 ("New Terminal" does not use GNOME default
+ applications). This involved changing the API, so it requires
+ changes to Nautilus 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-gnome-extensions.h:
+ * eel/eel-gnome-extensions.c: (try_terminal_command),
+ (try_terminal_command_argv), (get_terminal_command_prefix): New
+ functions, used to implement eel_gnome_open_terminal. These look
+ at the gnome-config setting that controls which terminal program
+ is used.
+ (eel_gnome_make_terminal_command): New public function. We've now
+ eliminated the concept of just getting the name of a terminal
+ program.
+ (eel_gnome_open_terminal): Use eel_gnome_make_terminal_command to
+ do the hard part.
+
+2001-04-30 John Sullivan <sullivan@eazel.com>
+
+ Fixed bug 6234 (Escape should close Properties window)
+ Fixed bug 6271 (Close dialogs with Escape to match GNOME standard)
+
+ * eel/eel-gtk-extensions.c:
+ (eel_gtk_window_event_is_close_accelerator): Close dialogs with
+ Escape as well as Control-W. (non-GnomeDialogs 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 <ramiro@eazel.com>
+
+ * 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-gnome-extensions.c:
+ * eel/eel-gnome-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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <sullivan@eazel.com>
+
+ * 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 <sullivan@eazel.com>
+
+ Merged from nautilus-1 branch:
+
+ 2001-03-30 Ramiro Estrugo <ramiro@eazel.com>
+
+ reviewed by: John Harper <jsh@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * 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-gnome-extensions.c: Formatting tweaks.
+
+2001-04-26 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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):
+ Nautilus 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 <ramiro@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ reviewed by: Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel/eel-debug.c:
+ (eel_make_warnings_and_criticals_stop_in_debugger):
+ Add more log domains, most importantly "".
+
+2001-04-20 John Harper <jsh@eazel.com>
+
+ reviewed by: Darin Adler <darin@eazel.com>
+
+ * eel/eel-gnome-extensions.h, eel/eel-gnome-extensions.c
+ (eel_gnome_win_hints_get_area,
+ eel_gnome_win_hints_get_current_area,
+ eel_gnome_win_hints_set_area,
+ eel_gnome_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 <jacob@ximian.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * eel/eel-font-manager.c: (try_using_font_server):
+ Remove printf left in by accident.
+
+2001-04-20 Ramiro Estrugo <ramiro@eazel.com>
+
+ 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * configure.in:
+ Use /usr/X instead of /usr/openwin which is the new way on
+ solaris.
+
+2001-04-20 Ramiro Estrugo <ramiro@eazel.com>
+
+ 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ reviewed by: Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ reviewed by: Darin Adler <darin@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * eel/eel-canvas-rect.c: (rect_update): Fixed backwards logic that
+ made it never draw the outline.
+
+2001-04-18 Darin Adler <darin@eazel.com>
+
+ * 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 GnomeCanvas 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 <clahey@ximian.com>
+
+ * 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 <darin@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * 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 <clahey@ximian.com>
+
+ * eel/eel-canvas-rect.c: Added some tests #ifdefed out. Wrote the
+ diff and intersection functions.
+
+2001-04-18 Darin Adler <darin@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * 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 Nautilus much faster.
+
+2001-04-18 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel/Makefile.am: Add the generated files to the CLEANFILES so
+ that 'make clean' gets rid of them properly.
+
+2001-04-18 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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
+ Nautilus style some more.
+
+2001-04-17 Darin Adler <darin@eazel.com>
+
+ * eel/Makefile.am:
+ * eel/eel.h:
+ Take eel-dnd.h out. This should go back to Nautilus at some
+ point, I think.
+
+ * eel/eel-dnd.h:
+ * eel/eel-dnd.c:
+ (is_path_that_gnome_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 <ramiro@eazel.com>
+
+ * 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 <darin@eazel.com>
+
+ * eel/eel-dnd.c: (add_one_path_with_file_prefix): Coddle existing
+ drag and drop recipients who use the gnome-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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 nautilus style more.
+
+2001-04-16 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <mjs@eazel.com>
+
+ * eel/Makefile.am: Fix `make distcheck'.
+
+2001-04-16 Darin Adler <darin@eazel.com>
+
+ * eel/Makefile.am: Remove stray reference to eel-boxed.defs
+ that was making the Tinderbox unhappy.
+
+2001-04-16 Maciej Stachowiak <mjs@eazel.com>
+
+ * 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 gnome do. This is needed for language bindings.
+
+2001-04-13 Pavel Cisler <pavel@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * eel/check-program.c: (main):
+ * eel/eel-glib-extensions.c: (eel_g_hash_table_new_free_at_exit):
+ Use NAUTILUS_DEBUG, not EEL_DEBUG for now.
+
+ * eel/eel-font-manager.c: (ensure_local_font_table):
+ Use ~/.nautilus instead of ~/.eel for compatibility.
+
+2001-04-09 Pavel Cisler <pavel@eazel.com>
+
+ reviewed by: Mike Engber <engber@eazel.com>
+
+ * 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 <sullivan@eazel.com>
+
+ reviewed by: Pavel Cisler <pavel@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 <andy@eazel.com>
+
+ * 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 <pavel@eazel.com>
+
+ reviewed by: John Harper <jsh@eazel.com>
+
+ 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 <pavel@eazel.com>
+
+ * eel/Makefile.am:
+ More fixes to not pick up libraries from /usr/lib first.
+ Checking in for Ramiro.
+
+2001-04-05 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel/Makefile.am:
+ Put freettype and png libs at end of link line to prevent /usr/lib conflict.
+
+2001-04-05 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 <ramiro@eazel.com>
+
+ * 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 Nautilus.
+
+2001-04-04 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel.spec.in:
+ Fix a dumb mistake in how the date was specified.
+
+2001-04-04 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 gnome-vfs extensions over from
+ nautilus/nautilus-file-utilities.[ch]
+
+2001-04-04 Ramiro Estrugo <ramiro@eazel.com>
+
+ * HACKING:
+ * README:
+ * RENAMING:
+ * THANKS:
+ Updated to be Eel specific. Removed crufy leftover from Nautilus
+ move.
+
+ * configure.in:
+ * eel.spec.in:
+ Remove unused popt and imlib depenencies.
+
+2001-04-04 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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-gnome-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 <darin@eazel.com>
+
+ 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 <ramiro@eazel.com>
+
+ * eel/eel-ellipsizing-label.c: (recompute_ellipsized_text):
+ Synchronize with Nautilus (for the last time hopefully).
+
+2001-04-02 Ramiro Estrugo <ramiro@eazel.com>
+
+ * test/test-eel-label.c:
+ * test/test.h:
+ Remove rogue unused #includes.
+
+2001-04-02 Ramiro Estrugo <ramiro@eazel.com>
+
+ * configure.in:
+ Stuff that goes in eelConf.sh was missing.
+
+2001-04-02 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel-config.in:
+ * eelConf.sh.in:
+ Eelify.
+
+2001-04-02 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel/check-eel:
+ Run checks with --sm-disable so that the session manager will not
+ hang and show dialogs.
+
+2001-04-02 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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 Nautilus.
+
+2001-04-02 Ramiro Estrugo <ramiro@eazel.com>
+
+ * 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-gnome-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 nautilus.
+
+2001-03-28 Ramiro Estrugo <ramiro@eazel.com>
+
+ * eel.spec.in:
+ First pass at making the spec file valid.
+
+2001-03-28 Ramiro Estrugo <ramiro@eazel.com>
+
+ * Makefile.am:
+ * acconfig.h:
+ * configure.in:
+ Remove more Nautilus cruft. Make distcheck now passes.
+
+2001-03-28 Ramiro Estrugo <ramiro@eazel.com>
+
+ Change 'nautilus' 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-gnome-extensions.c:
+ (eel_gnome_canvas_world_to_window_rectangle),
+ (eel_gnome_canvas_world_to_canvas_rectangle),
+ (eel_gnome_canvas_item_get_current_canvas_bounds),
+ (eel_gnome_canvas_item_request_redraw),
+ (eel_gnome_canvas_request_redraw_rectangle),
+ (eel_gnome_canvas_item_get_world_bounds),
+ (eel_gnome_canvas_item_get_canvas_bounds),
+ (eel_gnome_canvas_draw_pixbuf_helper),
+ (eel_gnome_canvas_draw_pixbuf_helper_alpha),
+ (eel_gnome_canvas_draw_pixbuf), (eel_gnome_canvas_fill_rgb),
+ (eel_gnome_dialog_get_button_by_index),
+ (eel_gnome_canvas_item_request_update_deep),
+ (eel_gnome_canvas_request_update_all),
+ (eel_gnome_canvas_set_scroll_region),
+ (eel_gnome_canvas_set_scroll_region_left_justify),
+ (eel_gnome_canvas_set_scroll_region_include_visible_area),
+ (eel_gnome_shell_execute), (eel_gnome_get_terminal_path),
+ (eel_gnome_open_terminal), (icon_selected_callback),
+ (eel_gnome_icon_selector_new),
+ (eel_gnome_stock_set_icon_or_register):
+ * eel/eel-gnome-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 <ramiro@eazel.com>
+
+ Started ChangeLog
+
+# Local Variables:
+# coding: utf-8
+# End:
diff --git a/eel/Makefile.am b/eel/Makefile.am
new file mode 100644
index 000000000..2e89dd78d
--- /dev/null
+++ b/eel/Makefile.am
@@ -0,0 +1,188 @@
+NULL=
+
+noinst_LTLIBRARIES=libeel-2.la
+
+INCLUDES = \
+ -DG_LOG_DOMAIN=\"Eel\" \
+ -I$(top_srcdir) \
+ $(CORE_CFLAGS) \
+ -DDATADIR=\""$(datadir)"\" \
+ -DSOURCE_DATADIR=\""$(top_srcdir)/data"\" \
+ -DGNOMELOCALEDIR=\""$(prefix)/${DATADIRNAME}/locale"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGDK_PIXBUF_DISABLE_DEPRECATED \
+ -DGMENU_I_KNOW_THIS_IS_UNSTABLE \
+ $(NULL)
+
+libeel_2_la_LDFLAGS = \
+ -version-info @EEL_VERSION_INFO@ \
+ -no-undefined \
+ $(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-gconf-extensions.c \
+ eel-gdk-extensions.c \
+ eel-gdk-pixbuf-extensions.c \
+ eel-glib-extensions.c \
+ eel-gnome-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)
+
+libeelincludedir = $(includedir)/eel-2/eel
+
+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-gconf-extensions.h \
+ eel-gdk-extensions.h \
+ eel-gdk-pixbuf-extensions.h \
+ eel-glib-extensions.h \
+ eel-gnome-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)
+
+libeelinclude_HEADERS = \
+ $(eel_headers) \
+ eel-type-builtins.h \
+ eel-marshal.h \
+ $(NULL)
+
+marshal_sources = \
+ eel-marshal.h \
+ eel-marshal.c \
+ $(NULL)
+
+eel-marshal.h: eelmarshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=eel_marshal > $@
+eel-marshal.c: eelmarshal.list $(GLIB_GENMARSHAL)
+ $(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)
+ $(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 = \
+ 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 000000000..15d86bbad
--- /dev/null
+++ b/eel/README
@@ -0,0 +1,4 @@
+README for eel/eel
+
+Writeme
+
diff --git a/eel/README.canvas b/eel/README.canvas
new file mode 100644
index 000000000..86103774e
--- /dev/null
+++ b/eel/README.canvas
@@ -0,0 +1,25 @@
+eel-canvas is a cut-and-pasted version of some parts foo-canvas.
+Please do not change the cut and pasted parts. If you need to
+upgrade to a new foo-canvas, use this:
+
+FOODIR=../../foocanvas/libfoocanvas
+
+cp $FOODIR/foo-canvas.c eel-canvas.c
+cp $FOODIR/foo-canvas.h eel-canvas.h
+cp $FOODIR/foo-canvas-util.c eel-canvas-util.c
+cp $FOODIR/foo-canvas-util.h eel-canvas-util.h
+cp $FOODIR/foo-canvas-rect-ellipse.h eel-canvas-rect-ellipse.h
+cp $FOODIR/foo-canvas-rect-ellipse.c eel-canvas-rect-ellipse.c
+
+perl -pi -e 's/foo_canvas_marshal_/eel_marshal_/s' eel-canvas.c
+perl -pi -e 's/foo-canvas-marshal\.h/eel-marshal\.h/s' eel-canvas.c
+perl -pi -e 's/#include\ \"foo-canvas-marshal\.c\"//s' eel-canvas.c
+perl -pi -e 's/foo-canvas-i18n\.h/eel-i18n\.h/s' eel-canvas.c
+
+perl -pi -e 's/foo_canvas_/eel_canvas_/g' eel-canvas*.[ch]
+perl -pi -e 's/FOO_CANVAS/EEL_CANVAS/g' eel-canvas*.[ch]
+perl -pi -e 's/FooCanvas/EelCanvas/g' eel-canvas*.[ch]
+perl -pi -e 's/foo-canvas/eel-canvas/g' eel-canvas*.[ch]
+perl -pi -e 's/libfoocanvas/eel/g' eel-canvas*.[ch]
+perl -pi -e 's/FOO_TYPE_/EEL_TYPE_/g' eel-canvas*.[ch]
+perl -pi -e 's/FOO_IS_/EEL_IS_/g' eel-canvas*.[ch]
diff --git a/eel/check-eel b/eel/check-eel
new file mode 100755
index 000000000..d1c67b62e
--- /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 000000000..e5d58ec77
--- /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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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 000000000..71fd7761a
--- /dev/null
+++ b/eel/eel-accessibility.c
@@ -0,0 +1,413 @@
+/* -*- 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 <andersca@gnu.org>
+ Michael Meeks <michael@ximian.com>
+*/
+#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. NautilusIconCanvasItemAccessible
+ * @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 GNOME_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 (object)->widget);
+ } 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 000000000..72db9781d
--- /dev/null
+++ b/eel/eel-accessibility.h
@@ -0,0 +1,152 @@
+/* -*- 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 <andersca@gnu.org>
+*/
+
+#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 000000000..9813fd99a
--- /dev/null
+++ b/eel/eel-alert-dialog.c
@@ -0,0 +1,467 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-alert-dialog.c: An HIG compliant alert dialog.
+
+ The Gnome 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 Gnome 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 Gnome 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 (dialog)->vbox), 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 (dialog)->vbox), 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 (EEL_ALERT_DIALOG (widget)->details->image->parent);
+
+ 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 000000000..d0a253462
--- /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 Gnome 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 Gnome 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 Gnome 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 000000000..a74ccab07
--- /dev/null
+++ b/eel/eel-art-extensions.c
@@ -0,0 +1,308 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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 000000000..ad9e9e517
--- /dev/null
+++ b/eel/eel-art-extensions.h
@@ -0,0 +1,111 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#ifndef EEL_ART_EXTENSIONS_H
+#define EEL_ART_EXTENSIONS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+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);
+
+
+G_END_DECLS
+
+#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 000000000..73d92079f
--- /dev/null
+++ b/eel/eel-art-gtk-extensions.c
@@ -0,0 +1,313 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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);
+ gdk_drawable_get_size (gdk_window, &width, &height);
+
+ 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;
+ }
+
+ gdk_drawable_get_size (gdk_window, &width, &height);
+
+ 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)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (gtk_widget), eel_irect_empty);
+
+ return eel_irect_assign (gtk_widget->allocation.x,
+ gtk_widget->allocation.y,
+ (int) gtk_widget->allocation.width,
+ (int) gtk_widget->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;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (gtk_widget), eel_dimensions_empty);
+
+ dimensions.width = (int) gtk_widget->allocation.width;
+ dimensions.height = (int) gtk_widget->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);
+
+ gdk_drawable_get_size (gdk_window, &dimensions.width, &dimensions.height);
+
+ 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 000000000..6b0704d3d
--- /dev/null
+++ b/eel/eel-art-gtk-extensions.h
@@ -0,0 +1,70 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+/* 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>
+
+G_BEGIN_DECLS
+
+/* 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);
+
+G_END_DECLS
+
+#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 000000000..a577bebcb
--- /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 Gnome 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 Gnome 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 Gnome 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 <dave@ximian.com>
+*/
+
+#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 (widget)->child,
+ 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 000000000..239858d6f
--- /dev/null
+++ b/eel/eel-background-box.h
@@ -0,0 +1,61 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <dave@ximian.com>
+*/
+
+#ifndef EEL_BACKGROUND_BOX_H
+#define EEL_BACKGROUND_BOX_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EEL_TYPE_BACKGROUND_BOX (eel_background_box_get_type ())
+#define EEL_BACKGROUND_BOX(obj) (GTK_CHECK_CAST ((obj), EEL_TYPE_BACKGROUND_BOX, EelBackgroundBox))
+#define EEL_BACKGROUND_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_BACKGROUND_BOX, EelBackgroundBoxClass))
+#define EEL_IS_BACKGROUND_BOX(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_BACKGROUND_BOX))
+#define EEL_IS_BACKGROUND_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_BACKGROUND_BOX))
+
+typedef struct EelBackgroundBox EelBackgroundBox;
+typedef struct EelBackgroundBoxClass EelBackgroundBoxClass;
+typedef struct EelBackgroundBoxDetails EelBackgroundBoxDetails;
+
+struct EelBackgroundBox
+{
+ /* Superclass */
+ GtkEventBox event_box;
+};
+
+struct EelBackgroundBoxClass
+{
+ GtkEventBoxClass parent_class;
+};
+
+GtkType eel_background_box_get_type (void);
+GtkWidget *eel_background_box_new (void);
+
+G_END_DECLS
+
+#endif /* EEL_BACKGROUND_TABLE_H */
+
+
diff --git a/eel/eel-background.c b/eel/eel-background.c
new file mode 100644
index 000000000..c2348c9ca
--- /dev/null
+++ b/eel/eel-background.c
@@ -0,0 +1,933 @@
+/* -*- 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 <darin@eazel.com>
+*/
+
+#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-gnome-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 <gio/gio.h>
+#include <math.h>
+#include <stdio.h>
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnomeui/gnome-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,
+ gboolean *changes_with_size);
+static void set_image_properties (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;
+
+ GnomeBG *bg;
+
+ /* Realized data: */
+ gboolean background_changes_with_size;
+ GdkPixmap *background_pixmap;
+ 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;
+ /* Can we use common pixmap for root window and desktop window */
+ gboolean use_common_pixmap;
+};
+
+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 (GnomeBG *bg, EelBackground *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 = gnome_bg_new ();
+
+ g_signal_connect (background->details->bg, "changed",
+ G_CALLBACK (on_bg_changed), 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
+eel_background_finalize (GObject *object)
+{
+ EelBackground *background;
+
+ background = EEL_BACKGROUND (object);
+
+ g_free (background->details->color);
+ eel_background_remove_current_image (background);
+
+ if (background->details->background_pixmap != NULL) {
+ g_object_unref (background->details->background_pixmap);
+ background->details->background_pixmap = NULL;
+ }
+
+ g_free (background->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static EelBackgroundImagePlacement
+placement_gnome_to_eel (GnomeBGPlacement p)
+{
+ switch (p) {
+ case GNOME_BG_PLACEMENT_CENTERED:
+ return EEL_BACKGROUND_CENTERED;
+ case GNOME_BG_PLACEMENT_FILL_SCREEN:
+ return EEL_BACKGROUND_SCALED;
+ case GNOME_BG_PLACEMENT_SCALED:
+ return EEL_BACKGROUND_SCALED_ASPECT;
+ case GNOME_BG_PLACEMENT_ZOOMED:
+ return EEL_BACKGROUND_ZOOM;
+ case GNOME_BG_PLACEMENT_TILED:
+ return EEL_BACKGROUND_TILED;
+ }
+
+ return EEL_BACKGROUND_TILED;
+}
+
+static GnomeBGPlacement
+placement_eel_to_gnome (EelBackgroundImagePlacement p)
+{
+ switch (p) {
+ case EEL_BACKGROUND_CENTERED:
+ return GNOME_BG_PLACEMENT_CENTERED;
+ case EEL_BACKGROUND_SCALED:
+ return GNOME_BG_PLACEMENT_FILL_SCREEN;
+ case EEL_BACKGROUND_SCALED_ASPECT:
+ return GNOME_BG_PLACEMENT_SCALED;
+ case EEL_BACKGROUND_ZOOM:
+ return GNOME_BG_PLACEMENT_ZOOMED;
+ case EEL_BACKGROUND_TILED:
+ return GNOME_BG_PLACEMENT_TILED;
+ }
+
+ return GNOME_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_gnome_to_eel (gnome_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));
+
+ gnome_bg_set_placement (background->details->bg,
+ placement_eel_to_gnome (new_placement));
+}
+
+EelBackground *
+eel_background_new (void)
+{
+ return EEL_BACKGROUND (g_object_new (EEL_TYPE_BACKGROUND, NULL));
+}
+
+static void
+eel_background_unrealize (EelBackground *background)
+{
+ if (background->details->background_pixmap != NULL) {
+ g_object_unref (background->details->background_pixmap);
+ background->details->background_pixmap = NULL;
+ }
+ 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.
+ */
+ gdk_drawable_get_size (drawable, width, height);
+
+ 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 pixmap doesn't change with the window size, never update
+ * it again.
+ */
+ if (background->details->background_pixmap != NULL &&
+ !background->details->background_changes_with_size) {
+ return FALSE;
+ }
+
+ /* 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;
+ }
+
+ if (background->details->background_pixmap != NULL) {
+ g_object_unref (background->details->background_pixmap);
+ background->details->background_pixmap = NULL;
+ }
+
+ changed = FALSE;
+
+ set_image_properties (background);
+
+ background->details->background_changes_with_size = gnome_bg_changes_with_size (background->details->bg);
+ background->details->background_pixmap = gnome_bg_create_pixmap (background->details->bg,
+ window,
+ entire_width, entire_height,
+ background->details->is_desktop);
+
+ changed = TRUE;
+
+
+ background->details->background_entire_width = entire_width;
+ background->details->background_entire_height = entire_height;
+
+ return changed;
+}
+
+static GdkPixmap *
+eel_background_get_pixmap_and_color (EelBackground *background,
+ GdkWindow *window,
+ GdkColor *color,
+ gboolean *changes_with_size)
+{
+ 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;
+ *changes_with_size = background->details->background_changes_with_size;
+
+ 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;
+ gboolean changes_with_size;
+ GdkPixmap *pixmap;
+ GdkGC *gc;
+ GdkGCValues gc_values;
+ GdkGCValuesMask value_mask;
+
+ EelBackground *background;
+
+ 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,
+ &changes_with_size);
+
+ if (!changes_with_size) {
+ /* The background was already drawn by X, since we set
+ * the GdkWindow background/back_pixmap.
+ * No need to draw it again. */
+ if (pixmap) {
+ g_object_unref (pixmap);
+ }
+ return;
+ }
+
+ 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)
+{
+ if (!background->details->color) {
+ gnome_bg_set_color (background->details->bg, GNOME_BG_COLOR_SOLID,
+ &background->details->default_color, NULL);
+ } else if (!eel_gradient_is_gradient (background->details->color)) {
+ GdkColor c;
+
+ eel_gdk_color_parse_with_white_default (background->details->color, &c);
+
+ gnome_bg_set_color (background->details->bg, GNOME_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);
+ g_free (spec);
+
+ spec = eel_gradient_get_end_color_spec (background->details->color);
+ eel_gdk_color_parse_with_white_default (spec, &c2);
+ g_free (spec);
+
+ if (eel_gradient_is_horizontal (background->details->color))
+ gnome_bg_set_color (background->details->bg, GNOME_BG_COLOR_H_GRADIENT, &c1, &c2);
+ else
+ gnome_bg_set_color (background->details->bg, GNOME_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 = gnome_bg_get_filename (background->details->bg);
+
+ return g_filename_to_uri (filename, NULL, 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;
+ }
+
+ gnome_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
+ || gnome_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
+eel_background_set_up_widget (EelBackground *background, GtkWidget *widget)
+{
+ GtkStyle *style;
+ GdkPixmap *pixmap;
+ GdkPixmap *root_pixmap;
+ GdkColor color;
+
+ int window_width;
+ int window_height;
+
+ GdkWindow *window;
+ gboolean changes_with_size;
+
+ if (!GTK_WIDGET_REALIZED (widget)) {
+ return;
+ }
+
+ drawable_get_adjusted_size (background, widget->window, &window_width, &window_height);
+
+ pixmap = eel_background_get_pixmap_and_color (background,
+ widget->window,
+ &color,
+ &changes_with_size);
+
+ style = gtk_widget_get_style (widget);
+
+ gdk_rgb_find_color (style->colormap, &color);
+
+ if (EEL_IS_CANVAS (widget)) {
+ window = GTK_LAYOUT (widget)->bin_window;
+ } else {
+ window = widget->window;
+ }
+
+ if (!changes_with_size || background->details->is_desktop) {
+ gdk_window_set_back_pixmap (window, pixmap, FALSE);
+ } else {
+ gdk_window_set_back_pixmap (window, NULL, FALSE);
+ gdk_window_set_background (window, &color);
+ }
+
+
+ background->details->background_changes_with_size =
+ gnome_bg_changes_with_size (background->details->bg);
+
+ if (background->details->is_desktop) {
+
+ root_pixmap = NULL;
+
+ if (background->details->use_common_pixmap) {
+ root_pixmap = g_object_ref (pixmap);
+ } else {
+ root_pixmap = gnome_bg_create_pixmap (background->details->bg, window,
+ window_width, window_height, TRUE);
+ }
+
+ gnome_bg_set_pixmap_as_root (gdk_drawable_get_screen (window), root_pixmap);
+ g_object_unref (root_pixmap);
+ }
+
+ if (pixmap) {
+ g_object_unref (pixmap);
+ }
+}
+
+static void
+eel_widget_background_changed (GtkWidget *widget, EelBackground *background)
+{
+ eel_background_unrealize (background);
+ eel_background_set_up_widget (background, widget);
+
+ gtk_widget_queue_draw (widget);
+}
+
+/* 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);
+
+ eel_widget_background_changed (widget, background);
+}
+
+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);
+
+ root_window = gdk_screen_get_root_window(screen);
+
+ if (gdk_drawable_get_visual (root_window) == gtk_widget_get_visual (widget)) {
+ background->details->use_common_pixmap = TRUE;
+ } else {
+ background->details->use_common_pixmap = FALSE;
+ }
+ }
+}
+
+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;
+ }
+ 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_REALIZED(widget) && background->details->is_desktop) {
+ widget_realized_setup (widget, background);
+ }
+
+}
+
+gboolean
+eel_background_is_desktop (EelBackground *background)
+{
+ return background->details->is_desktop;
+}
+
+/* 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 (background);
+ gtk_object_sink (GTK_OBJECT (background));
+ g_object_set_data_full (G_OBJECT (widget), "eel_background",
+ background, g_object_unref);
+
+ /* Arrange to get the signal whenever the background changes. */
+ g_signal_connect_object (background, "appearance_changed",
+ G_CALLBACK (eel_widget_background_changed), widget, G_CONNECT_SWAPPED);
+ eel_widget_background_changed (widget, background);
+
+ 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)
+{
+ return gnome_bg_is_dark (background->details->bg);
+}
+
+/* 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;
+
+ 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 (selection_data->length != 8 || selection_data->format != 16) {
+ g_warning ("received invalid color data");
+ return;
+ }
+ channels = (guint16 *) selection_data->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.
+ */
+ left_border = 32;
+ right_border = widget->allocation.width - 32;
+ top_border = 32;
+ bottom_border = widget->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_gconf (EelBackground *background)
+{
+ GConfClient *client = gconf_client_get_default ();
+
+ if (background->details->bg)
+ gnome_bg_save_to_preferences (background->details->bg, client);
+}
+
+/* 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");
+
+ gtk_object_sink (GTK_OBJECT (background));
+}
+
+#endif
diff --git a/eel/eel-background.h b/eel/eel-background.h
new file mode 100644
index 000000000..d2fff5139
--- /dev/null
+++ b/eel/eel-background.h
@@ -0,0 +1,155 @@
+/* -*- 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 <darin@eazel.com>
+*/
+
+#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) \
+ (GTK_CHECK_CAST ((obj), EEL_TYPE_BACKGROUND, EelBackground))
+#define EEL_BACKGROUND_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_BACKGROUND, EelBackgroundClass))
+#define EEL_IS_BACKGROUND(obj) \
+ (GTK_CHECK_TYPE ((obj), EEL_TYPE_BACKGROUND))
+#define EEL_IS_BACKGROUND_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_BACKGROUND))
+
+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
+} EelBackgroundImagePlacement;
+
+GtkType 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_gconf (EelBackground *background);
+
+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 000000000..fe86f625b
--- /dev/null
+++ b/eel/eel-canvas-rect-ellipse.c
@@ -0,0 +1,1489 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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 Gnome 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 Gnome 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 <federico@nuclecu.unam.mx>
+ */
+
+#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 *class);
+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 *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ EelCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (EelCanvasItemClass *) class;
+
+ re_parent_class = g_type_class_peek_parent (class);
+
+ 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_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y1,
+ g_param_spec_double ("y1", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X2,
+ g_param_spec_double ("x2", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y2,
+ g_param_spec_double ("y2", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR,
+ g_param_spec_string ("fill_color", NULL, NULL,
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ 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_READABLE | G_PARAM_WRITABLE)));
+ 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_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_STIPPLE,
+ g_param_spec_object ("fill_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_OUTLINE_COLOR,
+ g_param_spec_string ("outline_color", NULL, NULL,
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ 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_READABLE | G_PARAM_WRITABLE)));
+ 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_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_OUTLINE_STIPPLE,
+ g_param_spec_object ("outline_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH_PIXELS,
+ g_param_spec_uint ("width_pixels", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ 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_READABLE | G_PARAM_WRITABLE)));
+
+ 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_assert (object != NULL);
+ g_assert (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_assert (object != NULL);
+ g_assert (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_assert (object != NULL);
+ g_assert (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 (item->canvas->layout.bin_window);
+ re->fill_pixel = eel_canvas_get_color_pixel (item->canvas, re->fill_color);
+ re->outline_gc = gdk_gc_new (item->canvas->layout.bin_window);
+ 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 *class);
+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 *class)
+{
+ EelCanvasItemClass *item_class;
+
+ rect_parent_class = g_type_class_peek_parent (class);
+
+ item_class = (EelCanvasItemClass *) class;
+
+ 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 (class)->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;
+
+ priv = EEL_CANVAS_RECT (item)->priv;
+
+ priv->use_render = XRenderQueryExtension (gdk_display, &event_base, &error_base);
+
+ if (priv->use_render) {
+ Display *dpy;
+ GdkVisual *gdk_visual;
+ Visual *visual;
+
+ dpy = gdk_x11_drawable_get_xdisplay (GTK_WIDGET (item->canvas)->window);
+ 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 *class);
+
+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 *class)
+{
+ EelCanvasItemClass *item_class;
+
+ item_class = (EelCanvasItemClass *) class;
+
+ 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 000000000..6535ddd73
--- /dev/null
+++ b/eel/eel-canvas-rect-ellipse.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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 Gnome 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 Gnome 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 <federico@nuclecu.unam.mx>
+ */
+
+#ifndef EEL_CANVAS_RECT_ELLIPSE_H
+#define EEL_CANVAS_RECT_ELLIPSE_H
+
+
+#include <eel/eel-canvas.h>
+
+G_BEGIN_DECLS
+
+
+/* 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) (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS_RE, EelCanvasRE))
+#define EEL_CANVAS_RE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_RE, EelCanvasREClass))
+#define EEL_IS_CANVAS_RE(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS_RE))
+#define EEL_IS_CANVAS_RE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_RE))
+#define EEL_CANVAS_RE_GET_CLASS(obj) (GTK_CHECK_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) (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS_RECT, EelCanvasRect))
+#define EEL_CANVAS_RECT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_RECT, EelCanvasRectClass))
+#define EEL_IS_CANVAS_RECT(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS_RECT))
+#define EEL_IS_CANVAS_RECT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_RECT))
+#define EEL_CANVAS_RECT_GET_CLASS(obj) (GTK_CHECK_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) (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS_ELLIPSE, EelCanvasEllipse))
+#define EEL_CANVAS_ELLIPSE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_ELLIPSE, EelCanvasEllipseClass))
+#define EEL_IS_CANVAS_ELLIPSE(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS_ELLIPSE))
+#define EEL_IS_CANVAS_ELLIPSE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_ELLIPSE))
+#define EEL_CANVAS_ELLIPSE_GET_CLASS(obj) (GTK_CHECK_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;
+
+
+G_END_DECLS
+
+#endif
diff --git a/eel/eel-canvas-util.c b/eel/eel-canvas-util.c
new file mode 100644
index 000000000..724af7670
--- /dev/null
+++ b/eel/eel-canvas-util.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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 Gnome 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 Gnome 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 <federico@nuclecu.unam.mx>
+ */
+
+#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;
+ 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 000000000..d3bd7014d
--- /dev/null
+++ b/eel/eel-canvas-util.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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 Gnome 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 Gnome 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 <federico@nuclecu.unam.mx>
+ */
+
+#ifndef EEL_CANVAS_UTIL_H
+#define EEL_CANVAS_UTIL_H
+
+
+G_BEGIN_DECLS
+
+
+/* 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);
+
+G_END_DECLS
+
+#endif
diff --git a/eel/eel-canvas.c b/eel/eel-canvas.c
new file mode 100644
index 000000000..15a20b93a
--- /dev/null
+++ b/eel/eel-canvas.c
@@ -0,0 +1,3979 @@
+/* -*- 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 Gnome Library.
+ *
+ * The Gnome 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 Gnome 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 Gnome 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 Gnome
+ *
+ * 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 <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@gimp.org>
+ */
+
+/*
+ * 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 *class);
+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) {
+ 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->object.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_assert (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_assert (EEL_IS_CANVAS_ITEM (gobject));
+
+ item = EEL_CANVAS_ITEM (gobject);
+
+ switch (param_id) {
+ case ITEM_PROP_VISIBLE:
+ g_value_set_boolean (value, item->object.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->object.flags & EEL_CANVAS_ITEM_MAPPED) {
+ eel_canvas_item_request_redraw (item);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/* Standard object dispose function for canvas items */
+static void
+eel_canvas_item_dispose (GObject *object)
+{
+ EelCanvasItem *item;
+
+ g_assert (EEL_IS_CANVAS_ITEM (object));
+
+ item = EEL_CANVAS_ITEM (object);
+
+ 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->object.flags & EEL_CANVAS_ITEM_MAPPED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
+
+ if (item->object.flags & EEL_CANVAS_ITEM_REALIZED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
+
+ if (item->parent)
+ group_remove (EEL_CANVAS_GROUP (item->parent), item);
+
+ 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->object.flags & EEL_CANVAS_ITEM_REALIZED))
+ (* EEL_CANVAS_ITEM_GET_CLASS (item->parent)->realize) (item->parent);
+
+ if (item->parent == NULL && !GTK_WIDGET_REALIZED (GTK_WIDGET (item->canvas)))
+ gtk_widget_realize (GTK_WIDGET (item->canvas));
+
+ GTK_OBJECT_SET_FLAGS (item, 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->object.flags & EEL_CANVAS_ITEM_MAPPED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
+
+ GTK_OBJECT_UNSET_FLAGS (item, EEL_CANVAS_ITEM_REALIZED);
+}
+
+/* Map handler for canvas items */
+static void
+eel_canvas_item_map (EelCanvasItem *item)
+{
+ GTK_OBJECT_SET_FLAGS (item, EEL_CANVAS_ITEM_MAPPED);
+}
+
+/* Unmap handler for canvas items */
+static void
+eel_canvas_item_unmap (EelCanvasItem *item)
+{
+ GTK_OBJECT_UNSET_FLAGS (item, 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)
+{
+ GTK_OBJECT_UNSET_FLAGS (item, EEL_CANVAS_ITEM_NEED_UPDATE);
+ GTK_OBJECT_UNSET_FLAGS (item, 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->object.flags & EEL_CANVAS_ITEM_NEED_UPDATE)
+ child_flags |= EEL_CANVAS_UPDATE_REQUESTED;
+
+ if (item->object.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_assert (!(item->object.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 (GTK_OBJECT_TYPE (item)));
+ return;
+ }
+
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->translate) (item, dx, dy);
+
+ if (item->object.flags & EEL_CANVAS_ITEM_MAPPED)
+ item->canvas->need_repick = TRUE;
+
+ if (!(item->object.flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
+ item->object.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->object.flags & EEL_CANVAS_ITEM_VISIBLE)) {
+ item->object.flags |= EEL_CANVAS_ITEM_VISIBLE;
+
+ if (!(item->object.flags & EEL_CANVAS_ITEM_REALIZED))
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
+
+ if (item->parent != NULL) {
+ if (!(item->object.flags & EEL_CANVAS_ITEM_MAPPED) &&
+ item->parent->object.flags & EEL_CANVAS_ITEM_MAPPED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item);
+ } else {
+ if (!(item->object.flags & EEL_CANVAS_ITEM_MAPPED) &&
+ GTK_WIDGET_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->object.flags & EEL_CANVAS_ITEM_VISIBLE) {
+ item->object.flags &= ~EEL_CANVAS_ITEM_VISIBLE;
+
+ redraw_and_repick_if_mapped (item);
+
+ if (item->object.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_MAPPED (item->canvas), GDK_GRAB_NOT_VIEWABLE);
+
+ if (item->canvas->grabbed_item)
+ return GDK_GRAB_ALREADY_GRABBED;
+
+ if (!(item->object.flags & EEL_CANVAS_ITEM_MAPPED))
+ return GDK_GRAB_NOT_VIEWABLE;
+
+ retval = gdk_pointer_grab (item->canvas->layout.bin_window,
+ 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 (GTK_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);
+ group_add (new_group, item);
+
+ /* Redraw and repick */
+
+ redraw_and_repick_if_mapped (item);
+
+ g_object_unref (GTK_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_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 (item->canvas)->bin_window;
+ 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 (item->canvas)->bin_window;
+ 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)
+{
+ g_return_if_fail (!item->canvas->doing_update);
+
+ if (item->object.flags & EEL_CANVAS_ITEM_NEED_UPDATE)
+ return;
+
+ item->object.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->object.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 *class);
+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) {
+ 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 *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ EelCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (EelCanvasItemClass *) class;
+
+ group_parent_class = gtk_type_class (eel_canvas_item_get_type ());
+
+ 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_READABLE | G_PARAM_WRITABLE)));
+ 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_READABLE | G_PARAM_WRITABLE)));
+
+ 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_assert (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->object.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)
+{
+ EelCanvasGroup *group;
+
+ g_assert (EEL_IS_CANVAS_GROUP (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_assert (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->object.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->object.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->object.flags & EEL_CANVAS_ITEM_VISIBLE &&
+ !(i->object.flags & EEL_CANVAS_ITEM_MAPPED)) {
+ if (!(i->object.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->object.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->object.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->object.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;
+}
+
+static 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->object.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->object.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)
+{
+ g_object_ref (GTK_OBJECT (item));
+ gtk_object_sink (GTK_OBJECT (item));
+
+ 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->object.flags & EEL_CANVAS_ITEM_VISIBLE &&
+ group->item.object.flags & EEL_CANVAS_ITEM_MAPPED) {
+ if (!(item->object.flags & EEL_CANVAS_ITEM_REALIZED))
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
+
+ if (!(item->object.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_assert (EEL_IS_CANVAS_GROUP (group));
+ g_assert (EEL_IS_CANVAS_ITEM (item));
+
+ for (children = group->item_list; children; children = children->next)
+ if (children->data == item) {
+ if (item->object.flags & EEL_CANVAS_ITEM_MAPPED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
+
+ if (item->object.flags & EEL_CANVAS_ITEM_REALIZED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
+
+ /* Unparent the child */
+
+ item->parent = NULL;
+ g_object_unref (GTK_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 *class);
+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) {
+ 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 (canvas->layout.hadjustment,
+ "value_changed",
+ G_CALLBACK (eel_canvas_accessible_adjustment_changed),
+ obj);
+ g_signal_connect (canvas->layout.vadjustment,
+ "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 = accessible->widget;
+ if (widget == NULL) {
+ /* State is defunct */
+ return 0;
+ }
+
+ g_assert (EEL_IS_CANVAS (widget));
+
+ canvas = EEL_CANVAS (widget);
+ root_group = eel_canvas_root (canvas);
+ g_assert (root_group != NULL);
+ 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 = accessible->widget;
+ if (widget == NULL) {
+ /* State is defunct */
+ return NULL;
+ }
+
+ canvas = EEL_CANVAS (widget);
+ root_group = eel_canvas_root (canvas);
+ g_assert (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_assert (canvas != 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_assert (G_IS_OBJECT (obj));
+
+ 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) {
+ 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 = gtk_type_class (gtk_layout_get_type ());
+
+ 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)
+{
+ GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
+
+ gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas), FALSE);
+
+ canvas->scroll_x1 = 0.0;
+ canvas->scroll_y1 = 0.0;
+ canvas->scroll_x2 = canvas->layout.width;
+ canvas->scroll_y2 = canvas->layout.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;
+
+ g_object_ref (GTK_OBJECT (canvas->root));
+ gtk_object_sink (GTK_OBJECT (canvas->root));
+
+ canvas->root_destroy_id = g_signal_connect (GTK_OBJECT (canvas->root), "destroy",
+ (GtkSignalFunc) 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_assert (EEL_IS_CANVAS (object));
+
+ /* remember, destroy can be run multiple times! */
+
+ canvas = EEL_CANVAS (object);
+
+ if (canvas->root_destroy_id) {
+ g_signal_handler_disconnect (GTK_OBJECT (canvas->root), canvas->root_destroy_id);
+ canvas->root_destroy_id = 0;
+ }
+ if (canvas->root) {
+ g_object_unref (GTK_OBJECT (canvas->root));
+ canvas->root = NULL;
+ }
+
+ 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_assert (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->object.flags & EEL_CANVAS_ITEM_VISIBLE &&
+ !(canvas->root->object.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_assert (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_assert (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 (canvas->layout.bin_window,
+ (gdk_window_get_events (canvas->layout.bin_window)
+ | 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 (canvas->layout.bin_window);
+
+ (* 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_assert (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;
+
+ canvas_width = GTK_WIDGET (canvas)->allocation.width;
+ canvas_height = GTK_WIDGET (canvas)->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->object.flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
+ canvas->root->object.flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
+ eel_canvas_request_update (canvas);
+ }
+ gtk_widget_queue_draw (GTK_WIDGET (canvas));
+ }
+
+ if (((int) canvas->layout.hadjustment->value) != cx) {
+ canvas->layout.hadjustment->value = cx;
+ changed_x = TRUE;
+ }
+
+ if (((int) canvas->layout.vadjustment->value) != cy) {
+ canvas->layout.vadjustment->value = cy;
+ changed_y = TRUE;
+ }
+
+ if ((scroll_width != (int) canvas->layout.width) || (scroll_height != (int) canvas->layout.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 (GTK_OBJECT (canvas->layout.hadjustment), "value_changed");
+ if (changed_y)
+ g_signal_emit_by_name (GTK_OBJECT (canvas->layout.vadjustment), "value_changed");
+}
+
+/* Size allocation handler for the canvas */
+static void
+eel_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+ EelCanvas *canvas;
+
+ g_assert (EEL_IS_CANVAS (widget));
+ g_assert (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 */
+
+ canvas->layout.hadjustment->page_size = allocation->width;
+ canvas->layout.hadjustment->page_increment = allocation->width / 2;
+
+ canvas->layout.vadjustment->page_size = allocation->height;
+ canvas->layout.vadjustment->page_increment = allocation->height / 2;
+
+ scroll_to (canvas,
+ canvas->layout.hadjustment->value,
+ canvas->layout.vadjustment->value);
+
+ g_signal_emit_by_name (GTK_OBJECT (canvas->layout.hadjustment), "changed");
+ g_signal_emit_by_name (GTK_OBJECT (canvas->layout.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_REALIZED (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 (
+ GTK_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->object.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;
+
+ 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_assert (EEL_IS_CANVAS (widget));
+ g_assert (event != NULL);
+
+ 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 != canvas->layout.bin_window)
+ 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_assert (EEL_IS_CANVAS (widget));
+ g_assert (event != NULL);
+
+ canvas = EEL_CANVAS (widget);
+
+ if (event->window != canvas->layout.bin_window)
+ 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_assert (EEL_IS_CANVAS (widget));
+ g_assert (event != NULL);
+
+ 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_assert (EEL_IS_CANVAS (widget));
+ g_assert (event != NULL);
+
+ canvas = EEL_CANVAS (widget);
+
+ if (event->window != canvas->layout.bin_window)
+ 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;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+
+ 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;
+
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+
+ 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_DRAWABLE (widget) || (event->window != canvas->layout.bin_window)) 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_assert (!canvas->doing_update);
+
+ canvas->doing_update = TRUE;
+ eel_canvas_item_invoke_update (canvas->root, 0, 0, 0);
+
+ g_assert (canvas->doing_update);
+
+ 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->object.flags & EEL_CANVAS_ITEM_MAPPED)
+ (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->draw) (canvas->root,
+ canvas->layout.bin_window,
+ 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,
+ &GTK_WIDGET (canvas)->style->bg[GTK_STATE_NORMAL]);
+ gdk_draw_rectangle (canvas->layout.bin_window,
+ 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_assert (!canvas->doing_update);
+
+ canvas->doing_update = TRUE;
+ eel_canvas_item_invoke_update (canvas->root, 0, 0, 0);
+
+ g_assert (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;
+
+ 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.
+ */
+
+ eel_canvas_c2w (canvas,
+ GTK_LAYOUT (canvas)->hadjustment->value + canvas->zoom_xofs,
+ GTK_LAYOUT (canvas)->vadjustment->value + 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->object.flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
+ canvas->root->object.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)
+{
+ g_return_if_fail (EEL_IS_CANVAS (canvas));
+
+ canvas->center_scroll_region = center_scroll_region != 0;
+
+ scroll_to (canvas,
+ canvas->layout.hadjustment->value,
+ canvas->layout.vadjustment->value);
+}
+
+
+/**
+ * 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;
+
+ g_return_if_fail (EEL_IS_CANVAS (canvas));
+ g_return_if_fail (n > EEL_CANVAS_EPSILON);
+
+ widget = GTK_WIDGET (canvas);
+
+ center_x = widget->allocation.width / 2;
+ center_y = widget->allocation.height / 2;
+
+ /* Find the coordinates of the screen center in units. */
+ cx = (canvas->layout.hadjustment->value + center_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs;
+ cy = (canvas->layout.vadjustment->value + 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->object.flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
+ canvas->root->object.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_MAPPED (widget)) {
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->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)
+{
+ g_return_if_fail (EEL_IS_CANVAS (canvas));
+
+ if (cx)
+ *cx = canvas->layout.hadjustment->value;
+
+ if (cy)
+ *cy = canvas->layout.vadjustment->value;
+}
+
+/**
+ * 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_DRAWABLE (canvas) || (x1 >= x2) || (y1 >= y2)) return;
+
+ bbox.x = x1;
+ bbox.y = y1;
+ bbox.width = x2 - x1;
+ bbox.height = y2 - y1;
+
+ gdk_window_invalidate_rect (canvas->layout.bin_window,
+ &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
+ * returns 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);
+ y1 = floor (by1);
+ x2 = ceil (bx2);
+ y2 = ceil (by2);
+ 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 (widget->window) {
+ int window_width, window_height;
+
+ gdk_window_get_geometry (widget->window, 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_assert (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 (canvas->window);
+ 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_assert (item->canvas->root == item);
+ 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_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_assert (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->object.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_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) {
+ 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_assert (item != 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_assert (G_IS_OBJECT (obj));
+
+ 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) {
+ 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 *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) class;
+
+ item_parent_class = gtk_type_class (gtk_object_get_type ());
+
+ gobject_class->set_property = eel_canvas_item_set_property;
+ gobject_class->get_property = eel_canvas_item_get_property;
+
+ g_object_class_install_property
+ (gobject_class, ITEM_PROP_PARENT,
+ g_param_spec_object ("parent", NULL, NULL,
+ EEL_TYPE_CANVAS_ITEM,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class, ITEM_PROP_VISIBLE,
+ g_param_spec_boolean ("visible", NULL, NULL,
+ TRUE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ item_signals[ITEM_EVENT] =
+ g_signal_new ("event",
+ G_TYPE_FROM_CLASS (class),
+ 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);
+
+ gobject_class->dispose = eel_canvas_item_dispose;
+
+ class->realize = eel_canvas_item_realize;
+ class->unrealize = eel_canvas_item_unrealize;
+ class->map = eel_canvas_item_map;
+ class->unmap = eel_canvas_item_unmap;
+ class->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 000000000..83b19d171
--- /dev/null
+++ b/eel/eel-canvas.h
@@ -0,0 +1,530 @@
+/* -*- 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 Gnome Library.
+ *
+ * The Gnome 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 Gnome 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 Gnome 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 Gnome
+ *
+ * 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 <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@gimp.org>
+ */
+
+#ifndef EEL_CANVAS_H
+#define EEL_CANVAS_H
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdarg.h>
+
+G_BEGIN_DECLS
+
+
+/* "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) (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItem))
+#define EEL_CANVAS_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass))
+#define EEL_IS_CANVAS_ITEM(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS_ITEM))
+#define EEL_IS_CANVAS_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_ITEM))
+#define EEL_CANVAS_ITEM_GET_CLASS(obj) (GTK_CHECK_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;
+};
+
+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) (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroup))
+#define EEL_CANVAS_GROUP_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass))
+#define EEL_IS_CANVAS_GROUP(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS_GROUP))
+#define EEL_IS_CANVAS_GROUP_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_GROUP))
+#define EEL_CANVAS_GROUP_GET_CLASS(obj) (GTK_CHECK_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) (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS, EelCanvas))
+#define EEL_CANVAS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS, EelCanvasClass))
+#define EEL_IS_CANVAS(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS))
+#define EEL_IS_CANVAS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS))
+#define EEL_CANVAS_GET_CLASS(obj) (GTK_CHECK_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 bonobo */
+ 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);
+
+G_END_DECLS
+
+#endif
diff --git a/eel/eel-debug-drawing.c b/eel/eel-debug-drawing.c
new file mode 100644
index 000000000..39423b8fa
--- /dev/null
+++ b/eel/eel-debug-drawing.c
@@ -0,0 +1,527 @@
+/* -*- 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 <ramiro@eazel.com>
+*/
+
+#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) (GTK_CHECK_CAST ((obj), DEBUG_TYPE_PIXBUF_VIEWER, DebugPixbufViewer))
+#define DEBUG_IS_PIXBUF_VIEWER(obj) (GTK_CHECK_TYPE ((obj), DEBUG_TYPE_PIXBUF_VIEWER))
+
+typedef struct DebugPixbufViewer DebugPixbufViewer;
+typedef struct DebugPixbufViewerClass DebugPixbufViewerClass;
+
+static GtkType 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_UNSET_FLAGS (viewer, GTK_CAN_FOCUS);
+ GTK_WIDGET_SET_FLAGS (viewer, GTK_NO_WINDOW);
+}
+
+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;
+
+ g_assert (DEBUG_IS_PIXBUF_VIEWER (widget));
+ g_assert (event != NULL);
+ g_assert (event->window == widget->window);
+ g_assert (GTK_WIDGET_REALIZED (widget));
+
+ viewer = DEBUG_PIXBUF_VIEWER (widget);
+
+ if (viewer->pixbuf == NULL) {
+ return TRUE;
+ }
+
+ bounds.x0 = widget->allocation.x + (widget->allocation.width - gdk_pixbuf_get_width (viewer->pixbuf)) / 2;
+ bounds.y0 = widget->allocation.y + (widget->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,
+ widget->style->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;
+
+ g_return_if_fail (pixbuf != NULL);
+ g_return_if_fail (viewer_name != NULL);
+
+ file_name = g_strdup ("/tmp/eel-debug-png-file-XXXXXX");
+
+ if (mktemp (file_name) != file_name) {
+ g_free (file_name);
+ file_name = g_strdup_printf ("/tmp/isis-debug-png-file-%d", getpid ());
+ }
+
+ 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 (debug_window->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 000000000..294866952
--- /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 <ramiro@eazel.com>
+*/
+
+#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 000000000..ecd000f62
--- /dev/null
+++ b/eel/eel-debug.c
@@ -0,0 +1,129 @@
+/* -*- 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 <darin@eazel.com>
+*/
+
+#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 000000000..fdd5ca335
--- /dev/null
+++ b/eel/eel-debug.h
@@ -0,0 +1,48 @@
+/* -*- 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 <darin@eazel.com>
+*/
+
+#ifndef EEL_DEBUG_H
+#define EEL_DEBUG_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+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 Bonobo.
+ */
+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);
+
+G_END_DECLS
+
+#endif /* EEL_DEBUG_H */
diff --git a/eel/eel-editable-label.c b/eel/eel-editable-label.c
new file mode 100644
index 000000000..ab60eca76
--- /dev/null
+++ b/eel/eel-editable-label.c
@@ -0,0 +1,4410 @@
+/* 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);
+
+
+
+static GtkMiscClass *parent_class = NULL;
+
+GType
+eel_editable_label_get_type (void)
+{
+ static GType label_type = 0;
+
+ if (!label_type)
+ {
+ const GTypeInfo label_info =
+ {
+ sizeof (EelEditableLabelClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) eel_editable_label_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EelEditableLabel),
+ 32, /* n_preallocs */
+ (GInstanceInitFunc) eel_editable_label_init,
+ };
+
+ const GInterfaceInfo editable_info =
+ {
+ (GInterfaceInitFunc) eel_editable_label_editable_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+
+ label_type = g_type_register_static (GTK_TYPE_MISC, "EelEditableLabel", &label_info, 0);
+ g_type_add_interface_static (label_type,
+ GTK_TYPE_EDITABLE,
+ &editable_info);
+ }
+
+ return label_type;
+}
+
+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;
+
+ parent_class = gtk_type_class (GTK_TYPE_MISC);
+
+ 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_FLAGS (label, GTK_CAN_FOCUS);
+
+ /* 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.
+ **/
+G_CONST_RETURN 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 (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 (label)->style;
+
+ 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;
+
+ 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_usize().
+ * - 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);
+
+ width = label->misc.xpad * 2;
+ height = label->misc.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 (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 (parent_class)->state_changed)
+ GTK_WIDGET_CLASS (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_REALIZED (widget))
+ {
+ gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_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",
+ &widget->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 (parent_class)->direction_changed (widget, previous_dir);
+}
+
+static void
+get_layout_location (EelEditableLabel *label,
+ gint *xp,
+ gint *yp)
+{
+ GtkMisc *misc;
+ GtkWidget *widget;
+ gfloat xalign;
+ GtkRequisition req;
+ gint x, y;
+
+ misc = GTK_MISC (label);
+ widget = GTK_WIDGET (label);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ xalign = misc->xalign;
+ else
+ xalign = 1.0 - misc->xalign;
+
+ gtk_widget_get_child_requisition (widget, &req);
+
+ x = floor ((gint)misc->xpad
+ + ((widget->allocation.width - req.width) * xalign)
+ + 0.5);
+
+ y = floor ((gint)misc->ypad
+ + ((widget->allocation.height - req.height) * misc->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;
+
+ 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 (widget->style->colormap, &gc_values.foreground);
+ return gtk_gc_get (widget->style->depth, widget->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_DRAWABLE (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, widget->window,
+ 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, widget->window,
+ label->secondary_cursor_gc,
+ &cursor_location, dir2, TRUE);
+ }
+ }
+ else /* Block cursor */
+ {
+ GdkRegion *clip;
+
+ gdk_draw_rectangle (widget->window, 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 (widget->window,
+ label->primary_cursor_gc,
+ xoffset, yoffset,
+ label->layout,
+ &widget->style->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;
+ gint x, y;
+
+ g_assert (EEL_IS_EDITABLE_LABEL (widget));
+ g_assert (event != NULL);
+
+ label = EEL_EDITABLE_LABEL (widget);
+
+ eel_editable_label_ensure_layout (label, TRUE);
+
+ if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
+ label->text)
+ {
+ get_layout_location (label, &x, &y);
+
+ gtk_paint_layout (widget->style,
+ widget->window,
+ GTK_WIDGET_STATE (widget),
+ FALSE,
+ &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 (widget->style->black_gc, clip);
+
+
+ state = GTK_STATE_SELECTED;
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ state = GTK_STATE_ACTIVE;
+
+ gdk_draw_layout_with_colors (widget->window,
+ widget->style->black_gc,
+ x, y,
+ label->layout,
+ &widget->style->text[state],
+ &widget->style->base[state]);
+
+ gdk_gc_set_clip_region (widget->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)
+ gdk_draw_rectangle (widget->window,
+ widget->style->fg_gc [GTK_WIDGET_STATE (widget)],
+ FALSE,
+ 0, 0,
+ widget->allocation.width - 1,
+ widget->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 };
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+ label = EEL_EDITABLE_LABEL (widget);
+
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->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;
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (widget->window, widget);
+
+ gdk_cursor_unref (attributes.cursor);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+
+ gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+
+ gtk_im_context_set_client_window (label->im_context, widget->window);
+
+ label->primary_cursor_gc = make_cursor_gc (widget,
+ "cursor-color",
+ &widget->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 (parent_class)->unrealize) (widget);
+}
+
+static void
+eel_editable_label_map (GtkWidget *widget)
+{
+ (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
+}
+
+static void
+eel_editable_label_unmap (GtkWidget *widget)
+{
+ (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
+}
+
+static void
+window_to_layout_coords (EelEditableLabel *label,
+ gint *x,
+ gint *y)
+{
+ gint lx, ly;
+
+ /* get layout location in widget->window 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 (widget->window,
+ &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 (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 (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 */
+ new_pos++;
+ while (new_pos < n_attrs && !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 (GTK_OBJECT (menuitem), "activate",
+ GTK_SIGNAL_FUNC (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;
+
+ label = EEL_EDITABLE_LABEL (user_data);
+ widget = GTK_WIDGET (label);
+
+ g_assert (GTK_WIDGET_REALIZED (label));
+
+ gdk_window_get_origin (widget->window, x, y);
+
+ /*gtk_widget_size_request (label->popup_menu, &req);*/
+ req = widget->requisition;
+
+ *x += widget->allocation.width / 2;
+ *y += widget->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_REALIZED (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 (GTK_OBJECT (menuitem), "activate",
+ GTK_SIGNAL_FUNC (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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 (text)->widget;
+ 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 G_CONST_RETURN gchar*
+eel_editable_label_accessible_get_name (AtkObject *accessible)
+{
+ if (accessible->name != NULL)
+ return accessible->name;
+ else
+ {
+ GtkWidget *widget;
+
+ widget = GTK_ACCESSIBLE (accessible)->widget;
+ 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 (accessible)->widget;
+
+ 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 000000000..1255ea36f
--- /dev/null
+++ b/eel/eel-editable-label.h
@@ -0,0 +1,142 @@
+/* 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) (GTK_CHECK_CAST ((obj), EEL_TYPE_EDITABLE_LABEL, EelEditableLabel))
+#define EEL_EDITABLE_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_EDITABLE_LABEL, EelEditableLabelClass))
+#define EEL_IS_EDITABLE_LABEL(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_EDITABLE_LABEL))
+#define EEL_IS_EDITABLE_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_EDITABLE_LABEL))
+#define EEL_EDITABLE_LABEL_GET_CLASS(obj) (GTK_CHECK_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);
+G_CONST_RETURN 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 000000000..8691c80da
--- /dev/null
+++ b/eel/eel-enumeration.c
@@ -0,0 +1,533 @@
+/* -*- 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 <ramiro@eazel.com>
+*/
+
+#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 000000000..16db385ca
--- /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 <ramiro@eazel.com>
+*/
+
+#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-gconf-extensions.c b/eel/eel-gconf-extensions.c
new file mode 100644
index 000000000..5230b2741
--- /dev/null
+++ b/eel/eel-gconf-extensions.c
@@ -0,0 +1,647 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-gconf-extensions.c - Stuff to make GConf easier to use.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#include <config.h>
+#include "eel-gconf-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 <gconf/gconf-client.h>
+#include <gconf/gconf.h>
+
+static GConfClient *global_gconf_client = NULL;
+
+static void
+global_client_free (void)
+{
+ if (global_gconf_client == NULL) {
+ return;
+ }
+
+ g_object_unref (global_gconf_client);
+ global_gconf_client = NULL;
+}
+
+/* Public */
+GConfClient *
+eel_gconf_client_get_global (void)
+{
+ /* Initialize gconf if needed */
+ if (!gconf_is_initialized ()) {
+ char *argv[] = { "eel-preferences", NULL };
+ GError *error = NULL;
+
+ if (!gconf_init (1, argv, &error)) {
+ if (eel_gconf_handle_error (&error)) {
+ return NULL;
+ }
+ }
+ }
+
+ if (global_gconf_client == NULL) {
+ global_gconf_client = gconf_client_get_default ();
+ eel_debug_call_at_shutdown (global_client_free);
+ }
+
+ return global_gconf_client;
+}
+
+gboolean
+eel_gconf_handle_error (GError **error)
+{
+ char *message;
+ static gboolean shown_dialog = FALSE;
+
+ g_return_val_if_fail (error != NULL, FALSE);
+
+ if (*error != NULL) {
+ g_warning (_("GConf error:\n %s"), (*error)->message);
+ if (! shown_dialog) {
+ shown_dialog = TRUE;
+
+ message = g_strdup_printf (_("GConf 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_gconf_set_boolean (const char *key,
+ gboolean boolean_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_bool (client, key, boolean_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+gboolean
+eel_gconf_get_boolean (const char *key)
+{
+ gboolean result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ result = gconf_client_get_bool (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = FALSE;
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_integer (const char *key,
+ int int_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_int (client, key, int_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+int
+eel_gconf_get_integer (const char *key)
+{
+ int result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, 0);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, 0);
+
+ result = gconf_client_get_int (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = 0;
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_string (const char *key,
+ const char *string_value)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_set_string (client, key, string_value, &error);
+ eel_gconf_handle_error (&error);
+}
+
+char *
+eel_gconf_get_string (const char *key)
+{
+ char *result;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ result = gconf_client_get_string (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ result = g_strdup ("");
+ }
+
+ return result;
+}
+
+void
+eel_gconf_set_string_list (const char *key,
+ const GSList *slist)
+{
+ GConfClient *client;
+ GError *error;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ error = NULL;
+ gconf_client_set_list (client, key, GCONF_VALUE_STRING,
+ /* Need cast cause of GConf api bug */
+ (GSList *) slist,
+ &error);
+ eel_gconf_handle_error (&error);
+}
+
+GSList *
+eel_gconf_get_string_list (const char *key)
+{
+ GSList *slist;
+ GConfClient *client;
+ GError *error;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ error = NULL;
+ slist = gconf_client_get_list (client, key, GCONF_VALUE_STRING, &error);
+ if (eel_gconf_handle_error (&error)) {
+ slist = NULL;
+ }
+
+ return slist;
+}
+
+void
+eel_gconf_unset (const char *key)
+{
+ GConfClient *client;
+ GError *error;
+
+ g_return_if_fail (key != NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ error = NULL;
+ gconf_client_unset (client, key, &error);
+ eel_gconf_handle_error (&error);
+}
+
+gboolean
+eel_gconf_is_default (const char *key)
+{
+ gboolean result;
+ GConfValue *value;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ value = gconf_client_get_without_default (eel_gconf_client_get_global (), key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (value != NULL) {
+ gconf_value_free (value);
+ }
+ return FALSE;
+ }
+
+ result = (value == NULL);
+ eel_gconf_value_free (value);
+ return result;
+}
+
+gboolean
+eel_gconf_key_is_writable (const char *key)
+{
+ gboolean result;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ result = gconf_client_key_is_writable (eel_gconf_client_get_global (), key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ return result;
+ }
+
+ return result;
+}
+
+gboolean
+eel_gconf_monitor_add (const char *directory)
+{
+ GError *error = NULL;
+ GConfClient *client;
+
+ g_return_val_if_fail (directory != NULL, FALSE);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ gconf_client_add_dir (client,
+ directory,
+ GCONF_CLIENT_PRELOAD_NONE,
+ &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+eel_gconf_monitor_remove (const char *directory)
+{
+ GError *error = NULL;
+ GConfClient *client;
+
+ if (directory == NULL) {
+ return FALSE;
+ }
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, FALSE);
+
+ gconf_client_remove_dir (client,
+ directory,
+ &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+eel_gconf_preload_cache (const char *directory,
+ GConfClientPreloadType preload_type)
+{
+ GError *error = NULL;
+ GConfClient *client;
+
+ if (directory == NULL) {
+ return;
+ }
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_preload (client,
+ directory,
+ preload_type,
+ &error);
+
+ eel_gconf_handle_error (&error);
+}
+
+void
+eel_gconf_suggest_sync (void)
+{
+ GConfClient *client;
+ GError *error = NULL;
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_suggest_sync (client, &error);
+ eel_gconf_handle_error (&error);
+}
+
+GConfValue*
+eel_gconf_get_value (const char *key)
+{
+ GConfValue *value = NULL;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ value = gconf_client_get (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (value != NULL) {
+ gconf_value_free (value);
+ value = NULL;
+ }
+ }
+
+ return value;
+}
+
+GConfValue*
+eel_gconf_get_default_value (const char *key)
+{
+ GConfValue *value = NULL;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, NULL);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, NULL);
+
+ value = gconf_client_get_default_from_schema (client, key, &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (value != NULL) {
+ gconf_value_free (value);
+ value = NULL;
+ }
+ }
+
+ return value;
+}
+
+static gboolean
+simple_value_is_equal (const GConfValue *a,
+ const GConfValue *b)
+{
+ g_assert (a != NULL);
+ g_assert (b != NULL);
+
+ switch (a->type) {
+ case GCONF_VALUE_STRING:
+ return eel_str_is_equal (gconf_value_get_string (a),
+ gconf_value_get_string (b));
+
+ case GCONF_VALUE_INT:
+ return gconf_value_get_int (a) ==
+ gconf_value_get_int (b);
+
+ case GCONF_VALUE_FLOAT:
+ return gconf_value_get_float (a) ==
+ gconf_value_get_float (b);
+
+ case GCONF_VALUE_BOOL:
+ return gconf_value_get_bool (a) ==
+ gconf_value_get_bool (b);
+ default:
+ g_assert_not_reached ();
+ }
+
+ return FALSE;
+}
+
+gboolean
+eel_gconf_value_is_equal (const GConfValue *a,
+ const GConfValue *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 GCONF_VALUE_STRING:
+ case GCONF_VALUE_INT:
+ case GCONF_VALUE_FLOAT:
+ case GCONF_VALUE_BOOL:
+ return simple_value_is_equal (a, b);
+ break;
+
+ case GCONF_VALUE_LIST:
+ if (gconf_value_get_list_type (a) !=
+ gconf_value_get_list_type (b)) {
+ return FALSE;
+ }
+
+ node_a = gconf_value_get_list (a);
+ node_b = gconf_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_gconf_value_free (GConfValue *value)
+{
+ if (value == NULL) {
+ return;
+ }
+
+ gconf_value_free (value);
+}
+
+guint
+eel_gconf_notification_add (const char *key,
+ GConfClientNotifyFunc notification_callback,
+ gpointer callback_data)
+{
+ guint notification_id;
+ GConfClient *client;
+ GError *error = NULL;
+
+ g_return_val_if_fail (key != NULL, EEL_GCONF_UNDEFINED_CONNECTION);
+ g_return_val_if_fail (notification_callback != NULL, EEL_GCONF_UNDEFINED_CONNECTION);
+
+ client = eel_gconf_client_get_global ();
+ g_return_val_if_fail (client != NULL, EEL_GCONF_UNDEFINED_CONNECTION);
+
+ notification_id = gconf_client_notify_add (client,
+ key,
+ notification_callback,
+ callback_data,
+ NULL,
+ &error);
+
+ if (eel_gconf_handle_error (&error)) {
+ if (notification_id != EEL_GCONF_UNDEFINED_CONNECTION) {
+ gconf_client_notify_remove (client, notification_id);
+ notification_id = EEL_GCONF_UNDEFINED_CONNECTION;
+ }
+ }
+
+ return notification_id;
+}
+
+void
+eel_gconf_notification_remove (guint notification_id)
+{
+ GConfClient *client;
+
+ if (notification_id == EEL_GCONF_UNDEFINED_CONNECTION) {
+ return;
+ }
+
+ client = eel_gconf_client_get_global ();
+ g_return_if_fail (client != NULL);
+
+ gconf_client_notify_remove (client, notification_id);
+}
+
+GSList *
+eel_gconf_value_get_string_list (const GConfValue *value)
+{
+ GSList *result;
+ const GSList *slist;
+ const GSList *node;
+ const char *string;
+ const GConfValue *next_value;
+
+ if (value == NULL) {
+ return NULL;
+ }
+
+ g_return_val_if_fail (value->type == GCONF_VALUE_LIST, NULL);
+ g_return_val_if_fail (gconf_value_get_list_type (value) == GCONF_VALUE_STRING, NULL);
+
+ slist = gconf_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 == GCONF_VALUE_STRING, NULL);
+ string = gconf_value_get_string (next_value);
+ result = g_slist_prepend (result, g_strdup (string));
+ }
+ return g_slist_reverse (result);
+}
+
+void
+eel_gconf_value_set_string_list (GConfValue *value,
+ const GSList *string_list)
+{
+ const GSList *node;
+ GConfValue *next_value;
+ GSList *value_list;
+
+ g_return_if_fail (value->type == GCONF_VALUE_LIST);
+ g_return_if_fail (gconf_value_get_list_type (value) == GCONF_VALUE_STRING);
+
+ value_list = NULL;
+ for (node = string_list; node != NULL; node = node->next) {
+ next_value = gconf_value_new (GCONF_VALUE_STRING);
+ gconf_value_set_string (next_value, node->data);
+ value_list = g_slist_append (value_list, next_value);
+ }
+
+ gconf_value_set_list (value, value_list);
+
+ for (node = value_list; node != NULL; node = node->next) {
+ gconf_value_free (node->data);
+ }
+ g_slist_free (value_list);
+}
+
diff --git a/eel/eel-gconf-extensions.h b/eel/eel-gconf-extensions.h
new file mode 100644
index 000000000..c659ee0e9
--- /dev/null
+++ b/eel/eel-gconf-extensions.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-gconf-extensions.h - Stuff to make GConf easier to use.
+
+ Copyright (C) 2000, 2001 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#ifndef EEL_GCONF_EXTENSIONS_H
+#define EEL_GCONF_EXTENSIONS_H
+
+#include <glib.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+G_BEGIN_DECLS
+
+#define EEL_GCONF_UNDEFINED_CONNECTION 0
+
+GConfClient *eel_gconf_client_get_global (void);
+gboolean eel_gconf_handle_error (GError **error);
+void eel_gconf_set_boolean (const char *key,
+ gboolean boolean_value);
+gboolean eel_gconf_get_boolean (const char *key);
+int eel_gconf_get_integer (const char *key);
+void eel_gconf_set_integer (const char *key,
+ int int_value);
+char * eel_gconf_get_string (const char *key);
+void eel_gconf_set_string (const char *key,
+ const char *string_value);
+GSList * eel_gconf_get_string_list (const char *key);
+void eel_gconf_set_string_list (const char *key,
+ const GSList *string_list_value);
+void eel_gconf_unset (const char *key);
+gboolean eel_gconf_key_is_writable (const char *key);
+gboolean eel_gconf_is_default (const char *key);
+gboolean eel_gconf_monitor_add (const char *directory);
+gboolean eel_gconf_monitor_remove (const char *directory);
+void eel_gconf_preload_cache (const char *directory,
+ GConfClientPreloadType preload_type);
+void eel_gconf_suggest_sync (void);
+GConfValue* eel_gconf_get_value (const char *key);
+GConfValue* eel_gconf_get_default_value (const char *key);
+gboolean eel_gconf_value_is_equal (const GConfValue *a,
+ const GConfValue *b);
+void eel_gconf_value_free (GConfValue *value);
+guint eel_gconf_notification_add (const char *key,
+ GConfClientNotifyFunc notification_callback,
+ gpointer callback_data);
+void eel_gconf_notification_remove (guint notification_id);
+GSList * eel_gconf_value_get_string_list (const GConfValue *value);
+void eel_gconf_value_set_string_list (GConfValue *value,
+ const GSList *string_list);
+
+G_END_DECLS
+
+#endif /* EEL_GCONF_EXTENSIONS_H */
diff --git a/eel/eel-gdk-extensions.c b/eel/eel-gdk-extensions.c
new file mode 100644
index 000000000..7e34be145
--- /dev/null
+++ b/eel/eel-gdk-extensions.c
@@ -0,0 +1,947 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>,
+ Pavel Cisler <pavel@eazel.com>,
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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_fill_rectangle */
+ /* Make a GdkImage and fill it, maybe? */
+
+ /* eel_fill_rectangle_with_color */
+
+ /* eel_fill_rectangle_with_gradient */
+
+ /* 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 000000000..9df8d0442
--- /dev/null
+++ b/eel/eel-gdk-extensions.h
@@ -0,0 +1,163 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>,
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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 000000000..9f7dd665c
--- /dev/null
+++ b/eel/eel-gdk-pixbuf-extensions.c
@@ -0,0 +1,1305 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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-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 gdk_pixbuf_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;
+}
+
+
+#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 000000000..f6801e781
--- /dev/null
+++ b/eel/eel-gdk-pixbuf-extensions.h
@@ -0,0 +1,155 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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);
+
+#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 000000000..5152d9591
--- /dev/null
+++ b/eel/eel-glib-extensions.c
@@ -0,0 +1,1159 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <sullivan@eazel.com>
+*/
+
+#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;
+}
+
+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 NAUTILUS_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 000000000..bb3c41a30
--- /dev/null
+++ b/eel/eel-glib-extensions.h
@@ -0,0 +1,126 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <sullivan@eazel.com>
+*/
+
+#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);
+
+/* 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-gnome-extensions.c b/eel/eel-gnome-extensions.c
new file mode 100644
index 000000000..b6a27a5c6
--- /dev/null
+++ b/eel/eel-gnome-extensions.c
@@ -0,0 +1,203 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-gnome-extensions.c - implementation of new functions that operate on
+ gnome classes. Perhaps some of these should be
+ rolled into gnome someday.
+
+ Copyright (C) 1999, 2000, 2001 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#include <config.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+
+#include "eel-gnome-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 <libgnome/gnome-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] = {
+ { "gnome-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);
+ gnome_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_gnome_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_gnome_open_terminal_on_screen (const char *command,
+ GdkScreen *screen)
+{
+ char *command_line;
+
+ if (screen == NULL) {
+ screen = gdk_screen_get_default ();
+ }
+
+ command_line = eel_gnome_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_gnome_open_terminal (const char *command)
+{
+ eel_gnome_open_terminal_on_screen (command, NULL);
+}
diff --git a/eel/eel-gnome-extensions.h b/eel/eel-gnome-extensions.h
new file mode 100644
index 000000000..aea54f005
--- /dev/null
+++ b/eel/eel-gnome-extensions.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-gnome-extensions.h - interface for new functions that operate on
+ gnome classes. Perhaps some of these should be
+ rolled into gnome someday.
+
+ Copyright (C) 1999, 2000, 2001 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#ifndef EEL_GNOME_EXTENSIONS_H
+#define EEL_GNOME_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_gnome_make_terminal_command (const char *command);
+
+/* Open up a new terminal, optionally passing in a command to execute */
+void eel_gnome_open_terminal (const char *command);
+void eel_gnome_open_terminal_on_screen (const char *command,
+ GdkScreen *screen);
+
+#endif /* EEL_GNOME_EXTENSIONS_H */
diff --git a/eel/eel-graphic-effects.c b/eel/eel-graphic-effects.c
new file mode 100644
index 000000000..7d62987bb
--- /dev/null
+++ b/eel/eel-graphic-effects.c
@@ -0,0 +1,399 @@
+/* -*- 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 <andy@eazel.com>
+ *
+ * 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 000000000..41060e037
--- /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 <andy@eazel.com>
+ */
+
+#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 000000000..247d7eb13
--- /dev/null
+++ b/eel/eel-gtk-container.c
@@ -0,0 +1,209 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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 (child->parent == GTK_WIDGET (container));
+
+ if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_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 (child->parent == GTK_WIDGET (container));
+
+ if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_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)
+{
+ g_return_if_fail (GTK_IS_CONTAINER (container));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+
+ gtk_widget_set_parent (child, GTK_WIDGET (container));
+
+ if (GTK_WIDGET_REALIZED (container)) {
+ gtk_widget_realize (child);
+ }
+
+ if (GTK_WIDGET_VISIBLE (container) && GTK_WIDGET_VISIBLE (child)) {
+ if (GTK_WIDGET_MAPPED (container)) {
+ 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 (child->parent == GTK_WIDGET (container));
+
+ child_was_visible = GTK_WIDGET_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 (child->parent == 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 000000000..06415e641
--- /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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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 000000000..81b8014a8
--- /dev/null
+++ b/eel/eel-gtk-extensions.c
@@ -0,0 +1,1174 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <sullivan@eazel.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+ Darin Adler <darin@eazel.com>
+*/
+
+#include <config.h>
+#include "eel-gtk-extensions.h"
+
+#include "eel-gdk-pixbuf-extensions.h"
+#include "eel-glib-extensions.h"
+#include "eel-gnome-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 gnome 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 = widget->window;
+ 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_VISIBLE (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 GNOME 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_VISIBLE (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 */
+
+ gtk_object_sink (GTK_OBJECT (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);
+}
+
+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 widget->window 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)
+{
+ if (widget == NULL) {
+ return FALSE;
+ }
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+ return eel_point_in_allocation (&widget->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,
+ GtkSignalFunc func,
+ GtkCallbackMarshal marshal,
+ gpointer data,
+ GtkDestroyNotify 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,
+ GtkSignalFunc 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_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 (adjustment->upper - adjustment->page_size, adjustment->lower);
+ clamped_value = CLAMP (value, adjustment->lower, upper_page_start);
+ if (clamped_value != adjustment->value) {
+ adjustment->value = 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, adjustment->value);
+}
+
+/**
+ * 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;
+ int x, y;
+ int shadow_offset;
+
+ shadow_offset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (label),
+ "eel-label-shadow-offset"));
+
+ misc = GTK_MISC (label);
+ widget = GTK_WIDGET (label);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ xalign = misc->xalign;
+ else
+ xalign = 1.0 - misc->xalign;
+
+ x = floor (widget->allocation.x + (int)misc->xpad
+ + ((widget->allocation.width - widget->requisition.width - shadow_offset) * xalign)
+ + 0.5);
+
+ y = floor (widget->allocation.y + (int)misc->ypad
+ + ((widget->allocation.height - widget->requisition.height - shadow_offset) * misc->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 (widget->window);
+ gdk_gc_set_rgb_fg_color (gc, &color);
+ gdk_gc_set_clip_rectangle (gc, &event->area);
+
+ gdk_draw_layout (widget->window,
+ gc,
+ x + shadow_offset, y + shadow_offset,
+ label->layout);
+ g_object_unref (gc);
+ }
+
+ gtk_paint_layout (widget->style,
+ widget->window,
+ GTK_WIDGET_STATE (widget),
+ FALSE,
+ &event->area,
+ widget,
+ "label",
+ x, y,
+ label->layout);
+
+ 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_NO_WINDOW (widget)) {
+ widget = widget->parent;
+ }
+
+ 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 (label->style->font_desc);
+
+ gtk_object_sink (GTK_OBJECT (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;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (event != NULL);
+
+ gdk_window_get_position (event->window, &window_x, &window_y);
+ if (x != NULL) {
+ *x = event->x + window_x - widget->allocation.x;
+ }
+ if (y != NULL) {
+ *y = event->y + window_y - widget->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);
+}
+
+gboolean
+eel_gtk_tree_view_cell_is_completely_visible (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column)
+{
+ GdkRectangle cell_rect, visible_rect;
+
+ gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
+ gtk_tree_view_widget_to_tree_coords (tree_view, cell_rect.x, cell_rect.y,
+ &cell_rect.x, &cell_rect.y);
+ gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
+ return eel_gdk_rectangle_contains_rectangle (visible_rect, cell_rect);
+}
+
+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_REALIZED (viewport)) {
+ viewport_rect.x = 0;
+ viewport_rect.y = 0;
+ gdk_drawable_get_size (viewport->view_window,
+ &viewport_rect.width,
+ &viewport_rect.height);
+
+ gdk_window_get_position (viewport->bin_window,
+ &child_rect.x,
+ &child_rect.y);
+ gdk_drawable_get_size (viewport->bin_window,
+ &child_rect.width,
+ &child_rect.height);
+
+ 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 000000000..7bf16024e
--- /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 Gnome 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 Gnome 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 Gnome 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 <sullivan@eazel.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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,
+ GtkSignalFunc func,
+ GtkCallbackMarshal marshal,
+ gpointer data,
+ GtkDestroyNotify destroy_func,
+ gboolean object_signal,
+ gboolean after,
+ GtkObject *alive_object);
+void eel_gtk_signal_connect_while_realized (GtkObject *object,
+ const char *name,
+ GtkSignalFunc 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);
+
+/* 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 */
+gboolean eel_gtk_tree_view_cell_is_completely_visible (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column);
+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 000000000..c47453f1c
--- /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 <darin@bentspoon.com>
+ Ramiro Estrugo <ramiro@eazel.com>
+*/
+
+#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; \
+ \
+GtkType \
+prefix##_get_type (void) \
+{ \
+ GtkType parent_type; \
+ static GtkType 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 000000000..83f9fec64
--- /dev/null
+++ b/eel/eel-i18n.c
@@ -0,0 +1,51 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <fcrozat@mandrakesoft.com>
+*/
+
+#include <config.h>
+#include <glib.h>
+#include "eel-i18n.h"
+
+#ifdef ENABLE_NLS
+
+#include <libintl.h>
+
+
+
+G_CONST_RETURN char *
+_eel_gettext (const char *str)
+{
+ static gboolean _eel_gettext_initialized = FALSE;
+
+ if (!_eel_gettext_initialized) {
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+# 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 000000000..b45568968
--- /dev/null
+++ b/eel/eel-i18n.h
@@ -0,0 +1,53 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <fcrozat@mandrakesoft.com>
+*/
+
+#ifndef EEL_I18N_H
+#define EEL_I18N_H
+
+#ifdef ENABLE_NLS
+#include <glib.h>
+
+G_CONST_RETURN 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 000000000..977477e56
--- /dev/null
+++ b/eel/eel-image-table.c
@@ -0,0 +1,579 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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 GtkType 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_FLAGS (image_table, GTK_NO_WINDOW);
+
+ 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 GtkType
+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_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_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_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 000000000..dfda964f3
--- /dev/null
+++ b/eel/eel-image-table.h
@@ -0,0 +1,89 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#ifndef EEL_IMAGE_TABLE_H
+#define EEL_IMAGE_TABLE_H
+
+#include <eel/eel-wrap-table.h>
+
+G_BEGIN_DECLS
+
+#define EEL_TYPE_IMAGE_TABLE (eel_image_table_get_type ())
+#define EEL_IMAGE_TABLE(obj) (GTK_CHECK_CAST ((obj), EEL_TYPE_IMAGE_TABLE, EelImageTable))
+#define EEL_IMAGE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_IMAGE_TABLE, EelImageTableClass))
+#define EEL_IS_IMAGE_TABLE(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_IMAGE_TABLE))
+#define EEL_IS_IMAGE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_IMAGE_TABLE))
+
+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 */
+GtkType eel_image_table_get_type (void);
+GtkWidget *eel_image_table_new (gboolean homogeneous);
+GtkWidget *eel_image_table_add_empty_image (EelImageTable *image_table);
+
+G_END_DECLS
+
+#endif /* EEL_IMAGE_TABLE_H */
diff --git a/eel/eel-labeled-image.c b/eel/eel-labeled-image.c
new file mode 100644
index 000000000..bae5e9d28
--- /dev/null
+++ b/eel/eel-labeled-image.c
@@ -0,0 +1,2376 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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_FLAGS (labeled_image, GTK_NO_WINDOW);
+
+ 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);
+
+ widget->allocation = *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;
+
+ g_assert (EEL_IS_LABELED_IMAGE (widget));
+ g_assert (GTK_WIDGET_REALIZED (widget));
+ g_assert (event != NULL);
+
+ labeled_image = EEL_LABELED_IMAGE (widget);
+
+ if (GTK_WIDGET_STATE (widget) == GTK_STATE_SELECTED ||
+ GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) {
+ label_bounds = eel_labeled_image_get_label_bounds (EEL_LABELED_IMAGE (widget));
+
+ gtk_paint_flat_box (widget->style,
+ widget->window,
+ GTK_WIDGET_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 (widget->style, widget->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_FLAGS (widget, GTK_MAPPED);
+
+ 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_UNSET_FLAGS (widget, GTK_MAPPED);
+
+ 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) {
+ x_alignment = GTK_MISC (labeled_image->details->label)->xalign;
+ y_alignment = GTK_MISC (labeled_image->details->label)->yalign;
+
+ /* 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) {
+ x_alignment = GTK_MISC (labeled_image->details->image)->xalign;
+ y_alignment = GTK_MISC (labeled_image->details->image)->yalign;
+
+ /* 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 (labeled_image)->state == 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_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 (widget->parent,
+ 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)
+{
+ if (can_focus) {
+ GTK_WIDGET_SET_FLAGS
+ (GTK_WIDGET (labeled_image), GTK_CAN_FOCUS);
+
+ } else {
+ GTK_WIDGET_UNSET_FLAGS
+ (GTK_WIDGET (labeled_image), GTK_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 (object)->widget)) {
+ return NULL;
+ }
+
+ if (GTK_IS_BUTTON (widget))
+ widget = GTK_BIN (widget)->child;
+
+ return EEL_LABELED_IMAGE (widget);
+}
+
+static G_CONST_RETURN 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;
+
+ labeled_image = get_image (image);
+
+ if (!labeled_image || !labeled_image->details->image) {
+ *width = *height = 0;
+ return;
+ }
+
+ *width = labeled_image->details->image->allocation.width;
+ *height = labeled_image->details->image->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 000000000..61dbd043d
--- /dev/null
+++ b/eel/eel-labeled-image.h
@@ -0,0 +1,156 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+/* 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>
+
+G_BEGIN_DECLS
+
+#define EEL_TYPE_LABELED_IMAGE (eel_labeled_image_get_type ())
+#define EEL_LABELED_IMAGE(obj) (GTK_CHECK_CAST ((obj), EEL_TYPE_LABELED_IMAGE, EelLabeledImage))
+#define EEL_LABELED_IMAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_LABELED_IMAGE, EelLabeledImageClass))
+#define EEL_IS_LABELED_IMAGE(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_LABELED_IMAGE))
+#define EEL_IS_LABELED_IMAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_LABELED_IMAGE))
+
+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 */
+GtkType 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);
+
+G_END_DECLS
+
+#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 000000000..dd9770aac
--- /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 <darin@eazel.com>
+*/
+
+#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 000000000..837babfe8
--- /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 <darin@eazel.com>
+*/
+
+#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-pango-extensions.c b/eel/eel-pango-extensions.c
new file mode 100644
index 000000000..cbb9c0dce
--- /dev/null
+++ b/eel/eel-pango-extensions.c
@@ -0,0 +1,586 @@
+/* -*- 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 <andersca@gnu.org>
+*/
+
+#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 000000000..efa96572a
--- /dev/null
+++ b/eel/eel-pango-extensions.h
@@ -0,0 +1,54 @@
+/* -*- 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 <andersca@gnu.org>
+*/
+
+#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 000000000..d4522cec3
--- /dev/null
+++ b/eel/eel-preferences-builder.c
@@ -0,0 +1,564 @@
+/* -*- 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 gconf keys.
+
+ Copyright (C) 2002 Jan Arne Petersen
+
+ The Gnome 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 Gnome 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 Gnome 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 <jpetersen@uni-bonn.de>
+*/
+
+#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);
+}
+
+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 000000000..cc12160c8
--- /dev/null
+++ b/eel/eel-preferences.c
@@ -0,0 +1,1701 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#include <config.h>
+#include "eel-preferences.h"
+
+#include "eel-debug.h"
+#include "eel-gconf-extensions.h"
+#include "eel-lib-self-check-functions.h"
+#include "eel-enumeration.h"
+#include "eel-glib-extensions.h"
+#include "eel-string.h"
+#include <gconf/gconf-client.h>
+#include <gconf/gconf.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 gconf_connection_id;
+ char *enumeration_id;
+ GConfValue *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_gconf_value_get_int (const GConfValue *value)
+{
+ if (value == NULL) {
+ return 0;
+ }
+ g_assert (value->type == GCONF_VALUE_INT);
+ return gconf_value_get_int (value);
+}
+
+static gboolean
+preferences_gconf_value_get_bool (const GConfValue *value)
+{
+ if (value == NULL) {
+ return FALSE;
+ }
+ g_assert (value->type == GCONF_VALUE_BOOL);
+ return gconf_value_get_bool (value);
+}
+
+static char *
+preferences_gconf_value_get_string (const GConfValue *value)
+{
+ if (value == NULL) {
+ return g_strdup ("");
+ }
+ g_assert (value->type == GCONF_VALUE_STRING);
+ return g_strdup (gconf_value_get_string (value));
+}
+
+static char **
+preferences_gconf_value_get_string_array (const GConfValue *value)
+{
+ GSList *slist, *l;
+ GPtrArray *result;
+
+ if (value == NULL) {
+ return NULL;
+ }
+
+ g_assert (value->type == GCONF_VALUE_LIST);
+ g_assert (gconf_value_get_list_type (value) == GCONF_VALUE_STRING);
+
+ slist = eel_gconf_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_gconf_monitor_remove (storage_path);
+
+ g_free (storage_path);
+ storage_path = g_strdup (new_storage_path);
+
+ /* Start monitoring the new path */
+ eel_gconf_monitor_add (storage_path);
+}
+
+static gboolean
+preferences_is_initialized (void)
+{
+ return initialized;
+}
+
+static GConfValue *
+preferences_get_value (const char *name)
+{
+ GConfValue *result;
+ char *key;
+ PreferencesEntry *entry;
+
+ g_assert (name != NULL);
+ g_assert (preferences_is_initialized ());
+
+ key = preferences_key_make (name);
+ result = eel_gconf_get_value (key);
+ g_free (key);
+
+ if (result == NULL) {
+ entry = preferences_global_table_lookup_or_insert (name);
+
+ if (entry->fallback)
+ result = gconf_value_copy (entry->fallback);
+ }
+
+ return result;
+}
+
+/* If the preference name begind with a "/", we interpret
+ * it as a straight gconf key. */
+static gboolean
+preferences_preference_is_gconf_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_gconf_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 GConfValue *
+preferences_get_default_value (const char *name)
+{
+ GConfValue *result;
+ PreferencesEntry *entry;
+ char *key;
+
+ g_assert (name != NULL);
+
+ key = preferences_key_make (name);
+
+ result = eel_gconf_get_default_value (key);
+
+ g_free (key);
+
+ if (result == NULL) {
+ entry = preferences_global_table_lookup_or_insert (name);
+ if (entry && entry->fallback)
+ result = gconf_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_gconf_set_boolean (key, boolean_value);
+ g_free (key);
+
+ eel_gconf_suggest_sync ();
+}
+
+gboolean
+eel_preferences_get_boolean (const char *name)
+{
+ gboolean result;
+ GConfValue *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_gconf_value_get_bool (value);
+ eel_gconf_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_gconf_set_integer (key, int_value);
+ }
+ g_free (key);
+}
+
+int
+eel_preferences_get_integer (const char *name)
+{
+ int result;
+ GConfValue *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_gconf_value_get_int (value);
+ eel_gconf_value_free (value);
+
+ return result;
+}
+
+/* GConf 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;
+ GConfValue *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 == GCONF_VALUE_INT) { /* compatibility path */
+ ret_val = (guint)preferences_gconf_value_get_int (value);
+ eel_gconf_value_free (value);
+ return ret_val;
+ }
+
+ str_value = preferences_gconf_value_get_string (value);
+ eel_gconf_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_gconf_set_string (key, string_value);
+ }
+ g_free (key);
+ g_free (old_value);
+}
+
+char *
+eel_preferences_get (const char *name)
+{
+ char *result;
+ GConfValue *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_gconf_value_get_string (value);
+ eel_gconf_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_gconf_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;
+ GConfValue *value;
+ PreferencesEntry *entry;
+ GConfValue *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_gconf_value_get_string_array (value);
+ eel_gconf_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_gconf_value_get_string_array (default_value);
+ gconf_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_gconf_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_gconf_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 (GConfClient *client,
+ guint connection_id,
+ GConfEntry *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_gconf_connection (PreferencesEntry *entry)
+{
+ char *key;
+
+ /*
+ * We install only one gconf notification for each preference entry.
+ * Otherwise, we would invoke the installed callbacks more than once
+ * per registered callback.
+ */
+ if (entry->gconf_connection_id != EEL_GCONF_UNDEFINED_CONNECTION) {
+ return;
+ }
+
+ g_assert (entry->name != NULL);
+
+ key = preferences_key_make (entry->name);
+
+ entry->gconf_connection_id = eel_gconf_notification_add (key,
+ preferences_something_changed_notice,
+ entry);
+ g_free (key);
+
+ g_assert (entry->gconf_connection_id != EEL_GCONF_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_gconf_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_gconf_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 gconf notification.
+ */
+ if (entry->callback_list != NULL || entry->auto_storage_list != NULL) {
+ return;
+ }
+
+ eel_gconf_notification_remove (entry->gconf_connection_id);
+ entry->gconf_connection_id = EEL_GCONF_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_gconf_notification_remove (entry->gconf_connection_id);
+ entry->gconf_connection_id = EEL_GCONF_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_gconf_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,
+ GConfValue *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)
+ gconf_value_free (entry->fallback);
+ entry->fallback = value; /* steal ownership of value */
+}
+
+void
+eel_preferences_set_emergency_fallback_string (const char *name,
+ const char *value)
+{
+ GConfValue *gconf_value;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ gconf_value = gconf_value_new (GCONF_VALUE_STRING);
+
+ gconf_value_set_string (gconf_value, value);
+
+ preferences_set_emergency_fallback_stealing_value (name, gconf_value);
+}
+
+void
+eel_preferences_set_emergency_fallback_integer (const char *name,
+ int value)
+{
+ GConfValue *gconf_value;
+
+ g_return_if_fail (name != NULL);
+
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+
+ gconf_value_set_int (gconf_value, value);
+
+ preferences_set_emergency_fallback_stealing_value (name, gconf_value);
+}
+
+void
+eel_preferences_set_emergency_fallback_boolean (const char *name,
+ gboolean value)
+{
+ GConfValue *gconf_value;
+
+ g_return_if_fail (name != NULL);
+
+ gconf_value = gconf_value_new (GCONF_VALUE_BOOL);
+
+ gconf_value_set_bool (gconf_value, value);
+
+ preferences_set_emergency_fallback_stealing_value (name, gconf_value);
+}
+
+
+void
+eel_preferences_set_emergency_fallback_string_array (const char *name,
+ char **value)
+{
+ GConfValue *gconf_value;
+ GSList *list;
+ int i;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (value != NULL);
+
+ gconf_value = gconf_value_new (GCONF_VALUE_LIST);
+ gconf_value_set_list_type (gconf_value, GCONF_VALUE_STRING);
+
+ list = NULL;
+ for (i = 0; value[i] != NULL; ++i)
+ {
+ GConfValue *v;
+
+ v = gconf_value_new (GCONF_VALUE_STRING);
+ gconf_value_set_string (v, value[i]);
+
+ list = g_slist_prepend (list, v);
+ }
+
+ gconf_value_set_list_nocopy (gconf_value, g_slist_reverse (list));
+
+ preferences_set_emergency_fallback_stealing_value (name, gconf_value);
+}
+
+GConfValue*
+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 ? gconf_value_copy (entry->fallback) : NULL;
+}
+
+gboolean
+eel_preferences_monitor_directory (const char *directory)
+{
+ g_return_val_if_fail (preferences_is_initialized (), FALSE);
+
+ return eel_gconf_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 000000000..fa8779e23
--- /dev/null
+++ b/eel/eel-preferences.h
@@ -0,0 +1,157 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#ifndef EEL_PREFERENCES_H
+#define EEL_PREFERENCES_H
+
+#include <glib.h>
+#include <eel/eel-gconf-extensions.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/*
+ * 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);
+GConfValue *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_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);
+
+
+G_END_DECLS
+
+#endif /* EEL_PREFERENCES_H */
diff --git a/eel/eel-self-checks.c b/eel/eel-self-checks.c
new file mode 100644
index 000000000..f08358198
--- /dev/null
+++ b/eel/eel-self-checks.c
@@ -0,0 +1,221 @@
+/* -*- 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 <darin@eazel.com>
+*/
+
+#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 000000000..7910febaf
--- /dev/null
+++ b/eel/eel-self-checks.h
@@ -0,0 +1,100 @@
+/* -*- 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 <darin@eazel.com>
+*/
+
+#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 000000000..e55f90f59
--- /dev/null
+++ b/eel/eel-stock-dialogs.c
@@ -0,0 +1,571 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#include <config.h>
+#include "eel-stock-dialogs.h"
+
+#include "eel-alert-dialog.h"
+#include "eel-glib-extensions.h"
+#include "eel-gnome-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) {
+ gtk_widget_unref (GTK_WIDGET (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 (NULL,
+ 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) {
+ gtk_widget_ref (GTK_WIDGET (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);
+ gtk_dialog_set_default_response (dialog, response_2);
+ return dialog;
+}
diff --git a/eel/eel-stock-dialogs.h b/eel/eel-stock-dialogs.h
new file mode 100644
index 000000000..0fb16f464
--- /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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#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 gnome 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 000000000..c72ab9535
--- /dev/null
+++ b/eel/eel-string.c
@@ -0,0 +1,1178 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#include <config.h>
+#include "eel-string.h"
+
+#include <errno.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.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 = g_hash_table_new (g_str_hash, g_str_equal);
+ }
+
+ 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));
+
+ 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 {
+ g_atomic_int_exchange_and_add (count, -1);
+ }
+}
+
+
+#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 000000000..a7c9796aa
--- /dev/null
+++ b/eel/eel-string.h
@@ -0,0 +1,120 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#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 000000000..8a84e1374
--- /dev/null
+++ b/eel/eel-types.c
@@ -0,0 +1,73 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* eel-types.h -
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <mjs@eazel.com>
+*/
+
+
+#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;
+ GtkType type_id;
+ static gboolean initialized = FALSE;
+
+ static struct {
+ const gchar *type_name;
+ GtkType *type_id;
+ GtkType 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 000000000..801a7370f
--- /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 Gnome 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 Gnome 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 Gnome 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 <mjs@eazel.com>
+*/
+
+#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 000000000..c2dad3999
--- /dev/null
+++ b/eel/eel-vfs-extensions.c
@@ -0,0 +1,178 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-vfs-extensions.c - gnome-vfs extensions. Its likely some of these will
+ be part of gnome-vfs in the future.
+
+ Copyright (C) 1999, 2000 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+ Pavel Cisler <pavel@eazel.com>
+ Mike Fleming <mfleming@eazel.com>
+ John Sullivan <sullivan@eazel.com>
+*/
+
+#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 000000000..96d811817
--- /dev/null
+++ b/eel/eel-vfs-extensions.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-vfs-extensions.h - gnome-vfs extensions. Its likely some of these will
+ be part of gnome-vfs in the future.
+
+ Copyright (C) 1999, 2000 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+ Pavel Cisler <pavel@eazel.com>
+ Mike Fleming <mfleming@eazel.com>
+ John Sullivan <sullivan@eazel.com>
+*/
+
+#ifndef EEL_VFS_EXTENSIONS_H
+#define EEL_VFS_EXTENSIONS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define EEL_TRASH_URI "trash:"
+#define EEL_DESKTOP_URI "x-nautilus-desktop:"
+#define EEL_SEARCH_URI "x-nautilus-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);
+
+G_END_DECLS
+
+#endif /* EEL_VFS_EXTENSIONS_H */
diff --git a/eel/eel-wrap-table.c b/eel/eel-wrap-table.c
new file mode 100644
index 000000000..f2ddfe048
--- /dev/null
+++ b/eel/eel-wrap-table.c
@@ -0,0 +1,1053 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#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 GtkType 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_FLAGS (wrap_table, GTK_NO_WINDOW);
+
+ 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 (widget)->border_width * 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);
+
+ widget->allocation = *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_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_FLAGS (widget, GTK_MAPPED);
+
+ for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) {
+ GtkWidget *item;
+
+ item = iterator->data;
+
+ if (GTK_WIDGET_VISIBLE (item) && !GTK_WIDGET_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_UNSET_FLAGS (widget, GTK_MAPPED);
+
+ for (iterator = wrap_table->details->children; iterator; iterator = iterator->next) {
+ GtkWidget *item;
+
+ item = iterator->data;
+
+ if (GTK_WIDGET_VISIBLE (item) && GTK_WIDGET_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;
+
+ g_assert (container != NULL);
+ g_assert (EEL_IS_WRAP_TABLE (container));
+ g_assert (GTK_IS_WIDGET (child));
+
+ 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_REALIZED (container)) {
+ gtk_widget_realize (child);
+ }
+
+ if (GTK_WIDGET_VISIBLE (container) && GTK_WIDGET_VISIBLE (child)) {
+ if (GTK_WIDGET_MAPPED (container)) {
+ 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_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 GtkType
+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;
+
+ 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;
+
+ num_cols = wrap_table_get_num_fitting (GTK_WIDGET (wrap_table)->allocation.width -
+ GTK_CONTAINER (wrap_table)->border_width * 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_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_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 (wrap_table)->border_width * 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;
+
+ g_assert (EEL_IS_WRAP_TABLE (wrap_table));
+
+ content_bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (wrap_table));
+
+ content_bounds.x0 += GTK_CONTAINER (wrap_table)->border_width;
+ content_bounds.y0 += GTK_CONTAINER (wrap_table)->border_width;
+ content_bounds.x1 -= GTK_CONTAINER (wrap_table)->border_width;
+ content_bounds.y1 -= GTK_CONTAINER (wrap_table)->border_width;
+
+ return content_bounds;
+}
+
+static gboolean
+wrap_table_child_focus_in (GtkWidget *widget,
+ GdkEventFocus *event,
+ gpointer data)
+{
+ g_assert (widget->parent && widget->parent->parent);
+ g_assert (GTK_IS_VIEWPORT (widget->parent->parent));
+
+ eel_gtk_viewport_scroll_to_rect (GTK_VIEWPORT (widget->parent->parent),
+ &widget->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_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,
+ 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),
+ GTK_SHADOW_NONE);
+
+ 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 000000000..ab04e2b2e
--- /dev/null
+++ b/eel/eel-wrap-table.h
@@ -0,0 +1,97 @@
+/* -*- 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 Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com>
+*/
+
+#ifndef EEL_WRAP_TABLE_H
+#define EEL_WRAP_TABLE_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EEL_TYPE_WRAP_TABLE (eel_wrap_table_get_type ())
+#define EEL_WRAP_TABLE(obj) (GTK_CHECK_CAST ((obj), EEL_TYPE_WRAP_TABLE, EelWrapTable))
+#define EEL_WRAP_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_WRAP_TABLE, EelWrapTableClass))
+#define EEL_IS_WRAP_TABLE(obj) (GTK_CHECK_TYPE ((obj), EEL_TYPE_WRAP_TABLE))
+#define EEL_IS_WRAP_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EEL_TYPE_WRAP_TABLE))
+
+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 */
+GtkType 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,
+ GtkWidget **wrap_table_out);
+
+G_END_DECLS
+
+#endif /* EEL_WRAP_TABLE_H */
+
+
diff --git a/eel/eel-xml-extensions.c b/eel/eel-xml-extensions.c
new file mode 100644
index 000000000..7a89edd83
--- /dev/null
+++ b/eel/eel-xml-extensions.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-xml-extensions.c - functions that extend gnome-xml
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#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 000000000..e789dc6de
--- /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 gnome-xml
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ The Gnome 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 Gnome 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 Gnome 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 <darin@eazel.com>
+*/
+
+#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 000000000..69e49c54c
--- /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 Gnome 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 Gnome 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 Gnome 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 <mjs@eazel.com>
+*/
+
+#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-gconf-extensions.h>
+#include <eel/eel-gdk-extensions.h>
+#include <eel/eel-gdk-pixbuf-extensions.h>
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gnome-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 000000000..3974c4b77
--- /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 000000000..95a4816cf
--- /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 (gnome.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 000000000..4284eddd9
--- /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);
+}
diff --git a/eel/update-from-egg.sh b/eel/update-from-egg.sh
new file mode 100755
index 000000000..9be68a9b4
--- /dev/null
+++ b/eel/update-from-egg.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+function die() {
+ echo $*
+ exit 1
+}
+
+if test -z "$EGGDIR"; then
+ echo "Must set EGGDIR"
+ exit 1
+fi
+
+if test -z "$EGGFILES"; then
+ echo "Must set EGGFILES"
+ exit 1
+fi
+
+for FILE in $EGGFILES; do
+ if cmp -s $EGGDIR/$FILE $FILE; then
+ echo "File $FILE is unchanged"
+ else
+ cp $EGGDIR/$FILE $FILE || die "Could not move $EGGDIR/$FILE to $FILE"
+ echo "Updated $FILE"
+ fi
+done