Home | History | Annotate | Line # | Download | only in wsmoused
selection.c revision 1.3
      1 /* $NetBSD: selection.c,v 1.3 2002/12/25 19:04:27 jmmv Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Julio Merino.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. The name authors may not be used to endorse or promote products
     16  *    derived from this software without specific prior written
     17  *    permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
     20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     25  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 
     34 #ifndef lint
     35 __RCSID("$NetBSD: selection.c,v 1.3 2002/12/25 19:04:27 jmmv Exp $");
     36 #endif /* not lint */
     37 
     38 #include <sys/ioctl.h>
     39 #include <sys/time.h>
     40 #include <sys/types.h>
     41 #include <sys/tty.h>
     42 #include <dev/wscons/wsconsio.h>
     43 
     44 #include <ctype.h>
     45 #include <fcntl.h>
     46 #include <err.h>
     47 #include <errno.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 
     53 #include "pathnames.h"
     54 #include "wsmoused.h"
     55 
     56 /* This struct holds information about a sel. For now there is
     57  * only one global instace, but using a structre gives us a place for
     58  * maintaining all the variables together. Also, someone may want to
     59  * allow multiple sels, so it is easier this way. */
     60 static struct selection {
     61 	size_t start_row, start_col;
     62 	size_t end_row, end_col;
     63 	size_t abs_start, abs_end;
     64 	size_t text_size;
     65 	char *text;
     66 } sel;
     67 
     68 
     69 static void *
     70 alloc_sel(size_t len)
     71 {
     72 	void *ptr;
     73 	if ((ptr = malloc(len)) == NULL) {
     74 		warn("Cannot allocate memory for sel %lu",
     75 		    (unsigned long)len);
     76 		return NULL;
     77 	}
     78 	return ptr;
     79 }
     80 
     81 /*
     82  * Copies a region of a line inside the buffer pointed by ptr. We use
     83  * a double pointer because we modify the pointer. When the function
     84  * finishes, ptr points to the end of the buffer.
     85  */
     86 static char *
     87 fill_buf(char *ptr, struct mouse *m, size_t row, size_t col, size_t end)
     88 {
     89 	struct wsdisplay_char ch;
     90 	ch.row = row;
     91 	for (ch.col = col; ch.col < end; ch.col++) {
     92 		if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1) {
     93 			warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
     94 			*ptr++ = ' ';
     95 		} else {
     96 			*ptr++ = ch.letter;
     97 		}
     98 	}
     99 	return ptr;
    100 }
    101 
    102 
    103 /*
    104  * This function scans the specified line and checks its
    105  * length. Characters at the end of it which match isspace() are not
    106  * counted.
    107  */
    108 static size_t
    109 row_length(struct mouse *m, size_t row)
    110 {
    111 	struct wsdisplay_char ch;
    112 
    113 	ch.col = m->max_col;
    114 	ch.row = row;
    115 	do {
    116 		if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1)
    117 			warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
    118 		ch.col--;
    119 	} while (isspace((unsigned char)ch.letter) && ch.col >= 0);
    120 	return ch.col + 2;
    121 }
    122 
    123 /*
    124  * This (complex) function copies all the text englobed in the current
    125  * sel to the sel buffer. It does space trimming at end of
    126  * lines if it is selected.
    127  */
    128 static void
    129 sel_copy_text(struct mouse *m)
    130 {
    131 	char *str, *ptr;
    132 	size_t r, l;
    133 
    134 	if (sel.start_row == sel.end_row) {
    135 		/* Selection is one row */
    136 		l = row_length(m, sel.start_row);
    137 		if (sel.start_col > l)
    138 			/* Selection is after last character,
    139 			 * therefore it is empty */
    140 			str = NULL;
    141 		else {
    142 			if (sel.end_col > l)
    143 				sel.end_col = l;
    144 			ptr = str = alloc_sel(sel.end_col - sel.start_col + 1);
    145 			if (ptr == NULL)
    146 				return;
    147 
    148 			ptr = fill_buf(ptr, m, sel.start_row, sel.start_col,
    149 			    sel.end_col);
    150 			*ptr = '\0';
    151 		}
    152 	} else {
    153 		/* Selection is multiple rows */
    154 		ptr = str = alloc_sel(sel.abs_end - sel.abs_start + 1);
    155 		if (ptr == NULL)
    156 			return;
    157 
    158 		/* Calculate and copy first line */
    159 		l = row_length(m, sel.start_row);
    160 		if (sel.start_col < l) {
    161 			ptr = fill_buf(ptr, m, sel.start_row, sel.start_col, l);
    162 			*ptr++ = '\r';
    163 		}
    164 
    165 		/* Copy mid lines if there are any */
    166 		if ((sel.end_row - sel.start_row) > 1) {
    167 			for (r = sel.start_row + 1; r <= sel.end_row - 1; r++) {
    168 				ptr = fill_buf(ptr, m, r, 0, row_length(m, r));
    169 				*ptr++ = '\r';
    170 			}
    171 		}
    172 
    173 		/* Calculate and copy end line */
    174 		l = row_length(m, sel.end_row);
    175 		if (sel.end_col < l)
    176 			l = sel.end_col;
    177 		ptr = fill_buf(ptr, m, sel.end_row, 0, l);
    178 		*ptr = '\0';
    179 	}
    180 
    181 	if (sel.text != NULL) {
    182 		free(sel.text);
    183 		sel.text = NULL;
    184 	}
    185 
    186 	if (str != NULL) {
    187 		sel.text = str;
    188 		sel.text_size = ptr - str;
    189 	}
    190 }
    191 
    192 /*
    193  * Initializes sel data. It should be called only once, at
    194  * wsmoused startup to initialize pointers.
    195  */
    196 void
    197 mouse_sel_init()
    198 {
    199 	memset(&sel, 0, sizeof(struct selection));
    200 }
    201 
    202 /*
    203  * Starts a sel (when mouse is pressed).
    204  */
    205 void
    206 mouse_sel_start(struct mouse *m)
    207 {
    208 	if (sel.text != NULL) {
    209 		free(sel.text);
    210 		sel.text = NULL;
    211 	}
    212 
    213 	sel.start_row = m->row;
    214 	sel.start_col = m->col;
    215 	mouse_sel_calculate(m);
    216 	m->selecting = 1;
    217 }
    218 
    219 /*
    220  * Ends a sel. Text is copied to memory for future pasting and
    221  * highlighted region is returned to normal state.
    222  */
    223 void
    224 mouse_sel_end(struct mouse *m)
    225 {
    226 	size_t i;
    227 
    228 	mouse_sel_calculate(m);
    229 
    230 	/* Invert sel coordinates if needed */
    231 	if (sel.start_col > sel.end_col) {
    232 		i = sel.end_col;
    233 		sel.end_col = sel.start_col;
    234 		sel.start_col = i;
    235 	}
    236 	if (sel.start_row > sel.end_row) {
    237 		i = sel.end_row;
    238 		sel.end_row = sel.start_row;
    239 		sel.start_row = i;
    240 	}
    241 
    242 	sel_copy_text(m);
    243 	m->selecting = 0;
    244 }
    245 
    246 /*
    247  * Calculates sel absolute postitions.
    248  */
    249 void
    250 mouse_sel_calculate(struct mouse *m)
    251 {
    252 	size_t i = m->max_col + 1;
    253 
    254 	sel.end_row = m->row;
    255 	sel.end_col = m->col;
    256 	sel.abs_start = sel.start_row * i + sel.start_col;
    257 	sel.abs_end = sel.end_row * i + sel.end_col;
    258 
    259 	if (sel.abs_start > sel.abs_end) {
    260 		i = sel.abs_end;
    261 		sel.abs_end = sel.abs_start;
    262 		sel.abs_start = i;
    263 	}
    264 }
    265 
    266 /*
    267  * Hides highlighted region, returning it to normal colors.
    268  */
    269 void
    270 mouse_sel_hide(struct mouse *m)
    271 {
    272 	size_t i;
    273 
    274 	for (i = sel.abs_start; i <= sel.abs_end; i++)
    275 		char_invert(m, 0, i);
    276 }
    277 
    278 /*
    279  * Highlights selected region.
    280  */
    281 void
    282 mouse_sel_show(struct mouse *m)
    283 {
    284 	size_t i;
    285 
    286 	mouse_sel_calculate(m);
    287 	for (i = sel.abs_start; i <= sel.abs_end; i++)
    288 		char_invert(m, 0, i);
    289 }
    290 
    291 
    292 /*
    293  * Pastes selected text into the active console.
    294  */
    295 void
    296 mouse_sel_paste(struct mouse *m)
    297 {
    298 	size_t i;
    299 
    300 	if (sel.text == NULL)
    301 		return;
    302 	for (i = 0; i < sel.text_size; i++)
    303 		if (ioctl(m->tty_fd, TIOCSTI, &sel.text[i]) == -1)
    304 			warn("ioctl(TIOCSTI)");
    305 }
    306