diff options
| author | Nick Roberts | 2007-05-20 02:27:53 +0000 |
|---|---|---|
| committer | Nick Roberts | 2007-05-20 02:27:53 +0000 |
| commit | e882229cca36a3c24031e18fe44be1865f282659 (patch) | |
| tree | e4368d0c6bf62b3d78106b3fd622a13c31eab4dd /src | |
| parent | 60889ffab9383f2972e59eaebe4d60d91a92ad90 (diff) | |
| download | emacs-e882229cca36a3c24031e18fe44be1865f282659.tar.gz emacs-e882229cca36a3c24031e18fe44be1865f282659.zip | |
(write_glyphs_with_face): New function.
[HAVE_GPM_H]: Include buffer.h, sys/fcntl.h.
(mouse_face_beg_row, mouse_face_beg_col, mouse_face_end_row)
(mouse_face_end_col, mouse_face_past_end, mouse_face_window)
(mouse_face_face_id, term_gpm, pos_x, pos_y)
(last_mouse_x, last_mouse_y): New variables.
(term_show_mouse_face, term_clear_mouse_face, fast_find_position)
(term_mouse_highlight, term_mouse_movement, term_mouse_position)
(term_mouse_click, handle_one_term_event, Fterm_open_connection)
(Fterm_close_connection): New functions.
(term_init): Initialise mouse_face_window.
Diffstat (limited to 'src')
| -rw-r--r-- | src/term.c | 770 |
1 files changed, 751 insertions, 19 deletions
diff --git a/src/term.c b/src/term.c index 556ae9f65b1..5422d29efb9 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -144,25 +144,6 @@ int (*read_socket_hook) P_ ((int, int, struct input_event *)); | |||
| 144 | 144 | ||
| 145 | void (*frame_up_to_date_hook) P_ ((struct frame *)); | 145 | void (*frame_up_to_date_hook) P_ ((struct frame *)); |
| 146 | 146 | ||
| 147 | /* Return the current position of the mouse. | ||
| 148 | |||
| 149 | Set *f to the frame the mouse is in, or zero if the mouse is in no | ||
| 150 | Emacs frame. If it is set to zero, all the other arguments are | ||
| 151 | garbage. | ||
| 152 | |||
| 153 | If the motion started in a scroll bar, set *bar_window to the | ||
| 154 | scroll bar's window, *part to the part the mouse is currently over, | ||
| 155 | *x to the position of the mouse along the scroll bar, and *y to the | ||
| 156 | overall length of the scroll bar. | ||
| 157 | |||
| 158 | Otherwise, set *bar_window to Qnil, and *x and *y to the column and | ||
| 159 | row of the character cell the mouse is over. | ||
| 160 | |||
| 161 | Set *time to the time the mouse was at the returned position. | ||
| 162 | |||
| 163 | This should clear mouse_moved until the next motion | ||
| 164 | event arrives. */ | ||
| 165 | |||
| 166 | void (*mouse_position_hook) P_ ((FRAME_PTR *f, int insist, | 147 | void (*mouse_position_hook) P_ ((FRAME_PTR *f, int insist, |
| 167 | Lisp_Object *bar_window, | 148 | Lisp_Object *bar_window, |
| 168 | enum scroll_bar_part *part, | 149 | enum scroll_bar_part *part, |
| @@ -413,6 +394,9 @@ static int tty_cursor_hidden; | |||
| 413 | char *tparam (); | 394 | char *tparam (); |
| 414 | 395 | ||
| 415 | extern char *tgetstr (); | 396 | extern char *tgetstr (); |
| 397 | |||
| 398 | static void term_clear_mouse_face (); | ||
| 399 | static void term_mouse_highlight (struct frame *f, int x, int y); | ||
| 416 | 400 | ||
| 417 | 401 | ||
| 418 | #ifdef WINDOWSNT | 402 | #ifdef WINDOWSNT |
| @@ -426,6 +410,33 @@ extern char *tgetstr (); | |||
| 426 | #define FRAME_TERMCAP_P(_f_) 0 | 410 | #define FRAME_TERMCAP_P(_f_) 0 |
| 427 | #endif /* WINDOWSNT */ | 411 | #endif /* WINDOWSNT */ |
| 428 | 412 | ||
| 413 | #ifdef HAVE_GPM_H | ||
| 414 | #include <sys/fcntl.h> | ||
| 415 | #include "buffer.h" | ||
| 416 | |||
| 417 | /* Nonzero means mouse is enabled on Linux console. */ | ||
| 418 | int term_gpm = 0; | ||
| 419 | |||
| 420 | /* These variables describe the range of text currently shown in its | ||
| 421 | mouse-face, together with the window they apply to. As long as | ||
| 422 | the mouse stays within this range, we need not redraw anything on | ||
| 423 | its account. Rows and columns are glyph matrix positions in | ||
| 424 | MOUSE_FACE_WINDOW. */ | ||
| 425 | static int mouse_face_beg_row, mouse_face_beg_col; | ||
| 426 | static int mouse_face_end_row, mouse_face_end_col; | ||
| 427 | static int mouse_face_past_end; | ||
| 428 | static Lisp_Object mouse_face_window; | ||
| 429 | static int mouse_face_face_id; | ||
| 430 | |||
| 431 | /* FRAME and X, Y position of mouse when last checked for | ||
| 432 | highlighting. X and Y can be negative or out of range for the frame. */ | ||
| 433 | struct frame *mouse_face_mouse_frame; | ||
| 434 | int mouse_face_mouse_x, mouse_face_mouse_y; | ||
| 435 | |||
| 436 | static int pos_x, pos_y; | ||
| 437 | static int last_mouse_x, last_mouse_y; | ||
| 438 | #endif /* HAVE_GPM_H */ | ||
| 439 | |||
| 429 | void | 440 | void |
| 430 | ring_bell () | 441 | ring_bell () |
| 431 | { | 442 | { |
| @@ -1010,6 +1021,65 @@ write_glyphs (string, len) | |||
| 1010 | cmcheckmagic (); | 1021 | cmcheckmagic (); |
| 1011 | } | 1022 | } |
| 1012 | 1023 | ||
| 1024 | void | ||
| 1025 | write_glyphs_with_face (string, len, face_id) | ||
| 1026 | register struct glyph *string; | ||
| 1027 | register int len, face_id; | ||
| 1028 | { | ||
| 1029 | struct frame *sf = XFRAME (selected_frame); | ||
| 1030 | struct frame *f = updating_frame ? updating_frame : sf; | ||
| 1031 | unsigned char *conversion_buffer; | ||
| 1032 | struct coding_system *coding; | ||
| 1033 | |||
| 1034 | turn_off_insert (); | ||
| 1035 | tty_hide_cursor (); | ||
| 1036 | |||
| 1037 | /* Don't dare write in last column of bottom line, if Auto-Wrap, | ||
| 1038 | since that would scroll the whole frame on some terminals. */ | ||
| 1039 | |||
| 1040 | if (AutoWrap | ||
| 1041 | && curY + 1 == FRAME_LINES (sf) | ||
| 1042 | && (curX + len) == FRAME_COLS (sf)) | ||
| 1043 | len --; | ||
| 1044 | if (len <= 0) | ||
| 1045 | return; | ||
| 1046 | |||
| 1047 | cmplus (len); | ||
| 1048 | |||
| 1049 | /* If terminal_coding does any conversion, use it, otherwise use | ||
| 1050 | safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here | ||
| 1051 | because it always return 1 if the member src_multibyte is 1. */ | ||
| 1052 | coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK | ||
| 1053 | ? &terminal_coding : &safe_terminal_coding); | ||
| 1054 | /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at | ||
| 1055 | the tail. */ | ||
| 1056 | coding->mode &= ~CODING_MODE_LAST_BLOCK; | ||
| 1057 | |||
| 1058 | |||
| 1059 | /* Turn appearance modes of the face. */ | ||
| 1060 | highlight_if_desired (); | ||
| 1061 | turn_on_face (f, face_id); | ||
| 1062 | |||
| 1063 | coding->mode |= CODING_MODE_LAST_BLOCK; | ||
| 1064 | conversion_buffer = encode_terminal_code (string, len, coding); | ||
| 1065 | if (coding->produced > 0) | ||
| 1066 | { | ||
| 1067 | BLOCK_INPUT; | ||
| 1068 | fwrite (conversion_buffer, 1, coding->produced, stdout); | ||
| 1069 | if (ferror (stdout)) | ||
| 1070 | clearerr (stdout); | ||
| 1071 | if (termscript) | ||
| 1072 | fwrite (conversion_buffer, 1, coding->produced, termscript); | ||
| 1073 | UNBLOCK_INPUT; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | /* Turn appearance modes off. */ | ||
| 1077 | turn_off_face (f, face_id); | ||
| 1078 | turn_off_highlight (); | ||
| 1079 | |||
| 1080 | cmcheckmagic (); | ||
| 1081 | } | ||
| 1082 | |||
| 1013 | /* If start is zero, insert blanks instead of a string at start */ | 1083 | /* If start is zero, insert blanks instead of a string at start */ |
| 1014 | 1084 | ||
| 1015 | void | 1085 | void |
| @@ -2308,6 +2378,656 @@ set_tty_color_mode (f, val) | |||
| 2308 | 2378 | ||
| 2309 | 2379 | ||
| 2310 | /*********************************************************************** | 2380 | /*********************************************************************** |
| 2381 | Mouse | ||
| 2382 | ***********************************************************************/ | ||
| 2383 | |||
| 2384 | #ifdef HAVE_GPM_H | ||
| 2385 | static void | ||
| 2386 | term_show_mouse_face (enum draw_glyphs_face draw) | ||
| 2387 | { | ||
| 2388 | struct window *w = XWINDOW (mouse_face_window); | ||
| 2389 | int save_x, save_y; | ||
| 2390 | int i, j; | ||
| 2391 | |||
| 2392 | if (/* If window is in the process of being destroyed, don't bother | ||
| 2393 | to do anything. */ | ||
| 2394 | w->current_matrix != NULL | ||
| 2395 | /* Recognize when we are called to operate on rows that don't exist | ||
| 2396 | anymore. This can happen when a window is split. */ | ||
| 2397 | && mouse_face_end_row < w->current_matrix->nrows) | ||
| 2398 | { | ||
| 2399 | /* write_glyphs writes at cursor position, so we need to | ||
| 2400 | temporarily move cursor coordinates to the beginning of | ||
| 2401 | the highlight region. */ | ||
| 2402 | |||
| 2403 | /* Save current cursor co-ordinates */ | ||
| 2404 | save_y = curY; | ||
| 2405 | save_x = curX; | ||
| 2406 | |||
| 2407 | /* Note that mouse_face_beg_row etc. are window relative. */ | ||
| 2408 | for (i = mouse_face_beg_row; i <= mouse_face_end_row; i++) | ||
| 2409 | { | ||
| 2410 | int start_hpos, end_hpos, nglyphs; | ||
| 2411 | struct glyph_row *row = MATRIX_ROW (w->current_matrix, i); | ||
| 2412 | |||
| 2413 | /* Don't do anything if row doesn't have valid contents. */ | ||
| 2414 | if (!row->enabled_p) | ||
| 2415 | continue; | ||
| 2416 | |||
| 2417 | /* For all but the first row, the highlight starts at column 0. */ | ||
| 2418 | if (i == mouse_face_beg_row) | ||
| 2419 | start_hpos = mouse_face_beg_col; | ||
| 2420 | else | ||
| 2421 | start_hpos = 0; | ||
| 2422 | |||
| 2423 | if (i == mouse_face_end_row) | ||
| 2424 | end_hpos = mouse_face_end_col; | ||
| 2425 | else | ||
| 2426 | { | ||
| 2427 | end_hpos = row->used[TEXT_AREA]; | ||
| 2428 | if (draw == DRAW_NORMAL_TEXT) | ||
| 2429 | row->fill_line_p = 1; /* Clear to end of line */ | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | if (end_hpos <= start_hpos) | ||
| 2433 | continue; | ||
| 2434 | /* Record that some glyphs of this row are displayed in | ||
| 2435 | mouse-face. */ | ||
| 2436 | row->mouse_face_p = draw > 0; | ||
| 2437 | |||
| 2438 | nglyphs = end_hpos - start_hpos; | ||
| 2439 | |||
| 2440 | if (end_hpos >= row->used[TEXT_AREA]) | ||
| 2441 | nglyphs = row->used[TEXT_AREA] - start_hpos; | ||
| 2442 | |||
| 2443 | pos_y = row->y + WINDOW_TOP_EDGE_Y (w); | ||
| 2444 | pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos | ||
| 2445 | + WINDOW_LEFT_EDGE_X (w); | ||
| 2446 | |||
| 2447 | cursor_to (pos_y, pos_x); | ||
| 2448 | |||
| 2449 | if (draw == DRAW_MOUSE_FACE) | ||
| 2450 | { | ||
| 2451 | write_glyphs_with_face (row->glyphs[TEXT_AREA] + start_hpos, | ||
| 2452 | nglyphs, mouse_face_face_id); | ||
| 2453 | } | ||
| 2454 | else /* draw == DRAW_NORMAL_TEXT */ | ||
| 2455 | write_glyphs (row->glyphs[TEXT_AREA] + start_hpos, nglyphs); | ||
| 2456 | } | ||
| 2457 | cursor_to (save_y, save_x); | ||
| 2458 | } | ||
| 2459 | } | ||
| 2460 | |||
| 2461 | static void | ||
| 2462 | term_clear_mouse_face () | ||
| 2463 | { | ||
| 2464 | if (!NILP (mouse_face_window)) | ||
| 2465 | term_show_mouse_face (DRAW_NORMAL_TEXT); | ||
| 2466 | |||
| 2467 | mouse_face_beg_row = mouse_face_beg_col = -1; | ||
| 2468 | mouse_face_end_row = mouse_face_end_col = -1; | ||
| 2469 | mouse_face_window = Qnil; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | /* Find the glyph matrix position of buffer position POS in window W. | ||
| 2473 | *HPOS and *VPOS are set to the positions found. W's current glyphs | ||
| 2474 | must be up to date. If POS is above window start return (0, 0). | ||
| 2475 | If POS is after end of W, return end of last line in W. | ||
| 2476 | - taken from msdos.c */ | ||
| 2477 | static int | ||
| 2478 | fast_find_position (struct window *w, int pos, int *hpos, int *vpos) | ||
| 2479 | { | ||
| 2480 | int i, lastcol, line_start_position, maybe_next_line_p = 0; | ||
| 2481 | int yb = window_text_bottom_y (w); | ||
| 2482 | struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0), *best_row = row; | ||
| 2483 | |||
| 2484 | while (row->y < yb) | ||
| 2485 | { | ||
| 2486 | if (row->used[TEXT_AREA]) | ||
| 2487 | line_start_position = row->glyphs[TEXT_AREA]->charpos; | ||
| 2488 | else | ||
| 2489 | line_start_position = 0; | ||
| 2490 | |||
| 2491 | if (line_start_position > pos) | ||
| 2492 | break; | ||
| 2493 | /* If the position sought is the end of the buffer, | ||
| 2494 | don't include the blank lines at the bottom of the window. */ | ||
| 2495 | else if (line_start_position == pos | ||
| 2496 | && pos == BUF_ZV (XBUFFER (w->buffer))) | ||
| 2497 | { | ||
| 2498 | maybe_next_line_p = 1; | ||
| 2499 | break; | ||
| 2500 | } | ||
| 2501 | else if (line_start_position > 0) | ||
| 2502 | best_row = row; | ||
| 2503 | |||
| 2504 | /* Don't overstep the last matrix row, lest we get into the | ||
| 2505 | never-never land... */ | ||
| 2506 | if (row->y + 1 >= yb) | ||
| 2507 | break; | ||
| 2508 | |||
| 2509 | ++row; | ||
| 2510 | } | ||
| 2511 | |||
| 2512 | /* Find the right column within BEST_ROW. */ | ||
| 2513 | lastcol = 0; | ||
| 2514 | row = best_row; | ||
| 2515 | for (i = 0; i < row->used[TEXT_AREA]; i++) | ||
| 2516 | { | ||
| 2517 | struct glyph *glyph = row->glyphs[TEXT_AREA] + i; | ||
| 2518 | int charpos; | ||
| 2519 | |||
| 2520 | charpos = glyph->charpos; | ||
| 2521 | if (charpos == pos) | ||
| 2522 | { | ||
| 2523 | *hpos = i; | ||
| 2524 | *vpos = row->y; | ||
| 2525 | return 1; | ||
| 2526 | } | ||
| 2527 | else if (charpos > pos) | ||
| 2528 | break; | ||
| 2529 | else if (charpos > 0) | ||
| 2530 | lastcol = i; | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | /* If we're looking for the end of the buffer, | ||
| 2534 | and we didn't find it in the line we scanned, | ||
| 2535 | use the start of the following line. */ | ||
| 2536 | if (maybe_next_line_p) | ||
| 2537 | { | ||
| 2538 | ++row; | ||
| 2539 | lastcol = 0; | ||
| 2540 | } | ||
| 2541 | |||
| 2542 | *vpos = row->y; | ||
| 2543 | *hpos = lastcol + 1; | ||
| 2544 | return 0; | ||
| 2545 | } | ||
| 2546 | |||
| 2547 | static void | ||
| 2548 | term_mouse_highlight (struct frame *f, int x, int y) | ||
| 2549 | { | ||
| 2550 | enum window_part part; | ||
| 2551 | Lisp_Object window; | ||
| 2552 | struct window *w; | ||
| 2553 | struct buffer *b; | ||
| 2554 | |||
| 2555 | if (NILP (Vmouse_highlight) | ||
| 2556 | || !f->glyphs_initialized_p) | ||
| 2557 | return; | ||
| 2558 | |||
| 2559 | mouse_face_mouse_x = x; | ||
| 2560 | mouse_face_mouse_y = y; | ||
| 2561 | mouse_face_mouse_frame = f; | ||
| 2562 | |||
| 2563 | /* Which window is that in? */ | ||
| 2564 | window = window_from_coordinates (f, x, y, &part, &x, &y, 0); | ||
| 2565 | |||
| 2566 | /* Not on a window -> return. */ | ||
| 2567 | if (!WINDOWP (window)) | ||
| 2568 | return; | ||
| 2569 | |||
| 2570 | if (!EQ (window, mouse_face_window)) | ||
| 2571 | term_clear_mouse_face (); | ||
| 2572 | |||
| 2573 | w = XWINDOW (window); | ||
| 2574 | |||
| 2575 | /* Are we in a window whose display is up to date? | ||
| 2576 | And verify the buffer's text has not changed. */ | ||
| 2577 | b = XBUFFER (w->buffer); | ||
| 2578 | if (part == ON_TEXT | ||
| 2579 | && EQ (w->window_end_valid, w->buffer) | ||
| 2580 | && XFASTINT (w->last_modified) == BUF_MODIFF (b) | ||
| 2581 | && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) | ||
| 2582 | { | ||
| 2583 | int pos, i, nrows = w->current_matrix->nrows; | ||
| 2584 | struct glyph_row *row; | ||
| 2585 | struct glyph *glyph; | ||
| 2586 | |||
| 2587 | /* Find the glyph under X/Y. */ | ||
| 2588 | glyph = NULL; | ||
| 2589 | if (y >= 0 && y < nrows) | ||
| 2590 | { | ||
| 2591 | row = MATRIX_ROW (w->current_matrix, y); | ||
| 2592 | /* Give up if some row before the one we are looking for is | ||
| 2593 | not enabled. */ | ||
| 2594 | for (i = 0; i <= y; i++) | ||
| 2595 | if (!MATRIX_ROW (w->current_matrix, i)->enabled_p) | ||
| 2596 | break; | ||
| 2597 | if (i > y /* all rows upto and including the one at Y are enabled */ | ||
| 2598 | && row->displays_text_p | ||
| 2599 | && x < window_box_width (w, TEXT_AREA)) | ||
| 2600 | { | ||
| 2601 | glyph = row->glyphs[TEXT_AREA]; | ||
| 2602 | if (x >= row->used[TEXT_AREA]) | ||
| 2603 | glyph = NULL; | ||
| 2604 | else | ||
| 2605 | { | ||
| 2606 | glyph += x; | ||
| 2607 | if (!BUFFERP (glyph->object)) | ||
| 2608 | glyph = NULL; | ||
| 2609 | } | ||
| 2610 | } | ||
| 2611 | } | ||
| 2612 | |||
| 2613 | /* Clear mouse face if X/Y not over text. */ | ||
| 2614 | if (glyph == NULL) | ||
| 2615 | { | ||
| 2616 | term_clear_mouse_face (); | ||
| 2617 | return; | ||
| 2618 | } | ||
| 2619 | |||
| 2620 | if (!BUFFERP (glyph->object)) | ||
| 2621 | abort (); | ||
| 2622 | pos = glyph->charpos; | ||
| 2623 | |||
| 2624 | /* Check for mouse-face. */ | ||
| 2625 | { | ||
| 2626 | extern Lisp_Object Qmouse_face; | ||
| 2627 | Lisp_Object mouse_face, overlay, position, *overlay_vec; | ||
| 2628 | int noverlays, obegv, ozv;; | ||
| 2629 | struct buffer *obuf; | ||
| 2630 | |||
| 2631 | /* If we get an out-of-range value, return now; avoid an error. */ | ||
| 2632 | if (pos > BUF_Z (b)) | ||
| 2633 | return; | ||
| 2634 | |||
| 2635 | /* Make the window's buffer temporarily current for | ||
| 2636 | overlays_at and compute_char_face. */ | ||
| 2637 | obuf = current_buffer; | ||
| 2638 | current_buffer = b; | ||
| 2639 | obegv = BEGV; | ||
| 2640 | ozv = ZV; | ||
| 2641 | BEGV = BEG; | ||
| 2642 | ZV = Z; | ||
| 2643 | |||
| 2644 | /* Is this char mouse-active? */ | ||
| 2645 | XSETINT (position, pos); | ||
| 2646 | |||
| 2647 | /* Put all the overlays we want in a vector in overlay_vec. */ | ||
| 2648 | GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0); | ||
| 2649 | /* Sort overlays into increasing priority order. */ | ||
| 2650 | noverlays = sort_overlays (overlay_vec, noverlays, w); | ||
| 2651 | |||
| 2652 | /* Check mouse-face highlighting. */ | ||
| 2653 | if (!(EQ (window, mouse_face_window) | ||
| 2654 | && y >= mouse_face_beg_row | ||
| 2655 | && y <= mouse_face_end_row | ||
| 2656 | && (y > mouse_face_beg_row | ||
| 2657 | || x >= mouse_face_beg_col) | ||
| 2658 | && (y < mouse_face_end_row | ||
| 2659 | || x < mouse_face_end_col | ||
| 2660 | || mouse_face_past_end))) | ||
| 2661 | { | ||
| 2662 | /* Clear the display of the old active region, if any. */ | ||
| 2663 | term_clear_mouse_face (); | ||
| 2664 | |||
| 2665 | /* Find the highest priority overlay that has a mouse-face | ||
| 2666 | property. */ | ||
| 2667 | overlay = Qnil; | ||
| 2668 | for (i = noverlays - 1; i >= 0; --i) | ||
| 2669 | { | ||
| 2670 | mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); | ||
| 2671 | if (!NILP (mouse_face)) | ||
| 2672 | { | ||
| 2673 | overlay = overlay_vec[i]; | ||
| 2674 | break; | ||
| 2675 | } | ||
| 2676 | } | ||
| 2677 | |||
| 2678 | /* If no overlay applies, get a text property. */ | ||
| 2679 | if (NILP (overlay)) | ||
| 2680 | mouse_face = Fget_text_property (position, Qmouse_face, | ||
| 2681 | w->buffer); | ||
| 2682 | |||
| 2683 | /* Handle the overlay case. */ | ||
| 2684 | if (!NILP (overlay)) | ||
| 2685 | { | ||
| 2686 | /* Find the range of text around this char that | ||
| 2687 | should be active. */ | ||
| 2688 | Lisp_Object before, after; | ||
| 2689 | int ignore; | ||
| 2690 | |||
| 2691 | |||
| 2692 | before = Foverlay_start (overlay); | ||
| 2693 | after = Foverlay_end (overlay); | ||
| 2694 | /* Record this as the current active region. */ | ||
| 2695 | fast_find_position (w, XFASTINT (before), | ||
| 2696 | &mouse_face_beg_col, | ||
| 2697 | &mouse_face_beg_row); | ||
| 2698 | |||
| 2699 | mouse_face_past_end | ||
| 2700 | = !fast_find_position (w, XFASTINT (after), | ||
| 2701 | &mouse_face_end_col, | ||
| 2702 | &mouse_face_end_row); | ||
| 2703 | mouse_face_window = window; | ||
| 2704 | |||
| 2705 | mouse_face_face_id | ||
| 2706 | = face_at_buffer_position (w, pos, 0, 0, | ||
| 2707 | &ignore, pos + 1, 1); | ||
| 2708 | |||
| 2709 | /* Display it as active. */ | ||
| 2710 | term_show_mouse_face (DRAW_MOUSE_FACE); | ||
| 2711 | } | ||
| 2712 | /* Handle the text property case. */ | ||
| 2713 | else if (!NILP (mouse_face)) | ||
| 2714 | { | ||
| 2715 | /* Find the range of text around this char that | ||
| 2716 | should be active. */ | ||
| 2717 | Lisp_Object before, after, beginning, end; | ||
| 2718 | int ignore; | ||
| 2719 | |||
| 2720 | beginning = Fmarker_position (w->start); | ||
| 2721 | XSETINT (end, (BUF_Z (b) - XFASTINT (w->window_end_pos))); | ||
| 2722 | before | ||
| 2723 | = Fprevious_single_property_change (make_number (pos + 1), | ||
| 2724 | Qmouse_face, | ||
| 2725 | w->buffer, beginning); | ||
| 2726 | after | ||
| 2727 | = Fnext_single_property_change (position, Qmouse_face, | ||
| 2728 | w->buffer, end); | ||
| 2729 | |||
| 2730 | /* Record this as the current active region. */ | ||
| 2731 | fast_find_position (w, XFASTINT (before), | ||
| 2732 | &mouse_face_beg_col, | ||
| 2733 | &mouse_face_beg_row); | ||
| 2734 | mouse_face_past_end | ||
| 2735 | = !fast_find_position (w, XFASTINT (after), | ||
| 2736 | &mouse_face_end_col, | ||
| 2737 | &mouse_face_end_row); | ||
| 2738 | mouse_face_window = window; | ||
| 2739 | |||
| 2740 | mouse_face_face_id | ||
| 2741 | = face_at_buffer_position (w, pos, 0, 0, | ||
| 2742 | &ignore, pos + 1, 1); | ||
| 2743 | |||
| 2744 | /* Display it as active. */ | ||
| 2745 | term_show_mouse_face (DRAW_MOUSE_FACE); | ||
| 2746 | } | ||
| 2747 | } | ||
| 2748 | |||
| 2749 | /* Look for a `help-echo' property. */ | ||
| 2750 | { | ||
| 2751 | Lisp_Object help; | ||
| 2752 | extern Lisp_Object Qhelp_echo; | ||
| 2753 | |||
| 2754 | /* Check overlays first. */ | ||
| 2755 | help = Qnil; | ||
| 2756 | for (i = noverlays - 1; i >= 0 && NILP (help); --i) | ||
| 2757 | { | ||
| 2758 | overlay = overlay_vec[i]; | ||
| 2759 | help = Foverlay_get (overlay, Qhelp_echo); | ||
| 2760 | } | ||
| 2761 | |||
| 2762 | if (!NILP (help)) | ||
| 2763 | { | ||
| 2764 | help_echo_string = help; | ||
| 2765 | help_echo_window = window; | ||
| 2766 | help_echo_object = overlay; | ||
| 2767 | help_echo_pos = pos; | ||
| 2768 | } | ||
| 2769 | /* Try text properties. */ | ||
| 2770 | else if (NILP (help) | ||
| 2771 | && ((STRINGP (glyph->object) | ||
| 2772 | && glyph->charpos >= 0 | ||
| 2773 | && glyph->charpos < SCHARS (glyph->object)) | ||
| 2774 | || (BUFFERP (glyph->object) | ||
| 2775 | && glyph->charpos >= BEGV | ||
| 2776 | && glyph->charpos < ZV))) | ||
| 2777 | { | ||
| 2778 | help = Fget_text_property (make_number (glyph->charpos), | ||
| 2779 | Qhelp_echo, glyph->object); | ||
| 2780 | if (!NILP (help)) | ||
| 2781 | { | ||
| 2782 | help_echo_string = help; | ||
| 2783 | help_echo_window = window; | ||
| 2784 | help_echo_object = glyph->object; | ||
| 2785 | help_echo_pos = glyph->charpos; | ||
| 2786 | } | ||
| 2787 | } | ||
| 2788 | } | ||
| 2789 | |||
| 2790 | BEGV = obegv; | ||
| 2791 | ZV = ozv; | ||
| 2792 | current_buffer = obuf; | ||
| 2793 | } | ||
| 2794 | } | ||
| 2795 | } | ||
| 2796 | |||
| 2797 | static int | ||
| 2798 | term_mouse_movement (FRAME_PTR frame, Gpm_Event *event) | ||
| 2799 | { | ||
| 2800 | /* Has the mouse moved off the glyph it was on at the last sighting? */ | ||
| 2801 | if (event->x != last_mouse_x || event->y != last_mouse_y) | ||
| 2802 | { | ||
| 2803 | frame->mouse_moved = 1; | ||
| 2804 | term_mouse_highlight (frame, event->x - 1, event->y - 1); | ||
| 2805 | /* Remember which glyph we're now on. */ | ||
| 2806 | last_mouse_x = event->x; | ||
| 2807 | last_mouse_y = event->y; | ||
| 2808 | return 1; | ||
| 2809 | } | ||
| 2810 | return 0; | ||
| 2811 | } | ||
| 2812 | |||
| 2813 | /* Return the current position of the mouse. | ||
| 2814 | |||
| 2815 | Set *f to the frame the mouse is in, or zero if the mouse is in no | ||
| 2816 | Emacs frame. If it is set to zero, all the other arguments are | ||
| 2817 | garbage. | ||
| 2818 | |||
| 2819 | Set *bar_window to Qnil, and *x and *y to the column and | ||
| 2820 | row of the character cell the mouse is over. | ||
| 2821 | |||
| 2822 | Set *time to the time the mouse was at the returned position. | ||
| 2823 | |||
| 2824 | This should clear mouse_moved until the next motion | ||
| 2825 | event arrives. | ||
| 2826 | |||
| 2827 | NOT CURRENTLY INVOKED: see mouse_position_hook below. */ | ||
| 2828 | static void | ||
| 2829 | term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window, | ||
| 2830 | enum scroll_bar_part *part, Lisp_Object *x, | ||
| 2831 | Lisp_Object *y, unsigned long *time) | ||
| 2832 | { | ||
| 2833 | Gpm_Event event; | ||
| 2834 | struct timeval now; | ||
| 2835 | int i; | ||
| 2836 | |||
| 2837 | BLOCK_INPUT; | ||
| 2838 | |||
| 2839 | *fp = SELECTED_FRAME (); | ||
| 2840 | |||
| 2841 | *bar_window = Qnil; | ||
| 2842 | *part = 0; | ||
| 2843 | |||
| 2844 | i = Gpm_GetSnapshot (&event); | ||
| 2845 | |||
| 2846 | XSETINT (*x, event.x); | ||
| 2847 | XSETINT (*y, event.y); | ||
| 2848 | gettimeofday(&now, 0); | ||
| 2849 | *time = (now.tv_sec * 1000) + (now.tv_usec / 1000); | ||
| 2850 | |||
| 2851 | UNBLOCK_INPUT; | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | /* Prepare a mouse-event in *RESULT for placement in the input queue. | ||
| 2855 | |||
| 2856 | If the event is a button press, then note that we have grabbed | ||
| 2857 | the mouse. */ | ||
| 2858 | |||
| 2859 | static Lisp_Object | ||
| 2860 | term_mouse_click (struct input_event *result, Gpm_Event *event, | ||
| 2861 | struct frame *f) | ||
| 2862 | { | ||
| 2863 | struct timeval now; | ||
| 2864 | int i, j; | ||
| 2865 | |||
| 2866 | result->kind = GPM_CLICK_EVENT; | ||
| 2867 | for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 ) | ||
| 2868 | { | ||
| 2869 | if (event->buttons & j) { | ||
| 2870 | result->code = i; /* button number */ | ||
| 2871 | break; | ||
| 2872 | } | ||
| 2873 | } | ||
| 2874 | gettimeofday(&now, 0); | ||
| 2875 | result->timestamp = (now.tv_sec * 1000) + (now.tv_usec / 1000); | ||
| 2876 | |||
| 2877 | if (event->type & GPM_UP) | ||
| 2878 | result->modifiers = up_modifier; | ||
| 2879 | else if (event->type & GPM_DOWN) | ||
| 2880 | result->modifiers = down_modifier; | ||
| 2881 | else | ||
| 2882 | result->modifiers = 0; | ||
| 2883 | |||
| 2884 | if (event->type & GPM_SINGLE) | ||
| 2885 | result->modifiers |= click_modifier; | ||
| 2886 | |||
| 2887 | if (event->type & GPM_DOUBLE) | ||
| 2888 | result->modifiers |= double_modifier; | ||
| 2889 | |||
| 2890 | if (event->type & GPM_TRIPLE) | ||
| 2891 | result->modifiers |= triple_modifier; | ||
| 2892 | |||
| 2893 | if (event->type & GPM_DRAG) | ||
| 2894 | result->modifiers |= drag_modifier; | ||
| 2895 | |||
| 2896 | if (!(event->type & (GPM_MOVE|GPM_DRAG))) { | ||
| 2897 | |||
| 2898 | /* 1 << KG_SHIFT */ | ||
| 2899 | if (event->modifiers & (1 << 0)) | ||
| 2900 | result->modifiers |= shift_modifier; | ||
| 2901 | |||
| 2902 | /* 1 << KG_CTRL */ | ||
| 2903 | if (event->modifiers & (1 << 2)) | ||
| 2904 | result->modifiers |= ctrl_modifier; | ||
| 2905 | |||
| 2906 | /* 1 << KG_ALT || KG_ALTGR */ | ||
| 2907 | if (event->modifiers & (1 << 3) | ||
| 2908 | || event->modifiers & (1 << 1)) | ||
| 2909 | result->modifiers |= meta_modifier; | ||
| 2910 | } | ||
| 2911 | |||
| 2912 | XSETINT (result->x, event->x - 1); | ||
| 2913 | XSETINT (result->y, event->y - 1); | ||
| 2914 | XSETFRAME (result->frame_or_window, f); | ||
| 2915 | result->arg = Qnil; | ||
| 2916 | return Qnil; | ||
| 2917 | } | ||
| 2918 | |||
| 2919 | int | ||
| 2920 | handle_one_term_event (Gpm_Event *event, struct input_event* hold_quit) | ||
| 2921 | { | ||
| 2922 | struct frame *f = SELECTED_FRAME (); | ||
| 2923 | int i, j, fd; | ||
| 2924 | struct input_event ie; | ||
| 2925 | int do_help = 0; | ||
| 2926 | int count = 0; | ||
| 2927 | |||
| 2928 | EVENT_INIT (ie); | ||
| 2929 | ie.kind = NO_EVENT; | ||
| 2930 | ie.arg = Qnil; | ||
| 2931 | |||
| 2932 | if (event->type & GPM_MOVE) { | ||
| 2933 | unsigned char buf[6 * sizeof (short)]; | ||
| 2934 | unsigned short *arg = (unsigned short *) buf + 1; | ||
| 2935 | const char *name; | ||
| 2936 | |||
| 2937 | previous_help_echo_string = help_echo_string; | ||
| 2938 | help_echo_string = Qnil; | ||
| 2939 | |||
| 2940 | /* Display mouse pointer */ | ||
| 2941 | buf[sizeof(short) - 1] = 2; /* set selection */ | ||
| 2942 | |||
| 2943 | arg[0] = arg[2] = (unsigned short) event->x; | ||
| 2944 | arg[1] = arg[3] = (unsigned short) event->y; | ||
| 2945 | arg[4] = (unsigned short) 3; | ||
| 2946 | |||
| 2947 | name = (const char *) ttyname (0); | ||
| 2948 | fd = open (name, O_WRONLY); | ||
| 2949 | ioctl (fd, TIOCLINUX, buf + sizeof (short) - 1); | ||
| 2950 | close(fd); | ||
| 2951 | |||
| 2952 | term_mouse_movement (f, event); | ||
| 2953 | |||
| 2954 | /* If the contents of the global variable help_echo_string | ||
| 2955 | has changed, generate a HELP_EVENT. */ | ||
| 2956 | if (!NILP (help_echo_string) | ||
| 2957 | || !NILP (previous_help_echo_string)) | ||
| 2958 | do_help = 1; | ||
| 2959 | |||
| 2960 | goto done; | ||
| 2961 | } | ||
| 2962 | else { | ||
| 2963 | f->mouse_moved = 0; | ||
| 2964 | term_mouse_click (&ie, event, f); | ||
| 2965 | //kbd_buffer_store_event_hold (&ie, hold_quit); | ||
| 2966 | } | ||
| 2967 | |||
| 2968 | done: | ||
| 2969 | if (ie.kind != NO_EVENT) | ||
| 2970 | { | ||
| 2971 | kbd_buffer_store_event_hold (&ie, hold_quit); | ||
| 2972 | count++; | ||
| 2973 | } | ||
| 2974 | |||
| 2975 | if (do_help | ||
| 2976 | && !(hold_quit && hold_quit->kind != NO_EVENT)) | ||
| 2977 | { | ||
| 2978 | Lisp_Object frame; | ||
| 2979 | |||
| 2980 | if (f) | ||
| 2981 | XSETFRAME (frame, f); | ||
| 2982 | else | ||
| 2983 | frame = Qnil; | ||
| 2984 | |||
| 2985 | gen_help_event (help_echo_string, frame, help_echo_window, | ||
| 2986 | help_echo_object, help_echo_pos); | ||
| 2987 | count++; | ||
| 2988 | } | ||
| 2989 | |||
| 2990 | return count; | ||
| 2991 | } | ||
| 2992 | |||
| 2993 | DEFUN ("term-open-connection", Fterm_open_connection, Sterm_open_connection, | ||
| 2994 | 0, 0, 0, | ||
| 2995 | doc: /* Open a connection to Gpm. */) | ||
| 2996 | () | ||
| 2997 | { | ||
| 2998 | Gpm_Connect connection; | ||
| 2999 | |||
| 3000 | connection.eventMask = ~0; | ||
| 3001 | connection.defaultMask = ~GPM_HARD; | ||
| 3002 | connection.maxMod = ~0; | ||
| 3003 | connection.minMod = 0; | ||
| 3004 | |||
| 3005 | if (Gpm_Open (&connection, 0) < 0) | ||
| 3006 | return Qnil; | ||
| 3007 | else | ||
| 3008 | { | ||
| 3009 | term_gpm = 1; | ||
| 3010 | reset_sys_modes (); | ||
| 3011 | init_sys_modes (); | ||
| 3012 | add_gpm_wait_descriptor (gpm_fd); | ||
| 3013 | return Qt; | ||
| 3014 | } | ||
| 3015 | } | ||
| 3016 | |||
| 3017 | DEFUN ("term-close-connection", Fterm_close_connection, Sterm_close_connection, | ||
| 3018 | 0, 0, 0, | ||
| 3019 | doc: /* Close a connection to Gpm. */) | ||
| 3020 | () | ||
| 3021 | { | ||
| 3022 | delete_gpm_wait_descriptor (gpm_fd); | ||
| 3023 | while (Gpm_Close()); /* close all the stack */ | ||
| 3024 | term_gpm = 0; | ||
| 3025 | return Qnil; | ||
| 3026 | } | ||
| 3027 | #endif /* HAVE_GPM_H */ | ||
| 3028 | |||
| 3029 | |||
| 3030 | /*********************************************************************** | ||
| 2311 | Initialization | 3031 | Initialization |
| 2312 | ***********************************************************************/ | 3032 | ***********************************************************************/ |
| 2313 | 3033 | ||
| @@ -2325,6 +3045,14 @@ term_init (terminal_type) | |||
| 2325 | 3045 | ||
| 2326 | encode_terminal_bufsize = 0; | 3046 | encode_terminal_bufsize = 0; |
| 2327 | 3047 | ||
| 3048 | #ifdef HAVE_GPM_H | ||
| 3049 | /* TODO: Can't get Gpm_Snapshot in term_mouse_position to work: test with | ||
| 3050 | (mouse-position). Also set-mouse-position won't work as is. */ | ||
| 3051 | /* mouse_position_hook = term_mouse_position; */ | ||
| 3052 | |||
| 3053 | mouse_face_window = Qnil; | ||
| 3054 | #endif | ||
| 3055 | |||
| 2328 | #ifdef WINDOWSNT | 3056 | #ifdef WINDOWSNT |
| 2329 | initialize_w32_display (); | 3057 | initialize_w32_display (); |
| 2330 | 3058 | ||
| @@ -2772,6 +3500,10 @@ bigger, or it may make it blink, or it may do nothing at all. */); | |||
| 2772 | defsubr (&Stty_display_color_p); | 3500 | defsubr (&Stty_display_color_p); |
| 2773 | defsubr (&Stty_display_color_cells); | 3501 | defsubr (&Stty_display_color_cells); |
| 2774 | defsubr (&Stty_no_underline); | 3502 | defsubr (&Stty_no_underline); |
| 3503 | #ifdef HAVE_GPM_H | ||
| 3504 | defsubr (&Sterm_open_connection); | ||
| 3505 | defsubr (&Sterm_close_connection); | ||
| 3506 | #endif /* HAVE_GPM_H */ | ||
| 2775 | 3507 | ||
| 2776 | fullscreen_hook = NULL; | 3508 | fullscreen_hook = NULL; |
| 2777 | } | 3509 | } |