source: trunk/third/x3270/select.c @ 9081

Revision 9081, 23.6 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9080, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright 1993, 1994, 1995 by Paul Mattes.
3 *  Permission to use, copy, modify, and distribute this software and its
4 *  documentation for any purpose and without fee is hereby granted,
5 *  provided that the above copyright notice appear in all copies and that
6 *  both that copyright notice and this permission notice appear in
7 *  supporting documentation.
8 */
9
10/*
11 * Portions of this code were taken from xterm/button.c:
12 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
13 *
14 *                         All Rights Reserved
15 *
16 * Permission to use, copy, modify, and distribute this software and its
17 * documentation for any purpose and without fee is hereby granted,
18 * provided that the above copyright notice appear in all copies and that
19 * both that copyright notice and this permission notice appear in
20 * supporting documentation, and that the name of Digital Equipment
21 * Corporation not be used in advertising or publicity pertaining to
22 * distribution of the software without specific, written prior permission.
23 *
24 *
25 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
26 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
27 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
28 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
29 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
30 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
31 * SOFTWARE.
32 */
33
34/*
35 *      select.c
36 *              This module handles selections.
37 */
38
39#include "globals.h"
40#include <X11/Xatom.h>
41#include <X11/Xmu/Atoms.h>
42#include <X11/Xmu/StdSel.h>
43#include "3270ds.h"
44#include "appres.h"
45#include "ctlr.h"
46#include "screen.h"
47#include "cg.h"
48#include "resources.h"
49
50#include "actionsc.h"
51#include "ctlrc.h"
52#include "kybdc.h"
53#include "popupsc.h"
54#include "screenc.h"
55#include "selectc.h"
56#include "tablesc.h"
57#include "utilc.h"
58
59/*
60 * Mouse side.
61 */
62
63/* A button click establishes the boundaries of the 'fixed' area. */
64static int      f_start = 0;    /* 'fixed' area */
65static int      f_end = 0;
66
67/* Mouse motion moves the boundaries of the 'varying' area. */
68static int      v_start = 0;    /* 'varying' area */
69static int      v_end = 0;
70
71static unsigned long down_time = 0;
72static unsigned long down1_time = 0;
73static Dimension down1_x, down1_y;
74static unsigned long up_time = 0;
75static int      saw_motion = 0;
76static int      num_clicks = 0;
77static void     grab_sel();
78#define NS              5
79static Atom     want_sel[NS];
80static struct {                 /* owned selections */
81        Atom            atom;   /* atom */
82        char           *buffer; /* buffer contents */
83}               own_sel[NS];
84static Boolean  cursor_moved = False;
85static int      saved_cursor_addr;
86static void     own_sels();
87int             n_owned = -1;
88Boolean         any_selected = False;
89
90extern Widget  *screen;
91
92#define CLICK_INTERVAL  200
93
94#define event_x(event)          event->xbutton.x
95#define event_y(event)          event->xbutton.y
96#define event_time(event)       event->xbutton.time
97
98#define BOUNDED_XY(event, x, y) {       \
99        x = X_TO_COL(event_x(event));   \
100        if (x < 0)                      \
101                x = 0;                  \
102        if (x >= COLS)                  \
103                x = COLS - 1;           \
104        if (flipped)                    \
105                x = (COLS - x) - 1;     \
106        y = Y_TO_ROW(event_y(event));   \
107        if (y <= 0)                     \
108                y = 0;                  \
109        if (y >= ROWS)                  \
110                y = ROWS - 1;           \
111}
112
113
114static int char_class[256] = {
115/* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si */
116    32,  1,  1,  1,  1,  1,  1,  1,  1, 32,  1,  1,  1,  1,  1,  1,
117/* dle dc1 dc2 dc3 dc4 nak syn etb can  em sub esc  fs  gs  rs  us */
118     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
119/*  sp   !   "   #   $   %   &   '   (   )   *   +   ,   -   .   / */
120    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
121/*   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ? */
122    48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 58, 59, 60, 61, 62, 63,
123/*   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O */
124    64, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
125/*   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _ */
126    48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 91, 92, 93, 94, 48,
127/*   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o */
128    96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
129/*   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~  del */
130    48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,123,124,125,126,   1,
131/* ---,---,---,---,---,---,---,---,---,---,---,---,---,---,---,--- */
132     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
133/* ---,---,---,---,---,---,---,---,---,---,---,---,---,---,---,--- */
134     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
135/* nob exc cen ste cur yen bro sec dia cop ord gui not hyp reg mac */
136    32,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
137/* deg plu two thr acu mu  par per ce  one mas gui one one thr que */
138   176,177,178,179,180,181,182,183,184,185,186,178,188,189,190,191,
139/* Agr Aac Aci Ati Adi Ari AE  Cce Egr Eac Eci Edi Igr Iac Ici Idi */
140    48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
141/* ETH Nti Ogr Oac Oci Oti Odi mul Oob Ugr Uac Uci Udi Yac THO ssh */
142    48, 48, 48, 48, 48, 48, 48,215, 48, 48, 48, 48, 48, 48, 48, 48,
143/* agr aac aci ati adi ari ae  cce egr eac eci edi igr iac ici idi */
144    48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
145/* eth nti ogr oac oci oti odi div osl ugr uac uci udi yac tho ydi */
146    48, 48, 48, 48, 48, 48, 48,247, 48, 48, 48, 48, 48, 48, 48, 48
147};
148
149/* Parse a charClass string: [low-]high:value[,...] */
150void
151reclass(s)
152char *s;
153{
154        int n;
155        int low, high, value;
156        int i;
157        char c;
158
159        n = -1;
160        low = -1;
161        high = -1;
162        for (;;) {
163                c = *s++;
164                if (isdigit(c)) {
165                        if (n == -1)
166                                n = 0;
167                        n = (n * 10) + (c - '0');
168                        if (n > 255)
169                                goto fail;
170                } else if (c == '-') {
171                        if (n == -1 || low != -1)
172                                goto fail;
173                        low = n;
174                        n = -1;
175                } else if (c == ':') {
176                        if (n == -1)
177                                goto fail;
178                        high = n;
179                        n = -1;
180                } else if (c == ',' || c == '\0') {
181                        if (n == -1)
182                                goto fail;
183                        value = n;
184                        n = -1;
185                        if (high == -1)
186                                goto fail;
187                        if (low == -1)
188                                low = high;
189                        if (high < low)
190                                goto fail;
191                        for (i = low; i <= high; i++)
192                                char_class[i] = value;
193                        low = -1;
194                        high = -1;
195                        if (c == '\0')
196                                return;
197                } else
198                        goto fail;
199        }
200
201    fail:
202        xs_warning("Error in %s string", ResCharClass);
203}
204
205static void
206select_word(baddr, t)
207int baddr;
208Time t;
209{
210        unsigned char fa = *get_field_attribute(baddr);
211        unsigned char ch;
212        int class;
213
214        /* Find the initial character class */
215        if (FA_IS_ZERO(fa))
216                ch = CG_space;
217        else
218                ch = screen_buf[baddr];
219        class = char_class[cg2asc[ch]];
220
221        /* Find the beginning */
222        for (f_start = baddr; f_start % COLS; f_start--) {
223                fa = *get_field_attribute(f_start);
224                if (FA_IS_ZERO(fa))
225                        ch = CG_space;
226                else
227                        ch = screen_buf[f_start];
228                if (char_class[cg2asc[ch]] != class) {
229                        f_start++;
230                        break;
231                }
232        }
233
234        /* Find the end */
235        for (f_end = baddr; (f_end+1) % COLS; f_end++) {
236                fa = *get_field_attribute(f_end);
237                if (FA_IS_ZERO(fa))
238                        ch = CG_space;
239                else
240                        ch = screen_buf[f_end];
241                if (char_class[cg2asc[ch]] != class) {
242                        f_end--;
243                        break;
244                }
245        }
246
247        v_start = f_start;
248        v_end = f_end;
249        grab_sel(f_start, f_end, True, t);
250}
251
252static void
253select_line(baddr, t)
254int baddr;
255Time t;
256{
257        f_start = baddr - (baddr % COLS);
258        f_end = f_start + COLS - 1;
259        v_start = f_start;
260        v_end = f_end;
261        grab_sel(f_start, f_end, True, t);
262}
263
264
265/*
266 * Start a new selection.
267 * Usually bound to <Btn1Down>.
268 */
269/*ARGSUSED*/
270void
271select_start_action(w, event, params, num_params)
272Widget w;
273XEvent *event;
274String *params;
275Cardinal *num_params;
276{
277        int x, y;
278        register int baddr;
279
280        if (w != *screen)
281                return;
282        action_debug(select_start_action, event, params, num_params);
283        BOUNDED_XY(event, x, y);
284        baddr = ROWCOL_TO_BA(y, x);
285        f_start = f_end = v_start = v_end = baddr;
286        down1_time = down_time = event_time(event);
287        down1_x = event_x(event);
288        down1_y = event_y(event);
289        if (down_time - up_time > CLICK_INTERVAL) {
290                num_clicks = 0;
291                /* Commit any previous cursor move. */
292                cursor_moved = False;
293        }
294        if (num_clicks == 0)
295                unselect(0, ROWS*COLS);
296}
297
298/*
299 * Alternate form of select_start, which combines cursor motion with selection.
300 * Usually bound to <Btn1Down> in a user-specified keymap.
301 */
302/*ARGSUSED*/
303void
304move_select_action(w, event, params, num_params)
305Widget w;
306XEvent *event;
307String *params;
308Cardinal *num_params;
309{
310        int x, y;
311        register int baddr;
312
313        if (w != *screen)
314                return;
315        action_debug(move_select_action, event, params, num_params);
316        BOUNDED_XY(event, x, y);
317        baddr = ROWCOL_TO_BA(y, x);
318
319        f_start = f_end = v_start = v_end = baddr;
320        down1_time = down_time = event_time(event);
321        down1_x = event_x(event);
322        down1_y = event_y(event);
323
324        if (down_time - up_time > CLICK_INTERVAL) {
325                num_clicks = 0;
326                /* Commit any previous cursor move. */
327                cursor_moved = False;
328        }
329        if (num_clicks == 0) {
330                if (any_selected) {
331                        unselect(0, ROWS*COLS);
332                } else {
333                        cursor_moved = True;
334                        saved_cursor_addr = cursor_addr;
335                        cursor_move(baddr);
336                }
337        }
338}
339
340/*
341 * Begin extending the current selection.
342 * Usually bound to <Btn3Down>.
343 */
344/*ARGSUSED*/
345void
346start_extend_action(w, event, params, num_params)
347Widget w;
348XEvent *event;
349String *params;
350Cardinal *num_params;
351{
352        int x, y;
353        int baddr;
354
355        if (w != *screen)
356                return;
357        action_debug(start_extend_action, event, params, num_params);
358
359        down1_time = 0L;
360
361        BOUNDED_XY(event, x, y);
362        baddr = ROWCOL_TO_BA(y, x);
363
364        if (baddr < f_start)
365                v_start = baddr;                /* extend above */
366        else if (baddr > f_end)
367                v_end = baddr;                  /* extend below */
368        else if (baddr - f_start > f_end - baddr)
369                v_end = baddr;                  /* shrink end */
370        else
371                v_start = baddr;                /* shrink start */
372
373        grab_sel(v_start, v_end, True, event_time(event));
374        saw_motion = 1;
375        num_clicks = 0;
376}
377
378/*
379 * Continuously extend the current selection.
380 * Usually bound to <Btn1Motion> and <Btn3Motion>.
381 */
382/*ARGSUSED*/
383void
384select_extend_action(w, event, params, num_params)
385Widget w;
386XEvent *event;
387String *params;
388Cardinal *num_params;
389{
390        int x, y;
391        int baddr;
392
393        if (w != *screen)
394                return;
395        action_debug(select_extend_action, event, params, num_params);
396
397        /* Ignore initial drag events if are too near. */
398        if (down1_time != 0L &&
399            abs((int) event_x(event) - (int) down1_x) < CHAR_WIDTH &&
400            abs((int) event_y(event) - (int) down1_y) < CHAR_HEIGHT)
401                return;
402        else
403                down1_time = 0L;
404
405        /* If we moved the 3270 cursor on the first click, put it back. */
406        if (cursor_moved) {
407                cursor_move(saved_cursor_addr);
408                cursor_moved = False;
409        }
410
411        BOUNDED_XY(event, x, y);
412        baddr = ROWCOL_TO_BA(y, x);
413
414        /*
415         * If baddr falls outside if the v range, open up the v range.  In
416         * addition, if we are extending one end of the v range, make sure the
417         * other end at least covers the f range.
418         */
419        if (baddr <= v_start) {
420                v_start = baddr;
421                v_end = f_end;
422        }
423        if (baddr >= v_end) {
424                v_end = baddr;
425                v_start = f_start;
426        }
427
428        /*
429         * If baddr falls within the v range, narrow up the nearer end of the
430         * v range.
431         */
432        if (baddr > v_start && baddr < v_end) {
433                if (baddr - v_start < v_end - baddr)
434                        v_start = baddr;
435                else
436                        v_end = baddr;
437        }
438
439        num_clicks = 0;
440        saw_motion = 1;
441        grab_sel(v_start, v_end, False, event_time(event));
442}
443
444/*
445 * End the selection.
446 * Usually bound to <BtnUp>.
447 */
448/*ARGSUSED*/
449void
450select_end_action(w, event, params, num_params)
451Widget w;
452XEvent *event;
453String *params;
454Cardinal *num_params;
455{
456        int i;
457        int x, y;
458
459        action_debug(select_end_action, event, params, num_params);
460
461        if (n_owned == -1) {
462                for (i = 0; i < NS; i++)
463                        own_sel[i].atom = None;
464                n_owned = 0;
465        }
466        for (i = 0; i < NS; i++)
467                if (i < *num_params)
468                        want_sel[i] = XInternAtom(display, params[i], False);
469                else
470                        want_sel[i] = None;
471        if (*num_params == 0)
472                want_sel[0] = XA_PRIMARY;
473
474        BOUNDED_XY(event, x, y);
475        up_time = event_time(event);
476
477        if (up_time - down_time > CLICK_INTERVAL)
478                num_clicks = 0;
479
480        if (++num_clicks > 3)
481                num_clicks = 1;
482
483        switch (num_clicks) {
484            case 1:
485                if (saw_motion) {
486                        f_start = v_start;
487                        f_end = v_end;
488                        grab_sel(f_start, f_end, True, event_time(event));
489                }
490                break;
491            case 2:
492                /*
493                 * If we moved the 3270 cursor on the first click, put it back.
494                 */
495                if (cursor_moved) {
496                        cursor_move(saved_cursor_addr);
497                        cursor_moved = False;
498                }
499                select_word(f_start, event_time(event));
500                break;
501            case 3:
502                select_line(f_start, event_time(event));
503                break;
504        }
505        saw_motion = 0;
506}
507
508/*
509 * Set the selection.
510 * Usually bound to the Copy key.
511 */
512/*ARGSUSED*/
513void
514set_select_action(w, event, params, num_params)
515Widget w;
516XEvent *event;
517String *params;
518Cardinal *num_params;
519{
520        int i;
521
522        action_debug(set_select_action, event, params, num_params);
523
524        if (!any_selected)
525                return;
526        if (n_owned == -1) {
527                for (i = 0; i < NS; i++)
528                        own_sel[i].atom = None;
529                n_owned = 0;
530        }
531        for (i = 0; i < NS; i++)
532                if (i < *num_params)
533                        want_sel[i] = XInternAtom(display, params[i], False);
534                else
535                        want_sel[i] = None;
536        if (*num_params == 0)
537                want_sel[0] = XA_PRIMARY;
538        own_sels(event_time(event));
539}
540
541/*
542 * MoveCursor action.  Not a selection operation, but it uses the same macros
543 * to map the mouse position onto a cursor position.
544 * Usually bound to Shift<Btn1Down>.
545 */
546/*ARGSUSED*/
547void
548MoveCursor_action(w, event, params, num_params)
549Widget w;
550XEvent *event;
551String *params;
552Cardinal *num_params;
553{
554        int x, y;
555        register int baddr;
556        int row, col;
557
558        action_debug(MoveCursor_action, event, params, num_params);
559
560        if (kybdlock) {
561                if (*num_params == 2)
562                        enq_ta(MoveCursor_action, params[0], params[1]);
563                return;
564        }
565
566        switch (*num_params) {
567            case 0:             /* mouse click, presumably */
568                if (w != *screen)
569                        return;
570                BOUNDED_XY(event, x, y);
571                baddr = ROWCOL_TO_BA(y, x);
572                cursor_move(baddr);
573                break;
574            case 2:             /* probably a macro call */
575                row = atoi(params[0]);
576                col = atoi(params[1]);
577                if (!IN_3270) {
578                        row--;
579                        col--;
580                }
581                if (row < 0)
582                        row = 0;
583                if (col < 0)
584                        col = 0;
585                baddr = ((row * COLS) + col) % (ROWS * COLS);
586                cursor_move(baddr);
587                break;
588            default:            /* couln't say */
589                popup_an_error("%s: illegal argument count",
590                    action_name(MoveCursor_action));
591                break;
592        }
593}
594
595/*
596 * Cut action.
597 * For now, merely erases all unprotected characters currently selected.
598 * In future, it may interact more with selections.
599 */
600#define ULS     sizeof(unsigned long)
601#define ULBS    (ULS * 8)
602
603/*ARGSUSED*/
604void
605Cut_action(w, event, params, num_params)
606Widget w;
607XEvent *event;
608String *params;
609Cardinal *num_params;
610{
611        register int baddr;
612        unsigned char fa = *get_field_attribute(0);
613        unsigned long *target;
614        register unsigned char repl;
615
616        action_debug(Cut_action, event, params, num_params);
617
618        target = (unsigned long *)XtCalloc(ULS, ((ROWS*COLS)+(ULBS-1))/ULBS);
619
620        /* Identify the positions to empty. */
621        for (baddr = 0; baddr < ROWS*COLS; baddr++) {
622                unsigned char c = screen_buf[baddr];
623
624                if (IS_FA(c))
625                        fa = c;
626                else if ((IN_ANSI || !FA_IS_PROTECTED(fa)) && SELECTED(baddr))
627                        target[baddr/ULBS] |= 1 << (baddr%ULBS);
628        }
629
630        /* Erase them. */
631        if (IN_3270)
632                repl = CG_null;
633        else
634                repl = CG_space;
635        for (baddr = 0; baddr < ROWS*COLS; baddr++)
636                if (target[baddr/ULBS] & (1 << (baddr%ULBS)))
637                        ctlr_add(baddr, repl, 0);
638
639        XtFree((XtPointer)target);
640}
641
642
643/*
644 * Screen side.
645 */
646
647static char    *select_buf = CN;
648static char    *sb_ptr = CN;
649static int      sb_size = 0;
650#define SB_CHUNK        1024
651
652static Time     sel_time;
653
654static void
655init_select_buf()
656{
657        if (select_buf == CN)
658                select_buf = XtMalloc(sb_size = SB_CHUNK);
659        sb_ptr = select_buf;
660}
661
662static void
663store_sel(c)
664char c;
665{
666        if (sb_ptr - select_buf >= sb_size) {
667                sb_size += SB_CHUNK;
668                select_buf = XtRealloc(select_buf, sb_size);
669                sb_ptr = select_buf + sb_size - SB_CHUNK;
670        }
671        *(sb_ptr++) = c;
672}
673
674static Boolean
675convert_sel(w, selection, target, type, value, length, format)
676Widget w;
677Atom *selection, *target, *type;
678XtPointer *value;
679unsigned long *length;
680int *format;
681{
682        int i;
683
684        /* Find the right selection. */
685        for (i = 0; i < NS; i++)
686                if (own_sel[i].atom == *selection)
687                        break;
688        if (i >= NS)    /* not my selection */
689                return False;
690
691        if (*target == XA_TARGETS(display)) {
692                Atom* targetP;
693                Atom* std_targets;
694                unsigned long std_length;
695
696                XmuConvertStandardSelection(w, sel_time, selection,
697                    target, type, (caddr_t*) &std_targets, &std_length, format);
698                *length = std_length + 5;
699                *value = (XtPointer) XtMalloc(sizeof(Atom) * (*length));
700                targetP = *(Atom**)value;
701                *targetP++ = XA_STRING;
702                *targetP++ = XA_TEXT(display);
703                *targetP++ = XA_COMPOUND_TEXT(display);
704                *targetP++ = XA_LENGTH(display);
705                *targetP++ = XA_LIST_LENGTH(display);
706                (void) MEMORY_MOVE((char *) targetP,
707                                   (char *) std_targets,
708                                   (int) (sizeof(Atom) * std_length));
709                XtFree((char *) std_targets);
710                *type = XA_ATOM;
711                *format = 32;
712                return True;
713        }
714
715        if (*target == XA_STRING ||
716            *target == XA_TEXT(display) ||
717            *target == XA_COMPOUND_TEXT(display)) {
718                if (*target == XA_COMPOUND_TEXT(display))
719                        *type = *target;
720                else
721                        *type = XA_STRING;
722                *length = strlen(own_sel[i].buffer);
723                *value = XtMalloc(*length);
724                (void) MEMORY_MOVE(*value, own_sel[i].buffer, (int) *length);
725                *format = 8;
726                return True;
727        }
728        if (*target == XA_LIST_LENGTH(display)) {
729                *value = XtMalloc(4);
730                if (sizeof(long) == 4)
731                        *(long *)*value = 1;
732                else {
733                        long temp = 1;
734                        (void) MEMORY_MOVE((char *) *value,
735                                           ((char*) &temp) + sizeof(long) - 4,
736                                           4);
737                }
738                *type = XA_INTEGER;
739                *length = 1;
740                *format = 32;
741                return True;
742        }
743        if (*target == XA_LENGTH(display)) {
744                *value = XtMalloc(4);
745                if (sizeof(long) == 4)
746                        *(long*)*value = strlen(own_sel[i].buffer);
747                else {
748                        long temp = strlen(own_sel[i].buffer);
749                        (void) MEMORY_MOVE((char *) *value,
750                                           ((char *) &temp) + sizeof(long) - 4,
751                                           4);
752                }
753                *type = XA_INTEGER;
754                *length = 1;
755                *format = 32;
756                return True;
757        }
758
759        if (XmuConvertStandardSelection(w, sel_time, selection,
760            target, type, (caddr_t *)value, length, format))
761                return True;
762
763        /* else */
764#if 0
765        printf("Unknown conversion request: %s to %s\n",
766            XGetAtomName(display, *selection),
767            XGetAtomName(display, *target));
768#endif
769        return False;
770}
771
772/*ARGSUSED*/
773static void
774lose_sel(w, selection)
775Widget w;
776Atom *selection;
777{
778        int i;
779
780        for (i = 0; i < NS; i++)
781                if (own_sel[i].atom != None && own_sel[i].atom == *selection) {
782                        own_sel[i].atom = None;
783                        XtFree(own_sel[i].buffer);
784                        own_sel[i].buffer = CN;
785                        n_owned--;
786                        break;
787                }
788        if (!n_owned)
789                unselect(0, ROWS*COLS);
790}
791
792/*
793 * Somewhat convoluted logic to return an ASCII character for a given screen
794 * position.
795 *
796 * The character has to be found indirectly from screen_buf and the field
797 * attirbutes, so that zero-intensity fields become blanks.
798 */
799static Boolean osc_valid = False;
800
801static void
802osc_start()
803{
804        osc_valid = False;
805}
806
807static unsigned char
808onscreen_char(baddr, ge)
809int baddr;
810Boolean *ge;
811{
812        static int osc_baddr;
813        static unsigned char fa;
814
815        /* If we aren't moving forward, all bets are off. */
816        if (osc_valid && baddr < osc_baddr)
817                osc_valid = False;
818
819        if (osc_valid) {
820                /*
821                 * Search for a new field attribute between the address we
822                 * want and the last address we searched.  If we found a new
823                 * field attribute, save the address for next time.
824                 */
825                (void) get_bounded_field_attribute(baddr, osc_baddr, &fa);
826                osc_baddr = baddr;
827        } else {
828                /*
829                 * Find the attribute the old way.
830                 */
831                fa = *get_field_attribute(baddr);
832                osc_baddr = baddr;
833                osc_valid = True;
834        }
835
836        *ge = False;
837        if (FA_IS_ZERO(fa))
838                return ' ';
839        else {
840                switch (ea_buf[baddr].cs) {
841                    case 0:
842                    default:
843                        return cg2asc[screen_buf[baddr]];
844                    case 1:
845                        if (screen_buf[baddr] == CG_Yacute)
846                                return '[';
847                        else if (screen_buf[baddr] == CG_diaeresis)
848                                return ']';
849                        *ge = True;
850                        return cg2asc[screen_buf[baddr]];
851                    case 2:
852                        return screen_buf[baddr] + 0x5f;
853                }
854        }
855}
856
857/*
858 * Attempt to own the selections in want_sel[].
859 */
860static void
861own_sels(t)
862Time t;
863{
864        register int i, j;
865
866        /*
867         * Try to grab any new selections we may want.
868         */
869        for (i = 0; i < NS; i++) {
870                Boolean already_own = False;
871
872                if (want_sel[i] == None)
873                        continue;
874
875                /* Check if we already own it. */
876                for (j = 0; j < NS; j++)
877                        if (own_sel[j].atom == want_sel[i]) {
878                                already_own = True;
879                                break;
880                        }
881
882                /* Find the slot for it. */
883                if (!already_own) {
884                        for (j = 0; j < NS; j++)
885                                if (own_sel[j].atom == None)
886                                        break;
887                        if (j >= NS)
888                                continue;
889                }
890
891                if (XtOwnSelection(*screen, want_sel[i], t, convert_sel,
892                    lose_sel, NULL)) {
893                        if (!already_own) {
894                                n_owned++;
895                                own_sel[j].atom = want_sel[i];
896                        }
897                        if (own_sel[j].buffer != CN)
898                                XtFree(own_sel[j].buffer);
899                        own_sel[j].buffer = XtMalloc(strlen(select_buf) + 1);
900                        MEMORY_MOVE(own_sel[j].buffer, select_buf,
901                            strlen(select_buf) + 1);
902                } else {
903                        XtWarning("Could not get selection");
904                        if (own_sel[j].atom != None) {
905                                XtFree(own_sel[j].buffer);
906                                own_sel[j].buffer = CN;
907                                own_sel[j].atom = None;
908                                n_owned--;
909                        }
910                }
911        }
912        if (!n_owned)
913                unselect(0, ROWS*COLS);
914        sel_time = t;
915}
916
917/*
918 * Copy the selected area on the screen into a buffer and attempt to
919 * own the selections in want_sel[].
920 */
921static void
922grab_sel(start, end, really, t)
923int start, end;
924Boolean really;
925Time t;
926{
927        register int i;
928        int start_row, end_row;
929        unsigned char osc;
930        Boolean ge;
931
932        unselect(0, ROWS*COLS);
933
934        if (start > end) {
935                int exch = end;
936
937                end = start;
938                start = exch;
939        }
940
941        start_row = start / COLS;
942        end_row = end / COLS;
943
944        init_select_buf();      /* prime the store_sel() routine */
945        osc_start();            /* prime the onscreen_char() routine */
946
947        if (!ever_3270 && !toggled(RECTANGLE_SELECT)) {
948                /* Continuous selections */
949                for (i = start; i <= end; i++) {
950                        SET_SELECT(i);
951                        if (really) {
952                                if (i != start && !(i % COLS))
953                                        store_sel('\n');
954                                osc = onscreen_char(i, &ge);
955                                if (ge)
956                                        store_sel('\033');
957                                store_sel((char)osc);
958                        }
959                }
960                /* Check for newline extension */
961                if ((end % COLS) != (COLS - 1)) {
962                        Boolean all_blank = True;
963
964                        for (i = end; i < end + (COLS - (end % COLS)); i++)
965                                if (onscreen_char(i, &ge) != ' ') {
966                                        all_blank = False;
967                                        break;
968                                }
969                        if (all_blank) {
970                                for (i = end; i < end + (COLS - (end % COLS)); i++)
971                                        SET_SELECT(i);
972                                store_sel('\n');
973                        }
974                }
975        } else {
976                /* Rectangular selections */
977                if (start_row == end_row) {
978                        for (i = start; i <= end; i++) {
979                                SET_SELECT(i);
980                                if (really) {
981                                        osc = onscreen_char(i, &ge);
982                                        if (ge)
983                                                store_sel('\033');
984                                        store_sel((char)osc);
985                                }
986                        }
987                        if (really && (end % COLS == COLS - 1))
988                                store_sel('\n');
989                } else {
990                        int row, col;
991                        int start_col = start % COLS;
992                        int end_col = end % COLS;
993
994                        if (start_col > end_col) {
995                                int exch = end_col;
996
997                                end_col = start_col;
998                                start_col = exch;
999                        }
1000
1001                        for (row = start_row; row <= end_row; row++) {
1002                                for (col = start_col; col <= end_col; col++) {
1003                                        SET_SELECT(row*COLS + col);
1004                                        if (really) {
1005                                                osc = onscreen_char(row*COLS + col, &ge);
1006                                                if (ge)
1007                                                        store_sel('\033');
1008                                                store_sel((char)osc);
1009                                        }
1010                                }
1011                                if (really)
1012                                        store_sel('\n');
1013                        }
1014                }
1015        }
1016
1017        /* Trim trailing blanks on each line */
1018        if (really) {
1019                int k, l;
1020                char c;
1021                int nb = 0;
1022                int iy = 0;
1023
1024                store_sel('\0');
1025                for (k = 0; (c = select_buf[k]); k++) {
1026                        if (c == ' ')
1027                                nb++;
1028                        else {
1029                                if (c != '\n') {
1030                                        for (l = 0; l < nb; l++)
1031                                                select_buf[iy++] = ' ';
1032                                }
1033                                select_buf[iy++] = c;
1034                                nb = 0;
1035                        }
1036                }
1037                select_buf[iy] = '\0';
1038        }
1039        any_selected = True;
1040        ctlr_changed(0, ROWS*COLS);
1041        if (really)
1042                own_sels(t);
1043}
1044
1045/*
1046 * Check if any character in a given region is selected.
1047 */
1048Boolean
1049area_is_selected(baddr, len)
1050int baddr, len;
1051{
1052        register int i;
1053
1054        for (i = 0; i < len; i++)
1055                if (SELECTED(baddr+i))
1056                        return True;
1057        return False;
1058}
1059
1060/*
1061 * Unhighlight the region of selected text -- but don't give up the selection.
1062 */
1063/*ARGSUSED*/
1064void
1065unselect(baddr, len)
1066int baddr;
1067int len;
1068{
1069        if (any_selected) {
1070                (void) memset((char *) selected, 0, (ROWS*COLS + 7) / 8);
1071                ctlr_changed(0, ROWS*COLS);
1072                any_selected = False;
1073        }
1074}
Note: See TracBrowser for help on using the repository browser.