1 /*- 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/dev/syscons/scmouse.c,v 1.12.2.3 2001/07/28 12:51:47 yokota Exp $ 27 */ 28 29 #include "opt_syscons.h" 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/conf.h> 35 #include <sys/signalvar.h> 36 #include <sys/proc.h> 37 #include <sys/tty.h> 38 #include <sys/thread2.h> 39 40 #include <machine/console.h> 41 #include <sys/mouse.h> 42 43 #include "syscons.h" 44 45 #ifdef SC_TWOBUTTON_MOUSE 46 #define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON3DOWN /* right button */ 47 #define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON2DOWN /* not really used */ 48 #else 49 #define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON2DOWN /* middle button */ 50 #define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON3DOWN /* right button */ 51 #endif /* SC_TWOBUTTON_MOUSE */ 52 53 #define SC_WAKEUP_DELTA 20 54 55 #ifndef SC_NO_SYSMOUSE 56 57 static int cut_buffer_size; 58 static u_char *cut_buffer; 59 60 /* local functions */ 61 static void sc_mouse_init(void *); 62 static void sc_mouse_uninit(void *); 63 64 static void set_mouse_pos(scr_stat *scp); 65 #ifndef SC_NO_CUTPASTE 66 static int skip_spc_right(scr_stat *scp, int p); 67 static int skip_spc_left(scr_stat *scp, int p); 68 static void mouse_cut(scr_stat *scp); 69 static void mouse_cut_start(scr_stat *scp); 70 static void mouse_cut_end(scr_stat *scp); 71 static void mouse_cut_word(scr_stat *scp); 72 static void mouse_cut_line(scr_stat *scp); 73 static void mouse_cut_extend(scr_stat *scp); 74 static void mouse_paste(scr_stat *scp); 75 #endif /* SC_NO_CUTPASTE */ 76 77 static struct lwkt_token scmouse_tok = LWKT_TOKEN_INITIALIZER(scmouse_tok); 78 79 #ifndef SC_NO_CUTPASTE 80 /* allocate a cut buffer */ 81 void 82 sc_alloc_cut_buffer(scr_stat *scp, int wait) 83 { 84 u_char *p; 85 86 if ((cut_buffer == NULL) 87 || (cut_buffer_size < scp->xsize * scp->ysize + 1)) { 88 p = cut_buffer; 89 cut_buffer = NULL; 90 if (p != NULL) 91 kfree(p, M_SYSCONS); 92 cut_buffer_size = scp->xsize * scp->ysize + 1; 93 p = kmalloc(cut_buffer_size, M_SYSCONS, (wait) ? M_WAITOK : M_NOWAIT); 94 if (p != NULL) 95 p[0] = '\0'; 96 cut_buffer = p; 97 } 98 } 99 #endif /* SC_NO_CUTPASTE */ 100 101 /* move mouse */ 102 void 103 sc_mouse_move(scr_stat *scp, int x, int y) 104 { 105 crit_enter(); 106 scp->mouse_xpos = scp->mouse_oldxpos = x; 107 scp->mouse_ypos = scp->mouse_oldypos = y; 108 if (scp->font_height <= 0) 109 scp->mouse_pos = scp->mouse_oldpos = 0; 110 else 111 scp->mouse_pos = scp->mouse_oldpos = 112 (y / scp->font_height - scp->yoff) * scp->xsize + 113 x / scp->font_width - scp->xoff; 114 scp->status |= MOUSE_MOVED; 115 crit_exit(); 116 } 117 118 /* adjust mouse position */ 119 static void 120 set_mouse_pos(scr_stat *scp) 121 { 122 if (scp->mouse_xpos < scp->xoff * scp->font_width) 123 scp->mouse_xpos = scp->xoff * scp->font_width; 124 if (scp->mouse_ypos < scp->yoff * scp->font_height) 125 scp->mouse_ypos = scp->yoff * scp->font_height; 126 if (ISGRAPHSC(scp)) { 127 if (scp->mouse_xpos > scp->xpixel - 1) 128 scp->mouse_xpos = scp->xpixel - 1; 129 if (scp->mouse_ypos > scp->ypixel - 1) 130 scp->mouse_ypos = scp->ypixel - 1; 131 return; 132 } else { 133 if (scp->mouse_xpos > (scp->xsize + scp->xoff) * scp->font_width - 1) 134 scp->mouse_xpos = (scp->xsize + scp->xoff) * scp->font_width - 1; 135 if (scp->mouse_ypos > (scp->ysize + scp->yoff) * scp->font_height - 1) 136 scp->mouse_ypos = (scp->ysize + scp->yoff) * scp->font_height - 1; 137 } 138 139 if (scp->mouse_xpos != scp->mouse_oldxpos || 140 scp->mouse_ypos != scp->mouse_oldypos) { 141 scp->status |= MOUSE_MOVED; 142 scp->mouse_pos = 143 (scp->mouse_ypos / scp->font_height - scp->yoff) * scp->xsize + 144 scp->mouse_xpos / scp->font_width - scp->xoff; 145 #ifndef SC_NO_CUTPASTE 146 if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING)) 147 mouse_cut(scp); 148 #endif 149 } 150 } 151 152 #ifndef SC_NO_CUTPASTE 153 154 void 155 sc_draw_mouse_image(scr_stat *scp) 156 { 157 if (ISGRAPHSC(scp)) 158 return; 159 160 atomic_add_int(&scp->sc->videoio_in_progress, 1); 161 (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE); 162 scp->mouse_oldpos = scp->mouse_pos; 163 scp->mouse_oldxpos = scp->mouse_xpos; 164 scp->mouse_oldypos = scp->mouse_ypos; 165 scp->status |= MOUSE_VISIBLE; 166 atomic_add_int(&scp->sc->videoio_in_progress, -1); 167 } 168 169 void 170 sc_remove_mouse_image(scr_stat *scp) 171 { 172 int size; 173 int i; 174 175 if (ISGRAPHSC(scp)) 176 return; 177 178 atomic_add_int(&scp->sc->videoio_in_progress, 1); 179 (*scp->rndr->draw_mouse)(scp, 180 (scp->mouse_oldpos%scp->xsize + scp->xoff) * 181 scp->font_width, 182 (scp->mouse_oldpos/scp->xsize + scp->yoff) * 183 scp->font_height, 184 FALSE); 185 size = scp->xsize * scp->ysize; 186 i = scp->mouse_oldpos; 187 mark_for_update(scp, i); 188 mark_for_update(scp, i); 189 if (i + scp->xsize + 1 < size) { 190 mark_for_update(scp, i + scp->xsize + 1); 191 } else if (i + scp->xsize < size) { 192 mark_for_update(scp, i + scp->xsize); 193 } else if (i + 1 < size) { 194 mark_for_update(scp, i + 1); 195 } 196 scp->status &= ~MOUSE_VISIBLE; 197 atomic_add_int(&scp->sc->videoio_in_progress, -1); 198 } 199 200 int 201 sc_inside_cutmark(scr_stat *scp, int pos) 202 { 203 int start; 204 int end; 205 206 if (scp->mouse_cut_end < 0) 207 return FALSE; 208 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 209 start = scp->mouse_cut_start; 210 end = scp->mouse_cut_end; 211 } else { 212 start = scp->mouse_cut_end; 213 end = scp->mouse_cut_start - 1; 214 } 215 return ((start <= pos) && (pos <= end)); 216 } 217 218 void 219 sc_remove_cutmarking(scr_stat *scp) 220 { 221 crit_enter(); 222 if (scp->mouse_cut_end >= 0) { 223 mark_for_update(scp, scp->mouse_cut_start); 224 mark_for_update(scp, scp->mouse_cut_end); 225 } 226 scp->mouse_cut_start = scp->xsize*scp->ysize; 227 scp->mouse_cut_end = -1; 228 crit_exit(); 229 scp->status &= ~MOUSE_CUTTING; 230 } 231 232 void 233 sc_remove_all_cutmarkings(sc_softc_t *sc) 234 { 235 scr_stat *scp; 236 int i; 237 238 /* delete cut markings in all vtys */ 239 for (i = 0; i < sc->vtys; ++i) { 240 scp = SC_STAT(sc->dev[i]); 241 if (scp == NULL) 242 continue; 243 sc_remove_cutmarking(scp); 244 } 245 } 246 247 void 248 sc_remove_all_mouse(sc_softc_t *sc) 249 { 250 scr_stat *scp; 251 int i; 252 253 for (i = 0; i < sc->vtys; ++i) { 254 scp = SC_STAT(sc->dev[i]); 255 if (scp == NULL) 256 continue; 257 if (scp->status & MOUSE_VISIBLE) { 258 scp->status &= ~MOUSE_VISIBLE; 259 mark_all(scp); 260 } 261 } 262 } 263 264 #define IS_SPACE_CHAR(c) (((c) & 0xff) == ' ') 265 266 /* skip spaces to right */ 267 static int 268 skip_spc_right(scr_stat *scp, int p) 269 { 270 int c; 271 int i; 272 273 for (i = p % scp->xsize; i < scp->xsize; ++i) { 274 c = sc_vtb_getc(&scp->vtb, p); 275 if (!IS_SPACE_CHAR(c)) 276 break; 277 ++p; 278 } 279 return i; 280 } 281 282 /* skip spaces to left */ 283 static int 284 skip_spc_left(scr_stat *scp, int p) 285 { 286 int c; 287 int i; 288 289 for (i = p-- % scp->xsize - 1; i >= 0; --i) { 290 c = sc_vtb_getc(&scp->vtb, p); 291 if (!IS_SPACE_CHAR(c)) 292 break; 293 --p; 294 } 295 return i; 296 } 297 298 /* copy marked region to the cut buffer */ 299 static void 300 mouse_cut(scr_stat *scp) 301 { 302 int start; 303 int end; 304 int from; 305 int to; 306 int blank; 307 int c; 308 int p; 309 int i; 310 311 start = scp->mouse_cut_start; 312 if (scp->mouse_pos >= start) { 313 from = start; 314 to = end = scp->mouse_pos; 315 } else { 316 from = end = scp->mouse_pos; 317 to = start - 1; 318 } 319 for (p = from, i = blank = 0; p <= to; ++p) { 320 cut_buffer[i] = sc_vtb_getc(&scp->vtb, p); 321 /* remember the position of the last non-space char */ 322 if (!IS_SPACE_CHAR(cut_buffer[i++])) 323 blank = i; /* the first space after the last non-space */ 324 /* trim trailing blank when crossing lines */ 325 if ((p % scp->xsize) == (scp->xsize - 1)) { 326 cut_buffer[blank] = '\r'; 327 i = blank + 1; 328 } 329 } 330 cut_buffer[i] = '\0'; 331 332 /* scan towards the end of the last line */ 333 --p; 334 for (i = p % scp->xsize; i < scp->xsize; ++i) { 335 c = sc_vtb_getc(&scp->vtb, p); 336 if (!IS_SPACE_CHAR(c)) 337 break; 338 ++p; 339 } 340 /* if there is nothing but blank chars, trim them, but mark towards eol */ 341 if (i >= scp->xsize) { 342 if (end >= start) 343 to = end = p - 1; 344 else 345 to = start = p; 346 cut_buffer[blank++] = '\r'; 347 cut_buffer[blank] = '\0'; 348 } 349 350 /* remove the current marking */ 351 crit_enter(); 352 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 353 mark_for_update(scp, scp->mouse_cut_start); 354 mark_for_update(scp, scp->mouse_cut_end); 355 } else if (scp->mouse_cut_end >= 0) { 356 mark_for_update(scp, scp->mouse_cut_end); 357 mark_for_update(scp, scp->mouse_cut_start); 358 } 359 360 /* mark the new region */ 361 scp->mouse_cut_start = start; 362 scp->mouse_cut_end = end; 363 mark_for_update(scp, from); 364 mark_for_update(scp, to); 365 crit_exit(); 366 } 367 368 /* a mouse button is pressed, start cut operation */ 369 static void 370 mouse_cut_start(scr_stat *scp) 371 { 372 int i; 373 int j; 374 375 if (scp->status & MOUSE_VISIBLE) { 376 i = scp->mouse_cut_start; 377 j = scp->mouse_cut_end; 378 sc_remove_all_cutmarkings(scp->sc); 379 if (scp->mouse_pos == i && i == j) { 380 cut_buffer[0] = '\0'; 381 } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) { 382 /* if the pointer is on trailing blank chars, mark towards eol */ 383 i = skip_spc_left(scp, scp->mouse_pos) + 1; 384 crit_enter(); 385 scp->mouse_cut_start = 386 (scp->mouse_pos / scp->xsize) * scp->xsize + i; 387 scp->mouse_cut_end = 388 (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1; 389 crit_exit(); 390 cut_buffer[0] = '\r'; 391 cut_buffer[1] = '\0'; 392 scp->status |= MOUSE_CUTTING; 393 } else { 394 crit_enter(); 395 scp->mouse_cut_start = scp->mouse_pos; 396 scp->mouse_cut_end = scp->mouse_cut_start; 397 crit_exit(); 398 cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start); 399 cut_buffer[1] = '\0'; 400 scp->status |= MOUSE_CUTTING; 401 } 402 mark_all(scp); /* this is probably overkill XXX */ 403 } 404 } 405 406 /* end of cut operation */ 407 static void 408 mouse_cut_end(scr_stat *scp) 409 { 410 if (scp->status & MOUSE_VISIBLE) 411 scp->status &= ~MOUSE_CUTTING; 412 } 413 414 /* copy a word under the mouse pointer */ 415 static void 416 mouse_cut_word(scr_stat *scp) 417 { 418 int start; 419 int end; 420 int sol; 421 int eol; 422 int c; 423 int i; 424 int j; 425 426 /* 427 * Because we don't have locale information in the kernel, 428 * we only distinguish space char and non-space chars. Punctuation 429 * chars, symbols and other regular chars are all treated alike. 430 */ 431 if (scp->status & MOUSE_VISIBLE) { 432 /* remove the current cut mark */ 433 crit_enter(); 434 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 435 mark_for_update(scp, scp->mouse_cut_start); 436 mark_for_update(scp, scp->mouse_cut_end); 437 } else if (scp->mouse_cut_end >= 0) { 438 mark_for_update(scp, scp->mouse_cut_end); 439 mark_for_update(scp, scp->mouse_cut_start); 440 } 441 scp->mouse_cut_start = scp->xsize*scp->ysize; 442 scp->mouse_cut_end = -1; 443 crit_exit(); 444 445 sol = (scp->mouse_pos / scp->xsize) * scp->xsize; 446 eol = sol + scp->xsize; 447 c = sc_vtb_getc(&scp->vtb, scp->mouse_pos); 448 if (IS_SPACE_CHAR(c)) { 449 /* blank space */ 450 for (j = scp->mouse_pos; j >= sol; --j) { 451 c = sc_vtb_getc(&scp->vtb, j); 452 if (!IS_SPACE_CHAR(c)) 453 break; 454 } 455 start = ++j; 456 for (j = scp->mouse_pos; j < eol; ++j) { 457 c = sc_vtb_getc(&scp->vtb, j); 458 if (!IS_SPACE_CHAR(c)) 459 break; 460 } 461 end = j - 1; 462 } else { 463 /* non-space word */ 464 for (j = scp->mouse_pos; j >= sol; --j) { 465 c = sc_vtb_getc(&scp->vtb, j); 466 if (IS_SPACE_CHAR(c)) 467 break; 468 } 469 start = ++j; 470 for (j = scp->mouse_pos; j < eol; ++j) { 471 c = sc_vtb_getc(&scp->vtb, j); 472 if (IS_SPACE_CHAR(c)) 473 break; 474 } 475 end = j - 1; 476 } 477 478 /* copy the found word */ 479 for (i = 0, j = start; j <= end; ++j) 480 cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); 481 cut_buffer[i] = '\0'; 482 scp->status |= MOUSE_CUTTING; 483 484 /* mark the region */ 485 crit_enter(); 486 scp->mouse_cut_start = start; 487 scp->mouse_cut_end = end; 488 mark_for_update(scp, start); 489 mark_for_update(scp, end); 490 crit_exit(); 491 } 492 } 493 494 /* copy a line under the mouse pointer */ 495 static void 496 mouse_cut_line(scr_stat *scp) 497 { 498 int i; 499 int j; 500 501 if (scp->status & MOUSE_VISIBLE) { 502 /* remove the current cut mark */ 503 crit_enter(); 504 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 505 mark_for_update(scp, scp->mouse_cut_start); 506 mark_for_update(scp, scp->mouse_cut_end); 507 } else if (scp->mouse_cut_end >= 0) { 508 mark_for_update(scp, scp->mouse_cut_end); 509 mark_for_update(scp, scp->mouse_cut_start); 510 } 511 512 /* mark the entire line */ 513 scp->mouse_cut_start = 514 (scp->mouse_pos / scp->xsize) * scp->xsize; 515 scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1; 516 mark_for_update(scp, scp->mouse_cut_start); 517 mark_for_update(scp, scp->mouse_cut_end); 518 crit_exit(); 519 520 /* copy the line into the cut buffer */ 521 for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j) 522 cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); 523 cut_buffer[i++] = '\r'; 524 cut_buffer[i] = '\0'; 525 scp->status |= MOUSE_CUTTING; 526 } 527 } 528 529 /* extend the marked region to the mouse pointer position */ 530 static void 531 mouse_cut_extend(scr_stat *scp) 532 { 533 int start; 534 int end; 535 536 if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING) 537 && (scp->mouse_cut_end >= 0)) { 538 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 539 start = scp->mouse_cut_start; 540 end = scp->mouse_cut_end; 541 } else { 542 start = scp->mouse_cut_end; 543 end = scp->mouse_cut_start - 1; 544 } 545 crit_enter(); 546 if (scp->mouse_pos > end) { 547 scp->mouse_cut_start = start; 548 scp->mouse_cut_end = end; 549 } else if (scp->mouse_pos < start) { 550 scp->mouse_cut_start = end + 1; 551 scp->mouse_cut_end = start; 552 } else { 553 if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) { 554 scp->mouse_cut_start = start; 555 scp->mouse_cut_end = end; 556 } else { 557 scp->mouse_cut_start = end + 1; 558 scp->mouse_cut_end = start; 559 } 560 } 561 crit_exit(); 562 mouse_cut(scp); 563 scp->status |= MOUSE_CUTTING; 564 } 565 } 566 567 /* paste cut buffer contents into the current vty */ 568 static void 569 mouse_paste(scr_stat *scp) 570 { 571 if (scp->status & MOUSE_VISIBLE) 572 sc_paste(scp, cut_buffer, strlen(cut_buffer)); 573 } 574 575 #endif /* SC_NO_CUTPASTE */ 576 577 static void 578 sc_mouse_exit1_proc(struct proc *p) 579 { 580 scr_stat *scp; 581 582 scp = p->p_drv_priv; 583 KKASSERT(scp != NULL); 584 585 lwkt_gettoken(&scmouse_tok); 586 KKASSERT(scp->mouse_proc == p); 587 KKASSERT(scp->mouse_pid == p->p_pid); 588 589 scp->mouse_signal = 0; 590 scp->mouse_proc = NULL; 591 scp->mouse_pid = 0; 592 lwkt_reltoken(&scmouse_tok); 593 594 PRELE(p); 595 p->p_flags &= ~P_SCMOUSE; 596 p->p_drv_priv = NULL; 597 } 598 599 /* 600 * sc_mouse_exit1: 601 * 602 * Handle exit1 for processes registered as MOUSE_MODE handlers. 603 * We must remove a process hold, established when MOUSE_MODE 604 * was enabled. 605 */ 606 static void 607 sc_mouse_exit1(struct thread *td) 608 { 609 struct proc *p; 610 611 p = td->td_proc; 612 KKASSERT(p != NULL); 613 614 if ((p->p_flags & P_SCMOUSE) == 0) 615 return; 616 617 618 sc_mouse_exit1_proc(p); 619 } 620 621 int 622 sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) 623 { 624 mouse_info_t *mouse; 625 scr_stat *cur_scp; 626 scr_stat *scp; 627 int f; 628 629 scp = SC_STAT(tp->t_dev); 630 631 switch (cmd) { 632 633 case CONS_MOUSECTL: /* control mouse arrow */ 634 mouse = (mouse_info_t*) data; 635 cur_scp = scp->sc->cur_scp; 636 637 switch (mouse->operation) { 638 /* 639 * Setup a process to receive signals on mouse events. 640 */ 641 case MOUSE_MODE: 642 lwkt_gettoken(&scmouse_tok); 643 644 if (!ISSIGVALID(mouse->u.mode.signal)) { 645 /* Setting MOUSE_MODE w/ an invalid signal is used to disarm */ 646 if (scp->mouse_proc == curproc) { 647 sc_mouse_exit1_proc(curproc); 648 lwkt_reltoken(&scmouse_tok); 649 return 0; 650 } else { 651 lwkt_reltoken(&scmouse_tok); 652 return EINVAL; 653 } 654 } else { 655 /* Only one mouse process per syscons */ 656 if (scp->mouse_proc) { 657 lwkt_reltoken(&scmouse_tok); 658 return EINVAL; 659 } 660 661 /* Only one syscons signal source per process */ 662 if (curproc->p_flags & P_SCMOUSE) { 663 lwkt_reltoken(&scmouse_tok); 664 return EINVAL; 665 } 666 667 /* 668 * Process is stabilized by a hold, which is removed from 669 * sc_mouse_exit1. scp's mouse_{signal,proc,pid} fields 670 * are synchronized by the MP Lock. 671 */ 672 scp->mouse_signal = mouse->u.mode.signal; 673 scp->mouse_proc = curproc; 674 scp->mouse_pid = curproc->p_pid; 675 curproc->p_flags |= P_SCMOUSE; 676 KKASSERT(curproc->p_drv_priv == NULL); 677 curproc->p_drv_priv = scp; 678 PHOLD(curproc); 679 680 lwkt_reltoken(&scmouse_tok); 681 return 0; 682 } 683 /*NOTREACHED*/ 684 break; 685 686 case MOUSE_SHOW: 687 crit_enter(); 688 if (!(scp->sc->flags & SC_MOUSE_ENABLED)) { 689 scp->sc->flags |= SC_MOUSE_ENABLED; 690 cur_scp->status &= ~MOUSE_HIDDEN; 691 if (!ISGRAPHSC(cur_scp)) 692 mark_all(cur_scp); 693 crit_exit(); 694 return 0; 695 } else { 696 crit_exit(); 697 return EINVAL; 698 } 699 break; 700 701 case MOUSE_HIDE: 702 crit_enter(); 703 if (scp->sc->flags & SC_MOUSE_ENABLED) { 704 scp->sc->flags &= ~SC_MOUSE_ENABLED; 705 sc_remove_all_mouse(scp->sc); 706 crit_exit(); 707 return 0; 708 } else { 709 crit_exit(); 710 return EINVAL; 711 } 712 break; 713 714 case MOUSE_MOVEABS: 715 crit_enter(); 716 scp->mouse_xpos = mouse->u.data.x; 717 scp->mouse_ypos = mouse->u.data.y; 718 set_mouse_pos(scp); 719 crit_exit(); 720 break; 721 722 case MOUSE_MOVEREL: 723 crit_enter(); 724 scp->mouse_xpos += mouse->u.data.x; 725 scp->mouse_ypos += mouse->u.data.y; 726 set_mouse_pos(scp); 727 crit_exit(); 728 break; 729 730 case MOUSE_GETINFO: 731 mouse->u.data.x = scp->mouse_xpos; 732 mouse->u.data.y = scp->mouse_ypos; 733 mouse->u.data.z = 0; 734 mouse->u.data.buttons = scp->mouse_buttons; 735 return 0; 736 737 case MOUSE_ACTION: 738 case MOUSE_MOTION_EVENT: 739 /* send out mouse event on /dev/sysmouse */ 740 #if 0 741 /* this should maybe only be settable from /dev/consolectl SOS */ 742 if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) 743 return ENOTTY; 744 #endif 745 crit_enter(); 746 if (mouse->u.data.x != 0 || mouse->u.data.y != 0) { 747 cur_scp->mouse_xpos += mouse->u.data.x; 748 cur_scp->mouse_ypos += mouse->u.data.y; 749 set_mouse_pos(cur_scp); 750 } 751 f = 0; 752 if (mouse->operation == MOUSE_ACTION) { 753 f = cur_scp->mouse_buttons ^ mouse->u.data.buttons; 754 cur_scp->mouse_buttons = mouse->u.data.buttons; 755 } 756 crit_exit(); 757 758 if (sysmouse_event(mouse) == 0) 759 return 0; 760 761 /* 762 * If any buttons are down or the mouse has moved a lot, 763 * stop the screen saver. 764 */ 765 if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons) 766 || (mouse->u.data.x*mouse->u.data.x 767 + mouse->u.data.y*mouse->u.data.y 768 >= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) { 769 sc_touch_scrn_saver(); 770 } 771 772 cur_scp->status &= ~MOUSE_HIDDEN; 773 774 lwkt_gettoken(&scmouse_tok); 775 if (cur_scp->mouse_signal) { 776 KKASSERT(cur_scp->mouse_proc != NULL); 777 ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); 778 lwkt_reltoken(&scmouse_tok); 779 break; 780 } 781 lwkt_reltoken(&scmouse_tok); 782 783 if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) 784 break; 785 786 #ifndef SC_NO_CUTPASTE 787 if ((mouse->operation == MOUSE_ACTION) && f) { 788 /* process button presses */ 789 if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN) 790 mouse_cut_start(cur_scp); 791 else 792 mouse_cut_end(cur_scp); 793 if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN || 794 cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN) 795 mouse_paste(cur_scp); 796 } 797 #endif /* SC_NO_CUTPASTE */ 798 break; 799 800 case MOUSE_BUTTON_EVENT: 801 if ((mouse->u.event.id & MOUSE_BUTTONS) == 0) 802 return EINVAL; 803 if (mouse->u.event.value < 0) 804 return EINVAL; 805 #if 0 806 /* this should maybe only be settable from /dev/consolectl SOS */ 807 if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) 808 return ENOTTY; 809 #endif 810 if (mouse->u.event.value > 0) 811 cur_scp->mouse_buttons |= mouse->u.event.id; 812 else 813 cur_scp->mouse_buttons &= ~mouse->u.event.id; 814 815 if (sysmouse_event(mouse) == 0) 816 return 0; 817 818 /* if a button is held down, stop the screen saver */ 819 if (mouse->u.event.value > 0) 820 sc_touch_scrn_saver(); 821 822 cur_scp->status &= ~MOUSE_HIDDEN; 823 824 lwkt_gettoken(&scmouse_tok); 825 if (cur_scp->mouse_signal) { 826 KKASSERT(cur_scp->mouse_proc != NULL); 827 ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); 828 lwkt_reltoken(&scmouse_tok); 829 break; 830 } 831 lwkt_reltoken(&scmouse_tok); 832 833 if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) 834 break; 835 836 #ifndef SC_NO_CUTPASTE 837 switch (mouse->u.event.id) { 838 case MOUSE_BUTTON1DOWN: 839 switch (mouse->u.event.value % 4) { 840 case 0: /* up */ 841 mouse_cut_end(cur_scp); 842 break; 843 case 1: /* single click: start cut operation */ 844 mouse_cut_start(cur_scp); 845 break; 846 case 2: /* double click: cut a word */ 847 mouse_cut_word(cur_scp); 848 mouse_cut_end(cur_scp); 849 break; 850 case 3: /* triple click: cut a line */ 851 mouse_cut_line(cur_scp); 852 mouse_cut_end(cur_scp); 853 break; 854 } 855 break; 856 case SC_MOUSE_PASTEBUTTON: 857 switch (mouse->u.event.value) { 858 case 0: /* up */ 859 break; 860 default: 861 mouse_paste(cur_scp); 862 break; 863 } 864 break; 865 case SC_MOUSE_EXTENDBUTTON: 866 switch (mouse->u.event.value) { 867 case 0: /* up */ 868 if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)) 869 mouse_cut_end(cur_scp); 870 break; 871 default: 872 mouse_cut_extend(cur_scp); 873 break; 874 } 875 break; 876 } 877 #endif /* SC_NO_CUTPASTE */ 878 break; 879 880 case MOUSE_MOUSECHAR: 881 if (mouse->u.mouse_char < 0) { 882 mouse->u.mouse_char = scp->sc->mouse_char; 883 } else { 884 if (mouse->u.mouse_char >= (unsigned char)-1 - 4) 885 return EINVAL; 886 crit_enter(); 887 sc_remove_all_mouse(scp->sc); 888 #ifndef SC_NO_FONT_LOADING 889 if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL)) 890 sc_load_font(cur_scp, 0, cur_scp->font_height, 891 cur_scp->font, 892 cur_scp->sc->mouse_char, 4); 893 #endif 894 scp->sc->mouse_char = mouse->u.mouse_char; 895 crit_exit(); 896 } 897 break; 898 899 default: 900 return EINVAL; 901 } 902 903 return 0; 904 } 905 906 return ENOIOCTL; 907 } 908 909 void 910 sc_mouse_init(void *unused) 911 { 912 at_exit(sc_mouse_exit1); 913 } 914 915 void 916 sc_mouse_uninit(void *unused) 917 { 918 } 919 920 SYSINIT(sc_mouse_init, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_init, NULL); 921 SYSUNINIT(sc_mouse_uninit, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_uninit, NULL); 922 923 #endif /* SC_NO_SYSMOUSE */ 924