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 / editwidget.c < prev    next >
C/C++ Source or Header  |  1999-01-04  |  33KB  |  1,151 lines

  1. /* editor initialisation and callback handler.
  2.  
  3.    Copyright (C) 1996, 1997 the Free Software Foundation
  4.  
  5.    Authors: 1996, 1997 Paul Sheer
  6.  
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.  
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. #include <config.h>
  23. #include "edit.h"
  24.  
  25. #ifndef MIDNIGHT
  26. #include <X11/Xmd.h>        /* CARD32 */
  27. #include <X11/Xatom.h>
  28. #include "app_glob.c"
  29. #include "coollocal.h"
  30. #include "editcmddef.h"
  31. #include "mousemark.h"
  32. #endif
  33.  
  34.  
  35. #ifndef MIDNIGHT
  36.  
  37. extern int EditExposeRedraw;
  38. CWidget *wedit = 0;
  39.  
  40. void edit_destroy_callback (CWidget * w)
  41. {
  42.     if (w) {
  43.     edit_clean (w->editor);
  44.     if (w->editor)
  45.         free (w->editor);
  46.     w->editor = NULL;
  47.     } else
  48. /* NLS ? */
  49.     CError ("Trying to destroy non-existing editor widget.\n");
  50. }
  51.  
  52. void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);
  53.  
  54. /* returns the position in the edit buffer of a window click */
  55. long edit_get_click_pos (WEdit * edit, int x, int y)
  56. {
  57.     long click;
  58. /* (1) goto to left margin */
  59.     click = edit_bol (edit, edit->curs1);
  60.  
  61. /* (1) move up or down */
  62.     if (y > (edit->curs_row + 1))
  63.     click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0);
  64.     if (y < (edit->curs_row + 1))
  65.     click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);
  66.  
  67. /* (3) move right to x pos */
  68.     click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0);
  69.     return click;
  70. }
  71.  
  72. void edit_translate_xy (int xs, int ys, int *x, int *y)
  73. {
  74.     *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET;
  75.     *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;
  76. }
  77.  
  78. extern int just_dropped_something;
  79.  
  80. void mouse_redraw (WEdit * edit, long click)
  81. {
  82.     edit->force |= REDRAW_PAGE | REDRAW_LINE;
  83.     edit_update_curs_row (edit);
  84.     edit_update_curs_col (edit);
  85.     edit->prev_col = edit_get_col (edit);
  86.     edit_update_screen (edit);
  87.     edit->search_start = click;
  88. }
  89.  
  90. static void xy (int x, int y, int *x_return, int *y_return)
  91. {
  92.     edit_translate_xy (x, y, x_return, y_return);
  93. }
  94.  
  95. static long cp (WEdit *edit, int x, int y)
  96. {
  97.     return edit_get_click_pos (edit, x, y);
  98. }
  99.  
  100. /* return 1 if not marked */
  101. static int marks (WEdit * edit, long *start, long *end)
  102. {
  103.     return eval_marks (edit, start, end);
  104. }
  105.  
  106. int column_highlighting = 0;
  107.  
  108. static int erange (WEdit * edit, long start, long end, int click)
  109. {
  110.     if (column_highlighting) {
  111.     int x;
  112.     x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click);
  113.     if ((x >= edit->column1 && x < edit->column2)
  114.         || (x > edit->column2 && x <= edit->column1))
  115.         return (start <= click && click < end);
  116.     else
  117.         return 0;
  118.     }
  119.     return (start <= click && click < end);
  120. }
  121.  
  122. static void fin_mark (WEdit *edit)
  123. {
  124.     if (edit->mark2 < 0)
  125.     edit_mark_cmd (edit, 0);
  126. }
  127.  
  128. static void move_mark (WEdit *edit)
  129. {
  130.     edit_mark_cmd (edit, 1);
  131.     edit_mark_cmd (edit, 0);
  132. }
  133.  
  134. static void release_mark (WEdit * edit, XEvent * event)
  135. {
  136.     if (edit->mark2 < 0)
  137.     edit_mark_cmd (edit, 0);
  138.     else
  139.     edit_mark_cmd (edit, 1);
  140.     if (edit->mark1 != edit->mark2 && event) {
  141.     edit_get_selection (edit);
  142.     XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), event->xbutton.time);
  143.     } else {
  144.     edit->widget->editable.has_selection = TRUE;
  145.     }
  146. }
  147.  
  148. static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l)
  149. {
  150.     char *t;
  151.     t = (char *) edit_get_block (edit, start_mark, end_mark, l);
  152.     if (strlen (t) < *l)
  153.     *type = DndRawData;    /* if there are nulls in the data, send as raw */
  154.     else
  155.     *type = DndText;    /* else send as text */
  156.     return t;
  157. }
  158.  
  159. static void move (WEdit *edit, long click, int y)
  160. {
  161.     edit_cursor_move (edit, click - edit->curs1);
  162. }
  163.  
  164. static void dclick (WEdit *edit, XEvent *event)
  165. {
  166.     edit_mark_cmd (edit, 1);
  167.     edit_right_word_move (edit);
  168.     edit_mark_cmd (edit, 0);
  169.     edit_left_word_move (edit);
  170.     release_mark (edit, event);
  171. }
  172.  
  173. static void redraw (WEdit *edit, long click)
  174. {
  175.     mouse_redraw (edit, click);
  176. }
  177.  
  178. void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width);
  179.  
  180. /* strips out the first i chars and returns a null terminated string, result must be free'd */
  181. char *filename_from_url (char *data, int size, int i)
  182. {
  183.     char *p, *f;
  184.     int l;
  185.     for (p = data + i; (unsigned long) p - (unsigned long) data < size && *p && *p != '\n'; p++);
  186.     l = (unsigned long) p - (unsigned long) data - i;
  187.     f = malloc (l + 1);
  188.     memcpy (f, data + i, l);
  189.     f[l] = '\0';
  190.     return f;
  191. }
  192.  
  193. static int insert_drop (WEdit * e, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action)
  194. {
  195.     long start_mark = 0, end_mark = 0;
  196.     int x, y;
  197.  
  198.     edit_translate_xy (xs, ys, &x, &y);
  199. /* musn't be able to drop into a block, otherwise a single click will copy a block: */
  200.     if (eval_marks (e, &start_mark, &end_mark))
  201.     goto fine;
  202.     if (start_mark > e->curs1 || e->curs1 >= end_mark)
  203.     goto fine;
  204.     if (column_highlighting) {
  205.     if (!((x >= e->column1 && x < e->column2)
  206.           || (x > e->column2 && x <= e->column1)))
  207.         goto fine;
  208.     }
  209.     return 1;
  210.   fine:
  211.     if (from == e->widget->winid && action == CDndClass->XdndActionMove) {
  212.     edit_block_move_cmd (e);
  213.     edit_mark_cmd (e, 1);
  214.     return 0;
  215.     } else if (from == e->widget->winid) {
  216.     edit_block_copy_cmd (e);
  217.     return 0;
  218.     } else {            /*  data from another widget, or from another application */
  219.     edit_push_action (e, KEY_PRESS + e->start_display);
  220.     if (type == XInternAtom (CDisplay, "url/url", False)) {
  221.         if (!strncmp ((char *) data, "file:/", 6)) {
  222.         char *f;
  223.         edit_insert_file (e, f = filename_from_url ((char *) data, size, strlen ("file:")));
  224.         free (f);
  225.         } else {
  226.         while (size--)
  227.             edit_insert_ahead (e, data[size]);
  228.         }
  229.     } else {
  230.         if (column_highlighting) {
  231.         edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
  232.         } else {
  233.         while (size--)
  234.             edit_insert_ahead (e, data[size]);
  235.         }
  236.     }
  237.     }
  238.     CExpose (e->widget->ident);
  239.     return 0;
  240. }
  241.  
  242. static char *mime_majors[2] =
  243.     {"text", 0};
  244.  
  245. struct mouse_funcs edit_mouse_funcs =
  246. {
  247.     0,
  248.     (void (*)(int, int, int *, int *)) xy,
  249.     (long (*)(void *, int, int)) cp,
  250.     (int (*)(void *, long *, long *)) marks,
  251.     (int (*)(void *, long, long, long)) erange,
  252.     (void (*)(void *)) fin_mark,
  253.     (void (*)(void *)) move_mark,
  254.     (void (*)(void *, XEvent *)) release_mark,
  255.     (char *(*)(void *, long, long, int *, int *)) get_block,
  256.     (void (*)(void *, long, int)) move,
  257.     0,
  258.     (void (*)(void *, XEvent *)) dclick,
  259.     (void (*)(void *, long)) redraw,
  260.     (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) insert_drop,
  261.     (void (*)(void *)) edit_block_delete,
  262.     DndText,
  263.     mime_majors
  264. };
  265.  
  266. extern int option_editor_bg_normal;
  267. void edit_tri_cursor (Window win);
  268.  
  269. /* starting_directory is for the filebrowser */
  270. CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
  271.        int width, int height, const char *text, const char *filename,
  272.         const char *starting_directory, unsigned int options, unsigned long text_size)
  273. {
  274.     static made_directory = 0;
  275.     int extra_space_for_hscroll = 0;
  276.     CWidget *w;
  277.     WEdit *e;
  278.  
  279.     if (options & EDITOR_HORIZ_SCROLL)
  280.     extra_space_for_hscroll = 8;
  281.  
  282.     wedit = w = CSetupWidget (identifier, parent, x, y,
  283.                   width + 7, height + 6, C_EDITOR_WIDGET,
  284.            ExposureMask | ButtonPressMask | ButtonReleaseMask | \
  285.              KeyPressMask | KeyReleaseMask | ButtonMotionMask | \
  286.                   PropertyChangeMask | StructureNotifyMask | \
  287.                   EnterWindowMask | LeaveWindowMask, color_palette (option_editor_bg_normal), 1);
  288.  
  289.     xdnd_set_dnd_aware (CDndClass, w->winid, 0);
  290.     xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndText]);
  291.  
  292.     edit_tri_cursor (w->winid);
  293.     w->options = options | WIDGET_TAKES_SELECTION;
  294.  
  295.     w->destroy = edit_destroy_callback;
  296.     if (filename)
  297.     w->label = strdup (filename);
  298.     else
  299.     w->label = strdup ("");
  300.  
  301.     if (!made_directory) {
  302.     mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
  303.     made_directory = 1;
  304.     }
  305.     e = w->editor = CMalloc (sizeof (WEdit));
  306.     w->funcs = mouse_funcs_new (w->editor, &edit_mouse_funcs);
  307.  
  308.     if (!w->editor) {
  309. /* Not essential to translate */
  310.     CError (_ ("Error initialising editor.\n"));
  311.     return 0;
  312.     }
  313.     w->editor->widget = w;
  314.     w->editor = edit_init (e, height / FONT_PIX_PER_LINE, width / FONT_MEAN_WIDTH, filename, text, starting_directory, text_size);
  315.     w->funcs->data = (void *) w->editor;
  316.     if (!w->editor) {
  317.     free (e);
  318.     CDestroyWidget (w->ident);
  319.     return 0;
  320.     }
  321.     e->macro_i = -1;
  322.     e->widget = w;
  323.  
  324.     set_hint_pos (x + width + 7 + WIDGET_SPACING, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll);
  325.     if (extra_space_for_hscroll) {
  326.     w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent,
  327.         x, y + height + 6, width + 6, 12, 0, 0);
  328.     CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor);
  329.     }
  330.     if (!(options & EDITOR_NO_TEXT))
  331.     CDrawText (catstrs (identifier, ".text", 0), parent, x, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll, "%s", e->filename);
  332.     if (!(options & EDITOR_NO_SCROLL)) {
  333.     w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent,
  334.         x + width + 7 + WIDGET_SPACING, y, height + 6, 20, 0, 0);
  335.     CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_editor);
  336.     }
  337.     return w;
  338. }
  339.  
  340. void update_scroll_bars (WEdit * e)
  341. {
  342.     int i, x1, x2;
  343.     CWidget *scroll;
  344.     scroll = e->widget->vert_scrollbar;
  345.     if (scroll) {
  346.     i = e->total_lines - e->start_line + 1;
  347.     if (i > e->num_widget_lines)
  348.         i = e->num_widget_lines;
  349.     if (e->total_lines) {
  350.         x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
  351.         x2 = (double) 65535.0 *i / (e->total_lines + 1);
  352.     } else {
  353.         x1 = 0;
  354.         x2 = 65535;
  355.     }
  356.     if (x1 != scroll->firstline || x2 != scroll->numlines) {
  357.         scroll->firstline = x1;
  358.         scroll->numlines = x2;
  359.         EditExposeRedraw = 1;
  360.         render_scrollbar (scroll);
  361.         EditExposeRedraw = 0;
  362.     }
  363.     }
  364.     scroll = e->widget->hori_scrollbar;
  365.     if (scroll) {
  366.     i = e->max_column - (-e->start_col) + 1;
  367.     if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
  368.         i = e->num_widget_columns * FONT_MEAN_WIDTH;
  369.     x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
  370.     x2 = (double) 65535.0 *i / (e->max_column + 1);
  371.     if (x1 != scroll->firstline || x2 != scroll->numlines) {
  372.         scroll->firstline = x1;
  373.         scroll->numlines = x2;
  374.         EditExposeRedraw = 1;
  375.         render_scrollbar (scroll);
  376.         EditExposeRedraw = 0;
  377.     }
  378.     }
  379. }
  380.  
  381. void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click)
  382. {
  383.     edit_update_curs_row (edit);
  384.     edit_update_curs_col (edit);
  385.     if (event->type != MotionNotify) {
  386.     edit_push_action (edit, KEY_PRESS + edit->start_display);
  387.     if (edit->mark2 == -1)
  388.         edit_push_action (edit, MARK_1 + edit->mark1);    /* mark1 must be following the cursor */
  389.     }
  390.     if (event->type == ButtonPress) {
  391.     edit->highlight = 0;
  392.     edit->found_len = 0;
  393.     }
  394.     mouse_mark (
  395.     event,
  396.     double_click,
  397.     edit->widget->funcs
  398.     );
  399. }
  400.  
  401. void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
  402. {
  403.     int i, start_line;
  404.     WEdit *e;
  405.     e = editor->editor;
  406.     if (!e)
  407.     return;
  408.     if (!e->widget->vert_scrollbar)
  409.     return;
  410.     start_line = e->start_line;
  411.     if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
  412.     edit_move_display (e, (double) scrollbar->firstline * e->total_lines / 65535.0 + 1);
  413.     } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
  414.     switch (whichscrbutton) {
  415.     case 1:
  416.         edit_move_display (e, e->start_line - e->num_widget_lines + 1);
  417.         break;
  418.     case 2:
  419.         edit_move_display (e, e->start_line - 1);
  420.         break;
  421.     case 5:
  422.         edit_move_display (e, e->start_line + 1);
  423.         break;
  424.     case 4:
  425.         edit_move_display (e, e->start_line + e->num_widget_lines - 1);
  426.         break;
  427.     }
  428.     }
  429.     if (e->total_lines)
  430.     scrollbar->firstline = (double) 65535.0 *e->start_line / (e->total_lines + 1);
  431.     else
  432.     scrollbar->firstline = 0;
  433.     i = e->total_lines - e->start_line + 1;
  434.     if (i > e->num_widget_lines)
  435.     i = e->num_widget_lines;
  436.     if (e->total_lines)
  437.     scrollbar->numlines = (double) 65535.0 *i / (e->total_lines + 1);
  438.     else
  439.     scrollbar->numlines = 65535;
  440.     if (start_line != e->start_line) {
  441.     e->force |= REDRAW_PAGE | REDRAW_LINE;
  442.     set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
  443.     if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
  444.         return;
  445.     }
  446.     if (e->force) {
  447.     edit_render_keypress (e);
  448.     edit_status (e);
  449.     }
  450. }
  451.  
  452. void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
  453. {
  454.     int i, start_col;
  455.     WEdit *e;
  456.     e = editor->editor;
  457.     if (!e)
  458.     return;
  459.     if (!e->widget->hori_scrollbar)
  460.     return;
  461.     start_col = (-e->start_col);
  462.     if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
  463.     e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1;
  464.     e->start_col -= e->start_col % FONT_MEAN_WIDTH;
  465.     if (e->start_col < 0)
  466.         e->start_col = 0;
  467.     e->start_col = (-e->start_col);
  468.     } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
  469.     switch (whichscrbutton) {
  470.     case 1:
  471.         edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
  472.         break;
  473.     case 2:
  474.         edit_scroll_left (e, FONT_MEAN_WIDTH);
  475.         break;
  476.     case 5:
  477.         edit_scroll_right (e, FONT_MEAN_WIDTH);
  478.         break;
  479.     case 4:
  480.         edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
  481.         break;
  482.     }
  483.     }
  484.     scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
  485.     i = e->max_column - (-e->start_col) + 1;
  486.     if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
  487.     i = e->num_widget_columns * FONT_MEAN_WIDTH;
  488.     scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1);
  489.     if (start_col != (-e->start_col)) {
  490.     e->force |= REDRAW_PAGE | REDRAW_LINE;
  491.     set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
  492.     if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
  493.         return;
  494.     }
  495.     if (e->force) {
  496.     edit_render_keypress (e);
  497.     edit_status (e);
  498.     }
  499. }
  500.  
  501. /* 
  502.    This section comes from rxvt-2.21b1/src/screen.c by
  503.    Robert Nation <nation@rocket.sanders.lockheed.com> &
  504.    mods by mj olesen <olesen@me.QueensU.CA>
  505.  
  506.    Changes made for cooledit
  507.  */
  508. void selection_send (XSelectionRequestEvent * rq)
  509. {
  510.     XEvent ev;
  511.     static Atom xa_targets = None;
  512.     if (xa_targets == None)
  513.     xa_targets = XInternAtom (CDisplay, "TARGETS", False);
  514.  
  515.     ev.xselection.type = SelectionNotify;
  516.     ev.xselection.property = None;
  517.     ev.xselection.display = rq->display;
  518.     ev.xselection.requestor = rq->requestor;
  519.     ev.xselection.selection = rq->selection;
  520.     ev.xselection.target = rq->target;
  521.     ev.xselection.time = rq->time;
  522.  
  523.     if (rq->target == xa_targets) {
  524.     /*
  525.      * On some systems, the Atom typedef is 64 bits wide.
  526.      * We need to have a typedef that is exactly 32 bits wide,
  527.      * because a format of 64 is not allowed by the X11 protocol.
  528.      */
  529.     typedef CARD32 Atom32;
  530.  
  531.     Atom32 target_list[2];
  532.  
  533.     target_list[0] = (Atom32) xa_targets;
  534.     target_list[1] = (Atom32) XA_STRING;
  535.  
  536.     XChangeProperty (CDisplay, rq->requestor, rq->property,
  537.         xa_targets, 8 * sizeof (target_list[0]), PropModeReplace,
  538.              (unsigned char *) target_list,
  539.              sizeof (target_list) / sizeof (target_list[0]));
  540.     ev.xselection.property = rq->property;
  541.     } else if (rq->target == XA_STRING) {
  542.     XChangeProperty (CDisplay, rq->requestor, rq->property,
  543.              XA_STRING, 8, PropModeReplace,
  544.              selection.text, selection.len);
  545.     ev.xselection.property = rq->property;
  546.     }
  547.     XSendEvent (CDisplay, rq->requestor, False, 0, &ev);
  548. }
  549.  
  550. /*{{{ paste selection */
  551.  
  552. /*
  553.  * Respond to a notification that a primary selection has been sent
  554.  */
  555. void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete)
  556. {
  557.     long nread;
  558.     unsigned long bytes_after;
  559.  
  560.     if (prop == None)
  561.     return;
  562.  
  563.     nread = 0;
  564.     do {
  565.     unsigned char *s;
  566.     Atom actual_type;
  567.     int actual_fmt, i;
  568.     unsigned long nitems;
  569.     if (XGetWindowProperty (CDisplay, win, prop,
  570.                 nread / 4, 65536, delete,
  571.                   AnyPropertyType, &actual_type, &actual_fmt,
  572.                 &nitems, &bytes_after,
  573.                 &s) != Success) {
  574.         XFree (s);
  575.         return;
  576.     }
  577.     nread += nitems;
  578.     for (i = 0; i < nitems; i++)
  579.         (*insert) (data, s[i]);
  580.     XFree (s);
  581.     } while (bytes_after);
  582. }
  583.  
  584. void selection_paste (WEdit * edit, Window win, unsigned prop, int delete)
  585. {
  586.     long c;
  587.     c = edit->curs1;
  588.     paste_prop ((void *) edit,
  589.         (void (*)(void *, int)) edit_insert,
  590.         win, prop, delete);
  591.     edit_cursor_move (edit, c - edit->curs1);
  592.     edit->force |= REDRAW_COMPLETELY | REDRAW_LINE;
  593. }
  594.  
  595. /*}}} */
  596.  
  597. void selection_clear (void)
  598. {
  599.     selection.text = 0;
  600.     selection.len = 0;
  601. }
  602.  
  603. void edit_update_screen (WEdit * e)
  604. {
  605.     if (!e)
  606.     return;
  607.     if (!e->force)
  608.     return;
  609.  
  610.     edit_scroll_screen_over_cursor (e);
  611.     edit_update_curs_row (e);
  612.     edit_update_curs_col (e);
  613.     update_scroll_bars (e);
  614.     edit_status (e);
  615.  
  616.     if (e->force & REDRAW_COMPLETELY)
  617.     e->force |= REDRAW_PAGE;
  618.  
  619. /* pop all events for this window for internal handling */
  620.     if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) {
  621.     edit_render_keypress (e);
  622.     } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0)
  623.            || CKeyPending ()) {
  624.     e->force |= REDRAW_PAGE;
  625.     return;
  626.     } else {
  627.     edit_render_keypress (e);
  628.     }
  629. }
  630.  
  631.  
  632. extern int space_width;
  633.  
  634. #ifdef HAVE_DND
  635. #define free_data if (data) {free(data);data=0;}
  636.  
  637. /* handles drag and drop */
  638. void handle_client_message (CWidget * w, XEvent * xevent)
  639. {
  640.     int data_type;
  641.     unsigned char *data = 0;
  642.     unsigned long size;
  643.     int xs, ys;
  644.     long start_line;
  645.     int x, y, r, deleted = 0;
  646.     long click;
  647.     unsigned int state;
  648.     long start_mark = 0, end_mark = 0;
  649.     WEdit *e = w->editor;
  650.  
  651. /* see just below for a comment on what this is for: */
  652.     if (CIsDropAcknowledge (xevent, &state) != DndNotDnd) {
  653.     if (!(state & Button1Mask) && just_dropped_something) {
  654.         edit_push_action (e, KEY_PRESS + e->start_display);
  655.         edit_block_delete_cmd (e);
  656.     }
  657.     return;
  658.     }
  659.     data_type = CGetDrop (xevent, &data, &size, &xs, &ys);
  660.  
  661.     if (data_type == DndNotDnd || xs < 0 || ys < 0 || xs >= CWidthOf (w) || ys >= CHeightOf (w)) {
  662.     free_data;
  663.     return;
  664.     }
  665.     edit_translate_xy (xs, ys, &x, &y);
  666.     click = edit_get_click_pos (e, x, y);
  667.  
  668.     r = eval_marks (e, &start_mark, &end_mark);
  669. /* musn't be able to drop into a block, otherwise a single click will copy a block: */
  670.     if (r)
  671.     goto fine;
  672.     if (start_mark > click || click >= end_mark)
  673.     goto fine;
  674.     if (column_highlighting) {
  675.     if (!((x >= e->column1 && x < e->column2)
  676.           || (x > e->column2 && x <= e->column1)))
  677.         goto fine;
  678.     }
  679.     free_data;
  680.     return;
  681.   fine:
  682.     edit_push_action (e, KEY_PRESS + e->start_display);
  683.  
  684. /* drops to the same window moving to the left: */
  685.     start_line = e->start_line;
  686.     if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
  687.     if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) {
  688.         edit_block_delete_cmd (e);
  689.         deleted = 1;
  690.     }
  691.     edit_update_curs_row (e);
  692.     edit_move_display (e, start_line);
  693.     click = edit_get_click_pos (e, x, y);    /* click pos changes with edit_block_delete_cmd() */
  694.     edit_cursor_move (e, click - e->curs1);
  695.     if (data_type == DndFile) {
  696.     edit_insert_file (e, (char *) data);
  697.     } else if (data_type != DndFiles) {
  698.     if (dnd_null_term_type (data_type)) {
  699.         int len;
  700.         len = strlen ((char *) data);
  701.         size = min (len, size);
  702.     }
  703.     if (column_highlighting) {
  704.         edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
  705.     } else {
  706.         while (size--)
  707.         edit_insert_ahead (e, data[size]);
  708.     }
  709.     } else {
  710.     while (size--)
  711.         edit_insert_ahead (e, data[size] ? data[size] : '\n');
  712.     }
  713.  
  714. /* drops to the same window moving to the right: */
  715.     if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
  716.     if (column_highlighting && !deleted)
  717.         edit_block_delete_cmd (e);
  718.  
  719. /* The drop has now been successfully recieved. We can now send an acknowledge
  720.    event back to the window that send the data. When this window recieves
  721.    the acknowledge event, the app can decide whether or not to delete the data.
  722.    This allows text to be safely moved betweem text windows without the
  723.    risk of data being lost. In our case, drag with button1 is a copy
  724.    drag, while drag with any other button is a move drag (i.e. the sending
  725.    application must delete its selection after recieving an acknowledge
  726.    event). We must not, however, send an acknowledge signal if a filelist
  727.    (for example) was passed to us, since the sender might take this to
  728.    mean that all those files can be deleted! The two types we can acknowledge
  729.    are: */
  730.     if (xevent->xclient.data.l[2] != xevent->xclient.window)    /* drops to the same window */
  731.     if (data_type == DndText || data_type == DndRawData)
  732.         CDropAcknowledge (xevent);
  733.     e->force |= REDRAW_COMPLETELY | REDRAW_LINE;
  734.     free_data;
  735. }
  736. #endif
  737.  
  738. int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
  739. {
  740.     WEdit *e = w->editor;
  741.     int r = 0;
  742.     static int old_tab_spacing = -1;
  743.  
  744.     if (!e)
  745.     return 0;
  746.  
  747.     if (old_tab_spacing != option_tab_spacing)
  748.     e->force |= REDRAW_COMPLETELY + REDRAW_LINE;
  749.     old_tab_spacing = option_tab_spacing;
  750.  
  751.     if (xevent->type == KeyPress) {
  752.     if (xevent->xkey.keycode == 0x31 && xevent->xkey.state == 0xD) {
  753.         CSetColor (color_palette (18));
  754.         CRectangle (w->winid, 0, 0, w->width, w->height);
  755.     }
  756.     }
  757.     switch (xevent->type) {
  758.     case SelectionNotify:
  759.     selection_paste (e, xevent->xselection.requestor, xevent->xselection.property, True);
  760.     r = 1;
  761.     break;
  762.     case SelectionRequest:
  763.     selection_send (&(xevent->xselectionrequest));
  764.     return 1;
  765. /*  case SelectionClear:   ---> This is handled by coolnext.c: CNextEvent() */
  766. #ifdef HAVE_DND
  767.     case ClientMessage:
  768.     handle_client_message (w, xevent);
  769.     r = 1;
  770. #endif
  771.     break;
  772.     case ButtonPress:
  773.     CFocus (w);
  774.     edit_render_tidbits (w);
  775.     case ButtonRelease:
  776.     if (xevent->xbutton.state & ControlMask) {
  777.         if (!column_highlighting)
  778.         edit_push_action (e, COLUMN_OFF);
  779.         column_highlighting = 1;
  780.     } else {
  781.         if (column_highlighting)
  782.         edit_push_action (e, COLUMN_ON);
  783.         column_highlighting = 0;
  784.     }
  785.     case MotionNotify:
  786.     if (!xevent->xmotion.state && xevent->type == MotionNotify)
  787.         return 0;
  788.     resolve_button (xevent, cwevent);
  789.     if ((cwevent->button == Button4 || cwevent->button == Button5)
  790.         && (xevent->type == ButtonRelease)) {
  791.         /* ahaack: wheel mouse mapped as button 4 and 5 */
  792.         r = edit_execute_key_command (e, (cwevent->button == Button5) ? CK_Page_Down : CK_Page_Up, -1);
  793.         break;
  794.     }
  795.     edit_mouse_mark (e, xevent, cwevent->double_click);
  796.     break;
  797.     case Expose:
  798.     edit_render_expose (e, &(xevent->xexpose));
  799.     return 1;
  800.     case FocusIn:
  801.     CSetCursorColor (e->overwrite ? color_palette (24) : color_palette (19));
  802.     case FocusOut:
  803.     edit_render_tidbits (w);
  804.     e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
  805.     edit_render_keypress (e);
  806.     return 1;
  807.     break;
  808.     case KeyRelease:
  809. #if 0
  810.     if (column_highlighting) {
  811.         column_highlighting = 0;
  812.         e->force = REDRAW_COMPLETELY | REDRAW_LINE;
  813.         edit_mark_cmd (e, 1);
  814.     }
  815. #endif
  816.     break;
  817.     case KeyPress:
  818.     cwevent->ident = w->ident;
  819.     if (!cwevent->command && cwevent->insert < 0) {        /* no translation */
  820.         if ((cwevent->key == XK_r || cwevent->key == XK_R) && (cwevent->state & ControlMask)) {
  821.         cwevent->command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
  822.         } else {
  823.         cwevent->command = CKeySymMod (xevent);
  824.         if (cwevent->command > 0)
  825.             cwevent->command = CK_Macro (cwevent->command);
  826.         else
  827.             break;
  828.         }
  829.     }
  830.     r = edit_execute_key_command (e, cwevent->command, cwevent->insert);
  831.     if (r)
  832.         edit_update_screen (e);
  833.     return r;
  834.     break;
  835.     case EditorCommand:
  836.     cwevent->ident = w->ident;
  837.     cwevent->command = xevent->xkey.keycode;
  838.     r = cwevent->handled = edit_execute_key_command (e, xevent->xkey.keycode, -1);
  839.     if (r)
  840.         edit_update_screen (e);
  841.     return r;
  842.     default:
  843.     return 0;
  844.     }
  845.     edit_update_screen (e);
  846.     return r;
  847. }
  848.  
  849. #else
  850.  
  851. WEdit *wedit;
  852. WButtonBar *edit_bar;
  853. Dlg_head *edit_dlg;
  854. WMenu *edit_menubar;
  855.  
  856. int column_highlighting = 0;
  857.  
  858. static int edit_callback (Dlg_head * h, WEdit * edit, int msg, int par);
  859.  
  860. static int edit_mode_callback (struct Dlg_head *h, int id, int msg)
  861. {
  862.     return 0;
  863. }
  864.  
  865. int edit_event (WEdit * edit, Gpm_Event * event, int *result)
  866. {
  867.     *result = MOU_NORMAL;
  868.     edit_update_curs_row (edit);
  869.     edit_update_curs_col (edit);
  870.     if (event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) {
  871.     if (event->y > 1 && event->x > 0
  872.         && event->x <= edit->num_widget_columns
  873.         && event->y <= edit->num_widget_lines + 1) {
  874.         if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG))
  875.         return 1;    /* a lone up mustn't do anything */
  876.         if (event->type & (GPM_DOWN | GPM_UP))
  877.         edit_push_key_press (edit);
  878.         edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
  879.         if (--event->y > (edit->curs_row + 1))
  880.         edit_cursor_move (edit,
  881.                   edit_move_forward (edit, edit->curs1, event->y - (edit->curs_row + 1), 0)
  882.                   - edit->curs1);
  883.         if (event->y < (edit->curs_row + 1))
  884.         edit_cursor_move (edit,
  885.                   +edit_move_backward (edit, edit->curs1, (edit->curs_row + 1) - event->y)
  886.                   - edit->curs1);
  887.         edit_cursor_move (edit, (int) edit_move_forward3 (edit, edit->curs1,
  888.                event->x - edit->start_col - 1, 0) - edit->curs1);
  889.         edit->prev_col = edit_get_col (edit);
  890.         if (event->type & GPM_DOWN) {
  891.         edit_mark_cmd (edit, 1);    /* reset */
  892.         edit->highlight = 0;
  893.         }
  894.         if (!(event->type & GPM_DRAG))
  895.         edit_mark_cmd (edit, 0);
  896.         edit->force |= REDRAW_COMPLETELY;
  897.         edit_update_curs_row (edit);
  898.         edit_update_curs_col (edit);
  899.         edit_update_screen (edit);
  900.         return 1;
  901.     }
  902.     }
  903.     return 0;
  904. }
  905.  
  906.  
  907.  
  908. int menubar_event (Gpm_Event * event, WMenu * menubar);        /* menu.c */
  909.  
  910. int edit_mouse_event (Gpm_Event * event, void *x)
  911. {
  912.     int result;
  913.     if (edit_event ((WEdit *) x, event, &result))
  914.     return result;
  915.     else
  916.     return menubar_event (event, edit_menubar);
  917. }
  918.  
  919. extern Menu EditMenuBar[5];
  920.  
  921. int edit (const char *_file, int line)
  922. {
  923.     static int made_directory = 0;
  924.     int framed = 0;
  925.     int midnight_colors[4];
  926.     char *text = 0;
  927.  
  928.     if (option_backup_ext_int != -1) {
  929.     option_backup_ext = malloc (sizeof(int) + 1);
  930.     option_backup_ext[sizeof(int)] = '\0';
  931.     memcpy (option_backup_ext, (char *) &option_backup_ext_int, sizeof (int));
  932.     }
  933.  
  934.     if (!made_directory) {
  935.     mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
  936.     made_directory = 1;
  937.     }
  938.     if (_file) {
  939.     if (!(*_file)) {
  940.         _file = 0;
  941.         text = "";
  942.     }
  943.     } else
  944.     text = "";
  945.  
  946.     if (!(wedit = edit_init (NULL, LINES - 2, COLS, _file, text, "", 0))) {
  947.     message (1, _(" Error "), get_error_msg (""));
  948.     return 0;
  949.     }
  950.     wedit->macro_i = -1;
  951.  
  952.     /* Create a new dialog and add it widgets to it */
  953.     edit_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
  954.                edit_mode_callback, "[Internal File Editor]",
  955.                "edit",
  956.                DLG_NONE);
  957.  
  958.     edit_dlg->raw = 1;        /*so that tab = '\t' key works */
  959.  
  960.     init_widget (&(wedit->widget), 0, 0, LINES - 1, COLS,
  961.          (callback_fn) edit_callback,
  962.          (destroy_fn) edit_clean,
  963.          (mouse_h) edit_mouse_event, 0);
  964.  
  965.     widget_want_cursor (wedit->widget, 1);
  966.  
  967.     edit_bar = buttonbar_new (1);
  968.  
  969.     if (!framed) {
  970.     switch (edit_key_emulation) {
  971.     case EDIT_KEY_EMULATION_NORMAL:
  972.         edit_init_menu_normal ();    /* editmenu.c */
  973.         break;
  974.     case EDIT_KEY_EMULATION_EMACS:
  975.         edit_init_menu_emacs ();    /* editmenu.c */
  976.         break;
  977.     }
  978.     edit_menubar = menubar_new (0, 0, COLS, EditMenuBar, N_menus);
  979.     }
  980.     add_widget (edit_dlg, wedit);
  981.  
  982.     if (!framed)
  983.     add_widget (edit_dlg, edit_menubar);
  984.  
  985.     add_widget (edit_dlg, edit_bar);
  986.     edit_move_display (wedit, line - 1);
  987.     edit_move_to_line (wedit, line - 1);
  988.  
  989.     run_dlg (edit_dlg);
  990.  
  991.     if (!framed)
  992.     edit_done_menu ();    /* editmenu.c */
  993.  
  994.     destroy_dlg (edit_dlg);
  995.  
  996.     return 1;
  997. }
  998.  
  999. static void edit_my_define (Dlg_head * h, int idx, char *text,
  1000.                 void (*fn) (WEdit *), WEdit * edit)
  1001. {
  1002.     define_label_data (h, (Widget *) edit, idx, text, (buttonbarfn) fn, edit);
  1003. }
  1004.  
  1005.  
  1006. void cmd_F1 (WEdit * edit)
  1007. {
  1008.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (1));
  1009. }
  1010.  
  1011. void cmd_F2 (WEdit * edit)
  1012. {
  1013.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (2));
  1014. }
  1015.  
  1016. void cmd_F3 (WEdit * edit)
  1017. {
  1018.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (3));
  1019. }
  1020.  
  1021. void cmd_F4 (WEdit * edit)
  1022. {
  1023.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (4));
  1024. }
  1025.  
  1026. void cmd_F5 (WEdit * edit)
  1027. {
  1028.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (5));
  1029. }
  1030.  
  1031. void cmd_F6 (WEdit * edit)
  1032. {
  1033.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (6));
  1034. }
  1035.  
  1036. void cmd_F7 (WEdit * edit)
  1037. {
  1038.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (7));
  1039. }
  1040.  
  1041. void cmd_F8 (WEdit * edit)
  1042. {
  1043.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (8));
  1044. }
  1045.  
  1046. void cmd_F9 (WEdit * edit)
  1047. {
  1048.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (9));
  1049. }
  1050.  
  1051. void cmd_F10 (WEdit * edit)
  1052. {
  1053.     send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (10));
  1054. }
  1055.  
  1056. void edit_labels (WEdit * edit)
  1057. {
  1058.     Dlg_head *h = edit->widget.parent;
  1059.  
  1060.     edit_my_define (h, 1, _("Help"), cmd_F1, edit);
  1061.     edit_my_define (h, 2, _("Save"), cmd_F2, edit);
  1062.     edit_my_define (h, 3, _("Mark"), cmd_F3, edit);
  1063.     edit_my_define (h, 4, _("Replac"), cmd_F4, edit);
  1064.     edit_my_define (h, 5, _("Copy"), cmd_F5, edit);
  1065.     edit_my_define (h, 6, _("Move"), cmd_F6, edit);
  1066.     edit_my_define (h, 7, _("Search"), cmd_F7, edit);
  1067.     edit_my_define (h, 8, _("Delete"), cmd_F8, edit);
  1068.     if (!edit->have_frame)
  1069.     edit_my_define (h, 9, _("PullDn"), edit_menu_cmd, edit);
  1070.     edit_my_define (h, 10, _("Quit"), cmd_F10, edit);
  1071.  
  1072.     redraw_labels (h, (Widget *) edit);
  1073. }
  1074.  
  1075.  
  1076. long get_key_state ()
  1077. {
  1078.     return (long) get_modifier ();
  1079. }
  1080.  
  1081. void edit_adjust_size (Dlg_head * h)
  1082. {
  1083.     WEdit *edit;
  1084.     WButtonBar *edit_bar;
  1085.  
  1086.     edit = (WEdit *) find_widget_type (h, (callback_fn) edit_callback);
  1087.     edit_bar = (WButtonBar *) edit->widget.parent->current->next->widget;
  1088.     widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS);
  1089.     widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS);
  1090.     widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS);
  1091.  
  1092. #ifdef RESIZABLE_MENUBAR
  1093.     menubar_arrange(edit_menubar);
  1094. #endif
  1095. }
  1096.  
  1097. void edit_update_screen (WEdit * e)
  1098. {
  1099.     edit_scroll_screen_over_cursor (e);
  1100.  
  1101.     edit_update_curs_col (e);
  1102.     edit_status (e);
  1103.  
  1104. /* pop all events for this window for internal handling */
  1105.  
  1106.     if (!is_idle ()) {
  1107.     e->force |= REDRAW_PAGE;
  1108.     return;
  1109.     }
  1110.     if (e->force & REDRAW_COMPLETELY)
  1111.     e->force |= REDRAW_PAGE;
  1112.     edit_render_keypress (e);
  1113. }
  1114.  
  1115. static int edit_callback (Dlg_head * h, WEdit * e, int msg, int par)
  1116. {
  1117.     switch (msg) {
  1118.     case WIDGET_INIT:
  1119.     e->force |= REDRAW_COMPLETELY;
  1120.     edit_labels (e);
  1121.     break;
  1122.     case WIDGET_DRAW:
  1123.     e->force |= REDRAW_COMPLETELY;
  1124.     e->num_widget_lines = LINES - 2;
  1125.     e->num_widget_columns = COLS;
  1126.     case WIDGET_FOCUS:
  1127.     edit_update_screen (e);
  1128.     return 1;
  1129.     case WIDGET_KEY:{
  1130.         int cmd, ch;
  1131.         if (edit_drop_hotkey_menu (e, par))        /* first check alt-f, alt-e, alt-s, etc for drop menus */
  1132.         return 1;
  1133.         if (!edit_translate_key (e, 0, par, get_key_state (), &cmd, &ch))
  1134.         return 0;
  1135.         edit_execute_key_command (e, cmd, ch);
  1136.         edit_update_screen (e);
  1137.     }
  1138.     return 1;
  1139.     case WIDGET_COMMAND:
  1140.     edit_execute_key_command (e, par, -1);
  1141.     edit_update_screen (e);
  1142.     return 1;
  1143.     case WIDGET_CURSOR:
  1144.     widget_move (&e->widget, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET, e->curs_col + e->start_col);
  1145.     return 1;
  1146.     }
  1147.     return default_proc (h, msg, par);
  1148. }
  1149.  
  1150. #endif
  1151.