ru.po: Heavily updated translation
[midnight-commander.git] / gtkedit / editwidget.c
bloba02f7d77d0f80214d35e10d34ae287f3cc9fd4e9
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
40 extern int EditExposeRedraw;
41 CWidget *wedit = 0;
43 void edit_destroy_callback (CWidget * w)
45 if (w) {
46 edit_clean (w->editor);
47 if (w->editor)
48 free (w->editor);
49 w->editor = NULL;
50 } else
51 /* NLS ? */
52 CError ("Trying to destroy non-existing editor widget.\n");
55 void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);
57 /* returns the position in the edit buffer of a window click */
58 long edit_get_click_pos (WEdit * edit, int x, int y)
60 long click;
61 /* (1) goto to left margin */
62 click = edit_bol (edit, edit->curs1);
64 /* (1) move up or down */
65 if (y > (edit->curs_row + 1))
66 click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0);
67 if (y < (edit->curs_row + 1))
68 click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);
70 /* (3) move right to x pos */
71 click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0);
72 return click;
75 void edit_translate_xy (int xs, int ys, int *x, int *y)
77 *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET;
78 *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;
81 extern int just_dropped_something;
83 void mouse_redraw (WEdit * edit, long click)
85 edit->force |= REDRAW_PAGE | REDRAW_LINE;
86 edit_update_curs_row (edit);
87 edit_update_curs_col (edit);
88 edit->prev_col = edit_get_col (edit);
89 edit_update_screen (edit);
90 edit->search_start = click;
93 static void xy (int x, int y, int *x_return, int *y_return)
95 edit_translate_xy (x, y, x_return, y_return);
98 static long cp (WEdit *edit, int x, int y)
100 return edit_get_click_pos (edit, x, y);
103 /* return 1 if not marked */
104 static int marks (WEdit * edit, long *start, long *end)
106 return eval_marks (edit, start, end);
109 int column_highlighting = 0;
111 static int erange (WEdit * edit, long start, long end, int click)
113 if (column_highlighting) {
114 int x;
115 x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click);
116 if ((x >= edit->column1 && x < edit->column2)
117 || (x > edit->column2 && x <= edit->column1))
118 return (start <= click && click < end);
119 else
120 return 0;
122 return (start <= click && click < end);
125 static void fin_mark (WEdit *edit)
127 if (edit->mark2 < 0)
128 edit_mark_cmd (edit, 0);
131 static void move_mark (WEdit *edit)
133 edit_mark_cmd (edit, 1);
134 edit_mark_cmd (edit, 0);
137 static void release_mark (WEdit * edit, XEvent * event)
139 if (edit->mark2 < 0)
140 edit_mark_cmd (edit, 0);
141 else
142 edit_mark_cmd (edit, 1);
143 if (edit->mark1 != edit->mark2 && event) {
144 edit_get_selection (edit);
145 XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), event->xbutton.time);
147 #ifdef GTK
148 else {
149 edit->widget->editable.has_selection = TRUE;
151 #endif
154 static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l)
156 char *t;
157 t = (char *) edit_get_block (edit, start_mark, end_mark, l);
158 if (strlen (t) < *l)
159 *type = DndRawData; /* if there are nulls in the data, send as raw */
160 else
161 *type = DndText; /* else send as text */
162 return t;
165 static void move (WEdit *edit, long click, int y)
167 edit_cursor_move (edit, click - edit->curs1);
170 static void dclick (WEdit *edit, XEvent *event)
172 edit_mark_cmd (edit, 1);
173 edit_right_word_move (edit, 1);
174 edit_mark_cmd (edit, 0);
175 edit_left_word_move (edit, 1);
176 release_mark (edit, event);
179 static void redraw (WEdit *edit, long click)
181 mouse_redraw (edit, click);
184 void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width);
186 /* strips out the first i chars and returns a null terminated string, result must be free'd */
187 char *filename_from_url (char *data, int size, int i)
189 char *p, *f;
190 int l;
191 for (p = data + i; (unsigned long) p - (unsigned long) data < size && *p && *p != '\n'; p++);
192 l = (unsigned long) p - (unsigned long) data - i;
193 f = malloc (l + 1);
194 memcpy (f, data + i, l);
195 f[l] = '\0';
196 return f;
199 static int insert_drop (WEdit * e, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action)
201 long start_mark = 0, end_mark = 0;
202 int x, y;
204 edit_translate_xy (xs, ys, &x, &y);
205 /* musn't be able to drop into a block, otherwise a single click will copy a block: */
206 if (eval_marks (e, &start_mark, &end_mark))
207 goto fine;
208 if (start_mark > e->curs1 || e->curs1 >= end_mark)
209 goto fine;
210 if (column_highlighting) {
211 if (!((x >= e->column1 && x < e->column2)
212 || (x > e->column2 && x <= e->column1)))
213 goto fine;
215 return 1;
216 fine:
217 if (from == e->widget->winid && action == CDndClass->XdndActionMove) {
218 edit_block_move_cmd (e);
219 edit_mark_cmd (e, 1);
220 return 0;
221 } else if (from == e->widget->winid) {
222 edit_block_copy_cmd (e);
223 return 0;
224 } else { /* data from another widget, or from another application */
225 edit_push_action (e, KEY_PRESS + e->start_display);
226 if (type == XInternAtom (CDisplay, "url/url", False)) {
227 if (!strncmp ((char *) data, "file:/", 6)) {
228 char *f;
229 edit_insert_file (e, f = filename_from_url ((char *) data, size, strlen ("file:")));
230 free (f);
231 } else {
232 while (size--)
233 edit_insert_ahead (e, data[size]);
235 } else {
236 if (column_highlighting) {
237 edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
238 } else {
239 while (size--)
240 edit_insert_ahead (e, data[size]);
244 CExpose (e->widget->ident);
245 return 0;
248 static char *mime_majors[2] =
249 {"text", 0};
251 struct mouse_funcs edit_mouse_funcs =
254 (void (*)(int, int, int *, int *)) xy,
255 (long (*)(void *, int, int)) cp,
256 (int (*)(void *, long *, long *)) marks,
257 (int (*)(void *, long, long, long)) erange,
258 (void (*)(void *)) fin_mark,
259 (void (*)(void *)) move_mark,
260 (void (*)(void *, XEvent *)) release_mark,
261 (char *(*)(void *, long, long, int *, int *)) get_block,
262 (void (*)(void *, long, int)) move,
264 (void (*)(void *, XEvent *)) dclick,
265 (void (*)(void *, long)) redraw,
266 (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) insert_drop,
267 (void (*)(void *)) edit_block_delete,
268 DndText,
269 mime_majors
272 static void render_book_marks (CWidget *w);
273 extern int option_editor_bg_normal;
274 void edit_tri_cursor (Window win);
276 /* starting_directory is for the filebrowser */
277 CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
278 int width, int height, const char *text, const char *filename,
279 const char *starting_directory, unsigned int options, unsigned long text_size)
281 static int made_directory = 0;
282 int extra_space_for_hscroll = 0;
283 CWidget *w;
284 WEdit *e;
286 if (options & EDITOR_HORIZ_SCROLL)
287 extra_space_for_hscroll = 8;
289 wedit = w = CSetupWidget (identifier, parent, x, y,
290 width + EDIT_FRAME_W, height + EDIT_FRAME_H, C_EDITOR_WIDGET,
291 ExposureMask | ButtonPressMask | ButtonReleaseMask | \
292 KeyPressMask | KeyReleaseMask | ButtonMotionMask | \
293 PropertyChangeMask | StructureNotifyMask | \
294 EnterWindowMask | LeaveWindowMask, color_palette (option_editor_bg_normal), 1);
296 xdnd_set_dnd_aware (CDndClass, w->winid, 0);
297 xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndText]);
299 edit_tri_cursor (w->winid);
300 w->options = options | WIDGET_TAKES_SELECTION;
302 w->destroy = edit_destroy_callback;
303 if (filename)
304 w->label = (char *) strdup (filename);
305 else
306 w->label = (char *) strdup ("");
308 if (!made_directory) {
309 mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
310 made_directory = 1;
312 e = w->editor = CMalloc (sizeof (WEdit));
313 w->funcs = mouse_funcs_new (w->editor, &edit_mouse_funcs);
315 if (!w->editor) {
316 /* Not essential to translate */
317 CError (_ ("Error initialising editor.\n"));
318 return 0;
320 w->editor->widget = w;
321 w->editor = edit_init (e, height / FONT_PIX_PER_LINE, width / FONT_MEAN_WIDTH, filename, text, starting_directory, text_size);
322 w->funcs->data = (void *) w->editor;
323 if (!w->editor) {
324 free (e);
325 CDestroyWidget (w->ident);
326 return 0;
328 e->macro_i = -1;
329 e->widget = w;
331 set_hint_pos (x + width + EDIT_FRAME_W + WIDGET_SPACING, y + height + EDIT_FRAME_H + WIDGET_SPACING + extra_space_for_hscroll);
332 if (extra_space_for_hscroll) {
333 w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent,
334 x, y + height + EDIT_FRAME_H, width + EDIT_FRAME_W, 12, 0, 0);
335 CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor);
337 if (!(options & EDITOR_NO_TEXT))
338 CDrawStatus (catstrs (identifier, ".text", 0), parent, x, y + height + 3 + EDIT_FRAME_H + WIDGET_SPACING + extra_space_for_hscroll, width + EDIT_FRAME_W, e->filename);
339 if (!(options & EDITOR_NO_SCROLL)) {
340 w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent,
341 x + width + EDIT_FRAME_W + WIDGET_SPACING, y, height + EDIT_FRAME_H, 20, 0, 0);
342 CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_editor);
343 w->vert_scrollbar->scroll_bar_extra_render = render_book_marks;
345 return w;
348 static void render_book_marks (CWidget * w)
350 struct _book_mark *p;
351 WEdit *edit;
352 int l;
353 char i[32];
354 if (!w)
355 return;
356 strcpy (i, CIdentOf (w));
357 *(strstr (i, ".vsc")) = '\0';
358 edit = (CIdent (i))->editor;
359 if (!edit->book_mark)
360 return;
361 l = CHeightOf (w) - 10 * CWidthOf (w) / 3 - 10;
362 for (p = edit->book_mark; p->next; p = p->next);
363 for (; p->prev; p = p->prev) {
364 int y = (CWidthOf (w) + 2 * CWidthOf (w) / 3 + 4) + (int) ((double) l * p->line / edit->total_lines);
365 CSetColor (color_palette (p->c & 0xFF));
366 CLine (CWindowOf (w), 5, y, CWidthOf (w) - 6, y);
370 void update_scroll_bars (WEdit * e)
372 int i, x1, x2;
373 CWidget *scroll;
374 scroll = e->widget->vert_scrollbar;
375 if (scroll) {
376 i = e->total_lines - e->start_line + 1;
377 if (i > e->num_widget_lines)
378 i = e->num_widget_lines;
379 if (e->total_lines) {
380 x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
381 x2 = (double) 65535.0 *i / (e->total_lines + 1);
382 } else {
383 x1 = 0;
384 x2 = 65535;
386 if (x1 != scroll->firstline || x2 != scroll->numlines) {
387 scroll->firstline = x1;
388 scroll->numlines = x2;
389 EditExposeRedraw = 1;
390 render_scrollbar (scroll);
391 EditExposeRedraw = 0;
394 scroll = e->widget->hori_scrollbar;
395 if (scroll) {
396 i = e->max_column - (-e->start_col) + 1;
397 if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
398 i = e->num_widget_columns * FONT_MEAN_WIDTH;
399 x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
400 x2 = (double) 65535.0 *i / (e->max_column + 1);
401 if (x1 != scroll->firstline || x2 != scroll->numlines) {
402 scroll->firstline = x1;
403 scroll->numlines = x2;
404 EditExposeRedraw = 1;
405 render_scrollbar (scroll);
406 EditExposeRedraw = 0;
411 void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click)
413 edit_update_curs_row (edit);
414 edit_update_curs_col (edit);
415 if (event->type != MotionNotify) {
416 edit_push_action (edit, KEY_PRESS + edit->start_display);
417 if (edit->mark2 == -1)
418 edit_push_action (edit, MARK_1 + edit->mark1); /* mark1 must be following the cursor */
420 if (event->type == ButtonPress) {
421 edit->highlight = 0;
422 edit->found_len = 0;
424 mouse_mark (
425 event,
426 double_click,
427 edit->widget->funcs
431 void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
433 int i, start_line;
434 WEdit *e;
435 e = editor->editor;
436 if (!e)
437 return;
438 if (!e->widget->vert_scrollbar)
439 return;
440 start_line = e->start_line;
441 if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
442 edit_move_display (e, (double) scrollbar->firstline * e->total_lines / 65535.0 + 1);
443 } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
444 switch (whichscrbutton) {
445 case 1:
446 edit_move_display (e, e->start_line - e->num_widget_lines + 1);
447 break;
448 case 2:
449 edit_move_display (e, e->start_line - 1);
450 break;
451 case 5:
452 edit_move_display (e, e->start_line + 1);
453 break;
454 case 4:
455 edit_move_display (e, e->start_line + e->num_widget_lines - 1);
456 break;
459 if (e->total_lines)
460 scrollbar->firstline = (double) 65535.0 *e->start_line / (e->total_lines + 1);
461 else
462 scrollbar->firstline = 0;
463 i = e->total_lines - e->start_line + 1;
464 if (i > e->num_widget_lines)
465 i = e->num_widget_lines;
466 if (e->total_lines)
467 scrollbar->numlines = (double) 65535.0 *i / (e->total_lines + 1);
468 else
469 scrollbar->numlines = 65535;
470 if (start_line != e->start_line) {
471 e->force |= REDRAW_PAGE | REDRAW_LINE;
472 set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
473 if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
474 return;
476 if (e->force) {
477 edit_render_keypress (e);
478 edit_status (e);
482 void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
484 int i, start_col;
485 WEdit *e;
486 e = editor->editor;
487 if (!e)
488 return;
489 if (!e->widget->hori_scrollbar)
490 return;
491 start_col = (-e->start_col);
492 if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
493 e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1;
494 e->start_col -= e->start_col % FONT_MEAN_WIDTH;
495 if (e->start_col < 0)
496 e->start_col = 0;
497 e->start_col = (-e->start_col);
498 } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
499 switch (whichscrbutton) {
500 case 1:
501 edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
502 break;
503 case 2:
504 edit_scroll_left (e, FONT_MEAN_WIDTH);
505 break;
506 case 5:
507 edit_scroll_right (e, FONT_MEAN_WIDTH);
508 break;
509 case 4:
510 edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
511 break;
514 scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
515 i = e->max_column - (-e->start_col) + 1;
516 if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
517 i = e->num_widget_columns * FONT_MEAN_WIDTH;
518 scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1);
519 if (start_col != (-e->start_col)) {
520 e->force |= REDRAW_PAGE | REDRAW_LINE;
521 set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
522 if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
523 return;
525 if (e->force) {
526 edit_render_keypress (e);
527 edit_status (e);
532 This section comes from rxvt-2.21b1/src/screen.c by
533 Robert Nation <nation@rocket.sanders.lockheed.com> &
534 mods by mj olesen <olesen@me.QueensU.CA>
536 Changes made for cooledit
538 void selection_send (XSelectionRequestEvent * rq)
540 XEvent ev;
541 static Atom xa_targets = None;
542 if (xa_targets == None)
543 xa_targets = XInternAtom (CDisplay, "TARGETS", False);
545 ev.xselection.type = SelectionNotify;
546 ev.xselection.property = None;
547 ev.xselection.display = rq->display;
548 ev.xselection.requestor = rq->requestor;
549 ev.xselection.selection = rq->selection;
550 ev.xselection.target = rq->target;
551 ev.xselection.time = rq->time;
553 if (rq->target == xa_targets) {
555 * On some systems, the Atom typedef is 64 bits wide.
556 * We need to have a typedef that is exactly 32 bits wide,
557 * because a format of 64 is not allowed by the X11 protocol.
559 * XXX: yes, but Xlib requires that you pass it 64 bits for 32bit
560 * quantities on 64 bit archs.
562 /* typedef CARD32 Atom32; */
564 Atom target_list[2];
566 target_list[0] = xa_targets;
567 target_list[1] = XA_STRING;
569 XChangeProperty (CDisplay, rq->requestor, rq->property,
570 xa_targets, 8 * sizeof (target_list[0]), PropModeReplace,
571 (unsigned char *) target_list,
572 sizeof (target_list) / sizeof (target_list[0]));
573 ev.xselection.property = rq->property;
574 } else if (rq->target == XA_STRING) {
575 XChangeProperty (CDisplay, rq->requestor, rq->property,
576 XA_STRING, 8, PropModeReplace,
577 selection.text, selection.len);
578 ev.xselection.property = rq->property;
580 XSendEvent (CDisplay, rq->requestor, False, 0, &ev);
583 /*{{{ paste selection */
586 * Respond to a notification that a primary selection has been sent
588 void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete)
590 long nread;
591 unsigned long bytes_after;
593 if (prop == None)
594 return;
596 nread = 0;
597 do {
598 unsigned char *s;
599 Atom actual_type;
600 int actual_fmt, i;
601 unsigned long nitems;
603 if (XGetWindowProperty (CDisplay, win, prop,
604 nread / 4, 65536, delete,
605 AnyPropertyType, &actual_type, &actual_fmt,
606 &nitems, &bytes_after,
607 &s) != Success) {
608 XFree (s);
609 return;
611 nread += nitems;
612 for (i = 0; i < nitems; i++)
613 (*insert) (data, s[i]);
614 XFree (s);
615 } while (bytes_after);
618 void selection_paste (WEdit * edit, Window win, unsigned prop, int delete)
620 long c;
621 c = edit->curs1;
622 paste_prop ((void *) edit,
623 (void (*)(void *, int)) edit_insert,
624 win, prop, delete);
625 edit_cursor_move (edit, c - edit->curs1);
626 edit->force |= REDRAW_COMPLETELY | REDRAW_LINE;
629 /*}}} */
631 void selection_clear (void)
633 selection.text = 0;
634 selection.len = 0;
637 void edit_update_screen (WEdit * e)
639 if (!e)
640 return;
641 if (!e->force)
642 return;
644 edit_scroll_screen_over_cursor (e);
645 edit_update_curs_row (e);
646 edit_update_curs_col (e);
647 update_scroll_bars (e);
648 edit_status (e);
650 if (e->force & REDRAW_COMPLETELY)
651 e->force |= REDRAW_PAGE;
653 /* pop all events for this window for internal handling */
654 if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) {
655 edit_render_keypress (e);
656 } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0)
657 || CKeyPending ()) {
658 e->force |= REDRAW_PAGE;
659 return;
660 } else {
661 edit_render_keypress (e);
665 extern int space_width;
667 #ifdef HAVE_DND
668 #define free_data if (data) {free(data);data=0;}
670 /* handles drag and drop */
671 void handle_client_message (CWidget * w, XEvent * xevent)
673 int data_type;
674 unsigned char *data = 0;
675 unsigned long size;
676 int xs, ys;
677 long start_line;
678 int x, y, r, deleted = 0;
679 long click;
680 unsigned int state;
681 long start_mark = 0, end_mark = 0;
682 WEdit *e = w->editor;
684 /* see just below for a comment on what this is for: */
685 if (CIsDropAcknowledge (xevent, &state) != DndNotDnd) {
686 if (!(state & Button1Mask) && just_dropped_something) {
687 edit_push_action (e, KEY_PRESS + e->start_display);
688 edit_block_delete_cmd (e);
690 return;
692 data_type = CGetDrop (xevent, &data, &size, &xs, &ys);
694 if (data_type == DndNotDnd || xs < 0 || ys < 0 || xs >= CWidthOf (w) || ys >= CHeightOf (w)) {
695 free_data;
696 return;
698 edit_translate_xy (xs, ys, &x, &y);
699 click = edit_get_click_pos (e, x, y);
701 r = eval_marks (e, &start_mark, &end_mark);
702 /* musn't be able to drop into a block, otherwise a single click will copy a block: */
703 if (r)
704 goto fine;
705 if (start_mark > click || click >= end_mark)
706 goto fine;
707 if (column_highlighting) {
708 if (!((x >= e->column1 && x < e->column2)
709 || (x > e->column2 && x <= e->column1)))
710 goto fine;
712 free_data;
713 return;
714 fine:
715 edit_push_action (e, KEY_PRESS + e->start_display);
717 /* drops to the same window moving to the left: */
718 start_line = e->start_line;
719 if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
720 if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) {
721 edit_block_delete_cmd (e);
722 deleted = 1;
724 edit_update_curs_row (e);
725 edit_move_display (e, start_line);
726 click = edit_get_click_pos (e, x, y); /* click pos changes with edit_block_delete_cmd() */
727 edit_cursor_move (e, click - e->curs1);
728 if (data_type == DndFile) {
729 edit_insert_file (e, (char *) data);
730 } else if (data_type != DndFiles) {
731 if (dnd_null_term_type (data_type)) {
732 int len;
733 len = strlen ((char *) data);
734 size = min (len, size);
736 if (column_highlighting) {
737 edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
738 } else {
739 while (size--)
740 edit_insert_ahead (e, data[size]);
742 } else {
743 while (size--)
744 edit_insert_ahead (e, data[size] ? data[size] : '\n');
747 /* drops to the same window moving to the right: */
748 if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
749 if (column_highlighting && !deleted)
750 edit_block_delete_cmd (e);
752 /* The drop has now been successfully recieved. We can now send an acknowledge
753 event back to the window that send the data. When this window recieves
754 the acknowledge event, the app can decide whether or not to delete the data.
755 This allows text to be safely moved betweem text windows without the
756 risk of data being lost. In our case, drag with button1 is a copy
757 drag, while drag with any other button is a move drag (i.e. the sending
758 application must delete its selection after recieving an acknowledge
759 event). We must not, however, send an acknowledge signal if a filelist
760 (for example) was passed to us, since the sender might take this to
761 mean that all those files can be deleted! The two types we can acknowledge
762 are: */
763 if (xevent->xclient.data.l[2] != xevent->xclient.window) /* drops to the same window */
764 if (data_type == DndText || data_type == DndRawData)
765 CDropAcknowledge (xevent);
766 e->force |= REDRAW_COMPLETELY | REDRAW_LINE;
767 free_data;
769 #endif
771 int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
773 WEdit *e = w->editor;
774 int r = 0;
775 static int old_tab_spacing = -1;
777 if (!e)
778 return 0;
780 if (old_tab_spacing != option_tab_spacing)
781 e->force |= REDRAW_COMPLETELY + REDRAW_LINE;
782 old_tab_spacing = option_tab_spacing;
784 if (xevent->type == KeyPress) {
785 if (xevent->xkey.keycode == 0x31 && xevent->xkey.state == 0xD) {
786 CSetColor (color_palette (18));
787 CRectangle (w->winid, 0, 0, w->width, w->height);
790 switch (xevent->type) {
791 case SelectionNotify:
792 selection_paste (e, xevent->xselection.requestor, xevent->xselection.property, True);
793 r = 1;
794 break;
795 case SelectionRequest:
796 selection_send (&(xevent->xselectionrequest));
797 return 1;
798 /* case SelectionClear: ---> This is handled by coolnext.c: CNextEvent() */
799 #ifdef HAVE_DND
800 case ClientMessage:
801 handle_client_message (w, xevent);
802 r = 1;
803 #endif
804 break;
805 case ButtonPress:
806 CFocus (w);
807 edit_render_tidbits (w);
808 case ButtonRelease:
809 if (xevent->xbutton.state & ControlMask) {
810 if (!column_highlighting)
811 edit_push_action (e, COLUMN_OFF);
812 column_highlighting = 1;
813 } else {
814 if (column_highlighting)
815 edit_push_action (e, COLUMN_ON);
816 column_highlighting = 0;
818 case MotionNotify:
819 if (!xevent->xmotion.state && xevent->type == MotionNotify)
820 return 0;
821 resolve_button (xevent, cwevent);
822 if ((cwevent->button == Button4 || cwevent->button == Button5)
823 && (xevent->type == ButtonRelease)) {
824 /* ahaack: wheel mouse mapped as button 4 and 5 */
825 r = edit_execute_key_command (e, (cwevent->button == Button5) ? CK_Page_Down : CK_Page_Up, -1);
826 break;
828 edit_mouse_mark (e, xevent, cwevent->double_click);
829 break;
830 case Expose:
831 edit_render_expose (e, &(xevent->xexpose));
832 return 1;
833 case FocusIn:
834 CSetCursorColor (e->overwrite ? color_palette (24) : color_palette (19));
835 case FocusOut:
836 edit_render_tidbits (w);
837 e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
838 edit_render_keypress (e);
839 return 1;
840 break;
841 case KeyRelease:
842 #if 0
843 if (column_highlighting) {
844 column_highlighting = 0;
845 e->force = REDRAW_COMPLETELY | REDRAW_LINE;
846 edit_mark_cmd (e, 1);
848 #endif
849 break;
850 case KeyPress:
851 cwevent->ident = w->ident;
852 if (!cwevent->command && cwevent->insert < 0) { /* no translation */
853 if ((cwevent->key == XK_r || cwevent->key == XK_R) && (cwevent->state & ControlMask)) {
854 cwevent->command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
855 } else {
856 cwevent->command = CKeySymMod (xevent);
857 if (cwevent->command > 0)
858 cwevent->command = CK_Macro (cwevent->command);
859 else
860 break;
863 r = edit_execute_key_command (e, cwevent->command, cwevent->insert);
864 if (r)
865 edit_update_screen (e);
866 return r;
867 break;
868 case EditorCommand:
869 cwevent->ident = w->ident;
870 cwevent->command = xevent->xkey.keycode;
871 r = cwevent->handled = edit_execute_key_command (e, xevent->xkey.keycode, -1);
872 if (r)
873 edit_update_screen (e);
874 return r;
875 default:
876 return 0;
878 edit_update_screen (e);
879 return r;
882 #else
884 WEdit *wedit;
885 WButtonBar *edit_bar;
886 Dlg_head *edit_dlg;
887 WMenu *edit_menubar;
889 int column_highlighting = 0;
891 static int edit_callback (Dlg_head * h, WEdit * edit, int msg, int par);
893 static int edit_mode_callback (struct Dlg_head *h, int id, int msg)
895 return 0;
898 int edit_event (WEdit * edit, Gpm_Event * event, int *result)
900 *result = MOU_NORMAL;
901 edit_update_curs_row (edit);
902 edit_update_curs_col (edit);
903 if (event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) {
904 if (event->y > 1 && event->x > 0
905 && event->x <= edit->num_widget_columns
906 && event->y <= edit->num_widget_lines + 1) {
907 if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG))
908 return 1; /* a lone up mustn't do anything */
909 if (event->type & (GPM_DOWN | GPM_UP))
910 edit_push_key_press (edit);
911 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
912 if (--event->y > (edit->curs_row + 1))
913 edit_cursor_move (edit,
914 edit_move_forward (edit, edit->curs1, event->y - (edit->curs_row + 1), 0)
915 - edit->curs1);
916 if (event->y < (edit->curs_row + 1))
917 edit_cursor_move (edit,
918 +edit_move_backward (edit, edit->curs1, (edit->curs_row + 1) - event->y)
919 - edit->curs1);
920 edit_cursor_move (edit, (int) edit_move_forward3 (edit, edit->curs1,
921 event->x - edit->start_col - 1, 0) - edit->curs1);
922 edit->prev_col = edit_get_col (edit);
923 if (event->type & GPM_DOWN) {
924 edit_mark_cmd (edit, 1); /* reset */
925 edit->highlight = 0;
927 if (!(event->type & GPM_DRAG))
928 edit_mark_cmd (edit, 0);
929 edit->force |= REDRAW_COMPLETELY;
930 edit_update_curs_row (edit);
931 edit_update_curs_col (edit);
932 edit_update_screen (edit);
933 return 1;
936 return 0;
941 int menubar_event (Gpm_Event * event, WMenu * menubar); /* menu.c */
943 int edit_mouse_event (Gpm_Event * event, void *x)
945 int result;
946 if (edit_event ((WEdit *) x, event, &result))
947 return result;
948 else
949 return menubar_event (event, edit_menubar);
952 extern Menu EditMenuBar[5];
954 int edit (const char *_file, int line)
956 static int made_directory = 0;
957 int framed = 0;
958 int midnight_colors[4];
959 char *text = 0;
961 if (option_backup_ext_int != -1) {
962 option_backup_ext = malloc (sizeof(int) + 1);
963 option_backup_ext[sizeof(int)] = '\0';
964 memcpy (option_backup_ext, (char *) &option_backup_ext_int, sizeof (int));
967 if (!made_directory) {
968 mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
969 made_directory = 1;
971 if (_file) {
972 if (!(*_file)) {
973 _file = 0;
974 text = "";
976 } else
977 text = "";
979 if (!(wedit = edit_init (NULL, LINES - 2, COLS, _file, text, "", 0))) {
980 message (1, _(" Error "), get_error_msg (""));
981 return 0;
983 wedit->macro_i = -1;
985 /* Create a new dialog and add it widgets to it */
986 edit_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
987 edit_mode_callback, "[Internal File Editor]",
988 "edit",
989 DLG_NONE);
991 edit_dlg->raw = 1; /*so that tab = '\t' key works */
993 init_widget (&(wedit->widget), 0, 0, LINES - 1, COLS,
994 (callback_fn) edit_callback,
995 (destroy_fn) edit_clean,
996 (mouse_h) edit_mouse_event, 0);
998 widget_want_cursor (wedit->widget, 1);
1000 edit_bar = buttonbar_new (1);
1002 if (!framed) {
1003 switch (edit_key_emulation) {
1004 case EDIT_KEY_EMULATION_NORMAL:
1005 edit_init_menu_normal (); /* editmenu.c */
1006 break;
1007 case EDIT_KEY_EMULATION_EMACS:
1008 edit_init_menu_emacs (); /* editmenu.c */
1009 break;
1011 edit_menubar = menubar_new (0, 0, COLS, EditMenuBar, N_menus);
1013 add_widget (edit_dlg, wedit);
1015 if (!framed)
1016 add_widget (edit_dlg, edit_menubar);
1018 add_widget (edit_dlg, edit_bar);
1019 edit_move_display (wedit, line - 1);
1020 edit_move_to_line (wedit, line - 1);
1022 run_dlg (edit_dlg);
1024 if (!framed)
1025 edit_done_menu (); /* editmenu.c */
1027 destroy_dlg (edit_dlg);
1029 return 1;
1032 static void edit_my_define (Dlg_head * h, int idx, char *text,
1033 void (*fn) (WEdit *), WEdit * edit)
1035 define_label_data (h, (Widget *) edit, idx, text, (buttonbarfn) fn, edit);
1039 void cmd_F1 (WEdit * edit)
1041 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (1));
1044 void cmd_F2 (WEdit * edit)
1046 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (2));
1049 void cmd_F3 (WEdit * edit)
1051 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (3));
1054 void cmd_F4 (WEdit * edit)
1056 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (4));
1059 void cmd_F5 (WEdit * edit)
1061 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (5));
1064 void cmd_F6 (WEdit * edit)
1066 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (6));
1069 void cmd_F7 (WEdit * edit)
1071 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (7));
1074 void cmd_F8 (WEdit * edit)
1076 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (8));
1079 void cmd_F9 (WEdit * edit)
1081 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (9));
1084 void cmd_F10 (WEdit * edit)
1086 send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (10));
1089 void edit_labels (WEdit * edit)
1091 Dlg_head *h = edit->widget.parent;
1093 edit_my_define (h, 1, _("Help"), cmd_F1, edit);
1094 edit_my_define (h, 2, _("Save"), cmd_F2, edit);
1095 edit_my_define (h, 3, _("Mark"), cmd_F3, edit);
1096 edit_my_define (h, 4, _("Replac"), cmd_F4, edit);
1097 edit_my_define (h, 5, _("Copy"), cmd_F5, edit);
1098 edit_my_define (h, 6, _("Move"), cmd_F6, edit);
1099 edit_my_define (h, 7, _("Search"), cmd_F7, edit);
1100 edit_my_define (h, 8, _("Delete"), cmd_F8, edit);
1101 if (!edit->have_frame)
1102 edit_my_define (h, 9, _("PullDn"), edit_menu_cmd, edit);
1103 edit_my_define (h, 10, _("Quit"), cmd_F10, edit);
1105 redraw_labels (h, (Widget *) edit);
1109 long get_key_state ()
1111 return (long) get_modifier ();
1114 void edit_adjust_size (Dlg_head * h)
1116 WEdit *edit;
1117 WButtonBar *edit_bar;
1119 edit = (WEdit *) find_widget_type (h, (callback_fn) edit_callback);
1120 edit_bar = (WButtonBar *) edit->widget.parent->current->next->widget;
1121 widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS);
1122 widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS);
1123 widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS);
1125 #ifdef RESIZABLE_MENUBAR
1126 menubar_arrange(edit_menubar);
1127 #endif
1130 void edit_update_screen (WEdit * e)
1132 edit_scroll_screen_over_cursor (e);
1134 edit_update_curs_col (e);
1135 edit_status (e);
1137 /* pop all events for this window for internal handling */
1139 if (!is_idle ()) {
1140 e->force |= REDRAW_PAGE;
1141 return;
1143 if (e->force & REDRAW_COMPLETELY)
1144 e->force |= REDRAW_PAGE;
1145 edit_render_keypress (e);
1148 static int edit_callback (Dlg_head * h, WEdit * e, int msg, int par)
1150 switch (msg) {
1151 case WIDGET_INIT:
1152 e->force |= REDRAW_COMPLETELY;
1153 edit_labels (e);
1154 break;
1155 case WIDGET_DRAW:
1156 e->force |= REDRAW_COMPLETELY;
1157 e->num_widget_lines = LINES - 2;
1158 e->num_widget_columns = COLS;
1159 case WIDGET_FOCUS:
1160 edit_update_screen (e);
1161 return 1;
1162 case WIDGET_KEY:{
1163 int cmd, ch;
1164 if (edit_drop_hotkey_menu (e, par)) /* first check alt-f, alt-e, alt-s, etc for drop menus */
1165 return 1;
1166 if (!edit_translate_key (e, 0, par, get_key_state (), &cmd, &ch))
1167 return 0;
1168 edit_execute_key_command (e, cmd, ch);
1169 edit_update_screen (e);
1171 return 1;
1172 case WIDGET_COMMAND:
1173 edit_execute_key_command (e, par, -1);
1174 edit_update_screen (e);
1175 return 1;
1176 case WIDGET_CURSOR:
1177 widget_move (&e->widget, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET, e->curs_col + e->start_col);
1178 return 1;
1180 return default_proc (h, msg, par);
1183 #endif