diff options
| author | Owen Taylor <otaylor@redhat.com> | 2000-04-26 04:45:19 +0000 |
|---|---|---|
| committer | Owen Taylor <otaylor@src.gnome.org> | 2000-04-26 04:45:19 +0000 |
| commit | 2b39a5f36416f2a2f409ea036a492f3a91473718 (patch) | |
| tree | 3a68a66fb1dcc468a597b2d8782449d16bfc4eed | |
| parent | c046f7dc8cc78730bf48f74d3ecd9273ae17ec9f (diff) | |
| download | gtk+-2b39a5f36416f2a2f409ea036a492f3a91473718.tar.gz | |
Fix some bugs in alignment.
Wed Apr 26 00:43:00 2000 Owen Taylor <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
* gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug
in cursor location computation.
Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
* 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.)
| -rw-r--r-- | ChangeLog | 34 | ||||
| -rw-r--r-- | ChangeLog.pre-2-0 | 34 | ||||
| -rw-r--r-- | ChangeLog.pre-2-10 | 34 | ||||
| -rw-r--r-- | ChangeLog.pre-2-2 | 34 | ||||
| -rw-r--r-- | ChangeLog.pre-2-4 | 34 | ||||
| -rw-r--r-- | ChangeLog.pre-2-6 | 34 | ||||
| -rw-r--r-- | ChangeLog.pre-2-8 | 34 | ||||
| -rw-r--r-- | gdk/gdkwindow.c | 11 | ||||
| -rw-r--r-- | gtk/gtklayout.c | 29 | ||||
| -rw-r--r-- | gtk/gtktextdisplay.c | 2 | ||||
| -rw-r--r-- | gtk/gtktextlayout.c | 22 | ||||
| -rw-r--r-- | gtk/gtktexttypes.h | 1 | ||||
| -rw-r--r-- | gtk/gtktextview.c | 72 | ||||
| -rw-r--r-- | gtk/gtktextview.h | 5 | ||||
| -rw-r--r-- | gtk/testtext.c | 1278 | ||||
| -rw-r--r-- | po/ca.po | 2 | ||||
| -rw-r--r-- | po/cs.po | 2 | ||||
| -rw-r--r-- | po/da.po | 2 | ||||
| -rw-r--r-- | po/de.po | 2 | ||||
| -rw-r--r-- | po/el.po | 2 | ||||
| -rw-r--r-- | po/es.po | 2 | ||||
| -rw-r--r-- | po/et.po | 2 | ||||
| -rw-r--r-- | po/eu.po | 2 | ||||
| -rw-r--r-- | po/fi.po | 2 | ||||
| -rw-r--r-- | po/fr.po | 2 | ||||
| -rw-r--r-- | po/ga.po | 2 | ||||
| -rw-r--r-- | po/gl.po | 2 | ||||
| -rw-r--r-- | po/hr.po | 2 | ||||
| -rw-r--r-- | po/hu.po | 2 | ||||
| -rw-r--r-- | po/it.po | 2 | ||||
| -rw-r--r-- | po/ja.po | 2 | ||||
| -rw-r--r-- | po/ko.po | 2 | ||||
| -rw-r--r-- | po/lt.po | 2 | ||||
| -rw-r--r-- | po/nl.po | 2 | ||||
| -rw-r--r-- | po/no.po | 2 | ||||
| -rw-r--r-- | po/pl.po | 2 | ||||
| -rw-r--r-- | po/pt.po | 2 | ||||
| -rw-r--r-- | po/pt_BR.po | 2 | ||||
| -rw-r--r-- | po/ru.po | 2 | ||||
| -rw-r--r-- | po/sk.po | 2 | ||||
| -rw-r--r-- | po/sl.po | 2 | ||||
| -rw-r--r-- | po/sv.po | 2 | ||||
| -rw-r--r-- | po/tr.po | 2 | ||||
| -rw-r--r-- | po/uk.po | 2 | ||||
| -rw-r--r-- | po/wa.po | 2 | ||||
| -rw-r--r-- | po/zh_CN.GB2312.po | 2 | ||||
| -rw-r--r-- | po/zh_TW.Big5.po | 2 | ||||
| -rw-r--r-- | tests/testtext.c | 1278 |
48 files changed, 2535 insertions, 465 deletions
@@ -1,3 +1,37 @@ +Wed Apr 26 00:43:00 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * gtk/gtktextlayout.c (gtk_text_layout_get_iter_location): Fix bug + in cursor location computation. + +Tue Apr 25 23:22:59 2000 Owen Taylor <otaylor@redhat.com> + + * 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 <otaylor@redhat.com> + + * 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 <hp@redhat.com> * 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 <gtk/gtk.h> #include <stdio.h> +#include <sys/stat.h> #include <errno.h> #include <stdlib.h> +#include <string.h> +#include <unicode.h> + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +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); - - if (argv[1]) - { - FILE* f; + tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); - 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_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); + /* gtk_timeout_add(1000, blink_timeout, 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); + 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"); + tag = gtk_text_buffer_create_tag(buffer, "fg_red"); - setup_tag(tag); + setup_tag(tag); - color.blue = color.green = 0; - color.red = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "offset", -4, - "foreground_gdk", &color, - NULL); + 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"); + tag = gtk_text_buffer_create_tag(buffer, "bg_green"); - setup_tag(tag); + setup_tag(tag); - color.blue = color.red = 0; - color.green = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "background_gdk", &color, - "font", "Sans 10", - NULL); + 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"); + tag = gtk_text_buffer_create_tag(buffer, "overstrike"); - setup_tag(tag); + setup_tag(tag); - gtk_object_set(GTK_OBJECT(tag), - "overstrike", TRUE, - NULL); - + 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); + tag = gtk_text_buffer_create_tag(buffer, "underline"); - setup_tag(tag); + 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); + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); - tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); + setup_tag(tag); - gtk_object_set(GTK_OBJECT(tag), - "direction", GTK_TEXT_DIR_RTL, - "left_wrapped_line_margin", 20, - "left_margin", 20, - "right_margin", 20, - NULL); + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); - tag = gtk_text_buffer_create_tag(buffer, "wrap"); + tag = gtk_text_buffer_create_tag(buffer, "centered"); - 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); + gtk_object_set(GTK_OBJECT(tag), + "justify", GTK_JUSTIFY_CENTER, + NULL); - g_assert(pixmap != NULL); + tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); - i = 0; - while (i < 100) - { - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + 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) + { + 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_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_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, "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; - } + ++i; + } + + gdk_pixmap_unref(pixmap); + if (mask) + gdk_bitmap_unref(mask); + + printf("%d lines %d chars\n", + gtk_text_buffer_get_line_count(buffer), + gtk_text_buffer_get_char_count(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; - gdk_pixmap_unref(pixmap); - if (mask) - gdk_bitmap_unref(mask); + 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); - /* Set the whole buffer to wrap + 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_bounds (buffer, &iter, &iter2); - gtk_text_buffer_apply_tag (buffer, "wrap", &iter, &iter2); + gtk_text_buffer_get_last_iter (buffer, &end); + gtk_text_buffer_delete (buffer, &iter, &end); -#if 0 - str = gtk_text_buffer_get_chars_from_line(buffer, 0, 0, -1, TRUE); + gtk_text_buffer_set_modified (buffer, FALSE); - printf("Got: `%s'\n", str); + return TRUE; +} - g_free(str); +static gint +delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) +{ + View *view = view_from_widget (window); - gtk_text_buffer_spew(buffer); + push_active_window (GTK_WINDOW (window)); + check_close_view (view); + pop_active_window (); -#endif - printf("%d lines %d chars\n", - gtk_text_buffer_get_line_count(buffer), - gtk_text_buffer_get_char_count(buffer)); + 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; - /* create_window(buffer); */ - create_window(buffer); + 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, "<Branch>" }, + { "/File/_New", "<control>N", do_new, 0, NULL }, + { "/File/New _View", NULL, do_new_view, 0, NULL }, + { "/File/_Open", "<control>O", do_open, 0, NULL }, + { "/File/_Save", "<control>S", do_save, 0, NULL }, + { "/File/Save _As...", NULL, do_save_as, 0, NULL }, + { "/File/sep1", NULL, 0, 0, "<Separator>" }, + { "/File/_Close", "<control>W" , do_close, 0, NULL }, + { "/File/E_xit", "<control>Q" , do_exit, 0, NULL }, + + { "/_Settings", NULL, 0, 0, "<Branch>" }, + { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "<RadioItem>" }, + { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, + { "/Settings/sep1", NULL, 0, 0, "<Separator>" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" }, + { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, + + { "/_Test", NULL, 0, 0, "<Branch>" }, + { "/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, "<main>", 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, "<main>"), + 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(); @@ -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 <al011097@alumail.uji.es>\n" "Language-Team: linux-ca@chanae.alphanet.ch\n" @@ -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 <utx@k332.feld.cvut.cz>\n" "Language-Team: Czech <cs@li.org>\n" @@ -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 <birger.langkjer@image.dk>\n" "Language-Team: Danish <sslug-locale@sslug.dk>\n" @@ -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 <karsten@addx.au.s.shuttle.de>\n" "Language-Team: German <de@li.org>\n" @@ -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 <spapadim+@cs.cmu.edu>\n" "Language-Team: Greek <nls@tux.hellug.gr>\n" @@ -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 <srtxg@chanae.alphanet.ch>\n" "Language-Team: \n" @@ -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 <lauris@ariman.ee>\n" "Language-Team: Estonian\n" @@ -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 <gcpbivaj@lg.ehu.es>\n" "Language-Team: euskare <linux-eu@chanae.alphanet.ch>\n" @@ -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 <lukka@iki.fi>\n" "Language-Team: Finnish <fi@li.org>\n" @@ -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 <vincent@debian.org>\n" "Language-Team: Vincent Renardias <vincent@debian.org>\n" @@ -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 <s_oceallaigh@yahoo.com>\n" "Language-Team: Gaeilge <ga@li.org>\n" @@ -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 <jba@pobox.com>\n" "Language-Team: Galician <gpul-traduccion@ceu.fi.udc.es>\n" @@ -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 <vuksan@veus.hr>\n" "Language-Team: Croatian <lokalizacija@linux.hr>\n" @@ -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 <bansz@szif.hu>\n" "Language-Team: Hungarian <hu@li.org>\n" @@ -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 <cgabriel@pluto.linux.it>\n" "Language-Team: Italiano <it@li.org>\n" @@ -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: Çòºê Âٹ° <yasuhiro@awa.tohoku.ac.jp>\n" "Language-Team: Japanese <ja@li.org>\n" @@ -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 <cwryu@adam.kaist.ac.kr>\n" "Language-Team: Korean <ko@li.org>\n" @@ -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 <menesis@delfi.lt>\n" "Language-Team: Lithuanian\n" @@ -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 <pauls@euronet.nl>\n" "Language-Team: dutch <nl@li.org>\n" @@ -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 <kmaraas@online.no>\n" "Language-Team: Norwegian <no@li.org>\n" @@ -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 <gnomepl@pandora.info.bielsko.pl>\n" @@ -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 <nmrf@rnl.ist.utl.pt>\n" "Language-Team: Portuguese <pt@li.org>\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 <asandro@lcg.dc.ufc.br>\n" "Language-Team: Brazilian Portuguese <ldp-br@bazar.conectiva.com.br>\n" @@ -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 <sipan@mit.edu>\n" "Language-Team: Russian <ru@li.org>\n" @@ -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 <ondrej@idata.sk>\n" "Language-Team: Slovak <sk@li.org>\n" @@ -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 Tom¹iè <miha.tomsic@guest.arnes.si>\n" "Language-Team: slovenian <sl@li.org>\n" @@ -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 <stric@ing.umu.se>\n" "Language-Team: Swedish <sv@li.org>\n" @@ -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 <kabalak@gmx.net>\n" "Language-Team: Turkish Gnome Tranlation Team <gnotrap@gmx.net>\n" @@ -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 <yuri@renome.rovno.ua>\n" "Language-Team: Ukrainian <uk@li.org>\n" @@ -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 <srtxg@chanae.alphanet.ch>\n" "Language-Team: walon <linux-wa@chanae.alphanet.ch>\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 <dillon.chen@turbolinux.com.cn>\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: ¨¯¥ߤ¯ <hsin@med.cgu.edu.tw>\n" "Language-Team: Chinese <zh@li.org>\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 <gtk/gtk.h> #include <stdio.h> +#include <sys/stat.h> #include <errno.h> #include <stdlib.h> +#include <string.h> +#include <unicode.h> + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +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); - - if (argv[1]) - { - FILE* f; + tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); - 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_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); + /* gtk_timeout_add(1000, blink_timeout, 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); + 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"); + tag = gtk_text_buffer_create_tag(buffer, "fg_red"); - setup_tag(tag); + setup_tag(tag); - color.blue = color.green = 0; - color.red = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "offset", -4, - "foreground_gdk", &color, - NULL); + 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"); + tag = gtk_text_buffer_create_tag(buffer, "bg_green"); - setup_tag(tag); + setup_tag(tag); - color.blue = color.red = 0; - color.green = 0xffff; - gtk_object_set(GTK_OBJECT(tag), - "background_gdk", &color, - "font", "Sans 10", - NULL); + 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"); + tag = gtk_text_buffer_create_tag(buffer, "overstrike"); - setup_tag(tag); + setup_tag(tag); - gtk_object_set(GTK_OBJECT(tag), - "overstrike", TRUE, - NULL); - + 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); + tag = gtk_text_buffer_create_tag(buffer, "underline"); - setup_tag(tag); + 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); + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); - tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); + setup_tag(tag); - gtk_object_set(GTK_OBJECT(tag), - "direction", GTK_TEXT_DIR_RTL, - "left_wrapped_line_margin", 20, - "left_margin", 20, - "right_margin", 20, - NULL); + gtk_object_set(GTK_OBJECT(tag), + "underline", PANGO_UNDERLINE_SINGLE, + NULL); - tag = gtk_text_buffer_create_tag(buffer, "wrap"); + tag = gtk_text_buffer_create_tag(buffer, "centered"); - 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); + gtk_object_set(GTK_OBJECT(tag), + "justify", GTK_JUSTIFY_CENTER, + NULL); - g_assert(pixmap != NULL); + tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); - i = 0; - while (i < 100) - { - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + 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) + { + 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_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_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, "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; - } + ++i; + } + + gdk_pixmap_unref(pixmap); + if (mask) + gdk_bitmap_unref(mask); + + printf("%d lines %d chars\n", + gtk_text_buffer_get_line_count(buffer), + gtk_text_buffer_get_char_count(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; - gdk_pixmap_unref(pixmap); - if (mask) - gdk_bitmap_unref(mask); + 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); - /* Set the whole buffer to wrap + 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_bounds (buffer, &iter, &iter2); - gtk_text_buffer_apply_tag (buffer, "wrap", &iter, &iter2); + gtk_text_buffer_get_last_iter (buffer, &end); + gtk_text_buffer_delete (buffer, &iter, &end); -#if 0 - str = gtk_text_buffer_get_chars_from_line(buffer, 0, 0, -1, TRUE); + gtk_text_buffer_set_modified (buffer, FALSE); - printf("Got: `%s'\n", str); + return TRUE; +} - g_free(str); +static gint +delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) +{ + View *view = view_from_widget (window); - gtk_text_buffer_spew(buffer); + push_active_window (GTK_WINDOW (window)); + check_close_view (view); + pop_active_window (); -#endif - printf("%d lines %d chars\n", - gtk_text_buffer_get_line_count(buffer), - gtk_text_buffer_get_char_count(buffer)); + 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; - /* create_window(buffer); */ - create_window(buffer); + 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, "<Branch>" }, + { "/File/_New", "<control>N", do_new, 0, NULL }, + { "/File/New _View", NULL, do_new_view, 0, NULL }, + { "/File/_Open", "<control>O", do_open, 0, NULL }, + { "/File/_Save", "<control>S", do_save, 0, NULL }, + { "/File/Save _As...", NULL, do_save_as, 0, NULL }, + { "/File/sep1", NULL, 0, 0, "<Separator>" }, + { "/File/_Close", "<control>W" , do_close, 0, NULL }, + { "/File/E_xit", "<control>Q" , do_exit, 0, NULL }, + + { "/_Settings", NULL, 0, 0, "<Branch>" }, + { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "<RadioItem>" }, + { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, + { "/Settings/sep1", NULL, 0, 0, "<Separator>" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "<RadioItem>" }, + { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, + + { "/_Test", NULL, 0, 0, "<Branch>" }, + { "/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, "<main>", 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, "<main>"), + 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(); |
