Home | History | Annotate | Line # | Download | only in wsmoused
selection.c revision 1.1
      1 /* $NetBSD: selection.c,v 1.1 2002/06/26 23:13:08 christos 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.1 2002/06/26 23:13:08 christos 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 static void
     82 fill_buf(char *ptr, struct mouse *m, size_t row, size_t col, size_t end)
     83 {
     84 	struct wsdisplay_char ch;
     85 	ch.row = sel.start_row;
     86 	for (ch.col = col; ch.col < end; ch.col++) {
     87 		if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1) {
     88 			warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
     89 			*ptr++ = ' ';
     90 		} else {
     91 			*ptr++ = ch.letter;
     92 		}
     93 	}
     94 }
     95 
     96 
     97 /*
     98  * This function scans the specified line and checks its
     99  * length. Characters at the end of it which match isspace() are not
    100  * counted.
    101  */
    102 static size_t
    103 row_length(struct mouse *m, size_t row)
    104 {
    105 	struct wsdisplay_char ch;
    106 
    107 	ch.col = m->max_col;
    108 	ch.row = row;
    109 	do {
    110 		if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1)
    111 			warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
    112 		ch.col--;
    113 	} while (isspace((unsigned char)ch.letter));
    114 	return ch.col + 2;
    115 }
    116 
    117 /*
    118  * This (complex) function copies all the text englobed in the current
    119  * sel to the sel buffer. It does space trimming at end of
    120  * lines if it is selected.
    121  */
    122 static void
    123 sel_copy_text(struct mouse *m)
    124 {
    125 	char *str, *ptr;
    126 	size_t r, l;
    127 
    128 	if (sel.start_row == sel.end_row) {
    129 		/* Selection is one row */
    130 		l = row_length(m, sel.start_row);
    131 		if (sel.start_col > l)
    132 			/* Selection is after last character,
    133 			 * therefore it is empty */
    134 			str = NULL;
    135 		else {
    136 			if (sel.end_col > l)
    137 				sel.end_col = l;
    138 			ptr = str = alloc_sel( sel.end_col - sel.start_col + 1);
    139 			if (ptr == NULL)
    140 				return;
    141 
    142 			fill_buf(ptr, m, sel.start_row, sel.start_col,
    143 			    sel.end_col);
    144 			*ptr = '\0';
    145 		}
    146 	} else {
    147 		/* Selection is multiple rows */
    148 		ptr = str =  alloc_sel(sel.abs_end - sel.abs_start + 1);
    149 		if (ptr == NULL)
    150 			return;
    151 
    152 		/* Calculate and copy first line */
    153 		l = row_length(m, sel.start_row);
    154 		if (sel.start_col < l) {
    155 			fill_buf(ptr, m, sel.start_row, sel.start_col, l);
    156 			*ptr++ = '\r';
    157 		}
    158 
    159 		/* Copy mid lines if there are any */
    160 		if ((sel.end_row - sel.start_row) > 1) {
    161 			for (r = sel.start_row + 1; r <= sel.end_row - 1; r++) {
    162 				fill_buf(ptr, m, r, 0, row_length(m, r));
    163 				*ptr++ = '\r';
    164 			}
    165 		}
    166 
    167 		/* Calculate and copy end line */
    168 		l = row_length(m, sel.end_row);
    169 		if (sel.end_col < l)
    170 			l = sel.end_col;
    171 		fill_buf(ptr, m, sel.end_row, 0, l);
    172 		*ptr = '\0';
    173 	}
    174 
    175 	if (sel.text != NULL) {
    176 		free(sel.text);
    177 		sel.text = NULL;
    178 	}
    179 
    180 	if (str != NULL) {
    181 		sel.text = str;
    182 		sel.text_size = ptr - str;
    183 	}
    184 }
    185 
    186 /*
    187  * Initializes sel data. It should be called only once, at
    188  * wsmoused startup to initialize pointers.
    189  */
    190 void
    191 mouse_sel_init()
    192 {
    193 	memset(&sel, 0, sizeof(struct selection));
    194 }
    195 
    196 /*
    197  * Starts a sel (when mouse is pressed).
    198  */
    199 void
    200 mouse_sel_start(struct mouse *m)
    201 {
    202 	if (sel.text != NULL) {
    203 		free(sel.text);
    204 		sel.text = NULL;
    205 	}
    206 
    207 	sel.start_row = m->row;
    208 	sel.start_col = m->col;
    209 	mouse_sel_calculate(m);
    210 	m->selecting = 1;
    211 }
    212 
    213 /*
    214  * Ends a sel. Text is copied to memory for future pasting and
    215  * highlighted region is returned to normal state.
    216  */
    217 void
    218 mouse_sel_end(struct mouse *m)
    219 {
    220 	size_t i;
    221 
    222 	mouse_sel_calculate(m);
    223 
    224 	/* Invert sel coordinates if needed */
    225 	if (sel.start_col > sel.end_col) {
    226 		i = sel.end_col;
    227 		sel.end_col = sel.start_col;
    228 		sel.start_col = i;
    229 	}
    230 	if (sel.start_row > sel.end_row) {
    231 		i = sel.end_row;
    232 		sel.end_row = sel.start_row;
    233 		sel.start_row = i;
    234 	}
    235 
    236 	sel_copy_text(m);
    237 	m->selecting = 0;
    238 }
    239 
    240 /*
    241  * Calculates sel absolute postitions.
    242  */
    243 void
    244 mouse_sel_calculate(struct mouse *m)
    245 {
    246 	size_t i = m->max_col + 1;
    247 
    248 	sel.end_row = m->row;
    249 	sel.end_col = m->col;
    250 	sel.abs_start = sel.start_row * i + sel.start_col;
    251 	sel.abs_end = sel.end_row * i + sel.end_col;
    252 
    253 	if (sel.abs_start > sel.abs_end) {
    254 		i = sel.abs_end;
    255 		sel.abs_end = sel.abs_start;
    256 		sel.abs_start = i;
    257 	}
    258 }
    259 
    260 /*
    261  * Hides highlighted region, returning it to normal colors.
    262  */
    263 void
    264 mouse_sel_hide(struct mouse *m)
    265 {
    266 	size_t i;
    267 
    268 	for (i = sel.abs_start; i <= sel.abs_end; i++)
    269 		char_invert(m, 0, i);
    270 }
    271 
    272 /*
    273  * Highlights selected region.
    274  */
    275 void
    276 mouse_sel_show(struct mouse *m)
    277 {
    278 	size_t i;
    279 
    280 	mouse_sel_calculate(m);
    281 	for (i = sel.abs_start; i <= sel.abs_end; i++)
    282 		char_invert(m, 0, i);
    283 }
    284 
    285 
    286 /*
    287  * Pastes selected text into the active console.
    288  */
    289 void
    290 mouse_sel_paste(struct mouse *m)
    291 {
    292 	size_t i;
    293 
    294 	if (sel.text == NULL)
    295 		return;
    296 	for (i = 0; i < sel.text_size; i++)
    297 		if (ioctl(m->tty_fd, TIOCSTI, &sel.text[i]) == -1)
    298 			warn("ioctl(TIOCSTI)");
    299 }
    300