aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKen Raeburn2015-10-02 23:36:31 -0400
committerKen Raeburn2015-10-11 01:15:19 -0400
commit08e27d294468aa72cb06a50821dbade8ea03b2ce (patch)
treeb71fc8936932d3c818847e16386a9d2736cf98a5 /src
parentfcb5d3e8b158f7ea8492aa14f79804fae18e76f9 (diff)
downloademacs-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')
-rw-r--r--src/xfns.c264
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! */
669enum 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
680struct 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! */
695static 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
705struct 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
729static void
730x_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
668static void 748static void
669x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 749x_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 ();