diff options
| author | Ken Raeburn | 2015-10-02 23:36:31 -0400 |
|---|---|---|
| committer | Ken Raeburn | 2015-10-11 01:15:19 -0400 |
| commit | 08e27d294468aa72cb06a50821dbade8ea03b2ce (patch) | |
| tree | b71fc8936932d3c818847e16386a9d2736cf98a5 /src/xfns.c | |
| parent | fcb5d3e8b158f7ea8492aa14f79804fae18e76f9 (diff) | |
| download | emacs-08e27d294468aa72cb06a50821dbade8ea03b2ce.tar.gz emacs-08e27d294468aa72cb06a50821dbade8ea03b2ce.zip | |
Rewrite x_set_mouse_color to sync less.
We can track serial numbers of X requests and correlate error events
with the associated requests. This way we can identify errors for
specific calls without having to use XSync after every one.
* src/xfns.c (enum mouse_cursor): New type.
(struct mouse_cursor_types, struct mouse_cursor_data): New types.
(mouse_cursor_types): New array listing the Lisp variables and default
cursor appearances for each cursor type.
(x_set_mouse_color_handler): New function; checks error event serial
number against submitted requests.
(x_set_mouse_color): Updated to use the new error handler callback,
and to be more table-driven, to simplify repetitious code.
Diffstat (limited to 'src/xfns.c')
| -rw-r--r-- | src/xfns.c | 264 |
1 files changed, 150 insertions, 114 deletions
diff --git a/src/xfns.c b/src/xfns.c index 898359cb8f1..468a85645d0 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -665,15 +665,95 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 665 | } | 665 | } |
| 666 | } | 666 | } |
| 667 | 667 | ||
| 668 | /* This array must stay in sync with the mouse_cursor_types array below! */ | ||
| 669 | enum mouse_cursor { | ||
| 670 | mouse_cursor_text, | ||
| 671 | mouse_cursor_nontext, | ||
| 672 | mouse_cursor_hourglass, | ||
| 673 | mouse_cursor_mode, | ||
| 674 | mouse_cursor_hand, | ||
| 675 | mouse_cursor_horizontal_drag, | ||
| 676 | mouse_cursor_vertical_drag, | ||
| 677 | mouse_cursor_max | ||
| 678 | }; | ||
| 679 | |||
| 680 | struct mouse_cursor_types { | ||
| 681 | /* Printable name for error messages (optional). */ | ||
| 682 | const char *name; | ||
| 683 | |||
| 684 | /* Lisp variable controlling the cursor shape. */ | ||
| 685 | /* FIXME: A couple of these variables are defined in the C code but | ||
| 686 | are not actually accessible from Lisp. They should probably be | ||
| 687 | made accessible or removed. */ | ||
| 688 | Lisp_Object *shape_var_ptr; | ||
| 689 | |||
| 690 | /* The default shape. */ | ||
| 691 | int default_shape; | ||
| 692 | }; | ||
| 693 | |||
| 694 | /* This array must stay in sync with enum mouse_cursor above! */ | ||
| 695 | static const struct mouse_cursor_types mouse_cursor_types[] = { | ||
| 696 | { "text", &Vx_pointer_shape, XC_xterm }, | ||
| 697 | { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr }, | ||
| 698 | { "hourglass", &Vx_hourglass_pointer_shape, XC_watch }, | ||
| 699 | { "modeline", &Vx_mode_pointer_shape, XC_xterm }, | ||
| 700 | { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 }, | ||
| 701 | { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow }, | ||
| 702 | { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow }, | ||
| 703 | }; | ||
| 704 | |||
| 705 | struct mouse_cursor_data { | ||
| 706 | /* Last index for which XCreateFontCursor has been called, and thus | ||
| 707 | the last index for which x_request_serial[] is valid. */ | ||
| 708 | int last_cursor_create_request; | ||
| 709 | |||
| 710 | /* Last index for which an X error event was received in response to | ||
| 711 | attempting to create the cursor. */ | ||
| 712 | int error_cursor; | ||
| 713 | |||
| 714 | /* Cursor numbers chosen. */ | ||
| 715 | unsigned int cursor_num[mouse_cursor_max]; | ||
| 716 | |||
| 717 | /* Allocated Cursor values, or zero for failed attempts. */ | ||
| 718 | Cursor cursor[mouse_cursor_max]; | ||
| 719 | |||
| 720 | /* X serial numbers for the first request sent by XCreateFontCursor. | ||
| 721 | Note that there may be more than one request sent. */ | ||
| 722 | unsigned long x_request_serial[mouse_cursor_max]; | ||
| 723 | |||
| 724 | /* If an error has been received, a pointer to where the current | ||
| 725 | error-message text is stored. */ | ||
| 726 | char *error_string; | ||
| 727 | }; | ||
| 728 | |||
| 729 | static void | ||
| 730 | x_set_mouse_color_handler (Display *dpy, XErrorEvent *event, | ||
| 731 | char *error_string, void *data) | ||
| 732 | { | ||
| 733 | struct mouse_cursor_data *cursor_data = data; | ||
| 734 | int i; | ||
| 735 | |||
| 736 | cursor_data->error_cursor = -1; | ||
| 737 | cursor_data->error_string = error_string; | ||
| 738 | for (i = 0; i < cursor_data->last_cursor_create_request; i++) | ||
| 739 | { | ||
| 740 | if (event->serial >= cursor_data->x_request_serial[i]) | ||
| 741 | cursor_data->error_cursor = i; | ||
| 742 | } | ||
| 743 | if (cursor_data->error_cursor >= 0) | ||
| 744 | /* If we failed to allocate it, don't try to free it. */ | ||
| 745 | cursor_data->cursor[cursor_data->error_cursor] = 0; | ||
| 746 | } | ||
| 747 | |||
| 668 | static void | 748 | static void |
| 669 | x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | 749 | x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) |
| 670 | { | 750 | { |
| 671 | struct x_output *x = f->output_data.x; | 751 | struct x_output *x = f->output_data.x; |
| 672 | Display *dpy = FRAME_X_DISPLAY (f); | 752 | Display *dpy = FRAME_X_DISPLAY (f); |
| 673 | Cursor cursor, nontext_cursor, mode_cursor, hand_cursor; | 753 | struct mouse_cursor_data cursor_data = { -1, -1 }; |
| 674 | Cursor hourglass_cursor, horizontal_drag_cursor, vertical_drag_cursor; | ||
| 675 | unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | 754 | unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); |
| 676 | unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f); | 755 | unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f); |
| 756 | int i; | ||
| 677 | 757 | ||
| 678 | /* Don't let pointers be invisible. */ | 758 | /* Don't let pointers be invisible. */ |
| 679 | if (mask_color == pixel) | 759 | if (mask_color == pixel) |
| @@ -685,137 +765,93 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 685 | unload_color (f, x->mouse_pixel); | 765 | unload_color (f, x->mouse_pixel); |
| 686 | x->mouse_pixel = pixel; | 766 | x->mouse_pixel = pixel; |
| 687 | 767 | ||
| 688 | block_input (); | 768 | for (i = 0; i < mouse_cursor_max; i++) |
| 689 | |||
| 690 | /* It's not okay to crash if the user selects a screwy cursor. */ | ||
| 691 | x_catch_errors (dpy); | ||
| 692 | |||
| 693 | if (!NILP (Vx_pointer_shape)) | ||
| 694 | { | 769 | { |
| 695 | CHECK_NUMBER (Vx_pointer_shape); | 770 | Lisp_Object shape_var = *mouse_cursor_types[i].shape_var_ptr; |
| 696 | cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape)); | 771 | if (!NILP (shape_var)) |
| 772 | { | ||
| 773 | CHECK_TYPE_RANGED_INTEGER (unsigned, shape_var); | ||
| 774 | cursor_data.cursor_num[i] = XINT (shape_var); | ||
| 775 | } | ||
| 776 | else | ||
| 777 | cursor_data.cursor_num[i] = mouse_cursor_types[i].default_shape; | ||
| 697 | } | 778 | } |
| 698 | else | ||
| 699 | cursor = XCreateFontCursor (dpy, XC_xterm); | ||
| 700 | x_check_errors (dpy, "bad text pointer cursor: %s"); | ||
| 701 | 779 | ||
| 702 | if (!NILP (Vx_nontext_pointer_shape)) | 780 | block_input (); |
| 703 | { | ||
| 704 | CHECK_NUMBER (Vx_nontext_pointer_shape); | ||
| 705 | nontext_cursor | ||
| 706 | = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape)); | ||
| 707 | } | ||
| 708 | else | ||
| 709 | nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr); | ||
| 710 | x_check_errors (dpy, "bad nontext pointer cursor: %s"); | ||
| 711 | 781 | ||
| 712 | if (!NILP (Vx_hourglass_pointer_shape)) | 782 | /* It's not okay to crash if the user selects a screwy cursor. */ |
| 713 | { | 783 | x_catch_errors_with_handler (dpy, x_set_mouse_color_handler, &cursor_data); |
| 714 | CHECK_NUMBER (Vx_hourglass_pointer_shape); | ||
| 715 | hourglass_cursor | ||
| 716 | = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape)); | ||
| 717 | } | ||
| 718 | else | ||
| 719 | hourglass_cursor = XCreateFontCursor (dpy, XC_watch); | ||
| 720 | x_check_errors (dpy, "bad hourglass pointer cursor: %s"); | ||
| 721 | 784 | ||
| 722 | if (!NILP (Vx_mode_pointer_shape)) | 785 | for (i = 0; i < mouse_cursor_max; i++) |
| 723 | { | 786 | { |
| 724 | CHECK_NUMBER (Vx_mode_pointer_shape); | 787 | cursor_data.x_request_serial[i] = XNextRequest (dpy); |
| 725 | mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape)); | 788 | cursor_data.last_cursor_create_request = i; |
| 789 | cursor_data.cursor[i] = XCreateFontCursor (dpy, | ||
| 790 | cursor_data.cursor_num[i]); | ||
| 726 | } | 791 | } |
| 727 | else | ||
| 728 | mode_cursor = XCreateFontCursor (dpy, XC_xterm); | ||
| 729 | x_check_errors (dpy, "bad modeline pointer cursor: %s"); | ||
| 730 | 792 | ||
| 731 | if (!NILP (Vx_sensitive_text_pointer_shape)) | 793 | /* Now sync up and process all received errors from cursor |
| 794 | creation. */ | ||
| 795 | if (x_had_errors_p (dpy)) | ||
| 732 | { | 796 | { |
| 733 | CHECK_NUMBER (Vx_sensitive_text_pointer_shape); | 797 | const char *bad_cursor_name = NULL; |
| 734 | hand_cursor | 798 | /* Bounded by X_ERROR_MESSAGE_SIZE in xterm.c. */ |
| 735 | = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape)); | 799 | size_t message_length = strlen (cursor_data.error_string); |
| 736 | } | 800 | char *xmessage = alloca (1 + message_length); |
| 737 | else | 801 | memcpy (xmessage, cursor_data.error_string, message_length); |
| 738 | hand_cursor = XCreateFontCursor (dpy, XC_hand2); | ||
| 739 | 802 | ||
| 740 | if (!NILP (Vx_window_horizontal_drag_shape)) | 803 | x_uncatch_errors (); |
| 741 | { | ||
| 742 | CHECK_TYPE_RANGED_INTEGER (unsigned, Vx_window_horizontal_drag_shape); | ||
| 743 | horizontal_drag_cursor | ||
| 744 | = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape)); | ||
| 745 | } | ||
| 746 | else | ||
| 747 | horizontal_drag_cursor | ||
| 748 | = XCreateFontCursor (dpy, XC_sb_h_double_arrow); | ||
| 749 | 804 | ||
| 750 | if (!NILP (Vx_window_vertical_drag_shape)) | 805 | /* Free any successfully created cursors. */ |
| 751 | { | 806 | for (i = 0; i < mouse_cursor_max; i++) |
| 752 | CHECK_NUMBER (Vx_window_vertical_drag_shape); | 807 | if (cursor_data.cursor[i] != 0) |
| 753 | vertical_drag_cursor | 808 | XFreeCursor (dpy, cursor_data.cursor[i]); |
| 754 | = XCreateFontCursor (dpy, XINT (Vx_window_vertical_drag_shape)); | 809 | |
| 810 | /* This should only be able to fail if the server's serial | ||
| 811 | number tracking is broken. */ | ||
| 812 | if (cursor_data.error_cursor >= 0) | ||
| 813 | bad_cursor_name = mouse_cursor_types[cursor_data.error_cursor].name; | ||
| 814 | if (bad_cursor_name) | ||
| 815 | error ("bad %s pointer cursor: %s", bad_cursor_name, xmessage); | ||
| 816 | else | ||
| 817 | error ("can't set cursor shape: %s", xmessage); | ||
| 755 | } | 818 | } |
| 756 | else | ||
| 757 | vertical_drag_cursor | ||
| 758 | = XCreateFontCursor (dpy, XC_sb_v_double_arrow); | ||
| 759 | 819 | ||
| 760 | /* Check and report errors with the above calls. */ | ||
| 761 | x_check_errors (dpy, "can't set cursor shape: %s"); | ||
| 762 | x_uncatch_errors_after_check (); | 820 | x_uncatch_errors_after_check (); |
| 763 | 821 | ||
| 764 | { | 822 | { |
| 765 | XColor fore_color, back_color; | 823 | XColor colors[2]; /* 0=foreground, 1=background */ |
| 766 | 824 | ||
| 767 | fore_color.pixel = x->mouse_pixel; | 825 | colors[0].pixel = x->mouse_pixel; |
| 768 | x_query_color (f, &fore_color); | 826 | colors[1].pixel = mask_color; |
| 769 | back_color.pixel = mask_color; | 827 | x_query_colors (f, colors, 2); |
| 770 | x_query_color (f, &back_color); | 828 | |
| 771 | 829 | for (i = 0; i < mouse_cursor_max; i++) | |
| 772 | XRecolorCursor (dpy, cursor, &fore_color, &back_color); | 830 | XRecolorCursor (dpy, cursor_data.cursor[i], &colors[0], &colors[1]); |
| 773 | XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color); | ||
| 774 | XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color); | ||
| 775 | XRecolorCursor (dpy, hand_cursor, &fore_color, &back_color); | ||
| 776 | XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color); | ||
| 777 | XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color); | ||
| 778 | XRecolorCursor (dpy, vertical_drag_cursor, &fore_color, &back_color); | ||
| 779 | } | 831 | } |
| 780 | 832 | ||
| 781 | if (FRAME_X_WINDOW (f) != 0) | 833 | if (FRAME_X_WINDOW (f) != 0) |
| 782 | XDefineCursor (dpy, FRAME_X_WINDOW (f), | 834 | { |
| 783 | f->output_data.x->current_cursor = cursor); | 835 | f->output_data.x->current_cursor = cursor_data.cursor[mouse_cursor_text]; |
| 784 | 836 | XDefineCursor (dpy, FRAME_X_WINDOW (f), | |
| 785 | if (cursor != x->text_cursor | 837 | f->output_data.x->current_cursor); |
| 786 | && x->text_cursor != 0) | 838 | } |
| 787 | XFreeCursor (dpy, x->text_cursor); | 839 | |
| 788 | x->text_cursor = cursor; | 840 | #define INSTALL_CURSOR(FIELD, SHORT_INDEX) \ |
| 789 | 841 | eassert (x->FIELD != cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX]); \ | |
| 790 | if (nontext_cursor != x->nontext_cursor | 842 | if (x->FIELD != 0) \ |
| 791 | && x->nontext_cursor != 0) | 843 | XFreeCursor (dpy, x->FIELD); \ |
| 792 | XFreeCursor (dpy, x->nontext_cursor); | 844 | x->FIELD = cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX]; |
| 793 | x->nontext_cursor = nontext_cursor; | 845 | |
| 794 | 846 | INSTALL_CURSOR (text_cursor, text); | |
| 795 | if (hourglass_cursor != x->hourglass_cursor | 847 | INSTALL_CURSOR (nontext_cursor, nontext); |
| 796 | && x->hourglass_cursor != 0) | 848 | INSTALL_CURSOR (hourglass_cursor, hourglass); |
| 797 | XFreeCursor (dpy, x->hourglass_cursor); | 849 | INSTALL_CURSOR (modeline_cursor, mode); |
| 798 | x->hourglass_cursor = hourglass_cursor; | 850 | INSTALL_CURSOR (hand_cursor, hand); |
| 799 | 851 | INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag); | |
| 800 | if (mode_cursor != x->modeline_cursor | 852 | INSTALL_CURSOR (vertical_drag_cursor, vertical_drag); |
| 801 | && x->modeline_cursor != 0) | 853 | |
| 802 | XFreeCursor (dpy, f->output_data.x->modeline_cursor); | 854 | #undef INSTALL_CURSOR |
| 803 | x->modeline_cursor = mode_cursor; | ||
| 804 | |||
| 805 | if (hand_cursor != x->hand_cursor | ||
| 806 | && x->hand_cursor != 0) | ||
| 807 | XFreeCursor (dpy, x->hand_cursor); | ||
| 808 | x->hand_cursor = hand_cursor; | ||
| 809 | |||
| 810 | if (horizontal_drag_cursor != x->horizontal_drag_cursor | ||
| 811 | && x->horizontal_drag_cursor != 0) | ||
| 812 | XFreeCursor (dpy, x->horizontal_drag_cursor); | ||
| 813 | x->horizontal_drag_cursor = horizontal_drag_cursor; | ||
| 814 | |||
| 815 | if (vertical_drag_cursor != x->vertical_drag_cursor | ||
| 816 | && x->vertical_drag_cursor != 0) | ||
| 817 | XFreeCursor (dpy, x->vertical_drag_cursor); | ||
| 818 | x->vertical_drag_cursor = vertical_drag_cursor; | ||
| 819 | 855 | ||
| 820 | XFlush (dpy); | 856 | XFlush (dpy); |
| 821 | unblock_input (); | 857 | unblock_input (); |