From 2b39a5f36416f2a2f409ea036a492f3a91473718 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Wed, 26 Apr 2000 04:45:19 +0000 Subject: [PATCH] Fix some bugs in alignment. Wed Apr 26 00:43:00 2000 Owen Taylor * gtk/gtktextlayout.c (set_para_values): Fix some bugs in alignment. * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track the widget text directional dynamically. * gtk/gtktextview.[ch]: Added functions to get and set default wrap mode. Tue Apr 25 23:47:38 2000 Owen Taylor * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug in cursor location computation. Tue Apr 25 23:22:59 2000 Owen Taylor * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ vadjusment values properly when layout gets smaller. * gtk/gtktextview.c (need_repaint_handler): Areas being passed in are far completely inaccurate, and sometimes too small, so, for now, just queue a redraw on the whole visible region. Tue Apr 25 22:20:41 2000 Owen Taylor * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error with recursion where process_updates() is called from an expose handler. (GtkTextView is highly broken in doing this, but it should work, so it is a nice test case.) --- ChangeLog | 34 ++ ChangeLog.pre-2-0 | 34 ++ ChangeLog.pre-2-10 | 34 ++ ChangeLog.pre-2-2 | 34 ++ ChangeLog.pre-2-4 | 34 ++ ChangeLog.pre-2-6 | 34 ++ ChangeLog.pre-2-8 | 34 ++ gdk/gdkwindow.c | 11 +- gtk/gtklayout.c | 29 +- gtk/gtktextdisplay.c | 2 +- gtk/gtktextlayout.c | 22 +- gtk/gtktexttypes.h | 1 - gtk/gtktextview.c | 72 ++- gtk/gtktextview.h | 5 + gtk/testtext.c | 1326 ++++++++++++++++++++++++++++++++++-------- po/ca.po | 2 +- po/cs.po | 2 +- po/da.po | 2 +- po/de.po | 2 +- po/el.po | 2 +- po/es.po | 2 +- po/et.po | 2 +- po/eu.po | 2 +- po/fi.po | 2 +- po/fr.po | 2 +- po/ga.po | 2 +- po/gl.po | 2 +- po/hr.po | 2 +- po/hu.po | 2 +- po/it.po | 2 +- po/ja.po | 2 +- po/ko.po | 2 +- po/lt.po | 2 +- po/nl.po | 2 +- po/no.po | 2 +- po/pl.po | 2 +- po/pt.po | 2 +- po/pt_BR.po | 2 +- po/ru.po | 2 +- po/sk.po | 2 +- po/sl.po | 2 +- po/sv.po | 2 +- po/tr.po | 2 +- po/uk.po | 2 +- po/wa.po | 2 +- po/zh_CN.GB2312.po | 2 +- po/zh_TW.Big5.po | 2 +- tests/testtext.c | 1326 ++++++++++++++++++++++++++++++++++-------- 48 files changed, 2583 insertions(+), 513 deletions(-) diff --git a/ChangeLog b/ChangeLog index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 60e8a01988..4aefbd1e91 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor + + * gtk/gtktextlayout.c (set_para_values): Fix some bugs in + alignment. + + * gtk/gtktextview.c (gtk_text_view_ensure_layout): Track + the widget text directional dynamically. + + * gtk/gtktextview.[ch]: Added functions to get and set default + wrap mode. + +Tue Apr 25 23:47:38 2000 Owen Taylor + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor + + * gtk/gtklayout.c (gtk_layout_set_size): Clamp hadjustment/ + vadjusment values properly when layout gets smaller. + + * gtk/gtktextview.c (need_repaint_handler): Areas being + passed in are far completely inaccurate, and sometimes + too small, so, for now, just queue a redraw on the + whole visible region. + +Tue Apr 25 22:20:41 2000 Owen Taylor + + * gdk/gdkwindow.c (gdk_window_process_updates_internal): Fix error + with recursion where process_updates() is called from + an expose handler. (GtkTextView is highly broken in + doing this, but it should work, so it is a nice test + case.) + 2000-04-25 Havoc Pennington * gtk/gtktextbtree.c (summary_destroy): new function to diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 444ae5201b..7993471d06 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -1082,6 +1082,9 @@ gdk_window_process_updates_internal (GdkWindow *window) */ if (private->update_area) { + GdkRegion *update_area = private->update_area; + private->update_area = NULL; + if (gdk_event_func) { GdkEvent event; @@ -1092,13 +1095,13 @@ gdk_window_process_updates_internal (GdkWindow *window) window_rect.width = private->drawable.width; window_rect.height = private->drawable.height; - save_region = _gdk_windowing_window_queue_antiexpose (window, private->update_area); + save_region = _gdk_windowing_window_queue_antiexpose (window, update_area); event.expose.type = GDK_EXPOSE; event.expose.window = gdk_window_ref ((GdkWindow *)private); event.expose.count = 0; - gdk_region_get_clipbox (private->update_area, &event.expose.area); + gdk_region_get_clipbox (update_area, &event.expose.area); if (gdk_rectangle_intersect (&event.expose.area, &window_rect, &event.expose.area)) { (*gdk_event_func) (&event, gdk_event_data); @@ -1106,9 +1109,7 @@ gdk_window_process_updates_internal (GdkWindow *window) } if (!save_region) - gdk_region_destroy (private->update_area); - - private->update_area = NULL; + gdk_region_destroy (update_area); } } diff --git a/gtk/gtklayout.c b/gtk/gtklayout.c index 1dfac809ee..7542e17451 100644 --- a/gtk/gtklayout.c +++ b/gtk/gtklayout.c @@ -270,6 +270,28 @@ gtk_layout_move (GtkLayout *layout, } } +static void +gtk_layout_set_adjustment_upper (GtkAdjustment *adj, gfloat upper) +{ + if (upper != adj->upper) + { + gfloat min = MAX (0., upper - adj->page_size); + gboolean value_changed = FALSE; + + adj->upper = upper; + + if (adj->value > min) + { + adj->value = min; + value_changed = TRUE; + } + + gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed"); + if (value_changed) + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); + } +} + void gtk_layout_set_size (GtkLayout *layout, guint width, @@ -285,11 +307,8 @@ gtk_layout_set_size (GtkLayout *layout, layout->width = width; layout->height = height; - layout->hadjustment->upper = layout->width; - gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); - - layout->vadjustment->upper = layout->height; - gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); + gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width); + gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height); if (GTK_WIDGET_REALIZED (layout)) { diff --git a/gtk/gtktextdisplay.c b/gtk/gtktextdisplay.c index 5d5134dbba..1575a73dd6 100644 --- a/gtk/gtktextdisplay.c +++ b/gtk/gtktextdisplay.c @@ -284,7 +284,7 @@ render_para (GdkDrawable *drawable, pango_layout_line_get_extents (line, NULL, &logical_rect); - x_offset = line_display->x_offset * PANGO_SCALE; + x_offset = line_display->left_margin * PANGO_SCALE; switch (align) { diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 4e058191e7..a9d3a09f62 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -495,7 +495,17 @@ gtk_text_layout_real_invalidate (GtkTextLayout *layout, line = gtk_text_line_next (line); } - /* FIXME yeah we could probably do a bit better here */ + /* FIXME yeah we could probably do a bit better here + * + * -hp + * + * We could do a lot better. Not only could we queue + * only the changed areas, layout->width/height are the + * old width and height so may be too small, as well as + * too big. + * + * -owt + */ gtk_text_layout_need_repaint (layout, 0, 0, layout->width, layout->height); } @@ -532,7 +542,7 @@ gtk_text_layout_real_wrap (GtkTextLayout *layout, release_style () to free it. */ static GtkTextStyleValues* get_style (GtkTextLayout *layout, - const GtkTextIter *iter) + const GtkTextIter *iter) { GtkTextTag** tags; gint tag_count = 0; @@ -741,11 +751,11 @@ set_para_values (GtkTextLayout *layout, /* FIXME: Handle this; for now, fall-through */ case GTK_WRAPMODE_WORD: display->total_width = -1; - layout_width = layout->screen_width - display->x_offset - style->right_margin; + layout_width = MAX (layout->width, layout->screen_width) - display->x_offset - style->right_margin; pango_layout_set_width (display->layout, layout_width * PANGO_SCALE); break; case GTK_WRAPMODE_NONE: - display->total_width = layout->width - display->x_offset - style->right_margin; + display->total_width = MAX (layout->screen_width, layout->width) - display->x_offset - style->right_margin; break; } } @@ -1279,7 +1289,7 @@ gtk_text_layout_get_iter_location (GtkTextLayout *layout, pango_layout_line_get_extents (last_line, NULL, &pango_rect); rect->x = display->x_offset + (pango_rect.x + pango_rect.width) / PANGO_SCALE; - rect->y += display->top_margin + pango_rect.y / PANGO_SCALE; + rect->y += display->top_margin; rect->width = 0; rect->height = pango_rect.height / PANGO_SCALE; } @@ -1290,7 +1300,7 @@ gtk_text_layout_get_iter_location (GtkTextLayout *layout, pango_layout_index_to_pos (display->layout, byte_index, &pango_rect); rect->x = display->x_offset + pango_rect.x / PANGO_SCALE; - rect->y += display->top_margin + pango_rect.y / PANGO_SCALE; + rect->y += display->top_margin; rect->width = pango_rect.width / PANGO_SCALE; rect->height = pango_rect.height / PANGO_SCALE; } diff --git a/gtk/gtktexttypes.h b/gtk/gtktexttypes.h index c9c208b29b..d8c284a38a 100644 --- a/gtk/gtktexttypes.h +++ b/gtk/gtktexttypes.h @@ -148,4 +148,3 @@ gchar *gtk_text_latin1_to_utf (const gchar *latin1, gint len); #endif - diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index e55889531c..b0ecd2dadd 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -565,6 +565,8 @@ gtk_text_view_init (GtkTextView *text_view) GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + text_view->wrap_mode = GTK_WRAPMODE_NONE; + if (!clipboard_atom) clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); @@ -830,7 +832,7 @@ gtk_text_view_scroll_to_mark (GtkTextView *text_view, g_return_val_if_fail (mark_within_margin >= 0, FALSE); return gtk_text_view_scroll_to_mark_adjusted (text_view, mark_name, - mark_within_margin, 1.0); + mark_within_margin, 1.0); } static gboolean @@ -888,6 +890,34 @@ gtk_text_view_get_visible_rect (GtkTextView *text_view, } } +void +gtk_text_view_set_wrap_mode (GtkTextView *text_view, + GtkWrapMode wrap_mode) +{ + g_return_if_fail (text_view != NULL); + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + if (text_view->wrap_mode != wrap_mode) + { + text_view->wrap_mode = wrap_mode; + + if (text_view->layout) + { + text_view->layout->default_style->wrap_mode = wrap_mode; + gtk_text_layout_default_style_changed (text_view->layout); + } + } +} + +GtkWrapMode +gtk_text_view_get_wrap_mode (GtkTextView *text_view) +{ + g_return_if_fail (text_view != NULL); + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + return text_view->wrap_mode; +} + gboolean gtk_text_view_place_cursor_onscreen (GtkTextView *text_view) { @@ -1004,12 +1034,26 @@ gtk_text_view_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) } static void -gtk_text_view_size_request (GtkWidget *widget, - GtkRequisition *requisition) +gtk_text_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) { + GtkTextView *text_view = GTK_TEXT_VIEW (widget); + /* Hrm */ requisition->width = 1; requisition->height = 1; + + /* Check to see if the widget direction has changed */ + + if (text_view->layout) + { + GtkTextDirection direction = gtk_widget_get_direction (widget); + if (direction != text_view->layout->default_style->direction) + { + text_view->layout->default_style->direction = direction; + gtk_text_layout_default_style_changed (text_view->layout); + } + } } static void @@ -1036,6 +1080,22 @@ need_repaint_handler (GtkTextLayout *layout, gpointer data) { GtkTextView *text_view; + GdkRectangle visible_rect; + + text_view = GTK_TEXT_VIEW (data); + + /* FIXME: Right now, the area is usually far too big, and + * sometimes too small, so we just queue the whole visible + * rectangle + */ + if (GTK_WIDGET_REALIZED (text_view)) + { + gtk_text_view_get_visible_rect (text_view, &visible_rect); + gdk_window_invalidate_rect (GTK_LAYOUT (text_view)->bin_window, &visible_rect, FALSE); + } + +#if 0 + GdkRectangle screen; GdkRectangle area; GdkRectangle intersect; @@ -1077,6 +1137,7 @@ need_repaint_handler (GtkTextLayout *layout, intersect.height); } #endif +#endif 0 } static void @@ -1267,7 +1328,8 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event) else if (event->keyval == GDK_Return) { gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1); - return FALSE; + gtk_text_view_scroll_to_mark (text_view, "insert", 0); + return TRUE; } else return FALSE; @@ -2098,7 +2160,7 @@ gtk_text_view_ensure_layout (GtkTextView *text_view) style->pixels_below_lines = 2; style->pixels_inside_wrap = 1; - style->wrap_mode = GTK_WRAPMODE_NONE; + style->wrap_mode = text_view->wrap_mode; style->justify = GTK_JUSTIFY_LEFT; style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view)); diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index e2e1ef9526..923db59900 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -59,6 +59,8 @@ struct _GtkTextView { gboolean overwrite_mode; + GtkWrapMode wrap_mode; /* Default wrap mode */ + /* The virtual cursor position is normally the same as the * actual (strong) cursor position, except in two circumstances: * @@ -117,6 +119,9 @@ gboolean gtk_text_view_place_cursor_onscreen (GtkTextView *text_view); void gtk_text_view_get_visible_rect (GtkTextView *text_view, GdkRectangle *visible_rect); +void gtk_text_view_set_wrap_mode (GtkTextView *text_view, + GtkWrapMode wrap_mode); +GtkWrapMode gtk_text_view_get_wrap_mode (GtkTextView *text_view); #ifdef __cplusplus } diff --git a/gtk/testtext.c b/gtk/testtext.c index de21095d25..74b9fd2d2d 100644 --- a/gtk/testtext.c +++ b/gtk/testtext.c @@ -1,8 +1,295 @@ -#include #include +#include #include #include +#include +#include +#include +#include + +typedef struct _Buffer Buffer; +typedef struct _View View; + +static gint untitled_serial = 1; + +GSList *active_window_stack = NULL; + +struct _Buffer +{ + gint refcount; + GtkTextBuffer *buffer; + char *filename; + gint untitled_serial; +}; + +struct _View +{ + GtkWidget *window; + GtkWidget *text_view; + GtkAccelGroup *accel_group; + GtkItemFactory *item_factory; + Buffer *buffer; +}; + +static void push_active_window (GtkWindow *window); +static void pop_active_window (void); +static GtkWindow *get_active_window (void); + +static Buffer * create_buffer (void); +static gboolean check_buffer_saved (Buffer *buffer); +static gboolean save_buffer (Buffer *buffer); +static gboolean save_as_buffer (Buffer *buffer); +static char * buffer_pretty_name (Buffer *buffer); +static void buffer_filename_set (Buffer *buffer); + +static View *view_from_widget (GtkWidget *widget); + +static View *create_view (Buffer *buffer); +static void check_close_view (View *view); +static void close_view (View *view); +static void view_set_title (View *view); +static void view_init_menus (View *view); + +GSList *buffers = NULL; +GSList *views = NULL; + +static void +push_active_window (GtkWindow *window) +{ + gtk_object_ref (GTK_OBJECT (window)); + active_window_stack = g_slist_prepend (active_window_stack, window); +} + +static void +pop_active_window (void) +{ + gtk_object_unref (active_window_stack->data); + active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack); +} + +static GtkWindow * +get_active_window (void) +{ + if (active_window_stack) + return active_window_stack->data; + else + return NULL; +} + +/* + * Filesel utility function + */ + +typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data); + +static void +filesel_ok_cb (GtkWidget *button, GtkWidget *filesel) +{ + FileselOKFunc ok_func = gtk_object_get_data (GTK_OBJECT (filesel), "ok-func"); + gpointer data = gtk_object_get_data (GTK_OBJECT (filesel), "ok-data"); + gint *result = gtk_object_get_data (GTK_OBJECT (filesel), "ok-result"); + + gtk_widget_hide (filesel); + + if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data)) + { + gtk_widget_destroy (filesel); + *result = TRUE; + } + else + gtk_widget_show (filesel); +} + +gboolean +filesel_run (GtkWindow *parent, + const char *title, + const char *start_file, + FileselOKFunc func, + gpointer data) +{ + GtkWidget *filesel = gtk_file_selection_new (title); + gboolean result = FALSE; + + if (!parent) + parent = get_active_window (); + + if (parent) + gtk_window_set_transient_for (GTK_WINDOW (filesel), parent); + + if (start_file) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file); + + + gtk_object_set_data (GTK_OBJECT (filesel), "ok-func", func); + gtk_object_set_data (GTK_OBJECT (filesel), "ok-data", data); + gtk_object_set_data (GTK_OBJECT (filesel), "ok-result", &result); + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (filesel_ok_cb), filesel); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel)); + + gtk_signal_connect (GTK_OBJECT (filesel), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + gtk_window_set_modal (GTK_WINDOW (filesel), TRUE); + + gtk_widget_show (filesel); + gtk_main (); + + return result; +} + +/* + * MsgBox utility functions + */ + +static void +msgbox_yes_cb (GtkWidget *widget, gboolean *result) +{ + *result = 0; + gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget))); +} + +static void +msgbox_no_cb (GtkWidget *widget, gboolean *result) +{ + *result = 1; + gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget))); +} + +static gboolean +msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + if (event->keyval == GDK_Escape) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + gtk_object_destroy (GTK_OBJECT (widget)); + return TRUE; + } + + return FALSE; +} + +gint +msgbox_run (GtkWindow *parent, + const char *message, + const char *yes_button, + const char *no_button, + const char *cancel_button, + gint default_index) +{ + gboolean result = -1; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button_box; + GtkWidget *separator; + + g_return_val_if_fail (message != NULL, FALSE); + g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE); + + if (!parent) + parent = get_active_window (); + + /* Create a dialog + */ + dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + if (parent) + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* Quit our recursive main loop when the dialog is destroyed. + */ + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + + /* Catch Escape key presses and have them destroy the dialog + */ + gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", + GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL); + + /* Fill in the contents of the widget + */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (dialog), vbox); + + label = gtk_label_new (message); + gtk_misc_set_padding (GTK_MISC (label), 12, 12); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0); + + button_box = gtk_hbutton_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (button_box), 8); + + + /* When Yes is clicked, call the msgbox_yes_cb + * This sets the result variable and destroys the dialog + */ + if (yes_button) + { + button = gtk_button_new_with_label (yes_button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_container_add (GTK_CONTAINER (button_box), button); + + if (default_index == 0) + gtk_widget_grab_default (button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (msgbox_yes_cb), &result); + } + + /* When No is clicked, call the msgbox_no_cb + * This sets the result variable and destroys the dialog + */ + if (no_button) + { + button = gtk_button_new_with_label (no_button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_container_add (GTK_CONTAINER (button_box), button); + + if (default_index == 0) + gtk_widget_grab_default (button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (msgbox_no_cb), &result); + } + + /* When Cancel is clicked, destroy the dialog + */ + if (cancel_button) + { + button = gtk_button_new_with_label (cancel_button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_container_add (GTK_CONTAINER (button_box), button); + + if (default_index == 1) + gtk_widget_grab_default (button); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog)); + } + + gtk_widget_show_all (dialog); + + /* Run a recursive main loop until a button is clicked + * or the user destroys the dialog through the window mananger */ + gtk_main (); + + return result; +} + +/* + * Example buffer filling code + */ static gint blink_timeout(gpointer data) { @@ -88,42 +375,6 @@ setup_tag(GtkTextTag *tag) NULL); } -static gint -delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) -{ - gtk_main_quit(); - return TRUE; -} - -static void -create_window(GtkTextBuffer *buffer) -{ - GtkWidget *window; - GtkWidget *sw; - GtkWidget *tkxt; - - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_signal_connect(GTK_OBJECT(window), "delete_event", - GTK_SIGNAL_FUNC(delete_event_cb), NULL); - - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - tkxt = gtk_text_view_new_with_buffer(buffer); - - gtk_container_add(GTK_CONTAINER(window), sw); - gtk_container_add(GTK_CONTAINER(sw), tkxt); - - gtk_window_set_default_size(GTK_WINDOW(window), - 500, 500); - - gtk_widget_grab_focus(tkxt); - - gtk_widget_show_all(window); -} - static char *book_closed_xpm[] = { "16 16 6 1", " c None s None", @@ -149,239 +400,856 @@ static char *book_closed_xpm[] = { " .. ", " "}; -int -main(int argc, char** argv) + + +void +fill_example_buffer (GtkTextBuffer *buffer) { - GtkTextBuffer *buffer; GtkTextIter iter, iter2; - gchar *str; GtkTextTag *tag; GdkColor color; GdkColor color2; GdkPixmap *pixmap; GdkBitmap *mask; int i; + char *str; - gtk_init(&argc, &argv); - - buffer = gtk_text_buffer_new(NULL); + tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); - if (argv[1]) + /* gtk_timeout_add(1000, blink_timeout, tag); */ + + setup_tag(tag); + + color.red = color.green = 0; + color.blue = 0xffff; + color2.red = 0xfff; + color2.blue = 0x0; + color2.green = 0; + gtk_object_set(GTK_OBJECT(tag), + "foreground_gdk", &color, + "background_gdk", &color2, + "font", "Sans 24", + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "fg_red"); + + setup_tag(tag); + + color.blue = color.green = 0; + color.red = 0xffff; + gtk_object_set(GTK_OBJECT(tag), + "offset", -4, + "foreground_gdk", &color, + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "bg_green"); + + setup_tag(tag); + + color.blue = color.red = 0; + color.green = 0xffff; + gtk_object_set(GTK_OBJECT(tag), + "background_gdk", &color, + "font", "Sans 10", + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "overstrike"); + + setup_tag(tag); + + gtk_object_set(GTK_OBJECT(tag), + "overstrike", TRUE, + NULL); + + + tag = gtk_text_buffer_create_tag(buffer, "underline"); + + setup_tag(tag); + + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + + setup_tag(tag); + + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "centered"); + + gtk_object_set(GTK_OBJECT(tag), + "justify", GTK_JUSTIFY_CENTER, + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); + + gtk_object_set(GTK_OBJECT(tag), + "wrap_mode", GTK_WRAPMODE_WORD, + "direction", GTK_TEXT_DIR_RTL, + "left_wrapped_line_margin", 20, + "left_margin", 20, + "right_margin", 20, + NULL); + + pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, + gtk_widget_get_default_colormap(), + &mask, + NULL, book_closed_xpm); + + g_assert(pixmap != NULL); + + i = 0; + while (i < 100) { - FILE* f; - - f = fopen(argv[1], "r"); - - if (f == NULL) - { - fprintf(stderr, "Failed to open %s: %s\n", - argv[1], g_strerror(errno)); - exit(1); - } - - while (TRUE) - { - gchar buf[2048]; - gchar *s; - - s = fgets(buf, 2048, f); - - if (s == NULL) - break; + gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); - gtk_text_buffer_insert_after_line(buffer, -1, buf, -1); - } - } - else - { - tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); - - /* gtk_timeout_add(1000, blink_timeout, tag); */ - - setup_tag(tag); - - color.red = color.green = 0; - color.blue = 0xffff; - color2.red = 0xfff; - color2.blue = 0x0; - color2.green = 0; - gtk_object_set(GTK_OBJECT(tag), - "foreground_gdk", &color, - "background_gdk", &color2, - "font", "Sans 24", - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "fg_red"); - - setup_tag(tag); - - color.blue = color.green = 0; - color.red = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "offset", -4, - "foreground_gdk", &color, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "bg_green"); - - setup_tag(tag); - - color.blue = color.red = 0; - color.green = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "background_gdk", &color, - "font", "Sans 10", - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "overstrike"); - - setup_tag(tag); - - gtk_object_set(GTK_OBJECT(tag), - "overstrike", TRUE, - NULL); - - - tag = gtk_text_buffer_create_tag(buffer, "underline"); - - setup_tag(tag); - - gtk_object_set(GTK_OBJECT(tag), - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - - setup_tag(tag); - - gtk_object_set(GTK_OBJECT(tag), - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "centered"); - - gtk_object_set(GTK_OBJECT(tag), - "justify", GTK_JUSTIFY_CENTER, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); - - gtk_object_set(GTK_OBJECT(tag), - "direction", GTK_TEXT_DIR_RTL, - "left_wrapped_line_margin", 20, - "left_margin", 20, - "right_margin", 20, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "wrap"); - - gtk_object_set(GTK_OBJECT(tag), - "wrap_mode", GTK_WRAPMODE_WORD, - NULL); - - pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, - gtk_widget_get_default_colormap(), - &mask, - NULL, book_closed_xpm); - - g_assert(pixmap != NULL); - - i = 0; - while (i < 100) - { - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - - str = g_strdup_printf("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n", - i); + str = g_strdup_printf("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n", + i); - gtk_text_buffer_insert(buffer, &iter, str, -1); + gtk_text_buffer_insert(buffer, &iter, str, -1); - g_free(str); + g_free(str); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 5); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 5); - gtk_text_buffer_insert(buffer, &iter, - "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n" - /* This is UTF8 stuff, Emacs doesn't - really know how to display it */ - "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1); + gtk_text_buffer_insert(buffer, &iter, + "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n" + /* This is UTF8 stuff, Emacs doesn't + really know how to display it */ + "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1); - gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE); + gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE); #if 1 - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 6); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 13); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 6); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 13); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 10); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 16); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 10); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 16); - gtk_text_buffer_apply_tag(buffer, "underline", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "underline", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 14); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 24); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 14); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 24); - gtk_text_buffer_apply_tag(buffer, "overstrike", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "overstrike", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 9); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 16); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 9); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 16); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 10); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 2); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 10); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 8); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 15); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 8); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 15); - gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); #endif - gtk_text_buffer_get_iter_at_mark (buffer, &iter, "tmp_mark"); - gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, "tmp_mark"); + gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1); - gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); - gtk_text_buffer_apply_tag (buffer, "centered", &iter2, &iter); + gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); + gtk_text_buffer_apply_tag (buffer, "centered", &iter2, &iter); - gtk_text_buffer_move_mark (buffer, "tmp_mark", &iter); - gtk_text_buffer_insert (buffer, &iter, "Right-to-left Quote\n", -1); - gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1); - gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); - gtk_text_buffer_apply_tag (buffer, "rtl_quote", &iter2, &iter); + gtk_text_buffer_move_mark (buffer, "tmp_mark", &iter); + gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1); + gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1); + gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); + gtk_text_buffer_apply_tag (buffer, "rtl_quote", &iter2, &iter); - ++i; - } - - gdk_pixmap_unref(pixmap); - if (mask) - gdk_bitmap_unref(mask); + ++i; } - - /* Set the whole buffer to wrap - */ - gtk_text_buffer_get_bounds (buffer, &iter, &iter2); - gtk_text_buffer_apply_tag (buffer, "wrap", &iter, &iter2); + gdk_pixmap_unref(pixmap); + if (mask) + gdk_bitmap_unref(mask); -#if 0 - str = gtk_text_buffer_get_chars_from_line(buffer, 0, 0, -1, TRUE); - - printf("Got: `%s'\n", str); - - g_free(str); - - gtk_text_buffer_spew(buffer); - -#endif printf("%d lines %d chars\n", - gtk_text_buffer_get_line_count(buffer), - gtk_text_buffer_get_char_count(buffer)); + gtk_text_buffer_get_line_count(buffer), + gtk_text_buffer_get_char_count(buffer)); - /* create_window(buffer); */ - create_window(buffer); + gtk_text_buffer_set_modified (buffer, FALSE); +} + +gboolean +fill_file_buffer (GtkTextBuffer *buffer, const char *filename) +{ + FILE* f; + gchar buf[2048]; + gint remaining = 0; + GtkTextIter iter, end; + + f = fopen(filename, "r"); + + if (f == NULL) + { + gchar *err = g_strdup_printf ("Cannot open file '%s': %s", + filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + return FALSE; + } + + gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + while (!feof (f)) + { + gint count; + char *leftover, *next; + unicode_char_t wc; + int to_read = 2047 - remaining; + + count = fread (buf + remaining, 1, to_read, f); + buf[count + remaining] = '\0'; + + leftover = next = buf; + while (next) + { + leftover = next; + if (!*leftover) + break; + + next = unicode_get_utf8 (next, &wc); + } + + gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf); + + remaining = buf + remaining + count - leftover; + g_memmove (buf, leftover, remaining); + + if (remaining > 6 || count < to_read) + break; + } + + if (remaining) + { + gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + + /* We had a newline in the buffer to begin with. (The buffer always contains + * a newline, so we delete to the end of the buffer to clean up. + */ + gtk_text_buffer_get_last_iter (buffer, &end); + gtk_text_buffer_delete (buffer, &iter, &end); + + gtk_text_buffer_set_modified (buffer, FALSE); + + return TRUE; +} + +static gint +delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) +{ + View *view = view_from_widget (window); + + push_active_window (GTK_WINDOW (window)); + check_close_view (view); + pop_active_window (); + + return TRUE; +} + +/* + * Menu callbacks + */ + +static View * +get_empty_view (View *view) +{ + if (!view->buffer->filename && + !gtk_text_buffer_modified (view->buffer->buffer)) + return view; + else + return create_view (create_buffer ()); +} + +static View * +view_from_widget (GtkWidget *widget) +{ + GtkWidget *app; + + if (GTK_IS_MENU_ITEM (widget)) + { + GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget); + return gtk_object_get_data (GTK_OBJECT (item_factory), "view"); + } + else + { + GtkWidget *app = gtk_widget_get_toplevel (widget); + return gtk_object_get_data (GTK_OBJECT (app), "view"); + } +} + +static void +do_new (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + create_view (create_buffer ()); +} + +static void +do_new_view (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + create_view (view->buffer); +} + +gboolean +open_ok_func (const char *filename, gpointer data) +{ + View *view = data; + View *new_view = get_empty_view (view); + + if (!fill_file_buffer (new_view->buffer->buffer, filename)) + { + if (new_view != view) + close_view (new_view); + return FALSE; + } + else + { + g_free (new_view->buffer->filename); + new_view->buffer->filename = g_strdup (filename); + buffer_filename_set (new_view->buffer); + + return TRUE; + } +} + +static void +do_open (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + filesel_run (NULL, "Open File", NULL, open_ok_func, view); + pop_active_window (); +} + +static void +do_save_as (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + save_as_buffer (view->buffer); + pop_active_window (); +} + +static void +do_save (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + if (!view->buffer->filename) + do_save_as (callback_data, callback_action, widget); + else + save_buffer (view->buffer); + pop_active_window (); +} + +static void +do_close (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + check_close_view (view); + pop_active_window (); +} + +static void +do_exit (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + GSList *tmp_list = buffers; + + push_active_window (GTK_WINDOW (view->window)); + while (tmp_list) + { + if (!check_buffer_saved (tmp_list->data)) + return; + + tmp_list = tmp_list->next; + } + + gtk_main_quit(); + pop_active_window (); +} + +static void +do_example (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + View *new_view; + + new_view = get_empty_view (view); + + fill_example_buffer (new_view->buffer->buffer); +} + +static void +do_wrap_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_direction_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_widget_set_direction (view->text_view, callback_action); + gtk_widget_queue_resize (view->text_view); +} + +static void +view_init_menus (View *view) +{ + GtkTextDirection direction = gtk_widget_get_direction (view->text_view); + GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view)); + GtkWidget *menu_item = NULL; + + switch (direction) + { + case GTK_TEXT_DIR_LTR: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right"); + break; + case GTK_TEXT_DIR_RTL: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left"); + break; + default: + break; + } + + if (menu_item) + gtk_menu_item_activate (GTK_MENU_ITEM (menu_item)); + + switch (wrap_mode) + { + case GTK_WRAPMODE_NONE: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off"); + break; + case GTK_WRAPMODE_WORD: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words"); + break; + default: + break; + } + + if (menu_item) + gtk_menu_item_activate (GTK_MENU_ITEM (menu_item)); +} + +static GtkItemFactoryEntry menu_items[] = +{ + { "/_File", NULL, 0, 0, "" }, + { "/File/_New", "N", do_new, 0, NULL }, + { "/File/New _View", NULL, do_new_view, 0, NULL }, + { "/File/_Open", "O", do_open, 0, NULL }, + { "/File/_Save", "S", do_save, 0, NULL }, + { "/File/Save _As...", NULL, do_save_as, 0, NULL }, + { "/File/sep1", NULL, 0, 0, "" }, + { "/File/_Close", "W" , do_close, 0, NULL }, + { "/File/E_xit", "Q" , do_exit, 0, NULL }, + + { "/_Settings", NULL, 0, 0, "" }, + { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "" }, + { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "" }, + { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, + + { "/_Test", NULL, 0, 0, "" }, + { "/Test/_Example", NULL, do_example, 0, NULL }, +}; + +static gboolean +save_buffer (Buffer *buffer) +{ + GtkTextIter start, end; + gchar *chars; + gboolean result = FALSE; + gboolean have_backup = FALSE; + gchar *bak_filename; + FILE *file; + + g_return_val_if_fail (buffer->filename != NULL, FALSE); + + bak_filename = g_strconcat (buffer->filename, "~", NULL); + + if (rename (buffer->filename, bak_filename) != 0) + { + if (errno != ENOENT) + { + gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s", + buffer->filename, bak_filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + + return FALSE; + } + else + have_backup = TRUE; + + file = fopen (buffer->filename, "w"); + if (!file) + { + gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s", + buffer->filename, bak_filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + } + else + { + gtk_text_buffer_get_iter_at_char (buffer->buffer, &start, 0); + gtk_text_buffer_get_last_iter (buffer->buffer, &end); + + chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE); + + if (fputs (chars, file) == EOF || + fclose (file) == EOF) + { + gchar *err = g_strdup_printf ("Error writing to '%s': %s", + buffer->filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + else + { + /* Success + */ + result = TRUE; + gtk_text_buffer_set_modified (buffer->buffer, FALSE); + } + + g_free (chars); + } + + if (!result && have_backup) + { + if (rename (bak_filename, buffer->filename) != 0) + { + gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'", + buffer->filename, bak_filename, g_strerror (errno), bak_filename); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + } + + g_free (bak_filename); + + return result; +} + +static gboolean +save_as_ok_func (const char *filename, gpointer data) +{ + Buffer *buffer = data; + char *old_filename = buffer->filename; + + if (!buffer->filename || strcmp (filename, buffer->filename) != 0) + { + struct stat statbuf; + + if (stat(filename, &statbuf) == 0) + { + gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename); + gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1); + g_free (err); + + if (result != 0) + return FALSE; + } + } + + buffer->filename = g_strdup (filename); + + if (save_buffer (buffer)) + { + g_free (old_filename); + buffer_filename_set (buffer); + return TRUE; + } + else + { + g_free (buffer->filename); + buffer->filename = old_filename; + return FALSE; + } +} + +static gboolean +save_as_buffer (Buffer *buffer) +{ + return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer); +} + +static gboolean +check_buffer_saved (Buffer *buffer) +{ + if (gtk_text_buffer_modified (buffer->buffer)) + { + char *pretty_name = buffer_pretty_name (buffer); + char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name); + gint result; + + g_free (pretty_name); + + result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0); + g_free (msg); + + if (result == 0) + return save_as_buffer (buffer); + else if (result == 1) + return TRUE; + else + return FALSE; + } + else + return TRUE; +} + +static Buffer * +create_buffer (void) +{ + Buffer *buffer; + + buffer = g_new (Buffer, 1); + + buffer->buffer = gtk_text_buffer_new (NULL); + gtk_object_ref (GTK_OBJECT (buffer->buffer)); + gtk_object_sink (GTK_OBJECT (buffer->buffer)); + + buffer->refcount = 1; + buffer->filename = NULL; + buffer->untitled_serial = -1; + + buffers = g_slist_prepend (buffers, buffer); + + return buffer; +} + +static char * +buffer_pretty_name (Buffer *buffer) +{ + if (buffer->filename) + { + char *p; + char *result = g_strdup (g_basename (buffer->filename)); + p = strchr (result, '/'); + if (p) + *p = '\0'; + + return result; + } + else + { + if (buffer->untitled_serial == -1) + buffer->untitled_serial = untitled_serial++; + + if (buffer->untitled_serial == 1) + return g_strdup ("Untitled"); + else + return g_strdup_printf ("Untitled #%d", buffer->untitled_serial); + } +} + +static void +buffer_filename_set (Buffer *buffer) +{ + GSList *tmp_list = views; + + while (tmp_list) + { + View *view = tmp_list->data; + + if (view->buffer == buffer) + view_set_title (view); + + tmp_list = tmp_list->next; + } +} + +static void +buffer_ref (Buffer *buffer) +{ + buffer->refcount++; +} + +static void +buffer_unref (Buffer *buffer) +{ + buffer->refcount--; + if (buffer->refcount == 0) + { + buffers = g_slist_remove (buffers, buffer); + gtk_object_unref (GTK_OBJECT (buffer->buffer)); + g_free (buffer->filename); + g_free (buffer); + } +} + +static void +close_view (View *view) +{ + views = g_slist_remove (views, view); + buffer_unref (view->buffer); + gtk_widget_destroy (view->window); + g_free (view); + + if (!views) + gtk_main_quit(); +} + +static void +check_close_view (View *view) +{ + if (view->buffer->refcount > 1 || + check_buffer_saved (view->buffer)) + close_view (view); +} + +static void +view_set_title (View *view) +{ + char *pretty_name = buffer_pretty_name (view->buffer); + char *title = g_strconcat ("testtext - ", pretty_name, NULL); + + gtk_window_set_title (GTK_WINDOW (view->window), title); + + g_free (pretty_name); + g_free (title); +} + +static View * +create_view (Buffer *buffer) +{ + View *view; + + GtkWidget *sw; + GtkWidget *vbox; + + view = g_new0 (View, 1); + views = g_slist_prepend (views, view); + + view->buffer = buffer; + buffer_ref (buffer); + + view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (view->window), "view", view); + + gtk_signal_connect (GTK_OBJECT (view->window), "delete_event", + GTK_SIGNAL_FUNC(delete_event_cb), NULL); + + view->accel_group = gtk_accel_group_new (); + view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "
", view->accel_group); + gtk_object_set_data (GTK_OBJECT (view->item_factory), "view", view); + + gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view); + + gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (view->window), vbox); + + gtk_box_pack_start (GTK_BOX (vbox), + gtk_item_factory_get_widget (view->item_factory, "
"), + FALSE, FALSE, 0); + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + view->text_view = gtk_text_view_new_with_buffer (buffer->buffer); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), GTK_WRAPMODE_WORD); + + gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(sw), view->text_view); + + gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500); + + gtk_widget_grab_focus(view->text_view); + + view_set_title (view); + view_init_menus (view); + + gtk_widget_show_all (view->window); + return view; +} + +int +main(int argc, char** argv) +{ + Buffer *buffer; + View *view; + int i; + + gtk_init(&argc, &argv); + + buffer = create_buffer (); + view = create_view (buffer); + buffer_unref (buffer); + + push_active_window (GTK_WINDOW (view->window)); + for (i=1; i < argc; i++) + { + char *filename; + + /* Quick and dirty canonicalization - better should be in GLib + */ + + if (!g_path_is_absolute (argv[i])) + { + char *cwd = g_get_current_dir (); + filename = g_strconcat (cwd, "/", argv[i], NULL); + g_free (cwd); + } + else + filename = argv[i]; + + open_ok_func (filename, view); + + if (filename != argv[i]) + g_free (filename); + } + pop_active_window (); gtk_main(); diff --git a/po/ca.po b/po/ca.po index c9e4fc9040..0f5c75dd51 100644 --- a/po/ca.po +++ b/po/ca.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-11-18 21:11+01:00\n" "Last-Translator: Ivan Vilata i Balaguer \n" "Language-Team: linux-ca@chanae.alphanet.ch\n" diff --git a/po/cs.po b/po/cs.po index 0ac27ee6d8..d998f457fd 100644 --- a/po/cs.po +++ b/po/cs.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-10-04 14:50+02:00\n" "Last-Translator: Stanislav Brabec \n" "Language-Team: Czech \n" diff --git a/po/da.po b/po/da.po index e564073c14..dd9ed6b97e 100644 --- a/po/da.po +++ b/po/da.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-12-08 17:14+01:00\n" "Last-Translator: Birger Langkjer \n" "Language-Team: Danish \n" diff --git a/po/de.po b/po/de.po index a1b34f97c6..a2954dc17a 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.9\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-08-24 17:38+02:00\n" "Last-Translator: Karsten Weiss \n" "Language-Team: German \n" diff --git a/po/el.po b/po/el.po index dc934ec442..c2c3ad6013 100644 --- a/po/el.po +++ b/po/el.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.2.6\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-10-22 22:43-0000\n" "Last-Translator: Spiros Papadimitriou \n" "Language-Team: Greek \n" diff --git a/po/es.po b/po/es.po index dbdba64cf5..17f7ffa42b 100644 --- a/po/es.po +++ b/po/es.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-02-07 17:37+0100\n" "Last-Translator: Pablo Saratxaga \n" "Language-Team: \n" diff --git a/po/et.po b/po/et.po index 81f2fa85ef..ddca68d4f1 100644 --- a/po/et.po +++ b/po/et.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.2.6\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-09-26 23:40+0300\n" "Last-Translator: Lauris Kaplinski \n" "Language-Team: Estonian\n" diff --git a/po/eu.po b/po/eu.po index 70fa9cd854..66145ea747 100644 --- a/po/eu.po +++ b/po/eu.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ VERSION\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-07-05 19:17+0200\n" "Last-Translator: Joseba Bidaurrazaga van Dierdonck \n" "Language-Team: euskare \n" diff --git a/po/fi.po b/po/fi.po index 9ac8265ad9..2cb7f95d29 100644 --- a/po/fi.po +++ b/po/fi.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.9\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-08-13 14:15+0100\n" "Last-Translator: Mikko Rauhala \n" "Language-Team: Finnish \n" diff --git a/po/fr.po b/po/fr.po index 01b66730b1..6b860db6f2 100644 --- a/po/fr.po +++ b/po/fr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ VERSION\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1998-12-18 20:32+0100\n" "Last-Translator: Vincent Renardias \n" "Language-Team: Vincent Renardias \n" diff --git a/po/ga.po b/po/ga.po index a77fabe130..7986b4d197 100644 --- a/po/ga.po +++ b/po/ga.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-08-23 21:28+0600\n" "Last-Translator: Sean V. Kelley \n" "Language-Team: Gaeilge \n" diff --git a/po/gl.po b/po/gl.po index 94cd3ea180..489b27340e 100644 --- a/po/gl.po +++ b/po/gl.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 2000-01-02 13:19+0100\n" "Last-Translator: Jesus Bravo Alvarez \n" "Language-Team: Galician \n" diff --git a/po/hr.po b/po/hr.po index 5db4001416..4455614389 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: Tue Jan 11 2000 16:35:38+0200\n" "Last-Translator: Vladimir Vuksan \n" "Language-Team: Croatian \n" diff --git a/po/hu.po b/po/hu.po index ac6f2789ca..2621543839 100644 --- a/po/hu.po +++ b/po/hu.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.2\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-11-24 19:15+0100\n" "Last-Translator: Shooby Ban \n" "Language-Team: Hungarian \n" diff --git a/po/it.po b/po/it.po index 17d886b007..310da3c979 100644 --- a/po/it.po +++ b/po/it.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.2.7\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 2000-02-26 12:15+0100\n" "Last-Translator: Christopher R. Gabriel \n" "Language-Team: Italiano \n" diff --git a/po/ja.po b/po/ja.po index 2107d34248..53bb692f8a 100644 --- a/po/ja.po +++ b/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.2.7\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-10-08 11:42+0900\n" "Last-Translator: ٹ \n" "Language-Team: Japanese \n" diff --git a/po/ko.po b/po/ko.po index 6eda5b95f7..526f85abad 100644 --- a/po/ko.po +++ b/po/ko.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.15\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-04-24 22:53+0900\n" "Last-Translator: Changwoo Ryu \n" "Language-Team: Korean \n" diff --git a/po/lt.po b/po/lt.po index d6673249e3..7fb0e876d8 100644 --- a/po/lt.po +++ b/po/lt.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 2000-03-16 03:44+0200\n" "Last-Translator: Gediminas Paulauskas \n" "Language-Team: Lithuanian\n" diff --git a/po/nl.po b/po/nl.po index bc56c1ac73..adbe9dae18 100644 --- a/po/nl.po +++ b/po/nl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-01-31 23:04+0100\n" "Last-Translator: Paul Siegmann \n" "Language-Team: dutch \n" diff --git a/po/no.po b/po/no.po index 629dda5658..2ddaf4a264 100644 --- a/po/no.po +++ b/po/no.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 2000-02-04 09:54+0200\n" "Last-Translator: Kjartan Maraas \n" "Language-Team: Norwegian \n" diff --git a/po/pl.po b/po/pl.po index 1318671628..2e3d858343 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-09-03 05:00+0200\n" "Last-Translator: GNOME PL Team\n" "Language-Team: Polish \n" diff --git a/po/pt.po b/po/pt.po index 420174fb33..f091ce653c 100644 --- a/po/pt.po +++ b/po/pt.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.12\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-02-17 01:20+00:00\n" "Last-Translator: Nuno Ferreira \n" "Language-Team: Portuguese \n" diff --git a/po/pt_BR.po b/po/pt_BR.po index ac68b2034f..fda86faeac 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.12\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-09-29 17:40-03:00\n" "Last-Translator: Alex Sandro Queiroz e Silva \n" "Language-Team: Brazilian Portuguese \n" diff --git a/po/ru.po b/po/ru.po index 6618be08cf..e4825bcae0 100644 --- a/po/ru.po +++ b/po/ru.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-10-05 02:21-0400\n" "Last-Translator: Sergey Panov \n" "Language-Team: Russian \n" diff --git a/po/sk.po b/po/sk.po index 46a215ee57..1827d7ca64 100644 --- a/po/sk.po +++ b/po/sk.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-04-19 16:30+0100\n" "Last-Translator: Stefan Ondrejicka \n" "Language-Team: Slovak \n" diff --git a/po/sl.po b/po/sl.po index ae102a2a98..4b71f13dc9 100644 --- a/po/sl.po +++ b/po/sl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-03-06 10:00+0100\n" "Last-Translator: Miha Tomi \n" "Language-Team: slovenian \n" diff --git a/po/sv.po b/po/sv.po index 79687c56ce..f83fcee7a6 100644 --- a/po/sv.po +++ b/po/sv.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-01-12 22:50+0100\n" "Last-Translator: Tomas gren \n" "Language-Team: Swedish \n" diff --git a/po/tr.po b/po/tr.po index b64d163a3d..36caa7ecc3 100644 --- a/po/tr.po +++ b/po/tr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ CVS-?\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-11-18 16:38+02:00\n" "Last-Translator: Fatih Demir \n" "Language-Team: Turkish Gnome Tranlation Team \n" diff --git a/po/uk.po b/po/uk.po index 3e1b60dd55..c49444704d 100644 --- a/po/uk.po +++ b/po/uk.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-09-30 21:51 EST\n" "Last-Translator: Yuri Syrota \n" "Language-Team: Ukrainian \n" diff --git a/po/wa.po b/po/wa.po index 33f07d901b..0640a4a75a 100644 --- a/po/wa.po +++ b/po/wa.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.3.0\n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-02-07 17:37+0100\n" "Last-Translator: Pablo Saratxaga \n" "Language-Team: walon \n" diff --git a/po/zh_CN.GB2312.po b/po/zh_CN.GB2312.po index 74ec43057e..3a8c8313d6 100644 --- a/po/zh_CN.GB2312.po +++ b/po/zh_CN.GB2312.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.7 \n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-01-31 19:33+0800\n" "Last-Translator: Dillion Chen \n" "Language-Team: TLDN\n" diff --git a/po/zh_TW.Big5.po b/po/zh_TW.Big5.po index 8210c367ec..fac3533292 100644 --- a/po/zh_TW.Big5.po +++ b/po/zh_TW.Big5.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: gtk+ 1.1.7 \n" -"POT-Creation-Date: 2000-04-05 00:36-0400\n" +"POT-Creation-Date: 2000-04-12 19:55-0400\n" "PO-Revision-Date: 1999-01-31 19:33+0800\n" "Last-Translator: ߤ \n" "Language-Team: Chinese \n" diff --git a/tests/testtext.c b/tests/testtext.c index de21095d25..74b9fd2d2d 100644 --- a/tests/testtext.c +++ b/tests/testtext.c @@ -1,8 +1,295 @@ -#include #include +#include #include #include +#include +#include +#include +#include + +typedef struct _Buffer Buffer; +typedef struct _View View; + +static gint untitled_serial = 1; + +GSList *active_window_stack = NULL; + +struct _Buffer +{ + gint refcount; + GtkTextBuffer *buffer; + char *filename; + gint untitled_serial; +}; + +struct _View +{ + GtkWidget *window; + GtkWidget *text_view; + GtkAccelGroup *accel_group; + GtkItemFactory *item_factory; + Buffer *buffer; +}; + +static void push_active_window (GtkWindow *window); +static void pop_active_window (void); +static GtkWindow *get_active_window (void); + +static Buffer * create_buffer (void); +static gboolean check_buffer_saved (Buffer *buffer); +static gboolean save_buffer (Buffer *buffer); +static gboolean save_as_buffer (Buffer *buffer); +static char * buffer_pretty_name (Buffer *buffer); +static void buffer_filename_set (Buffer *buffer); + +static View *view_from_widget (GtkWidget *widget); + +static View *create_view (Buffer *buffer); +static void check_close_view (View *view); +static void close_view (View *view); +static void view_set_title (View *view); +static void view_init_menus (View *view); + +GSList *buffers = NULL; +GSList *views = NULL; + +static void +push_active_window (GtkWindow *window) +{ + gtk_object_ref (GTK_OBJECT (window)); + active_window_stack = g_slist_prepend (active_window_stack, window); +} + +static void +pop_active_window (void) +{ + gtk_object_unref (active_window_stack->data); + active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack); +} + +static GtkWindow * +get_active_window (void) +{ + if (active_window_stack) + return active_window_stack->data; + else + return NULL; +} + +/* + * Filesel utility function + */ + +typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data); + +static void +filesel_ok_cb (GtkWidget *button, GtkWidget *filesel) +{ + FileselOKFunc ok_func = gtk_object_get_data (GTK_OBJECT (filesel), "ok-func"); + gpointer data = gtk_object_get_data (GTK_OBJECT (filesel), "ok-data"); + gint *result = gtk_object_get_data (GTK_OBJECT (filesel), "ok-result"); + + gtk_widget_hide (filesel); + + if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data)) + { + gtk_widget_destroy (filesel); + *result = TRUE; + } + else + gtk_widget_show (filesel); +} + +gboolean +filesel_run (GtkWindow *parent, + const char *title, + const char *start_file, + FileselOKFunc func, + gpointer data) +{ + GtkWidget *filesel = gtk_file_selection_new (title); + gboolean result = FALSE; + + if (!parent) + parent = get_active_window (); + + if (parent) + gtk_window_set_transient_for (GTK_WINDOW (filesel), parent); + + if (start_file) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file); + + + gtk_object_set_data (GTK_OBJECT (filesel), "ok-func", func); + gtk_object_set_data (GTK_OBJECT (filesel), "ok-data", data); + gtk_object_set_data (GTK_OBJECT (filesel), "ok-result", &result); + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (filesel_ok_cb), filesel); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (filesel)); + + gtk_signal_connect (GTK_OBJECT (filesel), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + gtk_window_set_modal (GTK_WINDOW (filesel), TRUE); + + gtk_widget_show (filesel); + gtk_main (); + + return result; +} + +/* + * MsgBox utility functions + */ + +static void +msgbox_yes_cb (GtkWidget *widget, gboolean *result) +{ + *result = 0; + gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget))); +} + +static void +msgbox_no_cb (GtkWidget *widget, gboolean *result) +{ + *result = 1; + gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget))); +} + +static gboolean +msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + if (event->keyval == GDK_Escape) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + gtk_object_destroy (GTK_OBJECT (widget)); + return TRUE; + } + + return FALSE; +} + +gint +msgbox_run (GtkWindow *parent, + const char *message, + const char *yes_button, + const char *no_button, + const char *cancel_button, + gint default_index) +{ + gboolean result = -1; + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button_box; + GtkWidget *separator; + + g_return_val_if_fail (message != NULL, FALSE); + g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE); + + if (!parent) + parent = get_active_window (); + + /* Create a dialog + */ + dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + if (parent) + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* Quit our recursive main loop when the dialog is destroyed. + */ + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + + /* Catch Escape key presses and have them destroy the dialog + */ + gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", + GTK_SIGNAL_FUNC (msgbox_key_press_cb), NULL); + + /* Fill in the contents of the widget + */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (dialog), vbox); + + label = gtk_label_new (message); + gtk_misc_set_padding (GTK_MISC (label), 12, 12); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0); + + button_box = gtk_hbutton_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (button_box), 8); + + + /* When Yes is clicked, call the msgbox_yes_cb + * This sets the result variable and destroys the dialog + */ + if (yes_button) + { + button = gtk_button_new_with_label (yes_button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_container_add (GTK_CONTAINER (button_box), button); + + if (default_index == 0) + gtk_widget_grab_default (button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (msgbox_yes_cb), &result); + } + + /* When No is clicked, call the msgbox_no_cb + * This sets the result variable and destroys the dialog + */ + if (no_button) + { + button = gtk_button_new_with_label (no_button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_container_add (GTK_CONTAINER (button_box), button); + + if (default_index == 0) + gtk_widget_grab_default (button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (msgbox_no_cb), &result); + } + + /* When Cancel is clicked, destroy the dialog + */ + if (cancel_button) + { + button = gtk_button_new_with_label (cancel_button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_container_add (GTK_CONTAINER (button_box), button); + + if (default_index == 1) + gtk_widget_grab_default (button); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (dialog)); + } + + gtk_widget_show_all (dialog); + + /* Run a recursive main loop until a button is clicked + * or the user destroys the dialog through the window mananger */ + gtk_main (); + + return result; +} + +/* + * Example buffer filling code + */ static gint blink_timeout(gpointer data) { @@ -88,42 +375,6 @@ setup_tag(GtkTextTag *tag) NULL); } -static gint -delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) -{ - gtk_main_quit(); - return TRUE; -} - -static void -create_window(GtkTextBuffer *buffer) -{ - GtkWidget *window; - GtkWidget *sw; - GtkWidget *tkxt; - - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_signal_connect(GTK_OBJECT(window), "delete_event", - GTK_SIGNAL_FUNC(delete_event_cb), NULL); - - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - tkxt = gtk_text_view_new_with_buffer(buffer); - - gtk_container_add(GTK_CONTAINER(window), sw); - gtk_container_add(GTK_CONTAINER(sw), tkxt); - - gtk_window_set_default_size(GTK_WINDOW(window), - 500, 500); - - gtk_widget_grab_focus(tkxt); - - gtk_widget_show_all(window); -} - static char *book_closed_xpm[] = { "16 16 6 1", " c None s None", @@ -149,239 +400,856 @@ static char *book_closed_xpm[] = { " .. ", " "}; -int -main(int argc, char** argv) + + +void +fill_example_buffer (GtkTextBuffer *buffer) { - GtkTextBuffer *buffer; GtkTextIter iter, iter2; - gchar *str; GtkTextTag *tag; GdkColor color; GdkColor color2; GdkPixmap *pixmap; GdkBitmap *mask; int i; + char *str; - gtk_init(&argc, &argv); - - buffer = gtk_text_buffer_new(NULL); + tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); - if (argv[1]) + /* gtk_timeout_add(1000, blink_timeout, tag); */ + + setup_tag(tag); + + color.red = color.green = 0; + color.blue = 0xffff; + color2.red = 0xfff; + color2.blue = 0x0; + color2.green = 0; + gtk_object_set(GTK_OBJECT(tag), + "foreground_gdk", &color, + "background_gdk", &color2, + "font", "Sans 24", + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "fg_red"); + + setup_tag(tag); + + color.blue = color.green = 0; + color.red = 0xffff; + gtk_object_set(GTK_OBJECT(tag), + "offset", -4, + "foreground_gdk", &color, + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "bg_green"); + + setup_tag(tag); + + color.blue = color.red = 0; + color.green = 0xffff; + gtk_object_set(GTK_OBJECT(tag), + "background_gdk", &color, + "font", "Sans 10", + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "overstrike"); + + setup_tag(tag); + + gtk_object_set(GTK_OBJECT(tag), + "overstrike", TRUE, + NULL); + + + tag = gtk_text_buffer_create_tag(buffer, "underline"); + + setup_tag(tag); + + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + + setup_tag(tag); + + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "centered"); + + gtk_object_set(GTK_OBJECT(tag), + "justify", GTK_JUSTIFY_CENTER, + NULL); + + tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); + + gtk_object_set(GTK_OBJECT(tag), + "wrap_mode", GTK_WRAPMODE_WORD, + "direction", GTK_TEXT_DIR_RTL, + "left_wrapped_line_margin", 20, + "left_margin", 20, + "right_margin", 20, + NULL); + + pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, + gtk_widget_get_default_colormap(), + &mask, + NULL, book_closed_xpm); + + g_assert(pixmap != NULL); + + i = 0; + while (i < 100) { - FILE* f; - - f = fopen(argv[1], "r"); - - if (f == NULL) - { - fprintf(stderr, "Failed to open %s: %s\n", - argv[1], g_strerror(errno)); - exit(1); - } - - while (TRUE) - { - gchar buf[2048]; - gchar *s; - - s = fgets(buf, 2048, f); - - if (s == NULL) - break; + gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); - gtk_text_buffer_insert_after_line(buffer, -1, buf, -1); - } - } - else - { - tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); - - /* gtk_timeout_add(1000, blink_timeout, tag); */ - - setup_tag(tag); - - color.red = color.green = 0; - color.blue = 0xffff; - color2.red = 0xfff; - color2.blue = 0x0; - color2.green = 0; - gtk_object_set(GTK_OBJECT(tag), - "foreground_gdk", &color, - "background_gdk", &color2, - "font", "Sans 24", - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "fg_red"); - - setup_tag(tag); - - color.blue = color.green = 0; - color.red = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "offset", -4, - "foreground_gdk", &color, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "bg_green"); - - setup_tag(tag); - - color.blue = color.red = 0; - color.green = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "background_gdk", &color, - "font", "Sans 10", - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "overstrike"); - - setup_tag(tag); - - gtk_object_set(GTK_OBJECT(tag), - "overstrike", TRUE, - NULL); - - - tag = gtk_text_buffer_create_tag(buffer, "underline"); - - setup_tag(tag); - - gtk_object_set(GTK_OBJECT(tag), - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - - setup_tag(tag); - - gtk_object_set(GTK_OBJECT(tag), - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "centered"); - - gtk_object_set(GTK_OBJECT(tag), - "justify", GTK_JUSTIFY_CENTER, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); - - gtk_object_set(GTK_OBJECT(tag), - "direction", GTK_TEXT_DIR_RTL, - "left_wrapped_line_margin", 20, - "left_margin", 20, - "right_margin", 20, - NULL); - - tag = gtk_text_buffer_create_tag(buffer, "wrap"); - - gtk_object_set(GTK_OBJECT(tag), - "wrap_mode", GTK_WRAPMODE_WORD, - NULL); - - pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, - gtk_widget_get_default_colormap(), - &mask, - NULL, book_closed_xpm); - - g_assert(pixmap != NULL); - - i = 0; - while (i < 100) - { - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - - str = g_strdup_printf("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n", - i); + str = g_strdup_printf("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n", + i); - gtk_text_buffer_insert(buffer, &iter, str, -1); + gtk_text_buffer_insert(buffer, &iter, str, -1); - g_free(str); + g_free(str); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 5); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 5); - gtk_text_buffer_insert(buffer, &iter, - "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n" - /* This is UTF8 stuff, Emacs doesn't - really know how to display it */ - "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1); + gtk_text_buffer_insert(buffer, &iter, + "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n" + /* This is UTF8 stuff, Emacs doesn't + really know how to display it */ + "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew שלום Japanese (日本語)\n", -1); - gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE); + gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE); #if 1 - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 6); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 13); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 6); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 13); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 10); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 16); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 10); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 16); - gtk_text_buffer_apply_tag(buffer, "underline", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "underline", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 14); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 24); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 14); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 24); - gtk_text_buffer_apply_tag(buffer, "overstrike", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "overstrike", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 9); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 16); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 9); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 16); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 10); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 2); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 10); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 8); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 15); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 8); + gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 15); - gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); #endif - gtk_text_buffer_get_iter_at_mark (buffer, &iter, "tmp_mark"); - gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, "tmp_mark"); + gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1); - gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); - gtk_text_buffer_apply_tag (buffer, "centered", &iter2, &iter); + gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); + gtk_text_buffer_apply_tag (buffer, "centered", &iter2, &iter); - gtk_text_buffer_move_mark (buffer, "tmp_mark", &iter); - gtk_text_buffer_insert (buffer, &iter, "Right-to-left Quote\n", -1); - gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1); - gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); - gtk_text_buffer_apply_tag (buffer, "rtl_quote", &iter2, &iter); + gtk_text_buffer_move_mark (buffer, "tmp_mark", &iter); + gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1); + gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1); + gtk_text_buffer_get_iter_at_mark (buffer, &iter2, "tmp_mark"); + gtk_text_buffer_apply_tag (buffer, "rtl_quote", &iter2, &iter); - ++i; - } - - gdk_pixmap_unref(pixmap); - if (mask) - gdk_bitmap_unref(mask); + ++i; } - - /* Set the whole buffer to wrap - */ - gtk_text_buffer_get_bounds (buffer, &iter, &iter2); - gtk_text_buffer_apply_tag (buffer, "wrap", &iter, &iter2); + gdk_pixmap_unref(pixmap); + if (mask) + gdk_bitmap_unref(mask); -#if 0 - str = gtk_text_buffer_get_chars_from_line(buffer, 0, 0, -1, TRUE); - - printf("Got: `%s'\n", str); - - g_free(str); - - gtk_text_buffer_spew(buffer); - -#endif printf("%d lines %d chars\n", - gtk_text_buffer_get_line_count(buffer), - gtk_text_buffer_get_char_count(buffer)); + gtk_text_buffer_get_line_count(buffer), + gtk_text_buffer_get_char_count(buffer)); - /* create_window(buffer); */ - create_window(buffer); + gtk_text_buffer_set_modified (buffer, FALSE); +} + +gboolean +fill_file_buffer (GtkTextBuffer *buffer, const char *filename) +{ + FILE* f; + gchar buf[2048]; + gint remaining = 0; + GtkTextIter iter, end; + + f = fopen(filename, "r"); + + if (f == NULL) + { + gchar *err = g_strdup_printf ("Cannot open file '%s': %s", + filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + return FALSE; + } + + gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + while (!feof (f)) + { + gint count; + char *leftover, *next; + unicode_char_t wc; + int to_read = 2047 - remaining; + + count = fread (buf + remaining, 1, to_read, f); + buf[count + remaining] = '\0'; + + leftover = next = buf; + while (next) + { + leftover = next; + if (!*leftover) + break; + + next = unicode_get_utf8 (next, &wc); + } + + gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf); + + remaining = buf + remaining + count - leftover; + g_memmove (buf, leftover, remaining); + + if (remaining > 6 || count < to_read) + break; + } + + if (remaining) + { + gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + + /* We had a newline in the buffer to begin with. (The buffer always contains + * a newline, so we delete to the end of the buffer to clean up. + */ + gtk_text_buffer_get_last_iter (buffer, &end); + gtk_text_buffer_delete (buffer, &iter, &end); + + gtk_text_buffer_set_modified (buffer, FALSE); + + return TRUE; +} + +static gint +delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) +{ + View *view = view_from_widget (window); + + push_active_window (GTK_WINDOW (window)); + check_close_view (view); + pop_active_window (); + + return TRUE; +} + +/* + * Menu callbacks + */ + +static View * +get_empty_view (View *view) +{ + if (!view->buffer->filename && + !gtk_text_buffer_modified (view->buffer->buffer)) + return view; + else + return create_view (create_buffer ()); +} + +static View * +view_from_widget (GtkWidget *widget) +{ + GtkWidget *app; + + if (GTK_IS_MENU_ITEM (widget)) + { + GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget); + return gtk_object_get_data (GTK_OBJECT (item_factory), "view"); + } + else + { + GtkWidget *app = gtk_widget_get_toplevel (widget); + return gtk_object_get_data (GTK_OBJECT (app), "view"); + } +} + +static void +do_new (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + create_view (create_buffer ()); +} + +static void +do_new_view (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + create_view (view->buffer); +} + +gboolean +open_ok_func (const char *filename, gpointer data) +{ + View *view = data; + View *new_view = get_empty_view (view); + + if (!fill_file_buffer (new_view->buffer->buffer, filename)) + { + if (new_view != view) + close_view (new_view); + return FALSE; + } + else + { + g_free (new_view->buffer->filename); + new_view->buffer->filename = g_strdup (filename); + buffer_filename_set (new_view->buffer); + + return TRUE; + } +} + +static void +do_open (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + filesel_run (NULL, "Open File", NULL, open_ok_func, view); + pop_active_window (); +} + +static void +do_save_as (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + save_as_buffer (view->buffer); + pop_active_window (); +} + +static void +do_save (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + if (!view->buffer->filename) + do_save_as (callback_data, callback_action, widget); + else + save_buffer (view->buffer); + pop_active_window (); +} + +static void +do_close (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + push_active_window (GTK_WINDOW (view->window)); + check_close_view (view); + pop_active_window (); +} + +static void +do_exit (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + GSList *tmp_list = buffers; + + push_active_window (GTK_WINDOW (view->window)); + while (tmp_list) + { + if (!check_buffer_saved (tmp_list->data)) + return; + + tmp_list = tmp_list->next; + } + + gtk_main_quit(); + pop_active_window (); +} + +static void +do_example (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + View *new_view; + + new_view = get_empty_view (view); + + fill_example_buffer (new_view->buffer->buffer); +} + +static void +do_wrap_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_direction_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_widget_set_direction (view->text_view, callback_action); + gtk_widget_queue_resize (view->text_view); +} + +static void +view_init_menus (View *view) +{ + GtkTextDirection direction = gtk_widget_get_direction (view->text_view); + GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view)); + GtkWidget *menu_item = NULL; + + switch (direction) + { + case GTK_TEXT_DIR_LTR: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right"); + break; + case GTK_TEXT_DIR_RTL: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left"); + break; + default: + break; + } + + if (menu_item) + gtk_menu_item_activate (GTK_MENU_ITEM (menu_item)); + + switch (wrap_mode) + { + case GTK_WRAPMODE_NONE: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off"); + break; + case GTK_WRAPMODE_WORD: + menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words"); + break; + default: + break; + } + + if (menu_item) + gtk_menu_item_activate (GTK_MENU_ITEM (menu_item)); +} + +static GtkItemFactoryEntry menu_items[] = +{ + { "/_File", NULL, 0, 0, "" }, + { "/File/_New", "N", do_new, 0, NULL }, + { "/File/New _View", NULL, do_new_view, 0, NULL }, + { "/File/_Open", "O", do_open, 0, NULL }, + { "/File/_Save", "S", do_save, 0, NULL }, + { "/File/Save _As...", NULL, do_save_as, 0, NULL }, + { "/File/sep1", NULL, 0, 0, "" }, + { "/File/_Close", "W" , do_close, 0, NULL }, + { "/File/E_xit", "Q" , do_exit, 0, NULL }, + + { "/_Settings", NULL, 0, 0, "" }, + { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "" }, + { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "" }, + { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, + + { "/_Test", NULL, 0, 0, "" }, + { "/Test/_Example", NULL, do_example, 0, NULL }, +}; + +static gboolean +save_buffer (Buffer *buffer) +{ + GtkTextIter start, end; + gchar *chars; + gboolean result = FALSE; + gboolean have_backup = FALSE; + gchar *bak_filename; + FILE *file; + + g_return_val_if_fail (buffer->filename != NULL, FALSE); + + bak_filename = g_strconcat (buffer->filename, "~", NULL); + + if (rename (buffer->filename, bak_filename) != 0) + { + if (errno != ENOENT) + { + gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s", + buffer->filename, bak_filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + + return FALSE; + } + else + have_backup = TRUE; + + file = fopen (buffer->filename, "w"); + if (!file) + { + gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s", + buffer->filename, bak_filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + } + else + { + gtk_text_buffer_get_iter_at_char (buffer->buffer, &start, 0); + gtk_text_buffer_get_last_iter (buffer->buffer, &end); + + chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE); + + if (fputs (chars, file) == EOF || + fclose (file) == EOF) + { + gchar *err = g_strdup_printf ("Error writing to '%s': %s", + buffer->filename, g_strerror (errno)); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + else + { + /* Success + */ + result = TRUE; + gtk_text_buffer_set_modified (buffer->buffer, FALSE); + } + + g_free (chars); + } + + if (!result && have_backup) + { + if (rename (bak_filename, buffer->filename) != 0) + { + gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'", + buffer->filename, bak_filename, g_strerror (errno), bak_filename); + msgbox_run (NULL, err, "OK", NULL, NULL, 0); + g_free (err); + } + } + + g_free (bak_filename); + + return result; +} + +static gboolean +save_as_ok_func (const char *filename, gpointer data) +{ + Buffer *buffer = data; + char *old_filename = buffer->filename; + + if (!buffer->filename || strcmp (filename, buffer->filename) != 0) + { + struct stat statbuf; + + if (stat(filename, &statbuf) == 0) + { + gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename); + gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1); + g_free (err); + + if (result != 0) + return FALSE; + } + } + + buffer->filename = g_strdup (filename); + + if (save_buffer (buffer)) + { + g_free (old_filename); + buffer_filename_set (buffer); + return TRUE; + } + else + { + g_free (buffer->filename); + buffer->filename = old_filename; + return FALSE; + } +} + +static gboolean +save_as_buffer (Buffer *buffer) +{ + return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer); +} + +static gboolean +check_buffer_saved (Buffer *buffer) +{ + if (gtk_text_buffer_modified (buffer->buffer)) + { + char *pretty_name = buffer_pretty_name (buffer); + char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name); + gint result; + + g_free (pretty_name); + + result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0); + g_free (msg); + + if (result == 0) + return save_as_buffer (buffer); + else if (result == 1) + return TRUE; + else + return FALSE; + } + else + return TRUE; +} + +static Buffer * +create_buffer (void) +{ + Buffer *buffer; + + buffer = g_new (Buffer, 1); + + buffer->buffer = gtk_text_buffer_new (NULL); + gtk_object_ref (GTK_OBJECT (buffer->buffer)); + gtk_object_sink (GTK_OBJECT (buffer->buffer)); + + buffer->refcount = 1; + buffer->filename = NULL; + buffer->untitled_serial = -1; + + buffers = g_slist_prepend (buffers, buffer); + + return buffer; +} + +static char * +buffer_pretty_name (Buffer *buffer) +{ + if (buffer->filename) + { + char *p; + char *result = g_strdup (g_basename (buffer->filename)); + p = strchr (result, '/'); + if (p) + *p = '\0'; + + return result; + } + else + { + if (buffer->untitled_serial == -1) + buffer->untitled_serial = untitled_serial++; + + if (buffer->untitled_serial == 1) + return g_strdup ("Untitled"); + else + return g_strdup_printf ("Untitled #%d", buffer->untitled_serial); + } +} + +static void +buffer_filename_set (Buffer *buffer) +{ + GSList *tmp_list = views; + + while (tmp_list) + { + View *view = tmp_list->data; + + if (view->buffer == buffer) + view_set_title (view); + + tmp_list = tmp_list->next; + } +} + +static void +buffer_ref (Buffer *buffer) +{ + buffer->refcount++; +} + +static void +buffer_unref (Buffer *buffer) +{ + buffer->refcount--; + if (buffer->refcount == 0) + { + buffers = g_slist_remove (buffers, buffer); + gtk_object_unref (GTK_OBJECT (buffer->buffer)); + g_free (buffer->filename); + g_free (buffer); + } +} + +static void +close_view (View *view) +{ + views = g_slist_remove (views, view); + buffer_unref (view->buffer); + gtk_widget_destroy (view->window); + g_free (view); + + if (!views) + gtk_main_quit(); +} + +static void +check_close_view (View *view) +{ + if (view->buffer->refcount > 1 || + check_buffer_saved (view->buffer)) + close_view (view); +} + +static void +view_set_title (View *view) +{ + char *pretty_name = buffer_pretty_name (view->buffer); + char *title = g_strconcat ("testtext - ", pretty_name, NULL); + + gtk_window_set_title (GTK_WINDOW (view->window), title); + + g_free (pretty_name); + g_free (title); +} + +static View * +create_view (Buffer *buffer) +{ + View *view; + + GtkWidget *sw; + GtkWidget *vbox; + + view = g_new0 (View, 1); + views = g_slist_prepend (views, view); + + view->buffer = buffer; + buffer_ref (buffer); + + view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (view->window), "view", view); + + gtk_signal_connect (GTK_OBJECT (view->window), "delete_event", + GTK_SIGNAL_FUNC(delete_event_cb), NULL); + + view->accel_group = gtk_accel_group_new (); + view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "
", view->accel_group); + gtk_object_set_data (GTK_OBJECT (view->item_factory), "view", view); + + gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view); + + gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (view->window), vbox); + + gtk_box_pack_start (GTK_BOX (vbox), + gtk_item_factory_get_widget (view->item_factory, "
"), + FALSE, FALSE, 0); + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + view->text_view = gtk_text_view_new_with_buffer (buffer->buffer); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), GTK_WRAPMODE_WORD); + + gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(sw), view->text_view); + + gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500); + + gtk_widget_grab_focus(view->text_view); + + view_set_title (view); + view_init_menus (view); + + gtk_widget_show_all (view->window); + return view; +} + +int +main(int argc, char** argv) +{ + Buffer *buffer; + View *view; + int i; + + gtk_init(&argc, &argv); + + buffer = create_buffer (); + view = create_view (buffer); + buffer_unref (buffer); + + push_active_window (GTK_WINDOW (view->window)); + for (i=1; i < argc; i++) + { + char *filename; + + /* Quick and dirty canonicalization - better should be in GLib + */ + + if (!g_path_is_absolute (argv[i])) + { + char *cwd = g_get_current_dir (); + filename = g_strconcat (cwd, "/", argv[i], NULL); + g_free (cwd); + } + else + filename = argv[i]; + + open_ok_func (filename, view); + + if (filename != argv[i]) + g_free (filename); + } + pop_active_window (); gtk_main();