Codepage messages related translated & other stuff...
[midnight-commander.git] / gtkedit / editwidget.c
blob7feb95d723440e5dae1fd39a11c5d4bcd4afe291
1 /* editor initialisation and callback handler.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
23 #include <config.h>
24 #include "edit.h"
26 #ifndef MIDNIGHT
27 #include <X11/Xmd.h> /* CARD32 */
28 #include <X11/Xatom.h>
29 #include "app_glob.c"
30 #include "coollocal.h"
31 #include "editcmddef.h"
32 #include "mousemark.h"
33 #endif
34 #if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
35 #include "mad.h"
36 #endif
38 #ifndef MIDNIGHT
39 #include "xdnd.h"
41 extern int EditExposeRedraw;
42 CWidget *wedit = 0;
44 void edit_destroy_callback (CWidget * w)
46 if (w) {
47 edit_clean (w->editor);
48 if (w->editor)
49 free (w->editor);
50 w->editor = NULL;
51 } else
52 /* NLS ? */
53 CError ("Trying to destroy non-existing editor widget.\n");
56 void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);
58 /* returns the position in the edit buffer of a window click */
59 long edit_get_click_pos (WEdit * edit, int x, int y)
61 long click;
62 /* (1) goto to left margin */
63 click = edit_bol (edit, edit->curs1);
65 /* (1) move up or down */
66 if (y > (edit->curs_row + 1))
67 click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0);
68 if (y < (edit->curs_row + 1))
69 click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);
71 /* (3) move right to x pos */
72 click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0);
73 return click;
76 void edit_translate_xy (int xs, int ys, int *x, int *y)
78 *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET;
79 *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;
82 extern int just_dropped_something;
84 void mouse_redraw (WEdit * edit, long click)
86 edit->force |= REDRAW_PAGE | REDRAW_LINE;
87 edit_update_curs_row (edit);
88 edit_update_curs_col (edit);
89 edit->prev_col = edit_get_col (edit);
90 edit_update_screen (edit);
91 edit->search_start = click;
94 static void xy (int x, int y, int *x_return, int *y_return)
96 edit_translate_xy (x, y, x_return, y_return);
99 static long cp (WEdit * edit, int x, int y)
101 return edit_get_click_pos (edit, x, y);
104 /* return 1 if not marked */
105 static int marks (WEdit * edit, long *start, long *end)
107 return eval_marks (edit, start, end);
110 int column_highlighting = 0;
112 static int erange (WEdit * edit, long start, long end, int click)
114 if (column_highlighting) {
115 int x;
116 x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click);
117 if ((x >= edit->column1 && x < edit->column2)
118 || (x > edit->column2 && x <= edit->column1))
119 return (start <= click && click < end);
120 else
121 return 0;
123 return (start <= click && click < end);
126 static void fin_mark (WEdit * edit)
128 if (edit->mark2 < 0)
129 edit_mark_cmd (edit, 0);
132 static void move_mark (WEdit * edit)
134 edit_mark_cmd (edit, 1);
135 edit_mark_cmd (edit, 0);
138 static void release_mark (WEdit * edit, XEvent * event)
140 if (edit->mark2 < 0)
141 edit_mark_cmd (edit, 0);
142 else
143 edit_mark_cmd (edit, 1);
144 if (edit->mark1 != edit->mark2 && event) {
145 edit_get_selection (edit);
146 XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), event->xbutton.time);
148 #ifdef GTK
149 else {
150 edit->widget->editable.has_selection = TRUE;
152 #endif
155 static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l)
157 char *t;
158 t = (char *) edit_get_block (edit, start_mark, end_mark, l);
159 if (strlen (t) < *l)
160 *type = DndRawData; /* if there are nulls in the data, send as raw */
161 else
162 *type = DndText; /* else send as text */
163 return t;
166 static void move (WEdit * edit, long click, int y)
168 edit_cursor_move (edit, click - edit->curs1);
171 static void dclick (WEdit * edit, XEvent * event)
173 edit_mark_cmd (edit, 1);
174 edit_right_word_move (edit, 1);
175 edit_mark_cmd (edit, 0);
176 edit_left_word_move (edit, 1);
177 release_mark (edit, event);
180 static void redraw (WEdit * edit, long click)
182 mouse_redraw (edit, click);
185 void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width);
187 /* strips out the first i chars and returns a null terminated string, result must be free'd */
188 char *filename_from_url (char *data, int size, int i)
190 char *p, *f;
191 int l;
192 for (p = data + i; (unsigned long) p - (unsigned long) data < size && *p && *p != '\n'; p++);
193 l = (unsigned long) p - (unsigned long) data - i;
194 f = malloc (l + 1);
195 memcpy (f, data + i, l);
196 f[l] = '\0';
197 return f;
200 static int insert_drop (WEdit * e, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action)
202 long start_mark = 0, end_mark = 0;
203 int x, y;
205 edit_translate_xy (xs, ys, &x, &y);
206 /* musn't be able to drop into a block, otherwise a single click will copy a block: */
207 if (eval_marks (e, &start_mark, &end_mark))
208 goto fine;
209 if (start_mark > e->curs1 || e->curs1 >= end_mark)
210 goto fine;
211 if (column_highlighting) {
212 if (!((x >= e->column1 && x < e->column2)
213 || (x > e->column2 && x <= e->column1)))
214 goto fine;
216 return 1;
217 fine:
218 if (from == e->widget->winid && action == CDndClass->XdndActionMove) {
219 edit_block_move_cmd (e);
220 edit_mark_cmd (e, 1);
221 return 0;
222 } else if (from == e->widget->winid) {
223 edit_block_copy_cmd (e);
224 return 0;
225 } else { /* data from another widget, or from another application */
226 edit_push_action (e, KEY_PRESS + e->start_display);
227 if (type == XInternAtom (CDisplay, "url/url", False)) {
228 if (!strncmp ((char *) data, "file:/", 6)) {
229 char *f;
230 edit_insert_file (e, f = filename_from_url ((char *) data, size, strlen ("file:")));
231 free (f);
232 } else {
233 while (size--)
234 edit_insert_ahead (e, data[size]);
236 } else {
237 if (column_highlighting) {
238 edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
239 } else {
240 while (size--)
241 edit_insert_ahead (e, data[size]);
245 CExpose (e->widget->ident);
246 return 0;
249 static char *mime_majors[2] =
250 {"text", 0};
252 struct mouse_funcs edit_mouse_funcs =
255 (void (*)(int, int, int *, int *)) xy,
256 (long (*)(void *, int, int)) cp,
257 (int (*)(void *, long *, long *)) marks,
258 (int (*)(void *, long, long, long)) erange,
259 (void (*)(void *)) fin_mark,
260 (void (*)(void *)) move_mark,
261 (void (*)(void *, XEvent *)) release_mark,
262 (char *(*)(void *, long, long, int *, int *)) get_block,
263 (void (*)(void *, long, int)) move,
265 (void (*)(void *, XEvent *)) dclick,
266 (void (*)(void *, long)) redraw,
267 (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) insert_drop,
268 (void (*)(void *)) edit_block_delete,
269 DndText,
270 mime_majors
273 static void render_book_marks (CWidget * w);
274 extern int option_editor_bg_normal;
275 void edit_tri_cursor (Window win);
277 /* starting_directory is for the filebrowser */
278 CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
279 int width, int height, const char *text, const char *filename,
280 const char *starting_directory, unsigned int options, unsigned long text_size)
282 static int made_directory = 0;
283 int extra_space_for_hscroll = 0;
284 CWidget *w;
285 WEdit *e;
287 CPushFont ("editor", 0);
288 #ifdef NEXT_LOOK
289 x += NEXT_SPACING;
290 if (options & EDITOR_HORIZ_SCROLL)
291 extra_space_for_hscroll = 21;
292 #else
293 if (options & EDITOR_HORIZ_SCROLL)
294 extra_space_for_hscroll = 8;
295 #endif
296 wedit = w = CSetupWidget (identifier, parent, x, y,
297 width + EDIT_FRAME_W, height + EDIT_FRAME_H, C_EDITOR_WIDGET,
298 ExposureMask | ButtonPressMask | ButtonReleaseMask | \
299 KeyPressMask | KeyReleaseMask | ButtonMotionMask | \
300 PropertyChangeMask | StructureNotifyMask | \
301 EnterWindowMask | LeaveWindowMask, color_palette (option_editor_bg_normal), 1);
303 xdnd_set_dnd_aware (CDndClass, w->winid, 0);
304 xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndText]);
306 edit_tri_cursor (w->winid);
307 w->options = options | WIDGET_TAKES_SELECTION;
309 w->destroy = edit_destroy_callback;
310 if (filename)
311 w->label = (char *) strdup (filename);
312 else
313 w->label = (char *) strdup ("");
315 if (!made_directory) {
316 mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
317 made_directory = 1;
319 e = w->editor = CMalloc (sizeof (WEdit));
320 w->funcs = mouse_funcs_new (w->editor, &edit_mouse_funcs);
322 if (!w->editor) {
323 /* Not essential to translate */
324 CError (_ ("Error initialising editor.\n"));
325 CPopFont ();
326 return 0;
328 w->editor->widget = w;
329 w->editor = edit_init (e, height / FONT_PIX_PER_LINE, width / FONT_MEAN_WIDTH, filename, text, starting_directory, text_size);
330 w->funcs->data = (void *) w->editor;
331 if (!w->editor) {
332 free (e);
333 CDestroyWidget (w->ident);
334 CPopFont ();
335 return 0;
337 e->macro_i = -1;
338 e->widget = w;
340 if (!(options & EDITOR_NO_SCROLL)) {
341 w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent,
342 x + width + EDIT_FRAME_W + WIDGET_SPACING, y, height + EDIT_FRAME_H,
343 #ifdef NEXT_LOOK
344 AUTO_WIDTH,
345 #else
347 #endif
348 0, 0);
349 CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_editor);
350 w->vert_scrollbar->scroll_bar_extra_render = render_book_marks;
352 set_hint_pos (x + width + EDIT_FRAME_W + WIDGET_SPACING, y + height + EDIT_FRAME_H + WIDGET_SPACING + extra_space_for_hscroll);
353 if (extra_space_for_hscroll) {
354 w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent,
355 x, y + height + EDIT_FRAME_H, width + EDIT_FRAME_W,
356 #ifdef NEXT_LOOK
357 AUTO_HEIGHT,
358 #else
360 #endif
361 0, 0);
362 CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor);
364 CGetHintPos (0, &y);
365 if (!(options & EDITOR_NO_TEXT)) {
366 CPushFont ("widget", 0);
367 #ifdef NEXT_LOOK
368 CDrawStatus (catstrs (identifier, ".text", 0), parent, x, y + WIDGET_SPACING + NEXT_SPACING, width + EDIT_FRAME_W, e->filename);
369 #else
370 CDrawStatus (catstrs (identifier, ".text", 0), parent, x, y, width + EDIT_FRAME_W, e->filename);
371 #endif
372 CPopFont ();
374 CPopFont ();
375 return w;
378 static void render_book_marks (CWidget * w)
380 struct _book_mark *p;
381 WEdit *edit;
382 int l;
383 char i[32];
384 if (!w)
385 return;
386 strcpy (i, CIdentOf (w));
387 *(strstr (i, ".vsc")) = '\0';
388 edit = (CIdent (i))->editor;
389 if (!edit->book_mark)
390 return;
391 l = CHeightOf (w) - 10 * CWidthOf (w) / 3 - 10;
392 for (p = edit->book_mark; p->next; p = p->next);
393 for (; p->prev; p = p->prev) {
394 int y = (CWidthOf (w) + 2 * CWidthOf (w) / 3 + 4) + (int) ((double) l * p->line / edit->total_lines);
395 CSetColor (color_palette (((p->c & 0xFF00) >> 8) ? ((p->c & 0xFF00) >> 8) : (p->c & 0xFF)));
396 CLine (CWindowOf (w), 5, y, CWidthOf (w) - 6, y);
400 void update_scroll_bars (WEdit * e)
402 int i, x1, x2;
403 CWidget *scroll;
404 CPushFont ("editor", 0);
405 scroll = e->widget->vert_scrollbar;
406 if (scroll) {
407 i = e->total_lines - e->start_line + 1;
408 if (i > e->num_widget_lines)
409 i = e->num_widget_lines;
410 if (e->total_lines) {
411 x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
412 x2 = (double) 65535.0 *i / (e->total_lines + 1);
413 } else {
414 x1 = 0;
415 x2 = 65535;
417 if (x1 != scroll->firstline || x2 != scroll->numlines) {
418 scroll->firstline = x1;
419 scroll->numlines = x2;
420 EditExposeRedraw = 1;
421 render_scrollbar (scroll);
422 EditExposeRedraw = 0;
425 scroll = e->widget->hori_scrollbar;
426 if (scroll) {
427 i = e->max_column - (-e->start_col) + 1;
428 if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
429 i = e->num_widget_columns * FONT_MEAN_WIDTH;
430 x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
431 x2 = (double) 65535.0 *i / (e->max_column + 1);
432 if (x1 != scroll->firstline || x2 != scroll->numlines) {
433 scroll->firstline = x1;
434 scroll->numlines = x2;
435 EditExposeRedraw = 1;
436 render_scrollbar (scroll);
437 EditExposeRedraw = 0;
440 CPopFont ();
443 void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click)
445 CPushFont ("editor", 0);
446 edit_update_curs_row (edit);
447 edit_update_curs_col (edit);
448 if (event->type != MotionNotify) {
449 edit_push_action (edit, KEY_PRESS + edit->start_display);
450 if (edit->mark2 == -1)
451 edit_push_action (edit, MARK_1 + edit->mark1); /* mark1 must be following the cursor */
453 if (event->type == ButtonPress) {
454 edit->highlight = 0;
455 edit->found_len = 0;
457 mouse_mark (
458 event,
459 double_click,
460 edit->widget->funcs
462 CPopFont ();
465 void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
467 int i, start_line;
468 WEdit *e;
469 e = editor->editor;
470 if (!e)
471 return;
472 if (!e->widget->vert_scrollbar)
473 return;
474 CPushFont ("editor", 0);
475 start_line = e->start_line;
476 if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
477 edit_move_display (e, (double) scrollbar->firstline * e->total_lines / 65535.0 + 1);
478 } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
479 switch (whichscrbutton) {
480 case 1:
481 edit_move_display (e, e->start_line - e->num_widget_lines + 1);
482 break;
483 case 2:
484 edit_move_display (e, e->start_line - 1);
485 break;
486 case 5:
487 edit_move_display (e, e->start_line + 1);
488 break;
489 case 4:
490 edit_move_display (e, e->start_line + e->num_widget_lines - 1);
491 break;
494 if (e->total_lines)
495 scrollbar->firstline = (double) 65535.0 *e->start_line / (e->total_lines + 1);
496 else
497 scrollbar->firstline = 0;
498 i = e->total_lines - e->start_line + 1;
499 if (i > e->num_widget_lines)
500 i = e->num_widget_lines;
501 if (e->total_lines)
502 scrollbar->numlines = (double) 65535.0 *i / (e->total_lines + 1);
503 else
504 scrollbar->numlines = 65535;
505 if (start_line != e->start_line) {
506 e->force |= REDRAW_PAGE | REDRAW_LINE;
507 set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
508 if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0)) {
509 CPopFont ();
510 return;
513 if (e->force) {
514 edit_render_keypress (e);
515 edit_status (e);
517 CPopFont ();
520 void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
522 int i, start_col;
523 WEdit *e;
524 e = editor->editor;
525 if (!e)
526 return;
527 if (!e->widget->hori_scrollbar)
528 return;
529 CPushFont ("editor", 0);
530 start_col = (-e->start_col);
531 if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
532 e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1;
533 e->start_col -= e->start_col % FONT_MEAN_WIDTH;
534 if (e->start_col < 0)
535 e->start_col = 0;
536 e->start_col = (-e->start_col);
537 } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
538 switch (whichscrbutton) {
539 case 1:
540 edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
541 break;
542 case 2:
543 edit_scroll_left (e, FONT_MEAN_WIDTH);
544 break;
545 case 5:
546 edit_scroll_right (e, FONT_MEAN_WIDTH);
547 break;
548 case 4:
549 edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
550 break;
553 scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
554 i = e->max_column - (-e->start_col) + 1;
555 if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
556 i = e->num_widget_columns * FONT_MEAN_WIDTH;
557 scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1);
558 if (start_col != (-e->start_col)) {
559 e->force |= REDRAW_PAGE | REDRAW_LINE;
560 set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
561 if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0)) {
562 CPopFont ();
563 return;
566 if (e->force) {
567 edit_render_keypress (e);
568 edit_status (e);
570 CPopFont ();
574 This section comes from rxvt-2.21b1/src/screen.c by
575 Robert Nation <nation@rocket.sanders.lockheed.com> &
576 mods by mj olesen <olesen@me.QueensU.CA>
578 Changes made for cooledit
580 void selection_send (XSelectionRequestEvent * rq)
582 XEvent ev;
583 static Atom xa_targets = None;
584 if (xa_targets == None)
585 xa_targets = XInternAtom (CDisplay, "TARGETS", False);
587 ev.xselection.type = SelectionNotify;
588 ev.xselection.property = None;
589 ev.xselection.display = rq->display;
590 ev.xselection.requestor = rq->requestor;
591 ev.xselection.selection = rq->selection;
592 ev.xselection.target = rq->target;
593 ev.xselection.time = rq->time;
595 if (rq->target == xa_targets) {
597 * On some systems, the Atom typedef is 64 bits wide.
598 * We need to have a typedef that is exactly 32 bits wide,
599 * because a format of 64 is not allowed by the X11 protocol.
601 * XXX: yes, but Xlib requires that you pass it 64 bits for 32bit
602 * quantities on 64 bit archs.
604 /* typedef CARD32 Atom32; */
606 Atom target_list[2];
608 target_list[0] = xa_targets;
609 target_list[1] = XA_STRING;
611 XChangeProperty (CDisplay, rq->requestor, rq->property,
612 xa_targets, 8 * sizeof (target_list[0]), PropModeReplace,
613 (unsigned char *) target_list,
614 sizeof (target_list) / sizeof (target_list[0]));
615 ev.xselection.property = rq->property;
616 } else if (rq->target == XA_STRING) {
617 XChangeProperty (CDisplay, rq->requestor, rq->property,
618 XA_STRING, 8, PropModeReplace,
619 selection.text, selection.len);
620 ev.xselection.property = rq->property;
622 XSendEvent (CDisplay, rq->requestor, False, 0, &ev);
625 /*{{{ paste selection */
628 * Respond to a notification that a primary selection has been sent
630 void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete)
632 long nread;
633 unsigned long bytes_after;
635 if (prop == None)
636 return;
638 nread = 0;
639 do {
640 unsigned char *s;
641 Atom actual_type;
642 int actual_fmt, i;
643 unsigned long nitems;
645 if (XGetWindowProperty (CDisplay, win, prop,
646 nread / 4, 65536, delete,
647 AnyPropertyType, &actual_type, &actual_fmt,
648 &nitems, &bytes_after,
649 &s) != Success) {
650 XFree (s);
651 return;
653 nread += nitems;
654 for (i = 0; i < nitems; i++)
655 (*insert) (data, s[i]);
656 XFree (s);
657 } while (bytes_after);
660 void selection_paste (WEdit * edit, Window win, unsigned prop, int delete)
662 long c;
663 c = edit->curs1;
664 paste_prop ((void *) edit,
665 (void (*)(void *, int)) edit_insert,
666 win, prop, delete);
667 edit_cursor_move (edit, c - edit->curs1);
668 edit->force |= REDRAW_COMPLETELY | REDRAW_LINE;
671 /*}}} */
673 void selection_clear (void)
675 selection.text = 0;
676 selection.len = 0;
679 void edit_update_screen (WEdit * e)
681 if (!e)
682 return;
683 if (!e->force)
684 return;
686 CPushFont ("editor", 0);
687 edit_scroll_screen_over_cursor (e);
688 edit_update_curs_row (e);
689 edit_update_curs_col (e);
690 update_scroll_bars (e);
691 edit_status (e);
693 if (e->force & REDRAW_COMPLETELY)
694 e->force |= REDRAW_PAGE;
696 /* pop all events for this window for internal handling */
697 if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) {
698 edit_render_keypress (e);
699 } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0)
700 || CKeyPending ()) {
701 e->force |= REDRAW_PAGE;
702 CPopFont ();
703 return;
704 } else {
705 edit_render_keypress (e);
707 CPopFont ();
710 extern int space_width;
712 #ifdef HAVE_DND
713 #define free_data if (data) {free(data);data=0;}
715 /* handles drag and drop */
716 void handle_client_message (CWidget * w, XEvent * xevent)
718 int data_type;
719 unsigned char *data = 0;
720 unsigned long size;
721 int xs, ys;
722 long start_line;
723 int x, y, r, deleted = 0;
724 long click;
725 unsigned int state;
726 long start_mark = 0, end_mark = 0;
727 WEdit *e = w->editor;
729 /* see just below for a comment on what this is for: */
730 if (CIsDropAcknowledge (xevent, &state) != DndNotDnd) {
731 if (!(state & Button1Mask) && just_dropped_something) {
732 edit_push_action (e, KEY_PRESS + e->start_display);
733 edit_block_delete_cmd (e);
735 return;
737 data_type = CGetDrop (xevent, &data, &size, &xs, &ys);
739 if (data_type == DndNotDnd || xs < 0 || ys < 0 || xs >= CWidthOf (w) || ys >= CHeightOf (w)) {
740 free_data;
741 return;
743 edit_translate_xy (xs, ys, &x, &y);
744 click = edit_get_click_pos (e, x, y);
746 r = eval_marks (e, &start_mark, &end_mark);
747 /* musn't be able to drop into a block, otherwise a single click will copy a block: */
748 if (r)
749 goto fine;
750 if (start_mark > click || click >= end_mark)
751 goto fine;
752 if (column_highlighting) {
753 if (!((x >= e->column1 && x < e->column2)
754 || (x > e->column2 && x <= e->column1)))
755 goto fine;
757 free_data;
758 return;
759 fine:
760 edit_push_action (e, KEY_PRESS + e->start_display);
762 /* drops to the same window moving to the left: */
763 start_line = e->start_line;
764 if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
765 if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) {
766 edit_block_delete_cmd (e);
767 deleted = 1;
769 edit_update_curs_row (e);
770 edit_move_display (e, start_line);
771 click = edit_get_click_pos (e, x, y); /* click pos changes with edit_block_delete_cmd() */
772 edit_cursor_move (e, click - e->curs1);
773 if (data_type == DndFile) {
774 edit_insert_file (e, (char *) data);
775 } else if (data_type != DndFiles) {
776 if (dnd_null_term_type (data_type)) {
777 int len;
778 len = strlen ((char *) data);
779 size = min (len, size);
781 if (column_highlighting) {
782 edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
783 } else {
784 while (size--)
785 edit_insert_ahead (e, data[size]);
787 } else {
788 while (size--)
789 edit_insert_ahead (e, data[size] ? data[size] : '\n');
792 /* drops to the same window moving to the right: */
793 if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
794 if (column_highlighting && !deleted)
795 edit_block_delete_cmd (e);
797 /* The drop has now been successfully recieved. We can now send an acknowledge
798 event back to the window that send the data. When this window recieves
799 the acknowledge event, the app can decide whether or not to delete the data.
800 This allows text to be safely moved betweem text windows without the
801 risk of data being lost. In our case, drag with button1 is a copy
802 drag, while drag with any other button is a move drag (i.e. the sending
803 application must delete its selection after recieving an acknowledge
804 event). We must not, however, send an acknowledge signal if a filelist
805 (for example) was passed to us, since the sender might take this to
806 mean that all those files can be deleted! The two types we can acknowledge
807 are: */
808 if (xevent->xclient.data.l[2] != xevent->xclient.window) /* drops to the same window */
809 if (data_type == DndText || data_type == DndRawData)
810 CDropAcknowledge (xevent);
811 e->force |= REDRAW_COMPLETELY | REDRAW_LINE;
812 free_data;
814 #endif
816 int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
818 WEdit *e = w->editor;
819 int r = 0;
820 static int old_tab_spacing = -1;
822 if (!e)
823 return 0;
825 if (old_tab_spacing != option_tab_spacing)
826 e->force |= REDRAW_COMPLETELY + REDRAW_LINE;
827 old_tab_spacing = option_tab_spacing;
829 if (xevent->type == KeyPress) {
830 if (xevent->xkey.keycode == 0x31 && xevent->xkey.state == 0xD) {
831 CSetColor (color_palette (18));
832 CRectangle (w->winid, 0, 0, w->width, w->height);
835 switch (xevent->type) {
836 case SelectionNotify:
837 selection_paste (e, xevent->xselection.requestor, xevent->xselection.property, True);
838 r = 1;
839 break;
840 case SelectionRequest:
841 selection_send (&(xevent->xselectionrequest));
842 return 1;
843 /* case SelectionClear: ---> This is handled by coolnext.c: CNextEvent() */
844 #ifdef HAVE_DND
845 case ClientMessage:
846 handle_client_message (w, xevent);
847 r = 1;
848 #endif
849 break;
850 case ButtonPress:
851 CFocus (w);
852 edit_render_tidbits (w);
853 case ButtonRelease:
854 if (xevent->xbutton.state & ControlMask) {
855 if (!column_highlighting)
856 edit_push_action (e, COLUMN_OFF);
857 column_highlighting = 1;
858 } else {
859 if (column_highlighting)
860 edit_push_action (e, COLUMN_ON);
861 column_highlighting = 0;
863 case MotionNotify:
864 if (!xevent->xmotion.state && xevent->type == MotionNotify)
865 return 0;
866 resolve_button (xevent, cwevent);
867 if ((cwevent->button == Button4 || cwevent->button == Button5)
868 && (xevent->type == ButtonRelease)) {
869 /* ahaack: wheel mouse mapped as button 4 and 5 */
870 r = edit_execute_key_command (e, (cwevent->button == Button5) ? CK_Page_Down : CK_Page_Up, -1);
871 break;
873 edit_mouse_mark (e, xevent, cwevent->double_click);
874 break;
875 case Expose:
876 edit_render_expose (e, &(xevent->xexpose));
877 return 1;
878 case FocusIn:
879 CSetCursorColor (e->overwrite ? color_palette (24) : color_palette (19));
880 case FocusOut:
881 edit_render_tidbits (w);
882 e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
883 edit_render_keypress (e);
884 return 1;
885 break;
886 case KeyRelease:
887 #if 0
888 if (column_highlighting) {
889 column_highlighting = 0;
890 e->force = REDRAW_COMPLETELY | REDRAW_LINE;
891 edit_mark_cmd (e, 1);
893 #endif
894 break;
895 case KeyPress:
896 cwevent->ident = w->ident;
897 if (!cwevent->command && cwevent->insert < 0) { /* no translation */
898 if ((cwevent->key == XK_r || cwevent->key == XK_R) && (cwevent->state & ControlMask)) {
899 cwevent->command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
900 } else {
901 cwevent->command = CKeySymMod (xevent);
902 if (cwevent->command > 0)
903 cwevent->command = CK_Macro (cwevent->command);
904 else
905 break;
908 r = edit_execute_key_command (e, cwevent->command, cwevent->insert);
909 if (r)
910 edit_update_screen (e);
911 return r;
912 break;
913 case EditorCommand:
914 cwevent->ident = w->ident;
915 cwevent->command = xevent->xkey.keycode;
916 r = cwevent->handled = edit_execute_key_command (e, xevent->xkey.keycode, -1);
917 if (r)
918 edit_update_screen (e);
919 return r;
920 default:
921 return 0;
923 edit_update_screen (e);
924 return r;
927 #else
929 WEdit *wedit;
930 WButtonBar *edit_bar;
931 Dlg_head *edit_dlg;
932 WMenu *edit_menubar;
934 int column_highlighting = 0;
936 static int edit_callback (Dlg_head * h, WEdit * edit, int msg, int par);
938 static int edit_mode_callback (struct Dlg_head *h, int id, int msg)
940 return 0;
943 int edit_event (WEdit * edit, Gpm_Event * event, int *result)
945 *result = MOU_NORMAL;
946 edit_update_curs_row (edit);
947 edit_update_curs_col (edit);
948 if (event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) {
949 if (event->y > 1 && event->x > 0
950 && event->x <= edit->num_widget_columns
951 && event->y <= edit->num_widget_lines + 1) {
952 if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG))
953 return 1; /* a lone up mustn't do anything */
954 if (event->type & (GPM_DOWN | GPM_UP))
955 edit_push_key_press (edit);
956 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
957 if (--event->y > (edit->curs_row + 1))
958 edit_cursor_move (edit,
959 edit_move_forward (edit, edit->curs1, event->y - (edit->curs_row + 1), 0)
960 - edit->curs1);
961 if (event->y < (edit->curs_row + 1))
962 edit_cursor_move (edit,
963 +edit_move_backward (edit, edit->curs1, (edit->curs_row + 1) - event->y)
964 - edit->curs1);
965 edit_cursor_move (edit, (int) edit_move_forward3 (edit, edit->curs1,
966 event->x - edit->start_col - 1, 0) - edit->curs1);
967 edit->prev_col = edit_get_col (edit);
968 if (event->type & GPM_DOWN) {
969 edit_mark_cmd (edit, 1); /* reset */
970 edit->highlight = 0;
972 if (!(event->type & GPM_DRAG))
973 edit_mark_cmd (edit, 0);
974 edit->force |= REDRAW_COMPLETELY;
975 edit_update_curs_row (edit);
976 edit_update_curs_col (edit);
977 edit_update_screen (edit);
978 return 1;
981 return 0;
986 int menubar_event (Gpm_Event * event, WMenu * menubar); /* menu.c */
988 int edit_mouse_event (Gpm_Event * event, void *x)
990 int result;
991 if (edit_event ((WEdit *) x, event, &result))
992 return result;
993 else
994 return menubar_event (event, edit_menubar);
997 extern Menu EditMenuBar[5];
999 int edit (const char *_file, int line)
1001 static int made_directory = 0;
1002 int framed = 0;
1003 int midnight_colors[4];
1004 char *text = 0;
1006 if (option_backup_ext_int != -1) {
1007 option_backup_ext = malloc (sizeof (int) + 1);
1008 option_backup_ext[sizeof (int)] = '\0';
1009 memcpy (option_backup_ext, (char *) &option_backup_ext_int, sizeof (int));
1011 if (!made_directory) {
1012 mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
1013 made_directory = 1;
1015 if (_file) {
1016 if (!(*_file)) {
1017 _file = 0;
1018 text = "";
1020 } else
1021 text = "";
1023 if (!(wedit = edit_init (NULL, LINES - 2, COLS, _file, text, "", 0))) {
1024 message (1, _ (" Error "), get_error_msg (""));
1025 return 0;
1027 wedit->macro_i = -1;
1029 /* Create a new dialog and add it widgets to it */
1030 edit_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
1031 edit_mode_callback, "[Internal File Editor]",
1032 "edit",
1033 DLG_NONE);
1035 edit_dlg->raw = 1; /*so that tab = '\t' key works */
1037 init_widget (&(wedit->widget), 0, 0, LINES - 1, COLS,
1038 (callback_fn) edit_callback,
1039 (destroy_fn) edit_clean,
1040 (mouse_h) edit_mouse_event, 0);
1042 widget_want_cursor (wedit->widget, 1);
1044 edit_bar = buttonbar_new (1);
1046 if (!framed) {
1047 switch (edit_key_emulation) {
1048 case EDIT_KEY_EMULATION_NORMAL:
1049 edit_init_menu_normal (); /* editmenu.c */
1050 break;
1051 case EDIT_KEY_EMULATION_EMACS:
1052 edit_init_menu_emacs (); /* editmenu.c */
1053 break;
1055 edit_menubar = menubar_new (0, 0, COLS, EditMenuBar, N_menus);
1057 add_widget (edit_dlg, wedit);
1059 if (!framed)
1060 add_widget (edit_dlg, edit_menubar);
1062 add_widget (edit_dlg, edit_bar);
1063 edit_move_display (wedit, line - 1);
1064 edit_move_to_line (wedit, line - 1);
1066 run_dlg (edit_dlg);
1068 if (!framed)
1069 edit_done_menu (); /* editmenu.c */
1071 destroy_dlg (edit_dlg);
1073 return 1;
1076 static void edit_my_define (Dlg_head * h, int idx, char *text,
1077 void (*fn) (WEdit *), WEdit * edit)
1079 define_label_data (h, (Widget *) edit, idx, text, (buttonbarfn) fn, edit);
1083 void cmd_F1 (WEdit * edit)
1085 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (1));
1088 void cmd_F2 (WEdit * edit)
1090 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (2));
1093 void cmd_F3 (WEdit * edit)
1095 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (3));
1098 void cmd_F4 (WEdit * edit)
1100 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (4));
1103 void cmd_F5 (WEdit * edit)
1105 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (5));
1108 void cmd_F6 (WEdit * edit)
1110 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (6));
1113 void cmd_F7 (WEdit * edit)
1115 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (7));
1118 void cmd_F8 (WEdit * edit)
1120 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (8));
1123 void cmd_F9 (WEdit * edit)
1125 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (9));
1128 void cmd_F10 (WEdit * edit)
1130 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (10));
1133 void edit_labels (WEdit * edit)
1135 Dlg_head *h = edit->widget.parent;
1137 edit_my_define (h, 1, _ ("Help"), cmd_F1, edit);
1138 edit_my_define (h, 2, _ ("Save"), cmd_F2, edit);
1139 edit_my_define (h, 3, _ ("Mark"), cmd_F3, edit);
1140 edit_my_define (h, 4, _ ("Replac"), cmd_F4, edit);
1141 edit_my_define (h, 5, _ ("Copy"), cmd_F5, edit);
1142 edit_my_define (h, 6, _ ("Move"), cmd_F6, edit);
1143 edit_my_define (h, 7, _ ("Search"), cmd_F7, edit);
1144 edit_my_define (h, 8, _ ("Delete"), cmd_F8, edit);
1145 if (!edit->have_frame)
1146 edit_my_define (h, 9, _ ("PullDn"), edit_menu_cmd, edit);
1147 edit_my_define (h, 10, _ ("Quit"), cmd_F10, edit);
1149 redraw_labels (h, (Widget *) edit);
1153 long get_key_state ()
1155 return (long) get_modifier ();
1158 void edit_adjust_size (Dlg_head * h)
1160 WEdit *edit;
1161 WButtonBar *edit_bar;
1163 edit = (WEdit *) find_widget_type (h, (callback_fn) edit_callback);
1164 edit_bar = (WButtonBar *) edit->widget.parent->current->next->widget;
1165 widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS);
1166 widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS);
1167 widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS);
1169 #ifdef RESIZABLE_MENUBAR
1170 menubar_arrange (edit_menubar);
1171 #endif
1174 void edit_update_screen (WEdit * e)
1176 edit_scroll_screen_over_cursor (e);
1178 edit_update_curs_col (e);
1179 edit_status (e);
1181 /* pop all events for this window for internal handling */
1183 if (!is_idle ()) {
1184 e->force |= REDRAW_PAGE;
1185 return;
1187 if (e->force & REDRAW_COMPLETELY)
1188 e->force |= REDRAW_PAGE;
1189 edit_render_keypress (e);
1192 static int edit_callback (Dlg_head * h, WEdit * e, int msg, int par)
1194 switch (msg) {
1195 case WIDGET_INIT:
1196 e->force |= REDRAW_COMPLETELY;
1197 edit_labels (e);
1198 break;
1199 case WIDGET_DRAW:
1200 e->force |= REDRAW_COMPLETELY;
1201 e->num_widget_lines = LINES - 2;
1202 e->num_widget_columns = COLS;
1203 case WIDGET_FOCUS:
1204 edit_update_screen (e);
1205 return 1;
1206 case WIDGET_KEY:{
1207 int cmd, ch;
1208 if (edit_drop_hotkey_menu (e, par)) /* first check alt-f, alt-e, alt-s, etc for drop menus */
1209 return 1;
1210 if (!edit_translate_key (e, 0, par, get_key_state (), &cmd, &ch))
1211 return 0;
1212 edit_execute_key_command (e, cmd, ch);
1213 edit_update_screen (e);
1215 return 1;
1216 case WIDGET_COMMAND:
1217 edit_execute_key_command (e, par, -1);
1218 edit_update_screen (e);
1219 return 1;
1220 case WIDGET_CURSOR:
1221 widget_move (&e->widget, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET, e->curs_col + e->start_col);
1222 return 1;
1224 return default_proc (h, msg, par);
1227 #endif