home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / mc454src.zip / mc-4.5.4.src / mc-4.5.4 / gtkedit / gtkedit.c < prev    next >
C/C++ Source or Header  |  1999-01-04  |  43KB  |  1,396 lines

  1. /* gtkedit.c -
  2.  front end for gtk/gnome version
  3.  
  4.    Copyright (C) 1996, 1997 the Free Software Foundation
  5.  
  6.    Authors: 1996, 1997 Paul Sheer
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2 of the License, or
  11.    (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. #define _GTK_EDIT_C
  23.  
  24. #include <config.h>
  25. #include <gnome.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <pwd.h>
  29. #include "gdk/gdkkeysyms.h"
  30. #include "gtk/gtkmain.h"
  31. #include "gtk/gtkselection.h"
  32. #include "gtk/gtksignal.h"
  33. #include "edit.h"
  34. #include "mousemark.h"
  35.  
  36. #define EDIT_BORDER_ROOM         1
  37. #define MIN_EDIT_WIDTH_LINES     20
  38. #define MIN_EDIT_HEIGHT_LINES    10
  39.  
  40. #define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont)
  41.  
  42. int edit_key_emulation = 0;
  43. int column_highlighting = 0;
  44.  
  45. static GtkWidgetClass *parent_class = NULL;
  46.  
  47. WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size);
  48. void edit_destroy_callback (CWidget * w);
  49. int edit_translate_key (unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch);
  50. void gtk_edit_alloc_colors (GtkEdit *edit, GdkColormap *colormap);
  51. static void gtk_edit_set_position (GtkEditable *editable, gint position);
  52. void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click);
  53. void edit_move_to_prev_col (WEdit * edit, long p);
  54. int edit_load_file_from_filename (WEdit *edit, char *exp);
  55. static void gtk_edit_set_selection (GtkEditable * editable, gint start, gint end);
  56.  
  57.  
  58. guchar gtk_edit_font_width_per_char[256];
  59. int gtk_edit_option_text_line_spacing;
  60. int gtk_edit_option_font_ascent;
  61. int gtk_edit_option_font_descent;
  62. int gtk_edit_option_font_mean_width;
  63. int gtk_edit_fixed_font;
  64.  
  65. static void clear_focus_area (GtkEdit *edit, gint area_x, gint area_y, gint area_width, gint area_height)
  66. {
  67.     return;
  68. }
  69.  
  70. void gtk_edit_freeze (GtkEdit *edit)
  71. {
  72.     return;
  73. }
  74.  
  75. void       gtk_edit_insert          (GtkEdit       *edit,
  76.                      GdkFont       *font,
  77.                      GdkColor      *fore,
  78.                      GdkColor      *back,
  79.                      const char    *chars,
  80.                      gint           length)
  81. {
  82.     while (length-- > 0)
  83.     edit_insert (GTK_EDIT (edit)->editor, *chars++);
  84. }
  85.  
  86. void       gtk_edit_set_editable    (GtkEdit       *text,
  87.                      gint           editable)
  88. {
  89.     return;
  90. }
  91.  
  92. void       gtk_edit_thaw            (GtkEdit       *text)
  93. {
  94.     return;
  95. }
  96.  
  97.  
  98. void gtk_edit_configure_font_dimensions (GtkEdit * edit)
  99. {
  100.     XFontStruct *f;
  101.     XCharStruct s;
  102.     char *p;
  103.     char q[256];
  104.     unsigned char t;
  105.     int i, direction;
  106.     f = GDK_FONT_XFONT (edit->editable.widget.style->font);
  107.     p = _ ("The Quick Brown Fox Jumps Over The Lazy Dog");
  108.     for (i = ' '; i <= '~'; i++)
  109.     q[i - ' '] = i;
  110.     if (XTextWidth (f, "M", 1) == XTextWidth (f, "M", 1))
  111.     gtk_edit_fixed_font = 1;
  112.     else
  113.     gtk_edit_fixed_font = 0;
  114.     XTextExtents (f, q, '~' - ' ', &direction, >k_edit_option_font_ascent, >k_edit_option_font_descent, &s);
  115.     gtk_edit_option_font_mean_width = XTextWidth (f, p, strlen (p)) / strlen (p);
  116.     for (i = 0; i < 256; i++) {
  117.     t = (unsigned char) i;
  118.     if (i > f->max_char_or_byte2 || i < f->min_char_or_byte2) {
  119.         gtk_edit_font_width_per_char[i] = 0;
  120.     } else {
  121.         gtk_edit_font_width_per_char[i] = XTextWidth (f, (char *) &t, 1);
  122.     }
  123.     }
  124. }
  125.  
  126. void gtk_edit_set_adjustments (GtkEdit * edit,
  127.                    GtkAdjustment * hadj,
  128.                    GtkAdjustment * vadj)
  129. {
  130.     g_return_if_fail (edit != NULL);
  131.     g_return_if_fail (GTK_IS_EDIT (edit));
  132.  
  133.     if (edit->hadj && (edit->hadj != hadj)) {
  134.     gtk_signal_disconnect_by_data (GTK_OBJECT (edit->hadj), edit);
  135.     gtk_object_unref (GTK_OBJECT (edit->hadj));
  136.     }
  137.     if (edit->vadj && (edit->vadj != vadj)) {
  138.     gtk_signal_disconnect_by_data (GTK_OBJECT (edit->vadj), edit);
  139.     gtk_object_unref (GTK_OBJECT (edit->vadj));
  140.     }
  141.     if (!hadj)
  142.     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
  143.  
  144.     if (!vadj)
  145.     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
  146.  
  147.     if (edit->hadj != hadj) {
  148.     edit->hadj = hadj;
  149.     gtk_object_ref (GTK_OBJECT (edit->hadj));
  150.     gtk_object_sink (GTK_OBJECT (edit->hadj));
  151.  
  152. #if 0
  153.     gtk_signal_connect (GTK_OBJECT (edit->hadj), "changed",
  154.                 (GtkSignalFunc) gtk_edit_adjustment,
  155.                 edit);
  156.     gtk_signal_connect (GTK_OBJECT (edit->hadj), "value_changed",
  157.                 (GtkSignalFunc) gtk_edit_adjustment,
  158.                 edit);
  159.     gtk_signal_connect (GTK_OBJECT (edit->hadj), "disconnect",
  160.                 (GtkSignalFunc) gtk_edit_disconnect,
  161.                 edit);
  162. #endif
  163.     }
  164.     if (edit->vadj != vadj) {
  165.     edit->vadj = vadj;
  166.     gtk_object_ref (GTK_OBJECT (edit->vadj));
  167.     gtk_object_sink (GTK_OBJECT (edit->vadj));
  168.  
  169. #if 0
  170.     gtk_signal_connect (GTK_OBJECT (edit->vadj), "changed",
  171.                 (GtkSignalFunc) gtk_edit_adjustment,
  172.                 edit);
  173.     gtk_signal_connect (GTK_OBJECT (edit->vadj), "value_changed",
  174.                 (GtkSignalFunc) gtk_edit_adjustment,
  175.                 edit);
  176.     gtk_signal_connect (GTK_OBJECT (edit->vadj), "disconnect",
  177.                 (GtkSignalFunc) gtk_edit_disconnect,
  178.                 edit);
  179. #endif
  180.     }
  181. }
  182.  
  183. GtkWidget *gtk_edit_new (GtkAdjustment * hadj,
  184.              GtkAdjustment * vadj)
  185. {
  186.     GtkEdit *edit;
  187.     edit = gtk_type_new (gtk_edit_get_type ());
  188.     gtk_edit_set_adjustments (edit, hadj, vadj);
  189.     gtk_edit_configure_font_dimensions (edit);
  190.     return GTK_WIDGET (edit);
  191. }
  192.  
  193. static void gtk_edit_realize (GtkWidget * widget)
  194. {
  195.     GtkEdit *edit;
  196.     GtkEditable *editable;
  197.     GdkWindowAttr attributes;
  198.     GdkColormap *colormap;
  199.     gint attributes_mask;
  200.  
  201.     g_return_if_fail (widget != NULL);
  202.     g_return_if_fail (GTK_IS_EDIT (widget));
  203.  
  204.     edit = GTK_EDIT (widget);
  205.     editable = GTK_EDITABLE (widget);
  206.     GTK_WIDGET_SET_FLAGS (edit, GTK_REALIZED);
  207.  
  208.     attributes.window_type = GDK_WINDOW_CHILD;
  209.     attributes.x = widget->allocation.x;
  210.     attributes.y = widget->allocation.y;
  211.     attributes.width = widget->allocation.width;
  212.     attributes.height = widget->allocation.height;
  213.     attributes.wclass = GDK_INPUT_OUTPUT;
  214.     attributes.visual = gtk_widget_get_visual (widget);
  215.     colormap = attributes.colormap = gtk_widget_get_colormap (widget);
  216.     attributes.event_mask = gtk_widget_get_events (widget);
  217.     attributes.event_mask |= (GDK_EXPOSURE_MASK |
  218.                   GDK_BUTTON_PRESS_MASK |
  219.                   GDK_BUTTON_RELEASE_MASK |
  220.                   GDK_BUTTON_MOTION_MASK |
  221.                   GDK_ENTER_NOTIFY_MASK |
  222.                   GDK_LEAVE_NOTIFY_MASK |
  223.                   GDK_KEY_RELEASE_MASK |
  224.                   GDK_KEY_PRESS_MASK);
  225.     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
  226.  
  227.     widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
  228.     gdk_window_set_user_data (widget->window, edit);
  229.  
  230.     attributes.x = (widget->style->klass->xthickness + EDIT_BORDER_ROOM);
  231.     attributes.y = (widget->style->klass->ythickness + EDIT_BORDER_ROOM);
  232.     attributes.width = widget->allocation.width - attributes.x * 2;
  233.     attributes.height = widget->allocation.height - attributes.y * 2;
  234.  
  235.     edit->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
  236.     gdk_window_set_user_data (edit->text_area, edit);
  237.  
  238.     widget->style = gtk_style_attach (widget->style, widget->window);
  239.  
  240.     gtk_edit_alloc_colors (edit, colormap);
  241.  
  242.     /* Can't call gtk_style_set_background here because it's handled specially */
  243.     gdk_window_set_background (widget->window, &edit->color[1]);
  244.     gdk_window_set_background (edit->text_area, &edit->color[1]);
  245.  
  246.     edit->gc = gdk_gc_new (edit->text_area);
  247.     gdk_gc_set_exposures (edit->gc, TRUE);
  248.     gdk_gc_set_foreground (edit->gc, &edit->color[26]);
  249.     gdk_gc_set_background (edit->gc, &edit->color[1]);
  250.  
  251.  
  252.     gdk_window_show (edit->text_area);
  253.  
  254.     if (editable->selection_start_pos != editable->selection_end_pos)
  255.     gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
  256.  
  257. #if 0
  258.     if ((widget->allocation.width > 1) || (widget->allocation.height > 1))
  259.     recompute_geometry (edit);
  260. #endif
  261. }
  262.  
  263. static void gtk_edit_unrealize (GtkWidget * widget)
  264. {
  265.     GtkEdit *edit;
  266.  
  267.     g_return_if_fail (widget != NULL);
  268.     g_return_if_fail (GTK_IS_EDIT (widget));
  269.  
  270.     edit = GTK_EDIT (widget);
  271.  
  272.     gdk_window_set_user_data (edit->text_area, NULL);
  273.     gdk_window_destroy (edit->text_area);
  274.     edit->text_area = NULL;
  275.  
  276.     gdk_gc_destroy (edit->gc);
  277.     edit->gc = NULL;
  278.  
  279.     if (GTK_WIDGET_CLASS (parent_class)->unrealize)
  280.     (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
  281. }
  282.  
  283. static void gtk_edit_destroy (GtkObject * object)
  284. {
  285.     GtkEdit *edit;
  286.  
  287.     g_return_if_fail (object != NULL);
  288.     g_return_if_fail (GTK_IS_EDIT (object));
  289.  
  290.     edit = (GtkEdit *) object;
  291.     if (edit->hadj) {
  292.     gtk_object_unref (GTK_OBJECT (edit->hadj));
  293.     edit->hadj = NULL;
  294.     }
  295.     if (edit->vadj) {
  296.     gtk_object_unref (GTK_OBJECT (edit->vadj));
  297.     edit->vadj = NULL;
  298.     }
  299.     if (edit->timer) {
  300.     gtk_timeout_remove (edit->timer);
  301.     edit->timer = 0;
  302.     }
  303.     edit_clean (edit->editor);
  304.     if (edit->editor) {
  305.     free (edit->editor);
  306.     edit->editor = NULL;
  307.     }
  308.     GTK_OBJECT_CLASS (parent_class)->destroy (object);
  309. }
  310.  
  311. static void gtk_edit_style_set (GtkWidget * widget,
  312.                 GtkStyle * previous_style)
  313. {
  314.     GtkEdit *edit;
  315.  
  316.     g_return_if_fail (widget != NULL);
  317.     g_return_if_fail (GTK_IS_EDIT (widget));
  318.  
  319.     edit = GTK_EDIT (widget);
  320.     if (GTK_WIDGET_REALIZED (widget)) {
  321.     gdk_window_set_background (widget->window, &edit->color[1]);
  322.     gdk_window_set_background (edit->text_area, &edit->color[1]);
  323.  
  324. #if 0
  325.     if ((widget->allocation.width > 1) || (widget->allocation.height > 1))
  326.         recompute_geometry (edit);
  327. #endif
  328.     }
  329.     if (GTK_WIDGET_DRAWABLE (widget))
  330.     gdk_window_clear (widget->window);
  331. }
  332.  
  333. static void gtk_edit_draw_focus (GtkWidget * widget)
  334. {
  335.     GtkEdit *edit;
  336.     gint width, height;
  337.     gint x, y;
  338.  
  339.     g_return_if_fail (widget != NULL);
  340.     g_return_if_fail (GTK_IS_EDIT (widget));
  341.  
  342.     edit = GTK_EDIT (widget);
  343.  
  344.     if (GTK_WIDGET_DRAWABLE (widget)) {
  345.     gint ythick = widget->style->klass->ythickness;
  346.     gint xthick = widget->style->klass->xthickness;
  347.     gint xextra = EDIT_BORDER_ROOM;
  348.     gint yextra = EDIT_BORDER_ROOM;
  349.  
  350. /*      TDEBUG (("in gtk_edit_draw_focus\n")); */
  351.  
  352.     x = 0;
  353.     y = 0;
  354.     width = widget->allocation.width;
  355.     height = widget->allocation.height;
  356.  
  357.     if (GTK_WIDGET_HAS_FOCUS (widget)) {
  358.         x += 1;
  359.         y += 1;
  360.         width -= 2;
  361.         height -= 2;
  362.         xextra -= 1;
  363.         yextra -= 1;
  364.  
  365.         gdk_draw_rectangle (widget->window,
  366.                 widget->style->fg_gc[GTK_STATE_NORMAL],
  367.                 FALSE, 0, 0,
  368.                 widget->allocation.width - 1,
  369.                 widget->allocation.height - 1);
  370.     }
  371.     gtk_draw_shadow (widget->style, widget->window,
  372.              GTK_STATE_NORMAL, GTK_SHADOW_IN,
  373.              x, y, width, height);
  374.  
  375.     x += xthick;
  376.     y += ythick;
  377.     width -= 2 * xthick;
  378.     height -= 2 * ythick;
  379.  
  380.     if (widget->style->bg_pixmap[GTK_STATE_NORMAL]) {
  381.         /* top rect */
  382.         clear_focus_area (edit, x, y, width, yextra);
  383.         /* left rect */
  384.         clear_focus_area (edit, x, y + yextra,
  385.                   xextra, y + height - 2 * yextra);
  386.         /* right rect */
  387.         clear_focus_area (edit, x + width - xextra, y + yextra,
  388.                   xextra, height - 2 * ythick);
  389.         /* bottom rect */
  390.         clear_focus_area (edit, x, x + height - yextra, width, yextra);
  391.     } else if (!GTK_WIDGET_HAS_FOCUS (widget)) {
  392.         gdk_draw_rectangle (widget->window,
  393.              widget->style->base_gc[GTK_STATE_NORMAL], FALSE,
  394.                 x, y,
  395.                 width - 1,
  396.                 height - 1);
  397.     }
  398.     }
  399. #if 0
  400.     else {
  401.     TDEBUG (("in gtk_edit_draw_focus (undrawable !!!)\n"));
  402.     }
  403. #endif
  404. }
  405.  
  406. static void gtk_edit_size_request (GtkWidget * widget,
  407.                    GtkRequisition * requisition)
  408. {
  409.     gint xthickness;
  410.     gint ythickness;
  411.     gint char_height;
  412.     gint char_width;
  413.  
  414.     g_return_if_fail (widget != NULL);
  415.     g_return_if_fail (GTK_IS_EDIT (widget));
  416.     g_return_if_fail (requisition != NULL);
  417.  
  418.     xthickness = widget->style->klass->xthickness + EDIT_BORDER_ROOM;
  419.     ythickness = widget->style->klass->ythickness + EDIT_BORDER_ROOM;
  420.  
  421.     char_height = MIN_EDIT_HEIGHT_LINES * (widget->style->font->ascent +
  422.                        widget->style->font->descent);
  423.  
  424.     char_width = MIN_EDIT_WIDTH_LINES * (gdk_text_width (widget->style->font,
  425.                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  426.                              26)
  427.                      / 26);
  428.  
  429.     requisition->width = char_width + xthickness * 2;
  430.     requisition->height = char_height + ythickness * 2;
  431. }
  432.  
  433. static void gtk_edit_size_allocate (GtkWidget * widget,
  434.                     GtkAllocation * allocation)
  435. {
  436.     GtkEdit *edit;
  437.     GtkEditable *editable;
  438.  
  439.     g_return_if_fail (widget != NULL);
  440.     g_return_if_fail (GTK_IS_EDIT (widget));
  441.     g_return_if_fail (allocation != NULL);
  442.  
  443.     edit = GTK_EDIT (widget);
  444.     editable = GTK_EDITABLE (widget);
  445.  
  446.     widget->allocation = *allocation;
  447.     if (GTK_WIDGET_REALIZED (widget)) {
  448.     gdk_window_move_resize (widget->window,
  449.                 allocation->x, allocation->y,
  450.                 allocation->width, allocation->height);
  451.  
  452.     gdk_window_move_resize (edit->text_area,
  453.              widget->style->klass->xthickness + EDIT_BORDER_ROOM,
  454.              widget->style->klass->ythickness + EDIT_BORDER_ROOM,
  455.        widget->allocation.width - (widget->style->klass->xthickness +
  456.                        EDIT_BORDER_ROOM) * 2,
  457.       widget->allocation.height - (widget->style->klass->ythickness +
  458.                        EDIT_BORDER_ROOM) * 2);
  459.  
  460. #if 0
  461.     recompute_geometry (edit);
  462. #endif
  463.     }
  464. }
  465.  
  466. static void gtk_edit_draw (GtkWidget * widget,
  467.                GdkRectangle * area)
  468. {
  469.     GtkEdit *edit;
  470.     g_return_if_fail (widget != NULL);
  471.     g_return_if_fail (GTK_IS_EDIT (widget));
  472.     g_return_if_fail (area != NULL);
  473.  
  474.     if (GTK_WIDGET_DRAWABLE (widget)) {
  475. /* convert the gtk expose to a coolwidget expose */
  476.     XExposeEvent xexpose;
  477.     xexpose.x = area->x;
  478.     xexpose.y = area->y;
  479.     xexpose.width = area->width;
  480.     xexpose.height = area->height;
  481.     edit = GTK_EDIT (widget);
  482.     edit_render_expose (edit->editor, &xexpose);
  483.     edit_status (edit->editor);
  484.     }
  485. }
  486.  
  487. void gtk_edit_set_colors (GtkEdit *win)
  488. {
  489.     edit_set_foreground_colors (
  490.                  color_palette (option_editor_fg_normal),
  491.                    color_palette (option_editor_fg_bold),
  492.                    color_palette (option_editor_fg_italic)
  493.     );
  494.     edit_set_background_colors (
  495.                  color_palette (option_editor_bg_normal),
  496.                    color_palette (option_editor_bg_abnormal),
  497.                  color_palette (option_editor_bg_marked),
  498.             color_palette (option_editor_bg_marked_abnormal),
  499.                  color_palette (option_editor_bg_highlighted)
  500.     );
  501.     edit_set_cursor_color (
  502.                   color_palette (option_editor_fg_cursor)
  503.     );
  504. }
  505.  
  506. static gint
  507.  gtk_edit_expose (GtkWidget * widget,
  508.           GdkEventExpose * event)
  509. {
  510.     GtkEdit *edit;
  511.     g_return_val_if_fail (widget != NULL, FALSE);
  512.     g_return_val_if_fail (GTK_IS_EDIT (widget), FALSE);
  513.     g_return_val_if_fail (event != NULL, FALSE);
  514.  
  515.     if (GTK_WIDGET_DRAWABLE (widget)) {
  516. /* convert the gtk expose to a coolwidget expose */
  517.     XExposeEvent xexpose;
  518.     xexpose.x = event->area.x;
  519.     xexpose.y = event->area.y;
  520.     xexpose.width = event->area.width;
  521.     xexpose.height = event->area.height;
  522.     edit = GTK_EDIT (widget);
  523.     gtk_edit_set_colors (edit);
  524.     edit_render_expose (edit->editor, &xexpose);
  525.     edit_status (edit->editor);
  526.     }
  527.     return FALSE;
  528. }
  529.  
  530. void edit_update_screen (WEdit * e)
  531. {
  532.     if (!e)
  533.     return;
  534.     if (!e->force)
  535.     return;
  536.  
  537.     edit_scroll_screen_over_cursor (e);
  538.     edit_update_curs_row (e);
  539.     edit_update_curs_col (e);
  540. #if 0
  541.     update_scroll_bars (e);
  542. #endif
  543.     edit_status (e);
  544.  
  545.     if (e->force & REDRAW_COMPLETELY)
  546.     e->force |= REDRAW_PAGE;
  547.  
  548. /* pop all events for this window for internal handling */
  549.     if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) {
  550.     edit_render_keypress (e);
  551. #if 0
  552.     } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0)
  553.            || CKeyPending ()) {
  554.     e->force |= REDRAW_PAGE;
  555.     return;
  556. #endif
  557.     } else {
  558.     edit_render_keypress (e);
  559.     }
  560. }
  561.  
  562.  
  563. void gtk_edit_mouse_redraw (WEdit * edit, long click)
  564. {
  565.     edit->force |= REDRAW_PAGE | REDRAW_LINE;
  566.     edit_update_curs_row (edit);
  567.     edit_update_curs_col (edit);
  568.     edit->prev_col = edit_get_col (edit);
  569.     edit_update_screen (edit);
  570.     edit->search_start = click;
  571. }
  572.  
  573. /* returns the position in the edit buffer of a window click */
  574. static long edit_get_click_pos (WEdit * edit, int x, int y)
  575. {
  576.     long click;
  577. /* (1) goto to left margin */
  578.     click = edit_bol (edit, edit->curs1);
  579.  
  580. /* (1) move up or down */
  581.     if (y > (edit->curs_row + 1))
  582.     click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0);
  583.     if (y < (edit->curs_row + 1))
  584.     click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);
  585.  
  586. /* (3) move right to x pos */
  587.     click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0);
  588.     return click;
  589. }
  590.  
  591. static void edit_translate_xy (int xs, int ys, int *x, int *y)
  592. {
  593.     *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET;
  594.     *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;
  595. }
  596.  
  597. static gint gtk_edit_button_press_release (GtkWidget * widget,
  598.                        GdkEventButton * event)
  599. {
  600.     GtkEditable *editable;
  601.     GtkEdit *edit;
  602.     WEdit *e;
  603.     static GdkAtom ctext_atom = GDK_NONE;
  604.     int x_text = 0, y_text = 0;
  605.     long mouse_pos;
  606.     static long button_down_pos;
  607.     static long dragging = 0;
  608.  
  609.     g_return_val_if_fail (widget != NULL, FALSE);
  610.     g_return_val_if_fail (GTK_IS_EDIT (widget), FALSE);
  611.     g_return_val_if_fail (event != NULL, FALSE);
  612.  
  613.     if (ctext_atom == GDK_NONE)
  614.     ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
  615.  
  616.     edit = GTK_EDIT (widget);
  617.     e = edit->editor;
  618.     editable = GTK_EDITABLE (widget);
  619.  
  620.     if (!GTK_WIDGET_HAS_FOCUS (widget))
  621.     if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
  622.         gtk_widget_grab_focus (widget);
  623.  
  624.     edit_translate_xy (event->x, event->y, &x_text, &y_text);
  625.     mouse_pos = edit_get_click_pos (e, x_text, y_text);
  626.  
  627.     switch (event->type) {
  628.     case GDK_BUTTON_RELEASE:
  629.     if (!dragging)
  630.         return FALSE;
  631.     case GDK_MOTION_NOTIFY:
  632.     if (mouse_pos == button_down_pos)
  633.         return FALSE;
  634.     dragging = 1;
  635.     edit_cursor_move (e, mouse_pos - e->curs1);
  636.     gtk_edit_set_selection (GTK_EDITABLE (widget), mouse_pos, button_down_pos);
  637.     gtk_edit_mouse_redraw (e, mouse_pos);
  638.     break;
  639.     case GDK_BUTTON_PRESS:
  640.     dragging = 0;
  641.     if (event->button == 2) {
  642.         edit_cursor_move (e, mouse_pos - e->curs1);
  643.         editable->current_pos = mouse_pos;
  644.         gtk_selection_convert (GTK_WIDGET (edit), GDK_SELECTION_PRIMARY,
  645.                    ctext_atom, event->time);
  646.         gtk_edit_mouse_redraw (e, mouse_pos);
  647.         editable->selection_start_pos = e->mark1;
  648.         editable->selection_end_pos = e->mark2;
  649.         return FALSE;
  650.     }
  651.     button_down_pos = mouse_pos;
  652. #if 0
  653.     if (editable->has_selection)
  654.         if (mouse_pos >= editable->selection_start_pos
  655.         && mouse_pos < editable->selection_end_pos)
  656.         gtk_edit_set_selection (GTK_EDITABLE (widget), mouse_pos, mouse_pos);
  657. #endif
  658.     edit_cursor_move (e, mouse_pos - e->curs1);
  659.     gtk_edit_mouse_redraw (e, mouse_pos);
  660.     break;
  661.     case GDK_2BUTTON_PRESS:
  662.     dragging = 0;
  663.     edit_cursor_move (e, mouse_pos - e->curs1);
  664.     edit_right_word_move (e);
  665.     mouse_pos = e->curs1;
  666.     edit_left_word_move (e);
  667.     button_down_pos = e->curs1;
  668.     gtk_edit_set_selection (GTK_EDITABLE (widget), mouse_pos, button_down_pos);
  669.     gtk_edit_mouse_redraw (e, mouse_pos);
  670.     break;
  671.     case GDK_3BUTTON_PRESS:
  672.     dragging = 0;
  673.     mouse_pos = edit_bol (e, mouse_pos);
  674.     edit_cursor_move (e, mouse_pos - e->curs1);
  675.     button_down_pos = edit_eol (e, mouse_pos) + 1;
  676.     gtk_edit_set_selection (GTK_EDITABLE (widget), mouse_pos, button_down_pos);
  677.     gtk_edit_mouse_redraw (e, mouse_pos);
  678.     break;
  679.     default:
  680.     dragging = 0;
  681.     break;
  682.     }
  683.     editable->current_pos = e->curs1;
  684.     return FALSE;
  685. }
  686.  
  687. static gint
  688.  gtk_edit_button_motion (GtkWidget * widget,
  689.              GdkEventMotion * event)
  690. {
  691.     return gtk_edit_button_press_release (widget, (GdkEventButton *) event);
  692. }
  693.  
  694. static guint toggle_bit (guint x, guint mask)
  695. {
  696.     unsigned long m = -1;
  697.     if ((x & mask))
  698.     return x & (m - mask);
  699.     else
  700.     return x | mask;
  701. }
  702.  
  703. int mod_type_key (guint x)
  704. {
  705.     switch ((guint) x) {
  706.     case GDK_Shift_L:
  707.     case GDK_Shift_R:
  708.     case GDK_Control_L:
  709.     case GDK_Control_R:
  710.     case GDK_Caps_Lock:
  711.     case GDK_Shift_Lock:
  712.     case GDK_Meta_L:
  713.     case GDK_Meta_R:
  714.     case GDK_Alt_L:
  715.     case GDK_Alt_R:
  716.     case GDK_Super_L:
  717.     case GDK_Super_R:
  718.     case GDK_Hyper_L:
  719.     case GDK_Hyper_R:
  720.     return 1;
  721.     }
  722.     return 0;
  723. }
  724.  
  725. /* get a 15 bit "almost unique" key sym that includes keyboard modifier
  726.    info in the top 3 bits */
  727. short key_sym_mod (gint key, gint state)
  728. {
  729.     if (key && !mod_type_key (key)) {
  730.     key = toggle_bit (key, 0x1000 * ((state & GDK_SHIFT_MASK) != 0));
  731.     key = toggle_bit (key, 0x2000 * ((state & GDK_CONTROL_MASK) != 0));
  732.     key = toggle_bit (key, 0x4000 * ((state & GDK_MOD1_MASK) != 0));
  733.     key &= 0x7FFF;
  734.     } else
  735.     key = 0;
  736.     return key;
  737. }
  738.  
  739. static gint gtk_edit_key_press (GtkWidget * widget, GdkEventKey * event)
  740. {
  741.     GtkEditable *editable;
  742.     GtkEdit *edit;
  743.     WEdit *e;
  744.     gint command = 0, insert = -1, r = 0;
  745.     guint key, state;
  746.     g_return_val_if_fail (widget != NULL, FALSE);
  747.     g_return_val_if_fail (GTK_IS_EDIT (widget), FALSE);
  748.     g_return_val_if_fail (event != NULL, FALSE);
  749.     edit = GTK_EDIT (widget);
  750.     editable = GTK_EDITABLE (widget);
  751.     e = edit->editor;
  752.     if (!edit_translate_key (0, event->keyval, event->state, &command, &insert)) {
  753.     return FALSE;
  754.     }
  755.     key = event->keyval;
  756.     state = event->state;
  757.     if (!command && insert < 0) {    /* no translation took place, so lets see if we have a macro */
  758.     if ((key == GDK_r || key == GDK_R) && (state & ControlMask)) {
  759.         command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
  760.     } else {
  761.         command = key_sym_mod (key, state);
  762.         if (command > 0)
  763.         command = CK_Macro (command);
  764.     }
  765.     }
  766.     r = edit_execute_key_command (e, command, insert);
  767.     if (r)
  768.     edit_update_screen (e);
  769.     editable->selection_start_pos = e->mark1;
  770.     editable->selection_end_pos = ((e->mark2 < 0) ? e->curs1 : e->mark2);
  771.     editable->has_selection = editable->selection_start_pos != editable->selection_end_pos;
  772.     editable->current_pos = e->curs1;
  773.     return r;
  774. }
  775.  
  776. /**********************************************************************/
  777. /*                              Widget Crap                           */
  778. /**********************************************************************/
  779.  
  780. char *home_dir = 0;
  781.  
  782. static void get_home_dir (void)
  783. {
  784.     if (home_dir)        /* already been set */
  785.     return;
  786.     home_dir = getenv ("HOME");
  787.     if (home_dir)
  788.     if (*home_dir) {
  789.         home_dir = strdup (home_dir);
  790.         return;
  791.     }
  792.     home_dir = (getpwuid (geteuid ()))->pw_dir;
  793.     if (home_dir)
  794.     if (*home_dir) {
  795.         home_dir = strdup (home_dir);
  796.         return;
  797.     }
  798.     fprintf (stderr, _("gtkedit.c: HOME environment variable not set and no passwd entry - aborting\n"));
  799.     abort ();
  800. }
  801.  
  802. static gchar *gtk_edit_get_chars (GtkEditable * editable,
  803.                   gint start_pos,
  804.                   gint end_pos)
  805. {
  806.     GtkEdit *edit;
  807.     gchar *retval;
  808.     int i;
  809.     g_return_val_if_fail (editable != NULL, NULL);
  810.     g_return_val_if_fail (GTK_IS_EDIT (editable), NULL);
  811.     edit = GTK_EDIT (editable);
  812.     if (end_pos < 0)
  813.     end_pos = edit->editor->last_byte;
  814.     if ((start_pos < 0) ||
  815.     (end_pos > edit->editor->last_byte) ||
  816.     (end_pos < start_pos))
  817.     return 0;
  818.     retval = malloc (end_pos - start_pos + 1);
  819.     retval[end_pos - start_pos] = '\0';
  820.     for (i = 0; start_pos < end_pos; start_pos++, i++)
  821.     retval[i] = (gchar) edit_get_byte (edit->editor, start_pos);
  822.     return retval;
  823. }
  824.  
  825. static void gtk_edit_set_selection (GtkEditable * editable,
  826.                     gint start,
  827.                     gint end)
  828. {
  829.     GtkEdit *edit = GTK_EDIT (editable);
  830.     WEdit *e;
  831.     e = edit->editor;
  832.     if (end < 0)
  833.     end = edit->editor->last_byte;
  834.     editable->selection_start_pos = e->mark1 = MIN (start, end);
  835.     editable->selection_end_pos = e->mark2 = MAX (start, end);
  836.     editable->has_selection = (e->mark2 != e->mark1);
  837.     gtk_edit_mouse_redraw (e, e->curs1);
  838.     gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
  839. }
  840.  
  841. static void gtk_edit_insert_text (GtkEditable * editable,
  842.                   const gchar * new_text,
  843.                   gint new_text_length,
  844.                   gint * position)
  845. {
  846.     GtkEdit *edit = GTK_EDIT (editable);
  847.     edit_cursor_move (edit->editor, *position - edit->editor->curs1);
  848.     while (new_text_length--)
  849.     edit_insert_ahead (edit->editor, new_text[new_text_length]);
  850.     *position = edit->editor->curs1;
  851. }
  852.  
  853. static void gtk_edit_class_init (GtkEditClass * class)
  854. {
  855.     GtkObjectClass *object_class;
  856.     GtkWidgetClass *widget_class;
  857.     GtkEditableClass *editable_class;
  858.  
  859.     object_class = (GtkObjectClass *) class;
  860.     widget_class = (GtkWidgetClass *) class;
  861.     editable_class = (GtkEditableClass *) class;
  862.  
  863.     parent_class = gtk_type_class (gtk_editable_get_type ());
  864.  
  865.     object_class->destroy = gtk_edit_destroy;
  866.  
  867.     widget_class->realize = gtk_edit_realize;
  868.     widget_class->unrealize = gtk_edit_unrealize;
  869.     widget_class->style_set = gtk_edit_style_set;
  870.     widget_class->draw_focus = gtk_edit_draw_focus;
  871.     widget_class->size_request = gtk_edit_size_request;
  872.     widget_class->size_allocate = gtk_edit_size_allocate;
  873.     widget_class->draw = gtk_edit_draw;
  874.     widget_class->expose_event = gtk_edit_expose;
  875.     widget_class->button_press_event = gtk_edit_button_press_release;
  876.     widget_class->button_release_event = gtk_edit_button_press_release;
  877.     widget_class->motion_notify_event = gtk_edit_button_motion;
  878.  
  879.     widget_class->key_press_event = gtk_edit_key_press;
  880. #if 0
  881.     widget_class->focus_in_event = gtk_edit_focus_in;
  882.     widget_class->focus_out_event = gtk_edit_focus_out;
  883. #endif
  884.     widget_class->focus_in_event = 0;
  885.     widget_class->focus_out_event = 0;
  886.  
  887.     editable_class->insert_text = gtk_edit_insert_text;
  888. #if 0
  889.     editable_class->delete_text = gtk_edit_delete_text;
  890.     editable_class->update_text = gtk_edit_update_text;
  891. #else
  892.     editable_class->delete_text = 0;
  893.     editable_class->update_text = 0;
  894. #endif
  895.  
  896.     editable_class->get_chars = gtk_edit_get_chars;
  897.     editable_class->set_selection = gtk_edit_set_selection;
  898.     editable_class->set_position = gtk_edit_set_position;
  899.  
  900.  
  901. #if 0
  902.     editable_class->set_position = 0;
  903. #endif
  904.  
  905.     get_home_dir ();
  906. }
  907.  
  908. static void gtk_edit_init (GtkEdit * edit)
  909. {
  910.     static made_directory = 0;
  911.  
  912.     GTK_WIDGET_SET_FLAGS (edit, GTK_CAN_FOCUS);
  913.  
  914.     edit->editor = edit_init (0, 80, 25, 0, "", "/", 0);
  915.     edit->editor->macro_i = -1;
  916.     edit->editor->widget = edit;
  917.     edit->timer = 0;
  918.     edit->menubar = 0;
  919.     edit->status = 0;
  920.     edit->options = 0;
  921.  
  922.     gtk_edit_configure_font_dimensions (edit);
  923.  
  924.     if (!made_directory) {
  925.     mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
  926.     made_directory = 1;
  927.     }
  928.     GTK_EDITABLE (edit)->editable = TRUE;
  929. }
  930.  
  931. guint
  932. gtk_edit_get_type (void)
  933. {
  934.     static guint edit_type = 0;
  935.  
  936.     if (!edit_type) {
  937.     GtkTypeInfo edit_info =
  938.     {
  939.         "GtkEdit",
  940.         sizeof (GtkEdit),
  941.         sizeof (GtkEditClass),
  942.         (GtkClassInitFunc) gtk_edit_class_init,
  943.         (GtkObjectInitFunc) gtk_edit_init,
  944.         (GtkArgSetFunc) NULL,
  945.         (GtkArgGetFunc) NULL,
  946.     };
  947.  
  948.     edit_type = gtk_type_unique (gtk_editable_get_type (), &edit_info);
  949.     }
  950.     return edit_type;
  951. }
  952.  
  953. #include <libgnomeui/gtkcauldron.h>
  954. #include <libgnomeui/gnome-stock.h>
  955.  
  956. char *gtk_edit_dialog_get_save_file (guchar * dir, guchar * def, guchar * title)
  957. {
  958.     char *s;
  959.     s = gtk_dialog_cauldron (
  960.                 title, GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
  961.         " ( ( (Filename:)d | %Fgxf )f )xf / ( %Bxfgrq || %Bxfgq )f ",
  962.                 &def, "filename", title,
  963.                 GNOME_STOCK_BUTTON_OK,
  964.                 GNOME_STOCK_BUTTON_CANCEL
  965.     );
  966.     if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
  967.     return 0;
  968.     return def;
  969. }
  970.  
  971. char *gtk_edit_dialog_get_load_file (guchar * dir, guchar * def, guchar * title)
  972. {
  973.     char *s;
  974.     s = gtk_dialog_cauldron (
  975.                 title, GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
  976.         " ( ( (Filename:)d | %Fgxf )f )xf / ( %Bxfgrq || %Bxfgq )f ",
  977.                 &def, "filename", title,
  978.                 GNOME_STOCK_BUTTON_OK,
  979.                 GNOME_STOCK_BUTTON_CANCEL
  980.     );
  981.     if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL)
  982.     return 0;
  983.     return def;
  984. }
  985.  
  986. void gtk_edit_dialog_message (guchar * heading, char *fmt,...)
  987. {
  988.     gchar s[8192];
  989.     va_list ap;
  990.     va_start (ap, fmt);
  991.     vsprintf (s, fmt, ap);
  992.     va_end (ap);
  993.     gtk_dialog_cauldron (
  994.                 heading, GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
  995.                 " [ ( %Ld )xf ]xf / ( %Bxfgq )f ",
  996.                 s,
  997.                 GNOME_STOCK_BUTTON_CANCEL
  998.     );
  999.     return;
  1000. }
  1001.  
  1002. int gtk_edit_dialog_query (guchar * heading, guchar * first,...)
  1003. {
  1004.     char *buttons[16];
  1005.     char s[1024], *r;
  1006.     int n;
  1007.     va_list ap;
  1008.     va_start (ap, first);
  1009.     n = 0;
  1010.     while ((buttons[n++] = va_arg (ap, char *)) && n < 15);
  1011.     va_end (ap);
  1012.     buttons[n] = 0;
  1013.     strcpy (s, " [ ( %Lxf )xf ]xf / ( ");
  1014.     n = 0;
  1015.     while (buttons[n]) {
  1016.     strcat (s, " %Bqxf ");
  1017.     if (!buttons[n])
  1018.         break;
  1019.     strcat (s, " ||");
  1020.     n++;
  1021.     }
  1022.     strcat (s, " )f");
  1023.     r = gtk_dialog_cauldron (heading, GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_IGNOREENTER | GTK_CAULDRON_GRAB, s, first,
  1024.               buttons[0], buttons[1], buttons[2], buttons[3],
  1025.               buttons[4], buttons[5], buttons[6], buttons[7],
  1026.             buttons[8], buttons[9], buttons[10], buttons[11],
  1027.               buttons[12], buttons[13], buttons[14], buttons[15]
  1028.     );
  1029.     n = 0;
  1030.     if (r == GTK_CAULDRON_ESCAPE || !r || r == GNOME_STOCK_BUTTON_CANCEL)
  1031.     return -1;
  1032.     while (buttons[n]) {
  1033.     if (!strcmp (buttons[n], r))
  1034.         return n;
  1035.     n++;
  1036.     }
  1037.     return -1;
  1038. }
  1039.  
  1040. void gtk_edit_dialog_error (guchar * heading, char *fmt, ...)
  1041. {
  1042.     gchar s[8192];
  1043.     va_list ap;
  1044.     va_start (ap, fmt);
  1045.     vsprintf (s, fmt, ap);
  1046.     va_end (ap);
  1047.     gtk_dialog_cauldron (
  1048.                 heading, GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
  1049.                 " [ ( %Ld )xf ]xf / ( %Bxfgq )f",
  1050.                 s,
  1051.                 GNOME_STOCK_BUTTON_CANCEL
  1052.     );
  1053.     return;
  1054. }
  1055.  
  1056.  
  1057.  
  1058. struct color_matrix_struct {
  1059.     unsigned int R, G, B;
  1060. } color_matrix[27] =
  1061. {
  1062.     {0, 0, 0},
  1063.     {0, 0, 128},
  1064.     {0, 0, 255},
  1065.     {0, 139, 0},
  1066.     {0, 139, 139},
  1067.     {0, 154, 205},
  1068.     {0, 255, 0},
  1069.     {0, 250, 154},
  1070.     {0, 255, 255},
  1071.     {139, 37, 0},
  1072.     {139, 0, 139},
  1073.     {125, 38, 205},
  1074.     {139, 117, 0},
  1075.     {127, 127, 127},
  1076.     {123, 104, 238},
  1077.     {127, 255, 0},
  1078.     {135, 206, 235},
  1079.     {127, 255, 212},
  1080.     {238, 0, 0},
  1081.     {238, 18, 137},
  1082.     {238, 0, 238},
  1083.     {205, 102, 0},
  1084.     {248, 183, 183},
  1085.     {224, 102, 255},
  1086.     {238, 238, 0},
  1087.     {238, 230, 133},
  1088.     {248, 248, 255}
  1089. };
  1090.  
  1091. void gtk_edit_alloc_colors (GtkEdit *edit, GdkColormap *colormap)
  1092. {
  1093.     int i;
  1094.     for (i = 0; i < 27; i++) {
  1095.     edit->color[i].red = (gushort) color_matrix[i].R << 8;
  1096.     edit->color[i].green = (gushort) color_matrix[i].G << 8;
  1097.     edit->color[i].blue = (gushort) color_matrix[i].B << 8;
  1098.     if (!gdk_color_alloc (colormap, &edit->color[i]))
  1099.         g_warning ("cannot allocate color");
  1100.     }
  1101.     edit->color_last_pixel = 27;
  1102. }
  1103.  
  1104. int allocate_color (WEdit *edit, gchar *color)
  1105. {
  1106.     GtkEdit *win;
  1107.     win = (GtkEdit *) edit->widget;
  1108.     if (!color)
  1109.     return NO_COLOR;
  1110.     if (*color >= '0' && *color <= '9') {
  1111.     return atoi (color);
  1112.     } else {
  1113.     int i;
  1114.     GdkColor c;
  1115.     if (!color)
  1116.         return NO_COLOR;
  1117.     if (!gdk_color_parse (color, &c))
  1118.         return NO_COLOR;
  1119.     if (!gdk_color_alloc (gtk_widget_get_colormap(GTK_WIDGET (edit->widget)), &c))
  1120.         return NO_COLOR;
  1121.     for (i = 0; i < (GTK_EDIT (edit->widget))->color_last_pixel; i++)
  1122.         if (color_palette (i) == c.pixel)
  1123.         return i;
  1124.     GTK_EDIT (edit->widget)->color[(GTK_EDIT (edit->widget))->color_last_pixel].pixel = c.pixel;
  1125.     return (GTK_EDIT (edit->widget))->color_last_pixel++;
  1126.     }
  1127. }
  1128.  
  1129. static void gtk_edit_set_position (GtkEditable * editable, gint position)
  1130. {
  1131.     WEdit *edit;
  1132.     edit = GTK_EDIT(editable)->editor;
  1133.     edit_cursor_move (edit, position - edit->curs1);
  1134.     edit_move_to_prev_col (edit, 0);
  1135.     edit->force |= REDRAW_PAGE;
  1136.     edit->search_start = 0;
  1137.     edit_update_curs_row (edit);
  1138. }
  1139.  
  1140.  
  1141. /* returns 1 on error */
  1142. gint gtk_edit_load_file_from_filename (GtkWidget * edit, const gchar * filename)
  1143. {
  1144.     return edit_load_file_from_filename (GTK_EDIT (edit)->editor, (char *) filename);
  1145. }
  1146.  
  1147. void gtk_edit_set_top_line (GtkWidget * e, int line)
  1148. {
  1149.     WEdit *edit;
  1150.     edit = GTK_EDIT (e)->editor;
  1151.     edit_move_display (edit, line - edit->num_widget_lines / 2 - 1);
  1152.     edit->force |= REDRAW_COMPLETELY;
  1153. }
  1154.  
  1155. void gtk_edit_set_cursor_line (GtkWidget * e, int line)
  1156. {
  1157.     WEdit *edit;
  1158.     edit = GTK_EDIT (e)->editor;
  1159.     edit_move_to_line (edit, line - 1);
  1160.     edit->force |= REDRAW_COMPLETELY;
  1161. }
  1162.  
  1163. void about_cb (GtkWidget * widget, void *data)
  1164. {
  1165.     gtk_dialog_cauldron ("About", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB, " [ (Mcedit - an editor for the midnight commander\n\
  1166. ported from Cooledit - a user friendly text editor for the X Window System.)xf ]xf / ( %Bgqxf )f ", GNOME_STOCK_BUTTON_OK);
  1167.     return;
  1168. }
  1169.  
  1170. void gtk_edit_command (GtkEdit * edit, gint command)
  1171. {
  1172.     int r;
  1173.     gtk_widget_grab_focus (GTK_WIDGET (edit));
  1174.     r = edit_execute_key_command (edit->editor, command, -1);
  1175.     if (r)
  1176.     edit_update_screen (edit->editor);
  1177. }
  1178.  
  1179. void gtk_edit_quit (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Exit); }
  1180.  
  1181. void gtk_edit_load_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Load); }
  1182. void gtk_edit_new_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_New); }
  1183. void gtk_edit_save_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Save); }
  1184. void gtk_edit_save_as_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Save_As); }
  1185. void gtk_edit_insert_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Insert_File); }
  1186. void gtk_edit_copy_to_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Save_Block); }
  1187.  
  1188. void gtk_edit_clip_cut (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_XCut); }
  1189. void gtk_edit_clip_copy (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_XStore); }
  1190. void gtk_edit_clip_paste (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_XPaste); }
  1191.  
  1192. void gtk_edit_toggle_mark (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Mark); }
  1193. void gtk_edit_search (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Find); }
  1194. void gtk_edit_search_again (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Find_Again); }
  1195. void gtk_edit_replace (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Replace); }
  1196. void gtk_edit_copy (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Copy); }
  1197. void gtk_edit_move (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Move); }
  1198. void gtk_edit_delete (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Remove); }
  1199. void gtk_edit_undo (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Undo); }
  1200.  
  1201. #if 0
  1202. struct _GnomeUIInfo {
  1203.     GnomeUIInfoType type;
  1204.     gchar *label;
  1205.     gchar *hint;        /* For toolbar items, the tooltip. For menu items, the status bar message */
  1206.  
  1207.     /* For an item, toggleitem, or radioitem, procedure to call when activated.    
  1208.        For a subtree, point to the GnomeUIInfo array for that subtree.
  1209.        For a radioitem lead entry, point to the GnomeUIInfo array for
  1210.        the radio item group.  For the radioitem array, procedure to
  1211.        call when activated. For a help item, specifies the help node to load
  1212.        (or NULL for main prog's name) 
  1213.        For builder data, point to the GnomeUIBuilderData structure for the following items */
  1214.     gpointer moreinfo;
  1215.     gpointer user_data;
  1216.     gpointer unused_data;
  1217.     GnomeUIPixmapType pixmap_type;
  1218.     /* Either 
  1219.      * a pointer to the char for the pixmap (GNOME_APP_PIXMAP_DATA),
  1220.      * a char* for the filename (GNOME_APP_PIXMAP_FILENAME),
  1221.      * or a char* for the stock pixmap name (GNOME_APP_PIXMAP_STOCK).
  1222.      */
  1223.     gpointer pixmap_info;
  1224.     guint accelerator_key;    /* Accelerator key... Set to 0 to ignore */
  1225.     GdkModifierType ac_mods;    /* An OR of the masks for the accelerator */
  1226.     GtkWidget *widget;        /* Filled in by gnome_app_create* */
  1227. };
  1228.  
  1229. #endif
  1230.  
  1231. typedef struct _TbItems TbItems;
  1232. struct _TbItems {
  1233.     char *key, *text, *tooltip, *icon;
  1234.     void (*cb) (GtkEdit *, void *);
  1235.     GtkWidget *widget; /* will be filled in */
  1236. };
  1237.  
  1238. #define TB_PROP 7
  1239.  
  1240. static TbItems tb_items[] =
  1241. {
  1242.     {"F1", "Help", "Interactive help browser", GNOME_STOCK_MENU_BLANK, 0, NULL},
  1243.     {"F2", "Save", "Save to current file name", GNOME_STOCK_MENU_SAVE, gtk_edit_save_file, NULL},
  1244.     {"F3", "Mark", "Toggle In/Off invisible marker to highlight text", GNOME_STOCK_MENU_BLANK, gtk_edit_toggle_mark, NULL},
  1245.     {"F4", "Replc", "Find and replace strings/regular expressions", GNOME_STOCK_MENU_SRCHRPL, gtk_edit_replace, NULL},
  1246.     {"F5", "Copy", "Copy highlighted block to cursor postition", GNOME_STOCK_MENU_COPY, gtk_edit_copy, NULL},
  1247.  
  1248.     {"F6", "Move", "Copy highlighted block to cursor postition", GNOME_STOCK_MENU_BLANK, gtk_edit_move, NULL},
  1249.     {"F7", "Find", "Find strings/regular expressions", GNOME_STOCK_MENU_SEARCH, gtk_edit_search, NULL},
  1250.     {"F8", "Dlete", "Delete highlighted text", GNOME_STOCK_MENU_BLANK, gtk_edit_delete, NULL},
  1251.     {"F9", "Menu", "Pull down menu", GNOME_STOCK_MENU_BLANK, /* gtk_edit_menu*/ 0, NULL},
  1252.     {"F10", "Quit", "Exit editor", GNOME_STOCK_MENU_QUIT, gtk_edit_quit, NULL},
  1253.     {0, 0, 0, 0, 0, 0}
  1254. };
  1255.  
  1256. static GtkWidget *create_toolbar (GtkWidget * window, GtkEdit * edit)
  1257. {
  1258.     GtkWidget *toolbar;
  1259.     TbItems *t;
  1260.     toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH);
  1261.     for (t = &tb_items[0]; t->text; t++) {
  1262.     t->widget = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
  1263.                          t->text,
  1264.                          t->tooltip,
  1265.                          0,
  1266.                  gnome_stock_pixmap_widget (window, t->icon),
  1267.                          t->cb,
  1268.                          t->cb ? edit : 0);
  1269.     }
  1270.     return toolbar;
  1271. }
  1272.  
  1273. /* returns 1 on error */
  1274. int edit (const char *file, int line)
  1275. {
  1276.     GtkWidget *app;
  1277.     GtkWidget *edit, *statusbar;
  1278.  
  1279.     edit = gtk_edit_new (NULL, NULL);
  1280.     app = gnome_app_new ("mcedit", (char *) (file ? file : "Mcedit"));
  1281.  
  1282.     {
  1283.     GnomeUIInfo file_menu[] =
  1284.     {
  1285.         {
  1286.         GNOME_APP_UI_ITEM, N_ ("Open/Load"), N_ ("Load a different/new file"), gtk_edit_load_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN, 'O', GDK_CONTROL_MASK, 0
  1287.         },
  1288.         {
  1289.         GNOME_APP_UI_ITEM, N_ ("New"), N_ ("Clear the edit buffer"), gtk_edit_new_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_NEW, 'N', GDK_CONTROL_MASK, 0
  1290.         },
  1291.         GNOMEUIINFO_SEPARATOR,
  1292.         {
  1293.         GNOME_APP_UI_ITEM, N_ ("Save"), N_ ("Save the current edit buffer to filename"), gtk_edit_save_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE, 'S', GDK_CONTROL_MASK, 0
  1294.         },
  1295.         {
  1296.         GNOME_APP_UI_ITEM, N_ ("Save As"), N_ ("Save the current edit buffer as filename"), gtk_edit_save_as_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE_AS, 'A', GDK_CONTROL_MASK, 0
  1297.         },
  1298.         GNOMEUIINFO_SEPARATOR,
  1299.         {
  1300.         GNOME_APP_UI_ITEM, N_ ("Insert File"), N_ ("Insert text from a file"), gtk_edit_insert_file, edit, 0, 0, 0, 'I', GDK_CONTROL_MASK, 0
  1301.         },
  1302.         {
  1303.         GNOME_APP_UI_ITEM, N_ ("Copy to file"), N_ ("copy a block to a file"), gtk_edit_copy_to_file, edit, 0, 0, 0, 'C', GDK_CONTROL_MASK, 0
  1304.         },
  1305.         GNOMEUIINFO_SEPARATOR,
  1306.         {
  1307.         GNOME_APP_UI_ITEM, N_ ("Exit"), N_ ("Quit editor"), gtk_edit_quit, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'Q', GDK_CONTROL_MASK, NULL
  1308.         },
  1309.         GNOMEUIINFO_END
  1310.     };
  1311.  
  1312.     GnomeUIInfo edit_menu[] =
  1313.     {
  1314.         {
  1315.         GNOME_APP_UI_ITEM, N_ ("Copy"), N_ ("Copy selection to clipboard"), gtk_edit_clip_copy, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_COPY, 'C', GDK_CONTROL_MASK, 0
  1316.         },
  1317.         {
  1318.         GNOME_APP_UI_ITEM, N_ ("Cut"), N_ ("Cut selection to clipboard"), gtk_edit_clip_cut, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_CUT, 'X', GDK_CONTROL_MASK, 0
  1319.         },
  1320.         {
  1321.         GNOME_APP_UI_ITEM, N_ ("Paste"), N_ ("Paste clipboard"), gtk_edit_clip_paste, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PASTE, 'V', GDK_CONTROL_MASK, 0
  1322.         },
  1323.         GNOMEUIINFO_SEPARATOR,
  1324.         {
  1325.         GNOME_APP_UI_ITEM, N_ ("Undo"), N_ ("Go back in time one key press"), gtk_edit_undo, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PASTE, 'U', GDK_CONTROL_MASK, 0
  1326.         },
  1327.         GNOMEUIINFO_END
  1328.     };
  1329.  
  1330.     GnomeUIInfo search_menu[] =
  1331.     {
  1332.         {
  1333.         GNOME_APP_UI_ITEM, N_ ("Find"), N_ ("Find string/regular expression"), gtk_edit_search, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN, 'F', GDK_MOD1_MASK, 0
  1334.         },
  1335.         {
  1336.         GNOME_APP_UI_ITEM, N_ ("Find again"), N_ ("Repeat most recent search"), gtk_edit_search_again, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_NEW, 'A', GDK_MOD1_MASK, 0
  1337.         },
  1338.         {
  1339.         GNOME_APP_UI_ITEM, N_ ("Search/Replace"), N_ ("Find and replace text/regular expressions"), gtk_edit_replace, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE, 'R', GDK_MOD1_MASK, 0
  1340.         },
  1341.         GNOMEUIINFO_END
  1342.     };
  1343.  
  1344.     GnomeUIInfo help_menu[] =
  1345.     {
  1346.         {
  1347.         GNOME_APP_UI_ITEM,
  1348.         N_ ("About..."), N_ ("Info about Mcedit"),
  1349.         about_cb, NULL, NULL,
  1350.         GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT,
  1351.         0, (GdkModifierType) 0, NULL
  1352.         },
  1353. #if 0
  1354.         GNOMEUIINFO_SEPARATOR,
  1355.         GNOMEUIINFO_HELP ("hello"),
  1356. #endif
  1357.         GNOMEUIINFO_END
  1358.     };
  1359.  
  1360.     GnomeUIInfo main_menu[] =
  1361.     {
  1362.         GNOMEUIINFO_SUBTREE (N_ ("File"), file_menu),
  1363.         GNOMEUIINFO_SUBTREE (N_ ("Edit"), edit_menu),
  1364.         GNOMEUIINFO_SUBTREE (N_ ("Search/Replace"), search_menu),
  1365.         GNOMEUIINFO_SUBTREE (N_ ("Help"), help_menu),
  1366.         GNOMEUIINFO_END
  1367.     };
  1368.  
  1369.     gtk_widget_realize (app);
  1370.     statusbar = gtk_entry_new ();
  1371.     gtk_entry_set_editable (GTK_ENTRY (statusbar), 0);
  1372.     gtk_widget_set_usize (app, 400, 400);
  1373.     gnome_app_create_menus (GNOME_APP (app), main_menu);
  1374.     gnome_app_set_contents (GNOME_APP (app), edit);
  1375.     gnome_app_set_statusbar (GNOME_APP (app), GTK_WIDGET (statusbar));
  1376.     GTK_EDIT (edit)->menubar = GNOME_APP (app)->menubar;
  1377.     GTK_EDIT (edit)->status = statusbar;
  1378.     gnome_app_set_toolbar(GNOME_APP (app), GTK_TOOLBAR(create_toolbar(app, GTK_EDIT (edit))));
  1379.     GTK_EDIT(edit)->destroy_me = gtk_widget_destroy;
  1380.     GTK_EDIT(edit)->destroy_me_user_data = app;
  1381.  
  1382.     gtk_widget_show (edit);
  1383.     gtk_widget_realize (edit);
  1384.     if (file)
  1385.         if (*file)
  1386.         if (gtk_edit_load_file_from_filename (edit, file)) {
  1387.             gtk_widget_destroy (app);
  1388.             return 1;
  1389.         }
  1390.     gtk_edit_set_cursor_line (edit, line);
  1391.     gtk_widget_show_all (app);
  1392.     gtk_widget_grab_focus (edit);
  1393.     }
  1394.     return 0;
  1395. }
  1396.