1 /* textwidget.c - for drawing a scrollable text window widget
2 Copyright (C) 1996-2017 Paul Sheer
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307, USA.
18 */
19
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <my_string.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26
27 #include <X11/Intrinsic.h>
28 #include <X11/Xatom.h>
29 #include "lkeysym.h"
30
31 #include "stringtools.h"
32 #include "app_glob.c"
33 #include "edit.h"
34 #include "editcmddef.h"
35
36 #include "coolwidget.h"
37 #include "coollocal.h"
38 #include "mousemark.h"
39
40 #include "mad.h"
41
42 extern struct look *look;
43
44 int option_text_fg_normal = 0;
45 int option_text_fg_bold = 1;
46 int option_text_fg_italic = 18;
47
48 int option_text_bg_normal = 26;
49 int option_text_bg_marked = 25;
50 int option_text_bg_highlighted = 12;
51
52 void selection_clear (void);
53
54 static long current;
55
56 extern int calc_text_pos2 (CWidget * w, long b, long *q, int l);
57 extern void convert_text2 (CWidget * w, long from, cache_type *line, cache_type *eol, int x, int x_max, int row);
58 void edit_translate_xy (int xs, int ys, int *x, int *y);
59
60 /* returns the position in the edit buffer of a window click */
text_get_click_pos(CWidget * w,int x,int y)61 long text_get_click_pos (CWidget * w, int x, int y)
62 {
63 long click, c, q;
64 int width;
65 width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;
66 if (y > 1)
67 c = strmovelines (w->text, w->current, y - 1, width);
68 else
69 c = w->current;
70 if (y > 0)
71 click = strmovelines (w->text, c, 1, width);
72 else
73 click = w->current;
74 if (w->options & TEXTBOX_MARK_WHOLE_LINES) {
75 if (click == c && y > 0) {
76 calc_text_pos2 (w, click, &q, 32000); /* this is to get the last line */
77 return q;
78 }
79 return click;
80 } else
81 calc_text_pos2 (w, click, &q, x);
82 return q;
83 }
84
xy(int x,int y,int * x_return,int * y_return)85 static void xy (int x, int y, int *x_return, int *y_return)
86 {
87 edit_translate_xy (x, y, x_return, y_return);
88 }
89
cp(CWidget * w,int x,int y)90 static long cp (CWidget * w, int x, int y)
91 {
92 return text_get_click_pos (w, --x, --y);
93 }
94
95 /* return 1 if not marked */
marks(CWidget * w,long * start,long * end)96 static int marks (CWidget * w, long *start, long *end)
97 {
98 if (w->mark1 == w->mark2)
99 return 1;
100 *start = min (w->mark1, w->mark2);
101 *end = max (w->mark1, w->mark2);
102 return 0;
103 }
104
range(CWidget * w,long start,long end,int click)105 int range (CWidget * w, long start, long end, int click)
106 {
107 return (start <= click && click < end);
108 }
109
move_mark(CWidget * w)110 static void move_mark (CWidget * w)
111 {
112 w->mark2 = w->mark1 = current;
113 }
114
fin_mark(CWidget * w)115 static void fin_mark (CWidget * w)
116 {
117 w->mark2 = w->mark1 = -1;
118 }
119
release_mark(CWidget * w,XEvent * event)120 static void release_mark (CWidget * w, XEvent * event)
121 {
122 w->mark2 = current;
123 if (w->mark2 != w->mark1 && event) {
124 selection_clear ();
125 XSetSelectionOwner (CDisplay, XA_PRIMARY, w->winid, event->xbutton.time);
126 XSetSelectionOwner (CDisplay, ATOM_ICCCM_P2P_CLIPBOARD, w->winid, event->xbutton.time);
127 }
128 }
129
get_block(CWidget * w,long start_mark,long end_mark,int * type,int * l)130 static char *get_block (CWidget * w, long start_mark, long end_mark, int *type, int *l)
131 {
132 char *t, *t2;
133 *l = abs (w->mark2 - w->mark1);
134 t = CMalloc (*l + 1);
135 memcpy (t, w->text + min (w->mark1, w->mark2), *l);
136 t[*l] = 0;
137
138 t2 = str_strip_nroff ((char *) t, l);
139
140 free (t);
141 t2[*l] = 0;
142 if (w->options & TEXTBOX_FILE_LIST) {
143 #ifdef HAVE_DND
144 char *p;
145 int i;
146 p = CDndFileList (t2, l, &i);
147 if (!p) {
148 free (t2);
149 return 0;
150 }
151 free (t2);
152 t2 = p;
153 if (i == 1)
154 *type = DndFile;
155 else
156 #endif
157 *type = DndFiles;
158 } else {
159 *type = DndText;
160 }
161
162 return t2;
163 }
164
move(CWidget * w,long click,int row)165 static void move (CWidget * w, long click, int row)
166 {
167 int h;
168 current = click;
169 if (w->mark2 == -1)
170 w->mark1 = current;
171 h = (w->height - TEXTBOX_BDR) / FONT_PIX_PER_LINE;
172 if (row > h && w->firstline < w->numlines - h - 2)
173 CSetTextboxPos (w, TEXT_SET_LINE, w->firstline + row - h);
174 if (row < 1)
175 CSetTextboxPos (w, TEXT_SET_LINE, w->firstline + row - 1);
176 w->mark2 = click;
177 }
178
motion(CWidget * w,long click)179 static void motion (CWidget * w, long click)
180 {
181 w->mark2 = click;
182 }
183
184 struct mouse_funcs textbox_mouse_mark = {
185 0,
186 (void (*)(int, int, int *, int *)) xy,
187 (long (*)(void *, int, int)) cp,
188 (int (*)(void *, long *, long *)) marks,
189 (int (*)(void *, long, long, long)) range,
190 (void (*)(void *)) fin_mark,
191 (void (*)(void *)) move_mark,
192 (void (*)(void *, XEvent *)) release_mark,
193 (char *(*)(void *, long, long, int *, int *)) get_block,
194 (void (*)(void *, long, int)) move,
195 (void (*)(void *, long)) motion,
196 0,
197 0,
198 0,
199 0,
200 DndText
201 };
202
203
204 /*
205 If options & TEXTBOX_NO_STRDUP then text must be passed as an malloced string
206 which will be free'd automatically when the text box is destroyed.
207 If !options & TEXTBOX_NO_STRDUP then text will be strdup'ed (creating its own
208 internal copy of the text), like other widgets.
209 CRedrawTextbox will do the same as CDrawTextbox: it will not free old text
210 or make its own copy of new text.
211 */
CDrawTextbox(const char * identifier,Window parent,int x,int y,int width,int height,int line,int column,const char * text,long options)212 CWidget *CDrawTextbox (const char *identifier, Window parent, int x, int y,
213 int width, int height, int line, int column, const char *text, long options)
214 {
215 char *scroll;
216 int numlines;
217 CWidget *wdt;
218
219 int w, h;
220 CPushFont ("editor", 0);
221 if (width == AUTO_WIDTH || height == AUTO_HEIGHT)
222 CTextSize (&w, &h, text);
223 if (width == AUTO_WIDTH)
224 width = w + 6;
225 if (height == AUTO_HEIGHT)
226 height = h + 6;
227
228 wdt = CSetupWidget (identifier, parent, x, y,
229 width, height, C_TEXTBOX_WIDGET, INPUT_KEY,
230 color_palette (option_text_bg_normal), 1);
231 wdt->funcs = mouse_funcs_new (wdt, &textbox_mouse_mark);
232
233 xdnd_set_type_list (CDndClass, wdt->winid, xdnd_typelist_send[DndText]);
234
235 wdt->options = options | WIDGET_TAKES_SELECTION;
236 if (options & TEXTBOX_NO_STRDUP)
237 wdt->text = (char *) text;
238 else
239 wdt->text = (char *) strdup (text);
240 numlines = strcountlines (text, 0, 1000000000, options & TEXTBOX_WRAP ? (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000) + 1;
241
242 wdt->firstline = 0;
243 wdt->firstcolumn = 0;
244 wdt->cursor = 0;
245 wdt->current = 0;
246 wdt->numlines = numlines;
247 wdt->textlength = strlen (wdt->text);
248
249 CSetTextboxPos (wdt, TEXT_SET_LINE, line);
250 CSetTextboxPos (wdt, TEXT_SET_COLUMN, column);
251
252 if (height > 80) {
253 /* this will also set the hint position, set_hint_pos() */
254 wdt->vert_scrollbar = CDrawVerticalScrollbar (scroll = catstrs (identifier, ".vsc", NULL), parent,
255 x + width + WIDGET_SPACING, y, height, AUTO_WIDTH, 0, 0);
256 CSetScrollbarCallback (wdt->vert_scrollbar->ident, wdt->ident, link_scrollbar_to_textbox);
257 } else {
258 set_hint_pos (x + width + WIDGET_SPACING, y + height + WIDGET_SPACING);
259 }
260 CPopFont ();
261 return wdt;
262 }
263
264
265 int CSetTextboxPos (CWidget * w, int which, long p);
266
267 /* redraws the text box. If preserve is 0 then view position is reset to 0 */
CRedrawTextbox(const char * identifier,const char * text,int preserve)268 CWidget *CRedrawTextbox (const char *identifier, const char *text, int preserve)
269 {
270 CWidget *w = CIdent (identifier);
271 int numlines, firstline, firstcolumn, cursor;
272
273 if (!w)
274 return 0;
275 if (w->options & TEXTBOX_NO_STRDUP)
276 w->text = (char *) text;
277 else {
278 if (w->text)
279 free (w->text);
280 w->text = (char *) strdup (text);
281 }
282 CPushFont ("editor", 0);
283 w->textlength = strlen (w->text);
284 numlines = strcountlines (text, 0, 1000000000, w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000) + 1;
285 w->numlines = numlines;
286 firstline = w->firstline;
287 firstcolumn = w->firstcolumn;
288 cursor = w->cursor;
289
290 w->firstline = 0;
291 w->current = 0;
292 w->firstcolumn = 0;
293 w->cursor = 0;
294 w->mark1 = w->mark2 = -1;
295
296 if (preserve) {
297 CSetTextboxPos (w, TEXT_SET_LINE, firstline);
298 CSetTextboxPos (w, TEXT_SET_COLUMN, firstcolumn);
299 CSetTextboxPos (w, TEXT_SET_CURSOR_LINE, cursor);
300 }
301 CExpose (identifier);
302 CPopFont ();
303
304 return w;
305 }
306
307 /* result must not be free'd, and must be used immediately */
CGetTextBoxLine(CWidget * w,int i)308 char *CGetTextBoxLine (CWidget * w, int i)
309 {
310 int width;
311 char *r;
312 CPushFont ("editor", 0);
313 width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;
314 r = strline (w->text, strmovelines (w->text, w->current, i - w->firstline, width));
315 CPopFont ();
316 return r;
317 }
318
319 /* clears the text box */
CClearTextbox(const char * identifier)320 CWidget *CClearTextbox (const char *identifier)
321 {
322 CWidget *w;
323 w = CIdent (identifier);
324 if (w) {
325 if (!(w->options & TEXTBOX_NO_STRDUP))
326 if (w->text)
327 free (w->text);
328 w->text = (char *) strdup ("");
329 w->textlength = w->numlines = 0;
330 w->firstline = w->firstcolumn = 0;
331 w->mark1 = w->mark2 = 0;
332 CExpose (identifier);
333 }
334 return w;
335 }
336
CDrawManPage(const char * identifier,Window parent,int x,int y,int width,int height,int line,int column,const char * text)337 CWidget *CDrawManPage (const char *identifier, Window parent, int x, int y,
338 int width, int height, int line, int column, const char *text)
339 {
340 CWidget *w;
341 w = CDrawTextbox (identifier, parent, x, y, width, height, line, column, text, TEXTBOX_MAN_PAGE);
342 return w;
343 }
344
345
346
347 /*
348 If which is TEXT_SET_POS the current offset of the top right
349 corner is set to p.
350 returns non-zero if anything actually changed.
351 */
CSetTextboxPos(CWidget * wdt,int which,long p)352 int CSetTextboxPos (CWidget * wdt, int which, long p)
353 {
354 long q;
355 int width, i, j;
356 if (p < 0)
357 p = 0;
358 CPushFont ("editor", 0);
359
360 width = wdt->options & TEXTBOX_WRAP ? (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;
361
362 switch (which) {
363 case TEXT_SET_COLUMN:
364 i = wdt->firstcolumn;
365 wdt->firstcolumn = p;
366 CPopFont ();
367 return (i != wdt->firstcolumn);
368 case TEXT_SET_LINE:
369 i = wdt->firstline;
370 if (p >= wdt->numlines)
371 p = wdt->numlines - 1;
372 if (p < 0)
373 p = 0;
374 if (wdt->kind == C_FIELDED_TEXTBOX_WIDGET) {
375 wdt->firstline = p;
376 } else {
377 q = strmovelines (wdt->text, wdt->current, p - wdt->firstline, width);
378 wdt->firstline += strcountlines (wdt->text, wdt->current, q - wdt->current, width);
379 wdt->current = q;
380 }
381 CPopFont ();
382 return (i != wdt->firstline);
383 case TEXT_SET_POS:
384 i = wdt->firstline;
385 if (wdt->kind == C_FIELDED_TEXTBOX_WIDGET) {
386 break;
387 } else {
388 wdt->firstline += strcountlines (wdt->text, wdt->current, p - wdt->current, width);
389 wdt->current = p;
390 }
391 CPopFont ();
392 return (i != wdt->firstline);
393 case TEXT_SET_CURSOR_LINE:
394 i = wdt->firstline;
395 j = wdt->cursor;
396 if (p < 0)
397 p = 0;
398 if (p >= wdt->numlines)
399 p = wdt->numlines - 1;
400 wdt->cursor = p;
401 if (p < wdt->firstline)
402 CSetTextboxPos (wdt, TEXT_SET_LINE, p);
403 else if (p > wdt->firstline + (wdt->height - FONT_PIX_PER_LINE - 6) / FONT_PIX_PER_LINE)
404 CSetTextboxPos (wdt, TEXT_SET_LINE, p - (wdt->height - FONT_PIX_PER_LINE - 6) / FONT_PIX_PER_LINE);
405 CPopFont ();
406 return (i != wdt->firstline || j != wdt->cursor);
407 }
408 /* NLS ? */
409 CError ("settextpos: command not found.\n");
410 CPopFont ();
411 return 0;
412 }
413
414
text_print_line(CWidget * w,long b,int row)415 static void text_print_line (CWidget * w, long b, int row)
416 {
417 edit_draw_proportional (w,
418 (void (*)(void *, long, cache_type *, cache_type *, int, int, int)) convert_text2,
419 (int (*)(void *, long, long *, int)) calc_text_pos2,
420 -w->firstcolumn * FONT_MEAN_WIDTH, w->winid,
421 w->width, b, row, row * FONT_PIX_PER_LINE + EDIT_TEXT_VERTICAL_OFFSET, 0,
422 FONT_PER_CHAR(' ') * TAB_SIZE);
423 }
424
425
426
427 /*
428 ->firstline is line number of the top line in the window.
429 ->firstcolumn is column shift (positive).
430 ->current is actual char position of first line in display.
431 ->numlines is the total number of lines.
432 ->cursor is the number of the highlighted line.
433 ->textlength is the length of text excluding trailing NULL.
434 First three must be initialised to proper values (e.g. 0, 0 and 0).
435 */
436
437 extern int EditExposeRedraw;
438 extern int EditClear;
439 extern int highlight_this_line;
440 extern unsigned long edit_normal_background_color;
441
render_textbox(CWidget * w,int redrawall)442 long render_textbox (CWidget * w, int redrawall)
443 {
444 long b;
445 int c = 0, r = 0, row, height, isfocussed, wrap_width = 32000,
446 curs, lines_drawn = 0;
447 CPushFont ("editor", 0);
448 if (w->options & TEXTBOX_WRAP) {
449 wrap_width = (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH;
450 if (w->resized) { /* a resize will change the number lines if text is wrapping */
451 int firstline = w->firstline;
452 w->numlines = strcountlines (w->text, 0, 1000000000, wrap_width) + 1;
453 w->firstline = 0;
454 w->current = w->cursor = 0;
455 CSetTextboxPos (w, TEXT_SET_LINE, firstline);
456 w->resized = 0; /* done */
457 }
458 }
459 if (redrawall) {
460 EditExposeRedraw = 1;
461 EditClear = 1;
462 }
463 b = w->current;
464 height = w->height / FONT_PIX_PER_LINE + 1;
465
466 isfocussed = (w->winid == CGetFocus ());
467 curs = !(w->options & TEXTBOX_NO_CURSOR || w->mark1 != w->mark2); /* don't draw the cursor line */
468
469 edit_set_foreground_colors (color_palette (option_text_fg_normal), color_palette (option_text_fg_bold), color_palette (option_text_fg_italic));
470 edit_set_background_colors (color_palette (option_text_bg_normal), color_palette (0), color_palette (option_text_bg_marked), color_palette (9), color_palette (option_text_bg_highlighted));
471
472 for (row = 0; row < height; row++) {
473 if (row + w->firstline == w->cursor && isfocussed && curs)
474 highlight_this_line = 1;
475 else
476 highlight_this_line = 0;
477 if (row + w->firstline < w->numlines) {
478 c = strmovelines (w->text, b, 1, wrap_width);
479 if (c != b) { /* at last line strmovelines cannot move */
480 r = w->text[c];
481 w->text[c] = 0; /* mark where line wraps */
482 }
483 lines_drawn++;
484 text_print_line (w, b, row);
485 if (c != b)
486 w->text[c] = r; /* remove mark */
487 b = c;
488 } else {
489 text_print_line (w, w->textlength, row); /* print blank lines */
490 }
491 }
492
493 EditExposeRedraw = 0;
494 EditClear = 0;
495 (*look->render_textbox_tidbits) (w, isfocussed);
496 CSetColor (edit_normal_background_color);
497 CLine (w->winid, 3, 3, 3, w->height - 4);
498 CPopFont ();
499 return lines_drawn;
500 }
501
502 /*
503 Count the number of lines that would be printed
504 by the above routine, but don't print anything.
505 If all is non-zero then count all the lines.
506 */
count_textbox_lines(CWidget * wdt,int all)507 long count_textbox_lines (CWidget * wdt, int all)
508 {
509 int nroff, col = 0, row = 0, height, width;
510 long from;
511 unsigned char c;
512 int wrap_mode;
513 unsigned char *text;
514
515 CPushFont ("editor", 0);
516 nroff = (wdt->options & TEXTBOX_MAN_PAGE);
517 wrap_mode = (wdt->options & TEXTBOX_WRAP);
518 if (nroff)
519 wrap_mode = 0;
520
521 text = (unsigned char *) wdt->text;
522 height = wdt->height / FONT_PIX_PER_LINE;
523 width = (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH;
524 if (all)
525 from = 0;
526 else
527 from = wdt->current;
528
529 for (; row < height || all; from++) {
530 c = text[from];
531 if (!c)
532 break;
533 if ((c == '\n') || (col == width && wrap_mode)) {
534 col = 0;
535 row++;
536 if (c == '\n' || row >= height)
537 continue;
538 }
539 if (c == '\r')
540 continue;
541 if (c == '\t') {
542 col = (col / 8) * 8 + 8;
543 continue;
544 }
545 col++;
546 }
547 CPopFont ();
548 return row + 1;
549 }
550
551 /* move the text box cursor or the text window if there isn't one */
CTextboxCursorMove(CWidget * wdt,KeySym key)552 int CTextboxCursorMove (CWidget * wdt, KeySym key)
553 {
554 int handled = 0;
555 CPushFont ("editor", 0);
556 /* when text is highlighted, the cursor must be off */
557 if (wdt->options & TEXTBOX_NO_CURSOR || wdt->mark1 != wdt->mark2) {
558 int to_move = 0;
559 switch ((int) key) {
560 case CK_Up:
561 handled = 1;
562 to_move = -1;
563 break;
564 case CK_Down:
565 handled = 1;
566 to_move = 1;
567 break;
568 case CK_Page_Up:
569 handled = 1;
570 to_move = 1 - wdt->height / FONT_PIX_PER_LINE;
571 break;
572 case CK_Page_Down:
573 handled = 1;
574 to_move = wdt->height / FONT_PIX_PER_LINE - 1;
575 break;
576 case CK_Home:
577 handled = 1;
578 to_move = -32000;
579 break;
580 case CK_End:
581 handled = 1;
582 to_move = 32000;
583 break;
584 case CK_Left:
585 handled = 1;
586 if (wdt->firstcolumn > 0)
587 wdt->firstcolumn--;
588 break;
589 case CK_Right:
590 handled = 1;
591 wdt->firstcolumn++;
592 break;
593 }
594 CSetTextboxPos (wdt, TEXT_SET_LINE, wdt->firstline + to_move);
595 } else {
596 switch ((int) key) {
597 case CK_Up:
598 handled = 1;
599 wdt->cursor--;
600 break;
601 case CK_Down:
602 handled = 1;
603 wdt->cursor++;
604 break;
605 case CK_Page_Up:
606 handled = 1;
607 wdt->cursor -= (wdt->height / FONT_PIX_PER_LINE - 1);
608 break;
609 case CK_Page_Down:
610 handled = 1;
611 wdt->cursor += (wdt->height / FONT_PIX_PER_LINE - 1);
612 break;
613 case CK_Home:
614 handled = 1;
615 wdt->cursor = 0;
616 break;
617 case CK_End:
618 handled = 1;
619 wdt->cursor = wdt->numlines;
620 break;
621 case CK_Left:
622 handled = 1;
623 if (wdt->firstcolumn > 0) {
624 wdt->firstcolumn--;
625 }
626 break;
627 case CK_Right:
628 handled = 1;
629 wdt->firstcolumn++;
630 break;
631 }
632 CSetTextboxPos (wdt, TEXT_SET_CURSOR_LINE, wdt->cursor); /* just does some checks */
633 }
634 CPopFont ();
635 return handled;
636 }
637
text_mouse_mark(CWidget * w,XEvent * event,CEvent * ce)638 static void text_mouse_mark (CWidget * w, XEvent * event, CEvent * ce)
639 {
640 CPushFont ("editor", 0);
641 mouse_mark (event, ce->double_click, w->funcs);
642 CPopFont ();
643 }
644
645 static struct selection text_selection = {0, 0};
646
647 /* gets selected text into selection structure, stripping nroff */
text_get_selection(CWidget * w)648 void text_get_selection (CWidget * w)
649 {
650 char *t;
651 int len;
652 len = abs (w->mark2 - w->mark1);
653 t = CMalloc (len + 1);
654 memcpy (t, w->text + min (w->mark1, w->mark2), len);
655 t[len] = 0;
656 if (text_selection.text)
657 free (text_selection.text);
658 text_selection.text = (unsigned char *) str_strip_nroff ((char *) t, &text_selection.len);
659 free (t);
660 if (!text_selection.text) {
661 text_selection.text = CMalloc (1);
662 text_selection.len = 0;
663 }
664 text_selection.text[text_selection.len] = 0;
665 selection_clear ();
666 selection = text_selection;
667 }
668
669 void selection_send (XSelectionRequestEvent * rq);
670
eh_textbox(CWidget * w,XEvent * xevent,CEvent * cwevent)671 int eh_textbox (CWidget * w, XEvent * xevent, CEvent * cwevent)
672 {
673 int handled = 0, redrawall, count;
674
675 redrawall = 0;
676 switch (xevent->type) {
677 case SelectionRequest:
678 text_get_selection (w);
679 selection_send (&(xevent->xselectionrequest));
680 return 1;
681 case Expose:
682 if (!xevent->xexpose.count)
683 redrawall = 1;
684 break;
685 case ClientMessage:
686 w->mark1 = w->mark2 = 0;
687 break;
688 case ButtonPress:
689 CFocus (w);
690 CPushFont ("editor", 0);
691 if (xevent->xbutton.button == Button1)
692 w->cursor = (xevent->xbutton.y - TEXTBOX_BDR) / FONT_PIX_PER_LINE + w->firstline;
693 if (w->cursor > w->numlines - 1)
694 w->cursor = w->numlines - 1;
695 if (w->cursor < 0)
696 w->cursor = 0;
697 cwevent->ident = w->ident;
698 cwevent->xt = (xevent->xbutton.x - 7) / FONT_MEAN_WIDTH + w->firstcolumn;
699 cwevent->yt = w->cursor;
700 CPopFont ();
701 case ButtonRelease:
702 case MotionNotify:
703 if (!xevent->xmotion.state && xevent->type == MotionNotify)
704 return 0;
705 resolve_button (xevent, cwevent);
706 text_mouse_mark (w, xevent, cwevent);
707 break;
708 case FocusIn:
709 case FocusOut:
710 break;
711 case KeyPress:
712 cwevent->ident = w->ident;
713 if (!(TEXTBOX_NO_KEYS & w->options))
714 handled = CTextboxCursorMove (w, cwevent->command);
715 break;
716 default:
717 return 0;
718 }
719
720 /* Now draw the changed text box, count will contain
721 the number of textlines displayed */
722 count = render_textbox (w, redrawall);
723
724 /* now update the scrollbar position */
725 if (w->vert_scrollbar) {
726 w->vert_scrollbar->firstline = (double) 65535.0 *w->firstline / w->numlines;
727 w->vert_scrollbar->numlines = (double) 65535.0 *count / w->numlines;
728 w->vert_scrollbar->options = 0;
729 render_scrollbar (w->vert_scrollbar);
730 }
731
732 return handled;
733 }
734
link_scrollbar_to_textbox(CWidget * scrollbar,CWidget * textbox,XEvent * xevent,CEvent * cwevent,int whichscrbutton)735 void link_scrollbar_to_textbox (CWidget * scrollbar, CWidget * textbox, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
736 {
737 int redrawtext = 0, count = -1, c;
738 static int r = 0;
739 CPushFont ("editor", 0);
740 if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
741 redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, (double) scrollbar->firstline * textbox->numlines / 65535.0);
742 } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
743 switch (whichscrbutton) {
744 case 1:
745 redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline - (textbox->height / FONT_PIX_PER_LINE - 2));
746 break;
747 case 2:
748 redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline - 1);
749 break;
750 case 5:
751 redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline + 1);
752 break;
753 case 4:
754 redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline + (textbox->height / FONT_PIX_PER_LINE - 2));
755 break;
756 }
757 }
758 if (xevent->type == ButtonRelease)
759 count = render_textbox (textbox, 0);
760 else {
761 c = CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0);
762 if (redrawtext) {
763 if (!c) {
764 render_textbox (textbox, 0);
765 r = 0;
766 } else {
767 r = 1;
768 }
769 } else if (c && r) {
770 render_textbox (textbox, 0);
771 r = 0;
772 }
773 }
774 if (count < 0)
775 count = count_textbox_lines (textbox, 0);
776 if (!count)
777 count = 1;
778 scrollbar->firstline = (double) 65535.0 *textbox->firstline / textbox->numlines;
779 scrollbar->numlines = (double) 65535.0 *count / textbox->numlines;
780 CPopFont ();
781 return;
782 }
783
784
785
786
787