diff options
| author | Andrea Corallo | 2021-04-13 12:06:23 +0200 |
|---|---|---|
| committer | Andrea Corallo | 2021-04-13 12:06:23 +0200 |
| commit | b064ddd3f600ed28e62b09d556ecced5f80d9883 (patch) | |
| tree | 2ddf4889f385beb34cd064f245a7e59265377c37 /src | |
| parent | 2d23f19e7d5ff8a1ec1a188dcd530c185029d1f8 (diff) | |
| parent | 6de79542e43ece9a12ebc032c275a6c3fee0b73b (diff) | |
| download | emacs-b064ddd3f600ed28e62b09d556ecced5f80d9883.tar.gz emacs-b064ddd3f600ed28e62b09d556ecced5f80d9883.zip | |
Merge remote-tracking branch 'savannah/master' into native-comp
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs.c | 208 | ||||
| -rw-r--r-- | src/xdisp.c | 147 |
2 files changed, 217 insertions, 138 deletions
diff --git a/src/emacs.c b/src/emacs.c index d353679b0f0..e5940ce1de6 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -62,6 +62,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 62 | # include <sys/socket.h> | 62 | # include <sys/socket.h> |
| 63 | #endif | 63 | #endif |
| 64 | 64 | ||
| 65 | #if defined HAVE_LINUX_SECCOMP_H && defined HAVE_LINUX_FILTER_H \ | ||
| 66 | && HAVE_DECL_SECCOMP_SET_MODE_FILTER \ | ||
| 67 | && HAVE_DECL_SECCOMP_FILTER_FLAG_TSYNC | ||
| 68 | # define SECCOMP_USABLE 1 | ||
| 69 | #else | ||
| 70 | # define SECCOMP_USABLE 0 | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #if SECCOMP_USABLE | ||
| 74 | # include <linux/seccomp.h> | ||
| 75 | # include <linux/filter.h> | ||
| 76 | # include <sys/prctl.h> | ||
| 77 | # include <sys/syscall.h> | ||
| 78 | #endif | ||
| 79 | |||
| 65 | #ifdef HAVE_WINDOW_SYSTEM | 80 | #ifdef HAVE_WINDOW_SYSTEM |
| 66 | #include TERM_HEADER | 81 | #include TERM_HEADER |
| 67 | #endif /* HAVE_WINDOW_SYSTEM */ | 82 | #endif /* HAVE_WINDOW_SYSTEM */ |
| @@ -242,6 +257,11 @@ Initialization options:\n\ | |||
| 242 | --dump-file FILE read dumped state from FILE\n\ | 257 | --dump-file FILE read dumped state from FILE\n\ |
| 243 | ", | 258 | ", |
| 244 | #endif | 259 | #endif |
| 260 | #if SECCOMP_USABLE | ||
| 261 | "\ | ||
| 262 | --sandbox=FILE read Seccomp BPF filter from FILE\n\ | ||
| 263 | " | ||
| 264 | #endif | ||
| 245 | "\ | 265 | "\ |
| 246 | --no-build-details do not add build details such as time stamps\n\ | 266 | --no-build-details do not add build details such as time stamps\n\ |
| 247 | --no-desktop do not load a saved desktop\n\ | 267 | --no-desktop do not load a saved desktop\n\ |
| @@ -977,12 +997,195 @@ load_pdump (int argc, char **argv, char const *original_pwd) | |||
| 977 | } | 997 | } |
| 978 | #endif /* HAVE_PDUMPER */ | 998 | #endif /* HAVE_PDUMPER */ |
| 979 | 999 | ||
| 1000 | #if SECCOMP_USABLE | ||
| 1001 | |||
| 1002 | /* Wrapper function for the `seccomp' system call on GNU/Linux. This | ||
| 1003 | system call usually doesn't have a wrapper function. See the | ||
| 1004 | manual page of `seccomp' for the signature. */ | ||
| 1005 | |||
| 1006 | static int | ||
| 1007 | emacs_seccomp (unsigned int operation, unsigned int flags, void *args) | ||
| 1008 | { | ||
| 1009 | #ifdef SYS_seccomp | ||
| 1010 | return syscall (SYS_seccomp, operation, flags, args); | ||
| 1011 | #else | ||
| 1012 | errno = ENOSYS; | ||
| 1013 | return -1; | ||
| 1014 | #endif | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | /* Read SIZE bytes into BUFFER. Return the number of bytes read, or | ||
| 1018 | -1 if reading failed altogether. */ | ||
| 1019 | |||
| 1020 | static ptrdiff_t | ||
| 1021 | read_full (int fd, void *buffer, ptrdiff_t size) | ||
| 1022 | { | ||
| 1023 | eassert (0 <= fd); | ||
| 1024 | eassert (buffer != NULL); | ||
| 1025 | eassert (0 <= size); | ||
| 1026 | enum | ||
| 1027 | { | ||
| 1028 | /* See MAX_RW_COUNT in sysdep.c. */ | ||
| 1029 | #ifdef MAX_RW_COUNT | ||
| 1030 | max_size = MAX_RW_COUNT | ||
| 1031 | #else | ||
| 1032 | max_size = INT_MAX >> 18 << 18 | ||
| 1033 | #endif | ||
| 1034 | }; | ||
| 1035 | if (PTRDIFF_MAX < size || max_size < size) | ||
| 1036 | { | ||
| 1037 | errno = EFBIG; | ||
| 1038 | return -1; | ||
| 1039 | } | ||
| 1040 | char *ptr = buffer; | ||
| 1041 | ptrdiff_t read = 0; | ||
| 1042 | while (size != 0) | ||
| 1043 | { | ||
| 1044 | ptrdiff_t n = emacs_read (fd, ptr, size); | ||
| 1045 | if (n < 0) | ||
| 1046 | return -1; | ||
| 1047 | if (n == 0) | ||
| 1048 | break; /* Avoid infinite loop on encountering EOF. */ | ||
| 1049 | eassert (n <= size); | ||
| 1050 | size -= n; | ||
| 1051 | ptr += n; | ||
| 1052 | read += n; | ||
| 1053 | } | ||
| 1054 | return read; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | /* Attempt to load Secure Computing filters from FILE. Return false | ||
| 1058 | if that doesn't work for some reason. */ | ||
| 1059 | |||
| 1060 | static bool | ||
| 1061 | load_seccomp (const char *file) | ||
| 1062 | { | ||
| 1063 | bool success = false; | ||
| 1064 | void *buffer = NULL; | ||
| 1065 | int fd | ||
| 1066 | = emacs_open_noquit (file, O_RDONLY | O_CLOEXEC | O_BINARY, 0); | ||
| 1067 | if (fd < 0) | ||
| 1068 | { | ||
| 1069 | emacs_perror ("open"); | ||
| 1070 | goto out; | ||
| 1071 | } | ||
| 1072 | struct stat stat; | ||
| 1073 | if (fstat (fd, &stat) != 0) | ||
| 1074 | { | ||
| 1075 | emacs_perror ("fstat"); | ||
| 1076 | goto out; | ||
| 1077 | } | ||
| 1078 | if (! S_ISREG (stat.st_mode)) | ||
| 1079 | { | ||
| 1080 | fprintf (stderr, "seccomp file %s is not regular\n", file); | ||
| 1081 | goto out; | ||
| 1082 | } | ||
| 1083 | struct sock_fprog program; | ||
| 1084 | if (stat.st_size <= 0 || SIZE_MAX <= stat.st_size | ||
| 1085 | || PTRDIFF_MAX <= stat.st_size | ||
| 1086 | || stat.st_size % sizeof *program.filter != 0) | ||
| 1087 | { | ||
| 1088 | fprintf (stderr, "seccomp filter %s has invalid size %ld\n", | ||
| 1089 | file, (long) stat.st_size); | ||
| 1090 | goto out; | ||
| 1091 | } | ||
| 1092 | size_t size = stat.st_size; | ||
| 1093 | size_t count = size / sizeof *program.filter; | ||
| 1094 | eassert (0 < count && count < SIZE_MAX); | ||
| 1095 | if (USHRT_MAX < count) | ||
| 1096 | { | ||
| 1097 | fprintf (stderr, "seccomp filter %s is too big\n", file); | ||
| 1098 | goto out; | ||
| 1099 | } | ||
| 1100 | /* Try reading one more byte to detect file size changes. */ | ||
| 1101 | buffer = malloc (size + 1); | ||
| 1102 | if (buffer == NULL) | ||
| 1103 | { | ||
| 1104 | emacs_perror ("malloc"); | ||
| 1105 | goto out; | ||
| 1106 | } | ||
| 1107 | ptrdiff_t read = read_full (fd, buffer, size + 1); | ||
| 1108 | if (read < 0) | ||
| 1109 | { | ||
| 1110 | emacs_perror ("read"); | ||
| 1111 | goto out; | ||
| 1112 | } | ||
| 1113 | eassert (read <= SIZE_MAX); | ||
| 1114 | if (read != size) | ||
| 1115 | { | ||
| 1116 | fprintf (stderr, | ||
| 1117 | "seccomp filter %s changed size while reading\n", | ||
| 1118 | file); | ||
| 1119 | goto out; | ||
| 1120 | } | ||
| 1121 | if (emacs_close (fd) != 0) | ||
| 1122 | emacs_perror ("close"); /* not a fatal error */ | ||
| 1123 | fd = -1; | ||
| 1124 | program.len = count; | ||
| 1125 | program.filter = buffer; | ||
| 1126 | |||
| 1127 | /* See man page of `seccomp' why this is necessary. Note that we | ||
| 1128 | intentionally don't check the return value: a parent process | ||
| 1129 | might have made this call before, in which case it would fail; | ||
| 1130 | or, if enabling privilege-restricting mode fails, the `seccomp' | ||
| 1131 | syscall will fail anyway. */ | ||
| 1132 | prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
| 1133 | /* Install the filter. Make sure that potential other threads can't | ||
| 1134 | escape it. */ | ||
| 1135 | if (emacs_seccomp (SECCOMP_SET_MODE_FILTER, | ||
| 1136 | SECCOMP_FILTER_FLAG_TSYNC, &program) | ||
| 1137 | != 0) | ||
| 1138 | { | ||
| 1139 | emacs_perror ("seccomp"); | ||
| 1140 | goto out; | ||
| 1141 | } | ||
| 1142 | success = true; | ||
| 1143 | |||
| 1144 | out: | ||
| 1145 | if (0 <= fd) | ||
| 1146 | emacs_close (fd); | ||
| 1147 | free (buffer); | ||
| 1148 | return success; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | /* Load Secure Computing filter from file specified with the --seccomp | ||
| 1152 | option. Exit if that fails. */ | ||
| 1153 | |||
| 1154 | static void | ||
| 1155 | maybe_load_seccomp (int argc, char **argv) | ||
| 1156 | { | ||
| 1157 | int skip_args = 0; | ||
| 1158 | char *file = NULL; | ||
| 1159 | while (skip_args < argc - 1) | ||
| 1160 | { | ||
| 1161 | if (argmatch (argv, argc, "-seccomp", "--seccomp", 9, &file, | ||
| 1162 | &skip_args) | ||
| 1163 | || argmatch (argv, argc, "--", NULL, 2, NULL, &skip_args)) | ||
| 1164 | break; | ||
| 1165 | ++skip_args; | ||
| 1166 | } | ||
| 1167 | if (file == NULL) | ||
| 1168 | return; | ||
| 1169 | if (! load_seccomp (file)) | ||
| 1170 | fatal ("cannot enable seccomp filter from %s", file); | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | #endif /* SECCOMP_USABLE */ | ||
| 1174 | |||
| 980 | int | 1175 | int |
| 981 | main (int argc, char **argv) | 1176 | main (int argc, char **argv) |
| 982 | { | 1177 | { |
| 983 | /* Variable near the bottom of the stack, and aligned appropriately | 1178 | /* Variable near the bottom of the stack, and aligned appropriately |
| 984 | for pointers. */ | 1179 | for pointers. */ |
| 985 | void *stack_bottom_variable; | 1180 | void *stack_bottom_variable; |
| 1181 | |||
| 1182 | /* First, check whether we should apply a seccomp filter. This | ||
| 1183 | should come at the very beginning to allow the filter to protect | ||
| 1184 | the initialization phase. */ | ||
| 1185 | #if SECCOMP_USABLE | ||
| 1186 | maybe_load_seccomp (argc, argv); | ||
| 1187 | #endif | ||
| 1188 | |||
| 986 | bool no_loadup = false; | 1189 | bool no_loadup = false; |
| 987 | char *junk = 0; | 1190 | char *junk = 0; |
| 988 | char *dname_arg = 0; | 1191 | char *dname_arg = 0; |
| @@ -2179,12 +2382,15 @@ static const struct standard_args standard_args[] = | |||
| 2179 | { "-color", "--color", 5, 0}, | 2382 | { "-color", "--color", 5, 0}, |
| 2180 | { "-no-splash", "--no-splash", 3, 0 }, | 2383 | { "-no-splash", "--no-splash", 3, 0 }, |
| 2181 | { "-no-desktop", "--no-desktop", 3, 0 }, | 2384 | { "-no-desktop", "--no-desktop", 3, 0 }, |
| 2182 | /* The following two must be just above the file-name args, to get | 2385 | /* The following three must be just above the file-name args, to get |
| 2183 | them out of our way, but without mixing them with file names. */ | 2386 | them out of our way, but without mixing them with file names. */ |
| 2184 | { "-temacs", "--temacs", 1, 1 }, | 2387 | { "-temacs", "--temacs", 1, 1 }, |
| 2185 | #ifdef HAVE_PDUMPER | 2388 | #ifdef HAVE_PDUMPER |
| 2186 | { "-dump-file", "--dump-file", 1, 1 }, | 2389 | { "-dump-file", "--dump-file", 1, 1 }, |
| 2187 | #endif | 2390 | #endif |
| 2391 | #if SECCOMP_USABLE | ||
| 2392 | { "-seccomp", "--seccomp", 1, 1 }, | ||
| 2393 | #endif | ||
| 2188 | #ifdef HAVE_NS | 2394 | #ifdef HAVE_NS |
| 2189 | { "-NSAutoLaunch", 0, 5, 1 }, | 2395 | { "-NSAutoLaunch", 0, 5, 1 }, |
| 2190 | { "-NXAutoLaunch", 0, 5, 1 }, | 2396 | { "-NXAutoLaunch", 0, 5, 1 }, |
diff --git a/src/xdisp.c b/src/xdisp.c index a405d51f803..50d9040057a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -13607,8 +13607,9 @@ redisplay_tab_bar (struct frame *f) | |||
| 13607 | 13607 | ||
| 13608 | /* Get information about the tab-bar item which is displayed in GLYPH | 13608 | /* Get information about the tab-bar item which is displayed in GLYPH |
| 13609 | on frame F. Return in *PROP_IDX the index where tab-bar item | 13609 | on frame F. Return in *PROP_IDX the index where tab-bar item |
| 13610 | properties start in F->tab_bar_items. Value is false if | 13610 | properties start in F->tab_bar_items. Return in CLOSE_P an |
| 13611 | GLYPH doesn't display a tab-bar item. */ | 13611 | indication whether the click was on the close-tab icon of the tab. |
| 13612 | Value is false if GLYPH doesn't display a tab-bar item. */ | ||
| 13612 | 13613 | ||
| 13613 | static bool | 13614 | static bool |
| 13614 | tab_bar_item_info (struct frame *f, struct glyph *glyph, | 13615 | tab_bar_item_info (struct frame *f, struct glyph *glyph, |
| @@ -13654,7 +13655,6 @@ static int | |||
| 13654 | get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, | 13655 | get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, |
| 13655 | int *hpos, int *vpos, int *prop_idx, bool *close_p) | 13656 | int *hpos, int *vpos, int *prop_idx, bool *close_p) |
| 13656 | { | 13657 | { |
| 13657 | Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); | ||
| 13658 | struct window *w = XWINDOW (f->tab_bar_window); | 13658 | struct window *w = XWINDOW (f->tab_bar_window); |
| 13659 | int area; | 13659 | int area; |
| 13660 | 13660 | ||
| @@ -13668,18 +13668,7 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, | |||
| 13668 | if (!tab_bar_item_info (f, *glyph, prop_idx, close_p)) | 13668 | if (!tab_bar_item_info (f, *glyph, prop_idx, close_p)) |
| 13669 | return -1; | 13669 | return -1; |
| 13670 | 13670 | ||
| 13671 | /* Is mouse on the highlighted item? */ | 13671 | return *prop_idx == f->last_tab_bar_item ? 0 : 1; |
| 13672 | if (EQ (f->tab_bar_window, hlinfo->mouse_face_window) | ||
| 13673 | && *vpos >= hlinfo->mouse_face_beg_row | ||
| 13674 | && *vpos <= hlinfo->mouse_face_end_row | ||
| 13675 | && (*vpos > hlinfo->mouse_face_beg_row | ||
| 13676 | || *hpos >= hlinfo->mouse_face_beg_col) | ||
| 13677 | && (*vpos < hlinfo->mouse_face_end_row | ||
| 13678 | || *hpos < hlinfo->mouse_face_end_col | ||
| 13679 | || hlinfo->mouse_face_past_end)) | ||
| 13680 | return 0; | ||
| 13681 | |||
| 13682 | return 1; | ||
| 13683 | } | 13672 | } |
| 13684 | 13673 | ||
| 13685 | 13674 | ||
| @@ -13693,7 +13682,6 @@ void | |||
| 13693 | handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | 13682 | handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, |
| 13694 | int modifiers) | 13683 | int modifiers) |
| 13695 | { | 13684 | { |
| 13696 | Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); | ||
| 13697 | struct window *w = XWINDOW (f->tab_bar_window); | 13685 | struct window *w = XWINDOW (f->tab_bar_window); |
| 13698 | int hpos, vpos, prop_idx; | 13686 | int hpos, vpos, prop_idx; |
| 13699 | bool close_p; | 13687 | bool close_p; |
| @@ -13701,47 +13689,27 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | |||
| 13701 | Lisp_Object enabled_p; | 13689 | Lisp_Object enabled_p; |
| 13702 | int ts; | 13690 | int ts; |
| 13703 | 13691 | ||
| 13704 | /* If not on the highlighted tab-bar item, and mouse-highlight is | ||
| 13705 | non-nil, return. This is so we generate the tab-bar button | ||
| 13706 | click only when the mouse button is released on the same item as | ||
| 13707 | where it was pressed. However, when mouse-highlight is disabled, | ||
| 13708 | generate the click when the button is released regardless of the | ||
| 13709 | highlight, since tab-bar items are not highlighted in that | ||
| 13710 | case. */ | ||
| 13711 | frame_to_window_pixel_xy (w, &x, &y); | 13692 | frame_to_window_pixel_xy (w, &x, &y); |
| 13712 | ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); | 13693 | ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); |
| 13713 | if (ts == -1 | 13694 | if (ts == -1 |
| 13714 | || (ts != 0 && !NILP (Vmouse_highlight))) | 13695 | /* If the button is released on a tab other than the one where |
| 13696 | it was pressed, don't generate the tab-bar button click event. */ | ||
| 13697 | || (ts != 0 && !down_p)) | ||
| 13715 | return; | 13698 | return; |
| 13716 | 13699 | ||
| 13717 | /* When mouse-highlight is off, generate the click for the item | ||
| 13718 | where the button was pressed, disregarding where it was | ||
| 13719 | released. */ | ||
| 13720 | if (NILP (Vmouse_highlight) && !down_p) | ||
| 13721 | prop_idx = f->last_tab_bar_item; | ||
| 13722 | |||
| 13723 | /* If item is disabled, do nothing. */ | 13700 | /* If item is disabled, do nothing. */ |
| 13724 | enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); | 13701 | enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); |
| 13725 | if (NILP (enabled_p)) | 13702 | if (NILP (enabled_p)) |
| 13726 | return; | 13703 | return; |
| 13727 | 13704 | ||
| 13728 | if (down_p) | 13705 | if (down_p) |
| 13729 | { | 13706 | f->last_tab_bar_item = prop_idx; /* record the pressed tab */ |
| 13730 | /* Show item in pressed state. */ | ||
| 13731 | if (!NILP (Vmouse_highlight)) | ||
| 13732 | show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN); | ||
| 13733 | f->last_tab_bar_item = prop_idx; | ||
| 13734 | } | ||
| 13735 | else | 13707 | else |
| 13736 | { | 13708 | { |
| 13737 | Lisp_Object key, frame; | 13709 | Lisp_Object key, frame; |
| 13738 | struct input_event event; | 13710 | struct input_event event; |
| 13739 | EVENT_INIT (event); | 13711 | EVENT_INIT (event); |
| 13740 | 13712 | ||
| 13741 | /* Show item in released state. */ | ||
| 13742 | if (!NILP (Vmouse_highlight)) | ||
| 13743 | show_mouse_face (hlinfo, DRAW_IMAGE_RAISED); | ||
| 13744 | |||
| 13745 | key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY); | 13713 | key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY); |
| 13746 | 13714 | ||
| 13747 | XSETFRAME (frame, f); | 13715 | XSETFRAME (frame, f); |
| @@ -13754,97 +13722,6 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | |||
| 13754 | } | 13722 | } |
| 13755 | } | 13723 | } |
| 13756 | 13724 | ||
| 13757 | |||
| 13758 | /* Possibly highlight a tab-bar item on frame F when mouse moves to | ||
| 13759 | tab-bar window-relative coordinates X/Y. Called from | ||
| 13760 | note_mouse_highlight. */ | ||
| 13761 | |||
| 13762 | static void | ||
| 13763 | note_tab_bar_highlight (struct frame *f, int x, int y) | ||
| 13764 | { | ||
| 13765 | Lisp_Object window = f->tab_bar_window; | ||
| 13766 | struct window *w = XWINDOW (window); | ||
| 13767 | Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); | ||
| 13768 | int hpos, vpos; | ||
| 13769 | struct glyph *glyph; | ||
| 13770 | struct glyph_row *row; | ||
| 13771 | int i; | ||
| 13772 | Lisp_Object enabled_p; | ||
| 13773 | int prop_idx; | ||
| 13774 | bool close_p; | ||
| 13775 | enum draw_glyphs_face draw = DRAW_IMAGE_RAISED; | ||
| 13776 | int rc; | ||
| 13777 | |||
| 13778 | /* Function note_mouse_highlight is called with negative X/Y | ||
| 13779 | values when mouse moves outside of the frame. */ | ||
| 13780 | if (x <= 0 || y <= 0) | ||
| 13781 | { | ||
| 13782 | clear_mouse_face (hlinfo); | ||
| 13783 | return; | ||
| 13784 | } | ||
| 13785 | |||
| 13786 | rc = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); | ||
| 13787 | if (rc < 0) | ||
| 13788 | { | ||
| 13789 | /* Not on tab-bar item. */ | ||
| 13790 | clear_mouse_face (hlinfo); | ||
| 13791 | return; | ||
| 13792 | } | ||
| 13793 | else if (rc == 0) | ||
| 13794 | /* On same tab-bar item as before. */ | ||
| 13795 | goto set_help_echo; | ||
| 13796 | |||
| 13797 | clear_mouse_face (hlinfo); | ||
| 13798 | |||
| 13799 | bool mouse_down_p = false; | ||
| 13800 | #ifndef HAVE_NS | ||
| 13801 | /* Mouse is down, but on different tab-bar item? */ | ||
| 13802 | Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 13803 | mouse_down_p = (gui_mouse_grabbed (dpyinfo) | ||
| 13804 | && f == dpyinfo->last_mouse_frame); | ||
| 13805 | |||
| 13806 | if (mouse_down_p && f->last_tab_bar_item != prop_idx) | ||
| 13807 | return; | ||
| 13808 | #endif | ||
| 13809 | draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; | ||
| 13810 | |||
| 13811 | /* If tab-bar item is not enabled, don't highlight it. */ | ||
| 13812 | enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); | ||
| 13813 | if (!NILP (enabled_p) && !NILP (Vmouse_highlight)) | ||
| 13814 | { | ||
| 13815 | /* Compute the x-position of the glyph. In front and past the | ||
| 13816 | image is a space. We include this in the highlighted area. */ | ||
| 13817 | row = MATRIX_ROW (w->current_matrix, vpos); | ||
| 13818 | for (i = x = 0; i < hpos; ++i) | ||
| 13819 | x += row->glyphs[TEXT_AREA][i].pixel_width; | ||
| 13820 | |||
| 13821 | /* Record this as the current active region. */ | ||
| 13822 | hlinfo->mouse_face_beg_col = hpos; | ||
| 13823 | hlinfo->mouse_face_beg_row = vpos; | ||
| 13824 | hlinfo->mouse_face_beg_x = x; | ||
| 13825 | hlinfo->mouse_face_past_end = false; | ||
| 13826 | |||
| 13827 | hlinfo->mouse_face_end_col = hpos + 1; | ||
| 13828 | hlinfo->mouse_face_end_row = vpos; | ||
| 13829 | hlinfo->mouse_face_end_x = x + glyph->pixel_width; | ||
| 13830 | hlinfo->mouse_face_window = window; | ||
| 13831 | hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID; | ||
| 13832 | |||
| 13833 | /* Display it as active. */ | ||
| 13834 | show_mouse_face (hlinfo, draw); | ||
| 13835 | } | ||
| 13836 | |||
| 13837 | set_help_echo: | ||
| 13838 | |||
| 13839 | /* Set help_echo_string to a help string to display for this tab-bar item. | ||
| 13840 | XTread_socket does the rest. */ | ||
| 13841 | help_echo_object = help_echo_window = Qnil; | ||
| 13842 | help_echo_pos = -1; | ||
| 13843 | help_echo_string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_HELP); | ||
| 13844 | if (NILP (help_echo_string)) | ||
| 13845 | help_echo_string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION); | ||
| 13846 | } | ||
| 13847 | |||
| 13848 | #endif /* HAVE_WINDOW_SYSTEM */ | 13725 | #endif /* HAVE_WINDOW_SYSTEM */ |
| 13849 | 13726 | ||
| 13850 | /* Find the tab-bar item at X coordinate and return its information. */ | 13727 | /* Find the tab-bar item at X coordinate and return its information. */ |
| @@ -33537,13 +33414,9 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 33537 | frame_to_window_pixel_xy (w, &x, &y); | 33414 | frame_to_window_pixel_xy (w, &x, &y); |
| 33538 | 33415 | ||
| 33539 | #if defined (HAVE_WINDOW_SYSTEM) | 33416 | #if defined (HAVE_WINDOW_SYSTEM) |
| 33540 | /* Handle tab-bar window differently since it doesn't display a | 33417 | /* We don't highlight tab-bar buttons. */ |
| 33541 | buffer. */ | ||
| 33542 | if (EQ (window, f->tab_bar_window)) | 33418 | if (EQ (window, f->tab_bar_window)) |
| 33543 | { | 33419 | return; |
| 33544 | note_tab_bar_highlight (f, x, y); | ||
| 33545 | return; | ||
| 33546 | } | ||
| 33547 | #endif | 33420 | #endif |
| 33548 | 33421 | ||
| 33549 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) | 33422 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) |