commit 8969953328a6cb5b7f131c2b7441e9d5d21191aa (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Sat Mar 5 06:23:30 2022 +0000 Garbage Haiku tooltip frames on size change * haikuterm.c (haiku_read_socket): If tooltip frame dimensions actually changed, garbage the frame. diff --git a/src/haikuterm.c b/src/haikuterm.c index 833b3bee2a..ac087e3bec 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -2718,6 +2718,10 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) if (FRAME_TOOLTIP_P (f)) { + if (FRAME_PIXEL_WIDTH (f) != width + || FRAME_PIXEL_HEIGHT (f) != height) + SET_FRAME_GARBAGED (f); + FRAME_PIXEL_WIDTH (f) = width; FRAME_PIXEL_HEIGHT (f) = height; commit 2f5a8c4f275eeb36f575c312adb9a17bd8168994 Author: Paul Eggert Date: Fri Mar 4 19:21:38 2022 -0800 Fix process-attributes time precision on BSD * src/sysdep.c (timeval_to_timespec) [__FreeBSD__ || DARWIN_OS]: Remove; no longer needed. (make_lisp_s_us) [__FreeBSD__ || DARWIN_OS || __OpenBSD__]: New function. (make_lisp_timeval) [__FreeBSD__ || DARWIN_OS || __OpenBSD__]: Rework in terms of make_lisp_s_us. (system_process_attributes) [__FreeBSD__ || DARWIN_OS || __OpenBSD__]: Simplify by using the above. This fixes some minor problems where timestamps promised more precision than was actually available. diff --git a/src/sysdep.c b/src/sysdep.c index a266307588..b5b18ee6c0 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -3152,26 +3152,26 @@ list_system_processes (void) #endif /* !defined (WINDOWSNT) */ +#if defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__ -#if defined __FreeBSD__ || defined DARWIN_OS - -static struct timespec -timeval_to_timespec (struct timeval t) -{ - return make_timespec (t.tv_sec, t.tv_usec * 1000); -} static Lisp_Object -make_lisp_timeval (struct timeval t) +make_lisp_s_us (time_t s, long us) { - return make_lisp_time (timeval_to_timespec (t)); + Lisp_Object sec = make_int (s); + Lisp_Object usec = make_fixnum (us); + Lisp_Object hz = make_fixnum (1000000); + Lisp_Object ticks = CALLN (Fplus, CALLN (Ftimes, sec, hz), usec); + return Ftime_convert (Fcons (ticks, hz), Qnil); } -#elif defined __OpenBSD__ +#endif + +#if defined __FreeBSD__ || defined DARWIN_OS static Lisp_Object -make_lisp_timeval (long sec, long usec) +make_lisp_timeval (struct timeval t) { - return make_lisp_time(make_timespec(sec, usec * 1000)); + return make_lisp_s_us (t.tv_sec, t.tv_usec); } #endif @@ -3674,7 +3674,6 @@ system_process_attributes (Lisp_Object pid) char *ttyname; size_t len; char args[MAXPATHLEN]; - struct timespec t, now; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID}; struct kinfo_proc proc; @@ -3755,35 +3754,30 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qcminflt, make_fixnum (proc.ki_rusage_ch.ru_minflt)), attrs); attrs = Fcons (Fcons (Qcmajflt, make_fixnum (proc.ki_rusage_ch.ru_majflt)), attrs); - attrs = Fcons (Fcons (Qutime, make_lisp_timeval (proc.ki_rusage.ru_utime)), - attrs); - attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc.ki_rusage.ru_stime)), - attrs); - t = timespec_add (timeval_to_timespec (proc.ki_rusage.ru_utime), - timeval_to_timespec (proc.ki_rusage.ru_stime)); - attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs); + Lisp_Object utime = make_lisp_timeval (proc.ki_rusage.ru_utime); + attrs = Fcons (Fcons (Qutime, utime), attrs); + Lisp_Object stime = make_lisp_timeval (proc.ki_rusage.ru_stime); + attrs = Fcons (Fcons (Qstime, stime), attrs); + attrs = Fcons (Fcons (Qtime, Ftime_add (utime, stime)), attrs); - attrs = Fcons (Fcons (Qcutime, - make_lisp_timeval (proc.ki_rusage_ch.ru_utime)), - attrs); - attrs = Fcons (Fcons (Qcstime, - make_lisp_timeval (proc.ki_rusage_ch.ru_stime)), - attrs); - t = timespec_add (timeval_to_timespec (proc.ki_rusage_ch.ru_utime), - timeval_to_timespec (proc.ki_rusage_ch.ru_stime)); - attrs = Fcons (Fcons (Qctime, make_lisp_time (t)), attrs); + Lisp_Object cutime = make_lisp_timeval (proc.ki_rusage_ch.ru_utime); + attrs = Fcons (Fcons (Qcutime, cutime), attrs); + Lisp_Object cstime = make_lisp_timeval (proc.ki_rusage_ch.ru_stime); + attrs = Fcons (Fcons (Qcstime, cstime), attrs); + attrs = Fcons (Fcons (Qctime, Ftime_add (cutime, cstime)), attrs); attrs = Fcons (Fcons (Qthcount, INT_TO_INTEGER (proc.ki_numthreads)), attrs); attrs = Fcons (Fcons (Qpri, make_fixnum (proc.ki_pri.pri_native)), attrs); attrs = Fcons (Fcons (Qnice, make_fixnum (proc.ki_nice)), attrs); - attrs = Fcons (Fcons (Qstart, make_lisp_timeval (proc.ki_start)), attrs); + Lisp_Object start = make_lisp_timeval (proc.ki_start); + attrs = Fcons (Fcons (Qstart, start), attrs); attrs = Fcons (Fcons (Qvsize, make_fixnum (proc.ki_size >> 10)), attrs); attrs = Fcons (Fcons (Qrss, make_fixnum (proc.ki_rssize * pagesize >> 10)), attrs); - now = current_timespec (); - t = timespec_sub (now, timeval_to_timespec (proc.ki_start)); - attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs); + Lisp_Object now = Ftime_convert (Qnil, make_fixnum (1000000)); + Lisp_Object etime = Ftime_convert (Ftime_subtract (now, start), Qnil); + attrs = Fcons (Fcons (Qetime, etime), attrs); len = sizeof fscale; if (sysctlbyname ("kern.fscale", &fscale, &len, NULL, 0) == 0) @@ -3843,7 +3837,6 @@ system_process_attributes (Lisp_Object pid) struct kinfo_proc proc; struct passwd *pw; struct group *gr; - struct timespec t; struct uvmexp uvmexp; Lisp_Object attrs = Qnil; @@ -3925,20 +3918,14 @@ system_process_attributes (Lisp_Object pid) /* FIXME: missing cminflt, cmajflt. */ - attrs = Fcons (Fcons (Qutime, make_lisp_timeval (proc.p_uutime_sec, - proc.p_uutime_usec)), - attrs); - attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc.p_ustime_sec, - proc.p_ustime_usec)), - attrs); - t = timespec_add (make_timespec (proc.p_uutime_sec, - proc.p_uutime_usec * 1000), - make_timespec (proc.p_ustime_sec, - proc.p_ustime_usec * 1000)); - attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs); - - attrs = Fcons (Fcons (Qcutime, make_lisp_timeval (proc.p_uctime_sec, - proc.p_uctime_usec)), + Lisp_Object utime = make_lisp_s_us (proc.p_uutime_sec, proc.p_uutime_usec); + attrs = Fcons (Fcons (Qutime, utime), attrs); + Lisp_Object stime = make_lisp_s_us (proc.p_ustime_sec, proc.p_ustime_usec); + attrs = Fcons (Fcons (Qstime, stime), attrs); + attrs = Fcons (Fcons (Qtime, Ftime_add (utime, stime)), attrs); + + attrs = Fcons (Fcons (Qcutime, make_lisp_s_us (proc.p_uctime_sec, + proc.p_uctime_usec)), attrs); /* FIXME: missing cstime and thus ctime. */ @@ -3948,8 +3935,8 @@ system_process_attributes (Lisp_Object pid) /* FIXME: missing thcount (thread count) */ - attrs = Fcons (Fcons (Qstart, make_lisp_timeval (proc.p_ustart_sec, - proc.p_ustart_usec)), + attrs = Fcons (Fcons (Qstart, make_lisp_s_us (proc.p_ustart_sec, + proc.p_ustart_usec)), attrs); len = (proc.p_vm_tsize + proc.p_vm_dsize + proc.p_vm_ssize) * pagesize >> 10; @@ -3958,10 +3945,11 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qrss, make_fixnum (proc.p_vm_rssize * pagesize >> 10)), attrs); - t = make_timespec (proc.p_ustart_sec, - proc.p_ustart_usec * 1000); - t = timespec_sub (current_timespec (), t); - attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs); + Lisp_Object now = Ftime_convert (Qnil, make_fixnum (1000000)); + Lisp_Object start = make_lisp_s_us (proc.p_ustart_sec, + proc.p_ustart_usec); + Lisp_Object etime = Ftime_convert (Ftime_subtract (now, start), Qnil); + attrs = Fcons (Fcons (Qetime, etime), attrs); len = sizeof (fscale); mib[0] = CTL_KERN; @@ -4022,7 +4010,6 @@ system_process_attributes (Lisp_Object pid) struct group *gr; char *ttyname; struct timeval starttime; - struct timespec t, now; dev_t tdev; uid_t uid; gid_t gid; @@ -4133,11 +4120,12 @@ system_process_attributes (Lisp_Object pid) starttime = proc.kp_proc.p_starttime; attrs = Fcons (Fcons (Qnice, make_fixnum (proc.kp_proc.p_nice)), attrs); - attrs = Fcons (Fcons (Qstart, make_lisp_timeval (starttime)), attrs); + Lisp_Object start = make_lisp_timeval (starttime); + attrs = Fcons (Fcons (Qstart, start), attrs); - now = current_timespec (); - t = timespec_sub (now, timeval_to_timespec (starttime)); - attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs); + Lisp_Object now = Ftime_convert (Qnil, make_fixnum (1000000)); + Lisp_Object etime = Ftime_convert (Ftime_subtract (now, start), Qnil); + attrs = Fcons (Fcons (Qetime, etime), attrs); struct proc_taskinfo taskinfo; if (proc_pidinfo (proc_id, PROC_PIDTASKINFO, 0, &taskinfo, sizeof (taskinfo)) > 0) commit 2fbd48f733426824cb89b958378a52cfb053774c Author: Paul Eggert Date: Fri Mar 4 19:21:38 2022 -0800 Fix process-attributes time precision on GNU/Linux * src/sysdep.c [GNU_LINUX]: (time_from_jiffies): Simplify by using time-convert. Change args and result type. All uses changed. (ltime_from_jiffies): Remove; call time_from_jiffies instead. (put_jiffies): New function. (get_up_time): Return Lisp_Object not struct timespec. All uses changed. Simplify by using time-add. (system_process_attributes): Simplify by using the above. This fixes some minor problems where timestamps promised more precision than was actually available. When info is not available (e.g., sysconf fails) do not place it into the alist. * src/timefns.c (float_time): Now extern. diff --git a/src/sysdep.c b/src/sysdep.c index c9101f9481..a266307588 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -3177,70 +3177,45 @@ make_lisp_timeval (long sec, long usec) #endif #ifdef GNU_LINUX -static struct timespec -time_from_jiffies (unsigned long long tval, long hz) -{ - unsigned long long s = tval / hz; - unsigned long long frac = tval % hz; - int ns; - - if (TYPE_MAXIMUM (time_t) < s) - time_overflow (); - if (LONG_MAX - 1 <= ULLONG_MAX / TIMESPEC_HZ - || frac <= ULLONG_MAX / TIMESPEC_HZ) - ns = frac * TIMESPEC_HZ / hz; - else - { - /* This is reachable only in the unlikely case that HZ * HZ - exceeds ULLONG_MAX. It calculates an approximation that is - guaranteed to be in range. */ - long hz_per_ns = hz / TIMESPEC_HZ + (hz % TIMESPEC_HZ != 0); - ns = frac / hz_per_ns; - } - return make_timespec (s, ns); +static Lisp_Object +time_from_jiffies (unsigned long long ticks, Lisp_Object hz, Lisp_Object form) +{ + return Ftime_convert (Fcons (make_uint (ticks), hz), form); } static Lisp_Object -ltime_from_jiffies (unsigned long long tval, long hz) +put_jiffies (Lisp_Object attrs, Lisp_Object propname, + unsigned long long ticks, Lisp_Object hz) { - struct timespec t = time_from_jiffies (tval, hz); - return make_lisp_time (t); + return Fcons (Fcons (propname, time_from_jiffies (ticks, hz, Qnil)), attrs); } -static struct timespec +static Lisp_Object get_up_time (void) { FILE *fup; - struct timespec up = make_timespec (0, 0); + Lisp_Object up = Qnil; block_input (); fup = emacs_fopen ("/proc/uptime", "r"); if (fup) { - unsigned long long upsec, upfrac; + unsigned long long upsec; + EMACS_UINT upfrac; int upfrac_start, upfrac_end; - if (fscanf (fup, "%llu.%n%llu%n", + if (fscanf (fup, "%llu.%n%"pI"u%n", &upsec, &upfrac_start, &upfrac, &upfrac_end) == 2) { - if (TYPE_MAXIMUM (time_t) < upsec) - { - upsec = TYPE_MAXIMUM (time_t); - upfrac = TIMESPEC_HZ - 1; - } - else - { - int upfraclen = upfrac_end - upfrac_start; - for (; upfraclen < LOG10_TIMESPEC_HZ; upfraclen++) - upfrac *= 10; - for (; LOG10_TIMESPEC_HZ < upfraclen; upfraclen--) - upfrac /= 10; - upfrac = min (upfrac, TIMESPEC_HZ - 1); - } - up = make_timespec (upsec, upfrac); + EMACS_INT hz = 1; + for (int i = upfrac_start; i < upfrac_end; i++) + hz *= 10; + Lisp_Object sec = make_uint (upsec); + Lisp_Object subsec = Fcons (make_fixnum (upfrac), make_fixnum (hz)); + up = Ftime_add (sec, subsec); } fclose (fup); } @@ -3361,7 +3336,6 @@ system_process_attributes (Lisp_Object pid) unsigned long long u_time, s_time, cutime, cstime, start; long priority, niceness, rss; unsigned long minflt, majflt, cminflt, cmajflt, vsize; - struct timespec tnow, tstart, tboot, telapsed, us_time; double pcpu, pmem; Lisp_Object attrs = Qnil; Lisp_Object decoded_cmd; @@ -3449,45 +3423,41 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qmajflt, INT_TO_INTEGER (majflt)), attrs); attrs = Fcons (Fcons (Qcminflt, INT_TO_INTEGER (cminflt)), attrs); attrs = Fcons (Fcons (Qcmajflt, INT_TO_INTEGER (cmajflt)), attrs); + clocks_per_sec = sysconf (_SC_CLK_TCK); - if (clocks_per_sec < 0) - clocks_per_sec = 100; - attrs = Fcons (Fcons (Qutime, - ltime_from_jiffies (u_time, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qstime, - ltime_from_jiffies (s_time, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qtime, - ltime_from_jiffies (s_time + u_time, - clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qcutime, - ltime_from_jiffies (cutime, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qcstime, - ltime_from_jiffies (cstime, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qctime, - ltime_from_jiffies (cstime + cutime, - clocks_per_sec)), - attrs); + if (0 < clocks_per_sec) + { + Lisp_Object hz = make_int (clocks_per_sec); + attrs = put_jiffies (attrs, Qutime, u_time, hz); + attrs = put_jiffies (attrs, Qstime, s_time, hz); + attrs = put_jiffies (attrs, Qtime, s_time + u_time, hz); + attrs = put_jiffies (attrs, Qcutime, cutime, hz); + attrs = put_jiffies (attrs, Qcstime, cstime, hz); + attrs = put_jiffies (attrs, Qctime, cstime + cutime, hz); + + Lisp_Object uptime = get_up_time (); + if (!NILP (uptime)) + { + Lisp_Object now = Ftime_convert (Qnil, hz); + Lisp_Object boot = Ftime_subtract (now, uptime); + Lisp_Object tstart = time_from_jiffies (start, hz, hz); + Lisp_Object lstart = + Ftime_convert (Ftime_add (boot, tstart), Qnil); + attrs = Fcons (Fcons (Qstart, lstart), attrs); + Lisp_Object etime = + Ftime_convert (Ftime_subtract (uptime, tstart), Qnil); + attrs = Fcons (Fcons (Qetime, etime), attrs); + pcpu = (100.0 * (s_time + u_time) + / (clocks_per_sec * float_time (etime))); + attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs); + } + } + attrs = Fcons (Fcons (Qpri, make_fixnum (priority)), attrs); attrs = Fcons (Fcons (Qnice, make_fixnum (niceness)), attrs); attrs = Fcons (Fcons (Qthcount, INT_TO_INTEGER (thcount)), attrs); - tnow = current_timespec (); - telapsed = get_up_time (); - tboot = timespec_sub (tnow, telapsed); - tstart = time_from_jiffies (start, clocks_per_sec); - tstart = timespec_add (tboot, tstart); - attrs = Fcons (Fcons (Qstart, make_lisp_time (tstart)), attrs); attrs = Fcons (Fcons (Qvsize, INT_TO_INTEGER (vsize / 1024)), attrs); attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (4 * rss)), attrs); - telapsed = timespec_sub (tnow, tstart); - attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs); - us_time = time_from_jiffies (u_time + s_time, clocks_per_sec); - pcpu = timespectod (us_time) / timespectod (telapsed); - attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); pmem = 4.0 * 100 * rss / procfs_get_total_memory (); if (pmem > 100) pmem = 100; diff --git a/src/systime.h b/src/systime.h index f3b1b2394d..41d728f1c2 100644 --- a/src/systime.h +++ b/src/systime.h @@ -92,6 +92,7 @@ extern bool list4_to_timespec (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, struct timespec *); extern struct timespec lisp_time_argument (Lisp_Object); extern AVOID time_overflow (void); +extern double float_time (Lisp_Object); extern void init_timefns (void); extern void syms_of_timefns (void); diff --git a/src/timefns.c b/src/timefns.c index 795a6484ce..9b5b090ba7 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -881,7 +881,7 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, /* Convert a Lisp timestamp SPECIFIED_TIME to double. Signal an error if unsuccessful. */ -static double +double float_time (Lisp_Object specified_time) { double t; commit b19ec1be3c35b0ec231282ab51d0b320e2967052 Author: Paul Eggert Date: Fri Mar 4 19:21:38 2022 -0800 %CPU can exceed 100 on GNU/Linux * src/sysdep.c (system_process_attributes) [GNU_LINUX]: CPU usage can exceed 100% on a multicore platform when Emacs is not entirely single-threaded. diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index d338d59a81..ed07c1cbf7 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -2382,8 +2382,9 @@ occupied by the process in the machine's physical memory. @item pcpu The percentage of the CPU time used by the process since it started. -The corresponding @var{value} is a floating-point number between 0 and -100. +The corresponding @var{value} is a nonnegative floating-point number. +Although in theory the number can exceed 100 on a multicore platform, +it is usually less than 100 because Emacs is typically single-threaded. @item pmem The percentage of the total physical memory installed on the machine diff --git a/src/sysdep.c b/src/sysdep.c index 28d32c77c6..c9101f9481 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -3487,8 +3487,6 @@ system_process_attributes (Lisp_Object pid) attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs); us_time = time_from_jiffies (u_time + s_time, clocks_per_sec); pcpu = timespectod (us_time) / timespectod (telapsed); - if (pcpu > 1.0) - pcpu = 1.0; attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); pmem = 4.0 * 100 * rss / procfs_get_total_memory (); if (pmem > 100) commit af742bb3bbf37b844367e27fd598c6b0ae868d05 Author: Paul Eggert Date: Fri Mar 4 19:21:38 2022 -0800 Avoid unnecessary make_float in time arithmetic * src/timefns.c (float_time): New function. (time_arith, Ffloat_time): Use it. diff --git a/src/timefns.c b/src/timefns.c index f73c69149f..795a6484ce 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -879,6 +879,16 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, return form; } +/* Convert a Lisp timestamp SPECIFIED_TIME to double. + Signal an error if unsuccessful. */ +static double +float_time (Lisp_Object specified_time) +{ + double t; + decode_lisp_time (specified_time, false, 0, &t); + return t; +} + /* Convert Z to time_t, returning true if it fits. */ static bool mpz_time (mpz_t const z, time_t *t) @@ -1068,7 +1078,7 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) if (FLOATP (a) && !isfinite (XFLOAT_DATA (a))) { double da = XFLOAT_DATA (a); - double db = XFLOAT_DATA (Ffloat_time (b)); + double db = float_time (b); return make_float (subtract ? da - db : da + db); } enum timeform aform, bform; @@ -1264,9 +1274,7 @@ If precise time stamps are required, use either `encode-time', or (if you need time as a string) `format-time-string'. */) (Lisp_Object specified_time) { - double t; - decode_lisp_time (specified_time, false, 0, &t); - return make_float (t); + return make_float (float_time (specified_time)); } /* Write information into buffer S of size MAXSIZE, according to the commit 58b5652f6bd605e441037a29e8abcb615e76bea8 Author: Paul Eggert Date: Fri Mar 4 19:21:37 2022 -0800 Fix FreeBSD typo in process-attributes cstime * src/sysdep.c (system_process_attributes) [__FreeBSD__]: Fix typo that caused cstime to always equal cutime. diff --git a/src/sysdep.c b/src/sysdep.c index 95f77febcb..28d32c77c6 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -3799,7 +3799,7 @@ system_process_attributes (Lisp_Object pid) make_lisp_timeval (proc.ki_rusage_ch.ru_utime)), attrs); attrs = Fcons (Fcons (Qcstime, - make_lisp_timeval (proc.ki_rusage_ch.ru_utime)), + make_lisp_timeval (proc.ki_rusage_ch.ru_stime)), attrs); t = timespec_add (timeval_to_timespec (proc.ki_rusage_ch.ru_utime), timeval_to_timespec (proc.ki_rusage_ch.ru_stime)); commit 3c5aad0b8b88fd763e46c41a2fab87c9dc206e97 Author: Po Lu Date: Sat Mar 5 11:13:37 2022 +0800 Flush default GC before using it in functions that accept a GContext * src/xterm.c (x_scroll_run): Flush normal_gc, since some of the following code depends on it being up-to-date. diff --git a/src/xterm.c b/src/xterm.c index 55224d93c9..5f8e804c62 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5983,6 +5983,12 @@ x_scroll_run (struct window *w, struct run *run) } #endif + /* Some of the following code depends on `normal_gc' being + up-to-date on the X server, but doesn't call a routine that will + flush it first. So do this ourselves instead. */ + XFlushGC (FRAME_X_DISPLAY (f), + f->output_data.x->normal_gc); + #ifdef USE_CAIRO if (FRAME_CR_CONTEXT (f)) { commit 4564ae5a3d87ce6aee35d6a3c689fd0400f25859 Author: Po Lu Date: Sat Mar 5 10:44:26 2022 +0800 Remove render code in x_scroll_run and drop NoExpose events instead * src/xterm.c (x_scroll_run): Stop avoiding NoExpose events through XRenderComposite. (handle_one_xevent): Drop NoExpose events to placate some code in Athena widgets. diff --git a/src/xterm.c b/src/xterm.c index 89ec43b470..55224d93c9 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -6037,24 +6037,12 @@ x_scroll_run (struct window *w, struct run *run) } else #endif /* USE_CAIRO */ - { -#ifdef HAVE_XRENDER - /* Avoid useless NoExpose events. This way, we only get regular - exposure events when there is actually something to - expose. */ - if (FRAME_X_PICTURE (f) != None) - XRenderComposite (FRAME_X_DISPLAY (f), PictOpSrc, FRAME_X_PICTURE (f), - None, FRAME_X_PICTURE (f), x, from_y, 0, 0, x, to_y, - width, height); - else -#endif - XCopyArea (FRAME_X_DISPLAY (f), - FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), - f->output_data.x->normal_gc, - x, from_y, - width, height, - x, to_y); - } + XCopyArea (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), + f->output_data.x->normal_gc, + x, from_y, + width, height, + x, to_y); unblock_input (); } @@ -10367,6 +10355,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, case NoExpose: /* This occurs when an XCopyArea's source area was completely available. */ +#ifdef USE_X_TOOLKIT + *finish = X_EVENT_DROP; +#endif break; case UnmapNotify: commit a658be774268577cc8283ee05998d8b4225d7368 Author: Dmitry Gutov Date: Sat Mar 5 04:32:54 2022 +0200 project-shell: Ensure the resulting buffer is live * lisp/progmodes/project.el (project-shell): Make sure to recreate the shell if the buffer exists but not live (https://lists.gnu.org/archive/html/emacs-devel/2022-03/msg00017.html). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index b44f4618be..daaf86f327 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1007,6 +1007,8 @@ directories listed in `vc-directory-exclusion-list'." (interactive) (vc-dir (project-root (project-current t)))) +(declare-function comint-check-proc "comint") + ;;;###autoload (defun project-shell () "Start an inferior shell in the current project's root directory. @@ -1015,11 +1017,14 @@ switch to it. Otherwise, create a new shell buffer. With \\[universal-argument] prefix arg, create a new inferior shell buffer even if one already exists." (interactive) + (require 'comint) (let* ((default-directory (project-root (project-current t))) (default-project-shell-name (project-prefixed-buffer-name "shell")) (shell-buffer (get-buffer default-project-shell-name))) (if (and shell-buffer (not current-prefix-arg)) - (pop-to-buffer shell-buffer (bound-and-true-p display-comint-buffer-action)) + (if (comint-check-proc shell-buffer) + (pop-to-buffer shell-buffer (bound-and-true-p display-comint-buffer-action)) + (shell shell-buffer)) (shell (generate-new-buffer-name default-project-shell-name))))) ;;;###autoload commit 76d79e1576956eb0c07eb830fd75f7b7c4192efe Author: Po Lu Date: Sat Mar 5 10:05:14 2022 +0800 Prevent some NoExpose events from being generated * src/xterm.c (x_scroll_run): Use the rendering extension if available to avoid NoExpose events. diff --git a/src/xterm.c b/src/xterm.c index 948afa5680..89ec43b470 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -6037,12 +6037,24 @@ x_scroll_run (struct window *w, struct run *run) } else #endif /* USE_CAIRO */ - XCopyArea (FRAME_X_DISPLAY (f), - FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), - f->output_data.x->normal_gc, - x, from_y, - width, height, - x, to_y); + { +#ifdef HAVE_XRENDER + /* Avoid useless NoExpose events. This way, we only get regular + exposure events when there is actually something to + expose. */ + if (FRAME_X_PICTURE (f) != None) + XRenderComposite (FRAME_X_DISPLAY (f), PictOpSrc, FRAME_X_PICTURE (f), + None, FRAME_X_PICTURE (f), x, from_y, 0, 0, x, to_y, + width, height); + else +#endif + XCopyArea (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), + f->output_data.x->normal_gc, + x, from_y, + width, height, + x, to_y); + } unblock_input (); } commit 6efed75ff3158214d16482f2bcca06c9ac010da4 Author: Po Lu Date: Sat Mar 5 09:35:44 2022 +0800 Implement `pre_activate' callbacks for Motif menus * lwlib/lwlib-Xm.c (make_menu_in_widget): Add xm_pop_up_callback as the popup callback. (xm_pop_up_callback): New function. diff --git a/lwlib/lwlib-Xm.c b/lwlib/lwlib-Xm.c index a1114d4255..52ea304f71 100644 --- a/lwlib/lwlib-Xm.c +++ b/lwlib/lwlib-Xm.c @@ -115,6 +115,7 @@ static void xm_generic_callback (Widget, XtPointer, XtPointer); static void xm_nosel_callback (Widget, XtPointer, XtPointer); static void xm_pull_down_callback (Widget, XtPointer, XtPointer); static void xm_pop_down_callback (Widget, XtPointer, XtPointer); +static void xm_pop_up_callback (Widget, XtPointer, XtPointer); static void xm_internal_update_other_instances (Widget, XtPointer, XtPointer); static void xm_arm_callback (Widget, XtPointer, XtPointer); @@ -513,8 +514,12 @@ make_menu_in_widget (widget_instance* instance, /* Add a callback to popups and pulldowns that is called when it is made invisible again. */ if (!menubar_p) - XtAddCallback (XtParent (widget), XmNpopdownCallback, - xm_pop_down_callback, (XtPointer)instance); + { + XtAddCallback (XtParent (widget), XmNpopdownCallback, + xm_pop_down_callback, (XtPointer) instance); + XtAddCallback (XtParent (widget), XmNpopupCallback, + xm_pop_up_callback, (XtPointer) instance); + } /* Preserve the first KEEP_FIRST_CHILDREN old children. */ for (child_index = 0, cur = val; child_index < keep_first_children; @@ -1915,6 +1920,18 @@ xm_pop_down_callback (Widget widget, do_call (widget, closure, post_activate); } +static void +xm_pop_up_callback (Widget widget, + XtPointer closure, + XtPointer call_data) +{ + widget_instance *instance = (widget_instance *) closure; + + if ((!instance->pop_up_p && XtParent (widget) == instance->widget) + || XtParent (widget) == instance->parent) + do_call (widget, closure, pre_activate); +} + /* set the keyboard focus */ void commit 08221a58b752326c077707622b8b1df429564f3a Author: Po Lu Date: Sat Mar 5 08:15:25 2022 +0800 Fix the MS-DOS build * msdos/sedlibmk.inp: Update for gnulib merge. diff --git a/msdos/sedlibmk.inp b/msdos/sedlibmk.inp index a983b1bbb1..45e03621ce 100644 --- a/msdos/sedlibmk.inp +++ b/msdos/sedlibmk.inp @@ -446,6 +446,7 @@ OMIT_GNULIB_MODULE_group-member = true\ OMIT_GNULIB_MODULE_inttypes-incomplete = true\ OMIT_GNULIB_MODULE_localtime-buffer = true\ OMIT_GNULIB_MODULE_lstat = true\ +OMIT_GNULIB_MODULE_nanosleep = true\ OMIT_GNULIB_MODULE_open = true\ OMIT_GNULIB_MODULE_pipe2 = true\ OMIT_GNULIB_MODULE_pselect = true\ commit 6ad223fa9f0d30f321dea90f2228873d166003bb Author: Stefan Monnier Date: Fri Mar 4 12:18:41 2022 -0500 trace.el: Preserve the line structure Print newlines appearing inside values (i.e. inside strings) as \n rather than actual newlines so as to avoid messing up the main structure of the trace buffer. * lisp/emacs-lisp/trace.el (trace-entry-message) (trace-exit-message, trace--read-args): Quote newlines diff --git a/lisp/emacs-lisp/trace.el b/lisp/emacs-lisp/trace.el index 71eca5a323..165f5c7bfe 100644 --- a/lisp/emacs-lisp/trace.el +++ b/lisp/emacs-lisp/trace.el @@ -172,9 +172,10 @@ You can call this function to add internal values in the trace buffer." LEVEL is the trace level, ARGS is the list of arguments passed to FUNCTION, and CONTEXT is a string describing the dynamic context (e.g. values of some global variables)." - (let ((print-circle t)) + (let ((print-circle t) + (print-escape-newlines t)) (format "%s%s%d -> %S%s\n" - (mapconcat 'char-to-string (make-string (max 0 (1- level)) ?|) " ") + (mapconcat #'char-to-string (make-string (max 0 (1- level)) ?|) " ") (if (> level 1) " " "") level ;; FIXME: Make it so we can click the function name to jump to its @@ -187,7 +188,8 @@ some global variables)." LEVEL is the trace level, VALUE value returned by FUNCTION, and CONTEXT is a string describing the dynamic context (e.g. values of some global variables)." - (let ((print-circle t)) + (let ((print-circle t) + (print-escape-newlines t)) (format "%s%s%d <- %s: %S%s\n" (mapconcat 'char-to-string (make-string (1- level) ?|) " ") (if (> level 1) " " "") @@ -278,7 +280,8 @@ If `current-prefix-arg' is non-nil, also read a buffer and a \"context\" nil read-expression-map t 'read-expression-history)))) (lambda () - (let ((print-circle t)) + (let ((print-circle t) + (print-escape-newlines t)) (concat " [" (prin1-to-string (eval exp t)) "]")))))))) ;;;###autoload commit 5f7db63a93f0c670d6f88dd24f922462abce7d8c Author: Lars Ingebrigtsen Date: Fri Mar 4 17:36:20 2022 +0100 Avoid statting directories on startup for Info * doc/misc/efaq.texi (File-name conventions) Mention Info-directory-list instead. * doc/misc/info.texi (Emacs Info Variables): Mention Info--default-directory-list. * lisp/info.el (Info-default-directory-list): Default to nil to avoid statting directories on Emacs startup (bug#27933). (Info--default-directory-list): Factored out into own function. (Info-default-dirs): Append value of Info-default-directory-list to the value returned from Info--default-directory-list. diff --git a/doc/misc/efaq.texi b/doc/misc/efaq.texi index 5d4d378d82..87a70d064e 100644 --- a/doc/misc/efaq.texi +++ b/doc/misc/efaq.texi @@ -259,12 +259,13 @@ name displayed by this will be the full pathname of the installed @code{data-directory}, and @kbd{C-h v} displays the value and the documentation of a variable.) -The location of your Info directory (i.e., where Info documentation -is stored) is kept in the variable @code{Info-default-directory-list}. Use -@kbd{C-h v Info-default-directory-list @key{RET}} to see the value of -this variable, which will be a list of directory names. The last -directory in that list is probably where most Info files are stored. By -default, Emacs Info documentation is placed in @file{/usr/local/share/info}. +The location of your Info directory (i.e., where Info documentation is +stored) is kept in the variable @code{Info-directory-list}. Use +@kbd{C-h v Info-directory-list @key{RET}} to see the value of this +variable, which will be a list of directory names (after Info has been +started). The last directory in that list is probably where most Info +files are stored. By default, Emacs Info documentation is placed in +@file{/usr/local/share/info}. For information on some of the files in the @file{etc} directory, @pxref{Informational files for Emacs}. @@ -701,7 +702,7 @@ directory which is a subdirectory of your home directory named @file{Info}, you could put this in your @file{.emacs} file: @lisp -(add-to-list 'Info-default-directory-list "~/Info") +(add-to-list 'Info-default-directory-list "~/Info/") @end lisp You will need a top-level Info file named @file{dir} in this directory diff --git a/doc/misc/info.texi b/doc/misc/info.texi index 98e0dceb5a..6ebf60ce36 100644 --- a/doc/misc/info.texi +++ b/doc/misc/info.texi @@ -1191,8 +1191,9 @@ info-stnd, GNU Info}. The list of directories to search for Info files. Each element is a string (directory name) or @code{nil} (try default directory). If not initialized Info uses the environment variable @env{INFOPATH} to -initialize it, or @code{Info-default-directory-list} if there is no -@env{INFOPATH} variable in the environment. +initialize it, or @code{Info-default-directory-list} in addition to +the value returned by the @code{Info--default-directory-list} function +if there is no @env{INFOPATH} variable in the environment. If you wish to customize the Info directory search list for both Emacs Info and stand-alone Info, it is best to set the @env{INFOPATH} diff --git a/etc/NEWS b/etc/NEWS index 8deb699978..80cf0a2f72 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -107,6 +107,11 @@ of 'user-emacs-directory'. * Incompatible changes in Emacs 29.1 +--- +** 'Info-default-directory-list' is no longer populated at Emacs startup. +If you have code in your init file that removes directories from +'Info-default-directory-list', this will no longer work. + --- ** 'C-k' no longer deletes files in 'ido-mode'. To get the previous action back, put something like the following in diff --git a/lisp/info.el b/lisp/info.el index 0565663c38..db95574bf7 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -161,59 +161,8 @@ A header-line does not scroll with the rest of the buffer." "Face used to highlight matches in an index entry." :version "24.4") -;; This is a defcustom largely so that we can get the benefit -;; of `custom-initialize-delay'. Perhaps it would work to make it a -;; `defvar' and explicitly give it a `standard-value' property, and -;; call `custom-initialize-delay' on it. -;; The value is initialized at startup time, when command-line calls -;; `custom-reevaluate-setting' on all the defcustoms in -;; `custom-delayed-init-variables'. This is somewhat sub-optimal, as ideally -;; this should be done when Info mode is first invoked. ;;;###autoload -(defcustom Info-default-directory-list - (let* ((config-dir - (file-name-as-directory - ;; Self-contained NS build with info/ in the app-bundle. - (or (and (featurep 'ns) - (let ((dir (expand-file-name "../info" data-directory))) - (if (file-directory-p dir) dir))) - configure-info-directory))) - (prefixes - ;; Directory trees in which to look for info subdirectories - (prune-directory-list '("/usr/local/" "/usr/" "/opt/"))) - (suffixes - ;; Subdirectories in each directory tree that may contain info - ;; directories. - '("share/" "")) - (standard-info-dirs - (apply #'nconc - (mapcar (lambda (pfx) - (let ((dirs - (mapcar (lambda (sfx) - (concat pfx sfx "info/")) - suffixes))) - (prune-directory-list dirs))) - prefixes))) - ;; If $(prefix)/share/info is not one of the standard info - ;; directories, they are probably installing an experimental - ;; version of Emacs, so make sure that experimental version's Info - ;; files override the ones in standard directories. - (dirs - (if (member config-dir standard-info-dirs) - ;; FIXME? What is the point of adding it again at the end - ;; when it is already present earlier in the list? - (nconc standard-info-dirs (list config-dir)) - (cons config-dir standard-info-dirs)))) - (if (not (eq system-type 'windows-nt)) - dirs - ;; Include the info directory near where Emacs executable was installed. - (let* ((instdir (file-name-directory invocation-directory)) - (dir1 (expand-file-name "../info/" instdir)) - (dir2 (expand-file-name "../../../info/" instdir))) - (cond ((file-exists-p dir1) (append dirs (list dir1))) - ((file-exists-p dir2) (append dirs (list dir2))) - (t dirs))))) - +(defcustom Info-default-directory-list nil "Default list of directories to search for Info documentation files. They are searched in the order they are given in the list. Therefore, the directory of Info files that come with Emacs @@ -224,15 +173,12 @@ first in this list. Once Info is started, the list of directories to search comes from the variable `Info-directory-list'. -This variable `Info-default-directory-list' is used as the default -for initializing `Info-directory-list' when Info is started, unless -the environment variable INFOPATH is set. - -Although this is a customizable variable, that is mainly for technical -reasons. Normally, you should either set INFOPATH or customize -`Info-additional-directory-list', rather than changing this variable." - :initialize #'custom-initialize-delay - :type '(repeat directory)) + +This variable is used as the default for initializing +`Info-directory-list' when Info is started, unless the +environment variable INFOPATH is set." + :type '(repeat directory) + :version "29.1") (defvar Info-directory-list nil "List of directories to search for Info documentation files. @@ -679,6 +625,51 @@ in `Info-file-supports-index-cookies-list'." (cdr (assoc file Info-file-supports-index-cookies-list))) +(defun Info--default-directory-list () + "Compute a directory list suitable for Info." + (let* ((config-dir + (file-name-as-directory + ;; Self-contained NS build with info/ in the app-bundle. + (or (and (featurep 'ns) + (let ((dir (expand-file-name "../info" data-directory))) + (if (file-directory-p dir) dir))) + configure-info-directory))) + (prefixes + ;; Directory trees in which to look for info subdirectories + (prune-directory-list '("/usr/local/" "/usr/" "/opt/"))) + (suffixes + ;; Subdirectories in each directory tree that may contain info + ;; directories. + '("share/" "")) + (standard-info-dirs + (apply #'nconc + (mapcar (lambda (pfx) + (let ((dirs + (mapcar (lambda (sfx) + (concat pfx sfx "info/")) + suffixes))) + (prune-directory-list dirs))) + prefixes))) + ;; If $(prefix)/share/info is not one of the standard info + ;; directories, they are probably installing an experimental + ;; version of Emacs, so make sure that experimental version's Info + ;; files override the ones in standard directories. + (dirs + (if (member config-dir standard-info-dirs) + ;; FIXME? What is the point of adding it again at the end + ;; when it is already present earlier in the list? + (nconc standard-info-dirs (list config-dir)) + (cons config-dir standard-info-dirs)))) + (if (not (eq system-type 'windows-nt)) + dirs + ;; Include the info directory near where Emacs executable was installed. + (let* ((instdir (file-name-directory invocation-directory)) + (dir1 (expand-file-name "../info/" instdir)) + (dir2 (expand-file-name "../../../info/" instdir))) + (cond ((file-exists-p dir1) (append dirs (list dir1))) + ((file-exists-p dir2) (append dirs (list dir2))) + (t dirs)))))) + (defun Info-default-dirs () (let ((source (expand-file-name "info/" source-directory)) (sibling (if installation-directory @@ -701,25 +692,11 @@ in `Info-file-supports-index-cookies-list'." sibling ;; Uninstalled, builddir == srcdir source)) - (if (or (member alternative Info-default-directory-list) - ;; On DOS/NT, we use movable executables always, - ;; and we must always find the Info dir at run time. - (if (memq system-type '(ms-dos windows-nt)) - nil - ;; Use invocation-directory for Info - ;; only if we used it for exec-directory also. - (not (string= exec-directory - (expand-file-name "lib-src/" - installation-directory)))) - (not (file-exists-p alternative))) - Info-default-directory-list - ;; `alternative' contains the Info files that came with this - ;; version, so we should look there first. `Info-insert-dir' - ;; currently expects to find `alternative' first on the list. - (cons alternative - ;; Don't drop the last part, it might contain non-Emacs stuff. - ;; (reverse (cdr (reverse - Info-default-directory-list)))) ;; ))) + ;; `alternative' contains the Info files that came with this + ;; version, so we should look there first. `Info-insert-dir' + ;; currently expects to find `alternative' first on the list. + (append (cons alternative Info-default-directory-list) + (Info--default-directory-list)))) (defun info-initialize () "Initialize `Info-directory-list', if that hasn't been done yet." commit 18e25c198f39895438c05ef293789358232dfd76 Author: Lars Ingebrigtsen Date: Fri Mar 4 16:55:57 2022 +0100 Improve scroll-bar-mode/default-frame-alist interaction docs * lisp/scroll-bar.el (scroll-bar-mode): Mention default-frame-alist (bug#54237). * src/frame.c (syms_of_frame): Clarify further that setting this variable may have unintended consequences. diff --git a/lisp/scroll-bar.el b/lisp/scroll-bar.el index 3d12723c02..5786a21e88 100644 --- a/lisp/scroll-bar.el +++ b/lisp/scroll-bar.el @@ -132,8 +132,11 @@ Setting the variable with a customization buffer also takes effect." (define-minor-mode scroll-bar-mode "Toggle vertical scroll bars on all frames (Scroll Bar mode). -This command applies to all frames that exist and frames to be -created in the future." +This command applies to all frames that exist, as well as new +frames to be created in the future. This is done by altering the +frame parameters, so if you (re-)set `default-frame-alist' after +toggling the scroll bars on or off with this command, the scroll +bars may reappear on new frames." :variable ((get-scroll-bar-mode) . (lambda (v) (set-scroll-bar-mode (if v (or previous-scroll-bar-mode diff --git a/src/frame.c b/src/frame.c index b7ff7fd1fc..b3990ae2aa 100644 --- a/src/frame.c +++ b/src/frame.c @@ -6233,14 +6233,24 @@ You can also use a floating number between 0.0 and 1.0. */); doc: /* Alist of default values for frame creation. These may be set in your init file, like this: (setq default-frame-alist \\='((width . 80) (height . 55) (menu-bar-lines . 1))) + These override values given in window system configuration data, - including X Windows' defaults database. +including X Windows' defaults database. + +Note that many display-related modes (like `scroll-bar-mode' or +`menu-bar-mode') alter `default-frame-alist', so if you set this +variable directly, you may be overriding other settings +unintentionally. Instead it's often better to use +`modify-all-frames-parameters' or push new elements to the front of +this alist. + For values specific to the first Emacs frame, see `initial-frame-alist'. + For window-system specific values, see `window-system-default-frame-alist'. + For values specific to the separate minibuffer frame, see - `minibuffer-frame-alist'. -The `menu-bar-lines' element of the list controls whether new frames - have menu bars; `menu-bar-mode' works by altering this element. +`minibuffer-frame-alist'. + Setting this variable does not affect existing frames, only new ones. */); Vdefault_frame_alist = Qnil; commit cdbc2f9d274a23bcf6cb03046b1e5b4bdcedafb1 Author: Lars Ingebrigtsen Date: Fri Mar 4 16:27:10 2022 +0100 Add some sleeps to gnutls_try_handshake * admin/merge-gnulib (GNULIB_MODULES): Add the nanosleep module. * m4/gnulib-comp.m4 (gl_EARLY): * lib/gnulib.mk.in: Automatic update. * m4/nanosleep.m4: * lib/nanosleep.c: New module. * nt/mingw-cfg.site (gl_cv_func_free_preserves_errno): * nt/gnulib-cfg.mk (OMIT_GNULIB_MODULE_nanosleep): Omit nanosleep, since mingw has it. * src/gnutls.c (gnutls_try_handshake): Add some sleeping to the busy-wait loop so that we don't use 100% CPU here (bug#32452). diff --git a/admin/merge-gnulib b/admin/merge-gnulib index fec469c017..ea3d23686f 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -40,7 +40,7 @@ GNULIB_MODULES=' getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog ieee754-h ignore-value intprops largefile libgmp lstat manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime - nproc nstrftime + nanosleep nproc nstrftime pathmax pipe2 pselect pthread_sigmask qcopy-acl readlink readlinkat regex sig2str sigdescr_np socklen stat-time std-gnu11 stdalign stddef stdio diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 3a9f5b9818..3deeca98be 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -129,6 +129,7 @@ # minmax \ # mkostemp \ # mktime \ +# nanosleep \ # nproc \ # nstrftime \ # pathmax \ @@ -207,6 +208,7 @@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CRYPTOLIB = @CRYPTOLIB@ CXX = @CXX@ +CXXCPP = @CXXCPP@ CXXFLAGS = @CXXFLAGS@ CYGWIN_OBJ = @CYGWIN_OBJ@ C_SWITCH_MACHINE = @C_SWITCH_MACHINE@ @@ -283,6 +285,7 @@ GL_COND_OBJ_MEMPCPY_CONDITION = @GL_COND_OBJ_MEMPCPY_CONDITION@ GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@ GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@ GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@ +GL_COND_OBJ_NANOSLEEP_CONDITION = @GL_COND_OBJ_NANOSLEEP_CONDITION@ GL_COND_OBJ_OPEN_CONDITION = @GL_COND_OBJ_OPEN_CONDITION@ GL_COND_OBJ_PSELECT_CONDITION = @GL_COND_OBJ_PSELECT_CONDITION@ GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION = @GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION@ @@ -2497,6 +2500,16 @@ EXTRA_libgnu_a_SOURCES += mktime.c endif ## end gnulib module mktime-internal +## begin gnulib module nanosleep +ifeq (,$(OMIT_GNULIB_MODULE_nanosleep)) + +ifneq (,$(GL_COND_OBJ_NANOSLEEP_CONDITION)) +libgnu_a_SOURCES += nanosleep.c +endif + +endif +## end gnulib module nanosleep + ## begin gnulib module nproc ifeq (,$(OMIT_GNULIB_MODULE_nproc)) diff --git a/lib/nanosleep.c b/lib/nanosleep.c new file mode 100644 index 0000000000..446794edc0 --- /dev/null +++ b/lib/nanosleep.c @@ -0,0 +1,195 @@ +/* Provide a replacement for the POSIX nanosleep function. + + Copyright (C) 1999-2000, 2002, 2004-2022 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* written by Jim Meyering + and Bruno Haible for the native Windows part */ + +#include + +#include + +#include "intprops.h" +#include "verify.h" + +#include +#include +#include +#include +#include + +#include + +#include + + +enum { BILLION = 1000 * 1000 * 1000 }; + +#if HAVE_BUG_BIG_NANOSLEEP + +int +nanosleep (const struct timespec *requested_delay, + struct timespec *remaining_delay) +# undef nanosleep +{ + /* nanosleep mishandles large sleeps due to internal overflow problems. + The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which + can't sleep more than 24.85 days (2^31 milliseconds). Similarly, + cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds). + Solve this by breaking the sleep up into smaller chunks. */ + + if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec) + { + errno = EINVAL; + return -1; + } + + { + /* Verify that time_t is large enough. */ + verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60); + const time_t limit = 24 * 24 * 60 * 60; + time_t seconds = requested_delay->tv_sec; + struct timespec intermediate; + intermediate.tv_nsec = requested_delay->tv_nsec; + + while (limit < seconds) + { + int result; + intermediate.tv_sec = limit; + result = nanosleep (&intermediate, remaining_delay); + seconds -= limit; + if (result) + { + if (remaining_delay) + remaining_delay->tv_sec += seconds; + return result; + } + intermediate.tv_nsec = 0; + } + intermediate.tv_sec = seconds; + return nanosleep (&intermediate, remaining_delay); + } +} + +#elif defined _WIN32 && ! defined __CYGWIN__ +/* Native Windows platforms. */ + +# define WIN32_LEAN_AND_MEAN +# include + +/* The Windows API function Sleep() has a resolution of about 15 ms and takes + at least 5 ms to execute. We use this function for longer time periods. + Additionally, we use busy-looping over short time periods, to get a + resolution of about 0.01 ms. In order to measure such short timespans, + we use the QueryPerformanceCounter() function. */ + +int +nanosleep (const struct timespec *requested_delay, + struct timespec *remaining_delay) +{ + static bool initialized; + /* Number of performance counter increments per nanosecond, + or zero if it could not be determined. */ + static double ticks_per_nanosecond; + + if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec) + { + errno = EINVAL; + return -1; + } + + /* For requested delays of one second or more, 15ms resolution is + sufficient. */ + if (requested_delay->tv_sec == 0) + { + if (!initialized) + { + /* Initialize ticks_per_nanosecond. */ + LARGE_INTEGER ticks_per_second; + + if (QueryPerformanceFrequency (&ticks_per_second)) + ticks_per_nanosecond = + (double) ticks_per_second.QuadPart / 1000000000.0; + + initialized = true; + } + if (ticks_per_nanosecond) + { + /* QueryPerformanceFrequency worked. We can use + QueryPerformanceCounter. Use a combination of Sleep and + busy-looping. */ + /* Number of milliseconds to pass to the Sleep function. + Since Sleep can take up to 8 ms less or 8 ms more than requested + (or maybe more if the system is loaded), we subtract 10 ms. */ + int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10; + /* Determine how many ticks to delay. */ + LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond; + /* Start. */ + LARGE_INTEGER counter_before; + if (QueryPerformanceCounter (&counter_before)) + { + /* Wait until the performance counter has reached this value. + We don't need to worry about overflow, because the performance + counter is reset at reboot, and with a frequency of 3.6E6 + ticks per second 63 bits suffice for over 80000 years. */ + LONGLONG wait_until = counter_before.QuadPart + wait_ticks; + /* Use Sleep for the longest part. */ + if (sleep_millis > 0) + Sleep (sleep_millis); + /* Busy-loop for the rest. */ + for (;;) + { + LARGE_INTEGER counter_after; + if (!QueryPerformanceCounter (&counter_after)) + /* QueryPerformanceCounter failed, but succeeded earlier. + Should not happen. */ + break; + if (counter_after.QuadPart >= wait_until) + /* The requested time has elapsed. */ + break; + } + goto done; + } + } + } + /* Implementation for long delays and as fallback. */ + Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000); + + done: + /* Sleep is not interruptible. So there is no remaining delay. */ + if (remaining_delay != NULL) + { + remaining_delay->tv_sec = 0; + remaining_delay->tv_nsec = 0; + } + return 0; +} + +#else +/* Other platforms lacking nanosleep. + It's not clear whether these are still practical porting targets. + For now, just fall back on pselect. */ + +/* Suspend execution for at least *REQUESTED_DELAY seconds. The + *REMAINING_DELAY part isn't implemented yet. */ + +int +nanosleep (const struct timespec *requested_delay, + struct timespec *remaining_delay) +{ + return pselect (0, NULL, NULL, NULL, requested_delay, NULL); +} +#endif diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 1d31239d2d..fb5f1b52a4 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -140,6 +140,7 @@ AC_DEFUN([gl_EARLY], # Code from module mktime: # Code from module mktime-internal: # Code from module multiarch: + # Code from module nanosleep: # Code from module nocrash: # Code from module nproc: # Code from module nstrftime: @@ -430,6 +431,10 @@ AC_DEFUN([gl_INIT], fi gl_TIME_MODULE_INDICATOR([mktime]) gl_MULTIARCH + gl_FUNC_NANOSLEEP + gl_CONDITIONAL([GL_COND_OBJ_NANOSLEEP], + [test $HAVE_NANOSLEEP = 0 || test $REPLACE_NANOSLEEP = 1]) + gl_TIME_MODULE_INDICATOR([nanosleep]) gl_NPROC gl_FUNC_GNU_STRFTIME gl_PATHMAX @@ -1304,6 +1309,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/mkostemp.c lib/mktime-internal.h lib/mktime.c + lib/nanosleep.c lib/nproc.c lib/nproc.h lib/nstrftime.c @@ -1456,6 +1462,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/mktime.m4 m4/mode_t.m4 m4/multiarch.m4 + m4/nanosleep.m4 m4/nocrash.m4 m4/nproc.m4 m4/nstrftime.m4 diff --git a/m4/nanosleep.m4 b/m4/nanosleep.m4 new file mode 100644 index 0000000000..1964b1ea47 --- /dev/null +++ b/m4/nanosleep.m4 @@ -0,0 +1,139 @@ +# serial 41 + +dnl From Jim Meyering. +dnl Check for the nanosleep function. +dnl If not found, use the supplied replacement. +dnl + +# Copyright (C) 1999-2001, 2003-2022 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_NANOSLEEP], +[ + AC_REQUIRE([gl_TIME_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Persuade glibc and Solaris to declare nanosleep. + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_DECLS_ONCE([alarm]) + + nanosleep_save_libs=$LIBS + + # Solaris 2.5.1 needs -lposix4 to get the nanosleep function. + # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4. + LIB_NANOSLEEP= + AC_SUBST([LIB_NANOSLEEP]) + AC_SEARCH_LIBS([nanosleep], [rt posix4], + [test "$ac_cv_search_nanosleep" = "none required" || + LIB_NANOSLEEP=$ac_cv_search_nanosleep]) + if test "x$ac_cv_search_nanosleep" != xno; then + dnl The system has a nanosleep function. + + AC_REQUIRE([gl_MULTIARCH]) + if test $APPLE_UNIVERSAL_BUILD = 1; then + # A universal build on Apple Mac OS X platforms. + # The test result would be 'no (mishandles large arguments)' in 64-bit + # mode but 'yes' in 32-bit mode. But we need a configuration result that + # is valid in both modes. + gl_cv_func_nanosleep='no (mishandles large arguments)' + fi + + AC_CACHE_CHECK([for working nanosleep], + [gl_cv_func_nanosleep], + [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include + #include + #include + #include + #include + #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + #define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1))) + + #if HAVE_DECL_ALARM + static void + check_for_SIGALRM (int sig) + { + if (sig != SIGALRM) + _exit (1); + } + #endif + + int + main () + { + static struct timespec ts_sleep; + static struct timespec ts_remaining; + /* Test for major problems first. */ + if (! nanosleep) + return 2; + ts_sleep.tv_sec = 0; + ts_sleep.tv_nsec = 1; + #if HAVE_DECL_ALARM + { + static struct sigaction act; + act.sa_handler = check_for_SIGALRM; + sigemptyset (&act.sa_mask); + sigaction (SIGALRM, &act, NULL); + alarm (1); + if (nanosleep (&ts_sleep, NULL) != 0) + return 3; + /* Test for a minor problem: the handling of large arguments. */ + ts_sleep.tv_sec = TYPE_MAXIMUM (time_t); + ts_sleep.tv_nsec = 999999999; + alarm (1); + if (nanosleep (&ts_sleep, &ts_remaining) != -1) + return 4; + if (errno != EINTR) + return 5; + if (ts_remaining.tv_sec <= TYPE_MAXIMUM (time_t) - 10) + return 6; + } + #else /* A simpler test for native Windows. */ + if (nanosleep (&ts_sleep, &ts_remaining) < 0) + return 3; + #endif + return 0; + }]])], + [gl_cv_func_nanosleep=yes], + [case $? in dnl ( + 4|5|6) gl_cv_func_nanosleep='no (mishandles large arguments)';; dnl ( + *) gl_cv_func_nanosleep=no;; + esac], + [case "$host_os" in dnl (( + linux*) # Guess it halfway works when the kernel is Linux. + gl_cv_func_nanosleep='guessing no (mishandles large arguments)' ;; + mingw*) # Guess no on native Windows. + gl_cv_func_nanosleep='guessing no' ;; + *) # If we don't know, obey --enable-cross-guesses. + gl_cv_func_nanosleep="$gl_cross_guess_normal" ;; + esac + ]) + ]) + case "$gl_cv_func_nanosleep" in + *yes) + REPLACE_NANOSLEEP=0 + ;; + *) + REPLACE_NANOSLEEP=1 + case "$gl_cv_func_nanosleep" in + *"mishandles large arguments"*) + AC_DEFINE([HAVE_BUG_BIG_NANOSLEEP], [1], + [Define to 1 if nanosleep mishandles large arguments.]) + ;; + esac + ;; + esac + else + HAVE_NANOSLEEP=0 + fi + LIBS=$nanosleep_save_libs +]) diff --git a/nt/gnulib-cfg.mk b/nt/gnulib-cfg.mk index 4748474f1d..69119b135e 100644 --- a/nt/gnulib-cfg.mk +++ b/nt/gnulib-cfg.mk @@ -74,3 +74,4 @@ OMIT_GNULIB_MODULE_futimens = true OMIT_GNULIB_MODULE_utimensat = true OMIT_GNULIB_MODULE_file-has-acl = true OMIT_GNULIB_MODULE_nproc = true +OMIT_GNULIB_MODULE_nanosleep = true diff --git a/nt/mingw-cfg.site b/nt/mingw-cfg.site index 6ab81e943f..7ca19cbad0 100644 --- a/nt/mingw-cfg.site +++ b/nt/mingw-cfg.site @@ -167,3 +167,6 @@ ac_cv_func_strsignal=no # implementation of 'free' doesn't touch errno, and it emits a # compilation warning. gl_cv_func_free_preserves_errno=yes +# Don't build the Gnulib nanosleep module: it requires W2K or later, +# and MinGW does have nanosleep. +gl_cv_func_nanosleep=yes diff --git a/src/gnutls.c b/src/gnutls.c index 3ec3837067..09590ca005 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -616,6 +616,9 @@ gnutls_try_handshake (struct Lisp_Process *proc) gnutls_session_t state = proc->gnutls_state; int ret; bool non_blocking = proc->is_non_blocking_client; + /* Sleep for ten milliseconds when busy-looping in + gnutls_handshake. */ + struct timespec delay = { 0, 1000 * 1000 * 10 }; if (proc->gnutls_complete_negotiation_p) non_blocking = false; @@ -630,6 +633,7 @@ gnutls_try_handshake (struct Lisp_Process *proc) maybe_quit (); if (non_blocking && ret != GNUTLS_E_INTERRUPTED) break; + nanosleep (&delay, NULL); } proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED; commit 345c4c6532d3784eed5acbaea8a78ce3aad071e4 Author: Po Lu Date: Fri Mar 4 20:54:02 2022 +0800 Add a few warnings about special event structures on X * xterm.c (x_construct_mouse_click) (x_note_mouse_movement): Add comments explaining the nature of some special event structures. diff --git a/src/xterm.c b/src/xterm.c index 764638d5b8..948afa5680 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -6806,7 +6806,16 @@ get_keysym_name (int keysym) /* Prepare a mouse-event in *RESULT for placement in the input queue. If the event is a button press, then note that we have grabbed - the mouse. */ + the mouse. + + The XButtonEvent structure passed as EVENT might not come from the + X server, and instead be artificially constructed from input + extension events. In these special events, the only fields that + are initialized are `time', `button', `state', `type', `window' and + `x' and `y'. This function should not access any other fields in + EVENT without also initializing the corresponding fields in `bv' + under the XI_ButtonPress and XI_ButtonRelease labels inside + `handle_one_xevent'. */ static Lisp_Object x_construct_mouse_click (struct input_event *result, @@ -6849,7 +6858,15 @@ x_construct_mouse_click (struct input_event *result, We have received a mouse movement event, which is given in *event. If the mouse is over a different glyph than it was last time, tell the mainstream emacs code by setting mouse_moved. If not, ask for - another motion event, so we can check again the next time it moves. */ + another motion event, so we can check again the next time it moves. + + The XMotionEvent structure passed as EVENT might not come from the + X server, and instead be artificially constructed from input + extension events. In these special events, the only fields that + are initialized are `time', `window', and `x' and `y'. This + function should not access any other fields in EVENT without also + initializing the corresponding fields in `ev' under the XI_Motion, + XI_Enter and XI_Leave labels inside `handle_one_xevent'. */ static bool x_note_mouse_movement (struct frame *frame, const XMotionEvent *event) commit f685bcb65dbb6eb49d03fb1f420e16869c0224de Author: Po Lu Date: Fri Mar 4 20:37:50 2022 +0800 Fix some errors in stretch glyphs code on PGTK * src/pgtkterm.c (x_draw_stretch_glyph_string): Remove unnecessary code. Reported by Eli Zaretskii . diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 41e2f0ded0..abcf18e11d 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -2373,27 +2373,16 @@ x_draw_stretch_glyph_string (struct glyph_string *s) else if (!s->background_filled_p) { int background_width = s->background_width; - int x = s->x, text_left_x = window_box_left_offset (s->w, TEXT_AREA); + int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA); /* Don't draw into left fringe or scrollbar area except for - header line and mode line. */ - if (x < text_left_x && !s->row->mode_line_p) + header line and mode line. */ + if (s->area == TEXT_AREA + && x < text_left_x && !s->row->mode_line_p) { - int background_width = s->background_width; - int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA); - - /* Don't draw into left fringe or scrollbar area except for - header line and mode line. */ - if (s->area == TEXT_AREA - && x < text_left_x && !s->row->mode_line_p) - { - background_width -= text_left_x - x; - x = text_left_x; - } - if (background_width > 0) - x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height); + background_width -= text_left_x - x; + x = text_left_x; } - if (background_width > 0) x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height); } commit 33958bcd3d90d626090f83cabae94e615176c92c Author: Eli Zaretskii Date: Fri Mar 4 13:52:09 2022 +0200 Fix wording and punctuation in recent Gnus documentation changes * lisp/gnus/nnselect.el (nnselect-allow-ephemeral-expiry): Make the first sentence of the doc string be a single line. * doc/misc/gnus.texi (Creating Search Groups): Fix space between sentences. diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index 20a2d92084..f87eab7e51 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -21736,9 +21736,9 @@ that sticks around after exit from the summary buffer, you can call @code{gnus-group-make-search-group} (bound to @kbd{G g}). Unlike persistent groups, ephemeral groups by default do not run -articles through the expiry process on exiting. If you want expiry to +articles through the expiry process on exiting. If you want expiry to happen in ephemeral search groups you can customize the variable -@code{nnselect-allow-ephemeral-expiry}. In all cases the expiry +@code{nnselect-allow-ephemeral-expiry}. In all cases the expiry process uses the underlying group's expiry parameters. So you just performed a search whose results are so fabulous you diff --git a/lisp/gnus/nnselect.el b/lisp/gnus/nnselect.el index 9193b38e31..c880d79840 100644 --- a/lisp/gnus/nnselect.el +++ b/lisp/gnus/nnselect.el @@ -257,8 +257,7 @@ as `(keyfunc member)' and the corresponding element is just 'nnselect-retrieve-headers-override-function "28.1") (defcustom nnselect-allow-ephemeral-expiry nil - "If non-nil, articles in an ephemeral nnselect group will be put -through the expiry process." + "If non-nil, articles in ephemeral nnselect groups are subject to expiry." :version "29.1" :type 'boolean) commit f9f6c67181584cdf8334610031486baf1d9ad203 Author: Po Lu Date: Fri Mar 4 18:33:46 2022 +0800 Initialize time inside motion and button events converted from XI events * src/xterm.c (handle_one_xevent): Make sure time is initialized in artificial events passed to functions that use it. diff --git a/src/xterm.c b/src/xterm.c index 2c6289a9cb..764638d5b8 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11507,9 +11507,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, { if (!dpyinfo->supports_xi2) goto OTHER; + if (event->xgeneric.extension != dpyinfo->xi2_opcode) /* Not an XI2 event. */ goto OTHER; + bool must_free_data = false; XIEvent *xi_event = (XIEvent *) event->xcookie.data; /* Sometimes the event is already claimed by GTK, which @@ -11521,16 +11523,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, } XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; -#ifdef HAVE_XINPUT2_1 - XIValuatorState *states; - double *values; - bool found_valuator = false; -#endif - - /* A fake XMotionEvent for x_note_mouse_movement. */ - XMotionEvent ev; - /* A fake XButtonEvent for x_construct_mouse_click. */ - XButtonEvent bv; if (!xi_event) { @@ -11588,11 +11580,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, case XI_Enter: { XIEnterEvent *enter = (XIEnterEvent *) xi_event; + XMotionEvent ev; any = x_top_window_to_frame (dpyinfo, enter->event); ev.x = lrint (enter->event_x); ev.y = lrint (enter->event_y); ev.window = enter->event; + ev.time = enter->time; + x_display_set_last_user_time (dpyinfo, xi_event->time); #ifdef USE_MOTIF @@ -11668,10 +11663,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, case XI_Leave: { XILeaveEvent *leave = (XILeaveEvent *) xi_event; +#ifdef USE_GTK + XMotionEvent ev; ev.x = lrint (leave->event_x); ev.y = lrint (leave->event_y); ev.window = leave->event; + ev.time = leave->time; +#endif + any = x_top_window_to_frame (dpyinfo, leave->event); /* This allows us to catch LeaveNotify events generated by @@ -11784,6 +11784,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, case XI_Motion: { struct xi_device_t *device; +#ifdef HAVE_XINPUT2_1 + XIValuatorState *states; + double *values; + bool found_valuator = false; +#endif + /* A fake XMotionEvent for x_note_mouse_movement. */ + XMotionEvent ev; #ifdef HAVE_XINPUT2_1 states = &xev->valuators; @@ -12122,6 +12129,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef HAVE_XWIDGETS struct xwidget_view *xvw; #endif + /* A fake XButtonEvent for x_construct_mouse_click. */ + XButtonEvent bv; #ifdef USE_MOTIF #ifdef USE_TOOLKIT_SCROLL_BARS commit 62d97d4afd4a13cb2cd0f7eacbc4b5af1d620cf7 Author: Andrew G Cohen Date: Fri Mar 4 16:20:01 2022 +0800 Turn expiry on for nnselect groups Articles in (persistent) groups from the gnus/nnselect backend will now be run through the expiry process upon exit, like other persistent groups. Expiry is not on by default for ephemeral nnselect groups but may be turned on with nnselect-allow-ephemeral-expiry set to t. * lisp/gnus/nnselect.el (nnselect-request-expire-articles): Make article expiry work. (nnselect-allow-ephemeral-expiry): New variable. * doc/misc/gnus.texi (Creating Search Groups): Document nnselect-allow-ephemeral-expiry. diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index a3def495c4..20a2d92084 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -21735,6 +21735,12 @@ articles are drawn. If you want to create a @emph{persistent} group that sticks around after exit from the summary buffer, you can call @code{gnus-group-make-search-group} (bound to @kbd{G g}). +Unlike persistent groups, ephemeral groups by default do not run +articles through the expiry process on exiting. If you want expiry to +happen in ephemeral search groups you can customize the variable +@code{nnselect-allow-ephemeral-expiry}. In all cases the expiry +process uses the underlying group's expiry parameters. + So you just performed a search whose results are so fabulous you wished you had done a persistent search rather than an ephemeral one? No problem; you can create such a group by calling diff --git a/lisp/gnus/nnselect.el b/lisp/gnus/nnselect.el index b9072d4cb3..9193b38e31 100644 --- a/lisp/gnus/nnselect.el +++ b/lisp/gnus/nnselect.el @@ -256,6 +256,12 @@ as `(keyfunc member)' and the corresponding element is just (define-obsolete-variable-alias 'nnir-retrieve-headers-override-function 'nnselect-retrieve-headers-override-function "28.1") +(defcustom nnselect-allow-ephemeral-expiry nil + "If non-nil, articles in an ephemeral nnselect group will be put +through the expiry process." + :version "29.1" + :type 'boolean) + (defcustom nnselect-retrieve-headers-override-function nil "A function that retrieves article headers for ARTICLES from GROUP. The retrieved headers should populate the `nntp-server-buffer'. @@ -457,24 +463,26 @@ If this variable is nil, or if the provided function returns nil, :test #'equal :count 1))))) (deffoo nnselect-request-expire-articles - (articles _group &optional _server force) - (if force - (let (not-expired) - (pcase-dolist (`(,artgroup . ,artids) (ids-by-group articles)) - (let ((artlist (sort (mapcar #'cdr artids) #'<))) - (unless (gnus-check-backend-function 'request-expire-articles - artgroup) - (error "Group %s does not support article expiration" artgroup)) - (unless (gnus-check-server (gnus-find-method-for-group artgroup)) - (error "Couldn't open server for group %s" artgroup)) - (push (mapcar (lambda (art) - (car (rassq art artids))) - (let ((nnimap-expunge 'immediately)) - (gnus-request-expire-articles - artlist artgroup force))) - not-expired))) - (sort (delq nil not-expired) #'<)) - articles)) + (articles group &optional _server force) + (let ((nnimap-expunge 'immediately) not-deleted) + (if (and (not force) + (not nnselect-allow-ephemeral-expiry) + (gnus-ephemeral-group-p (nnselect-add-prefix group))) + articles + (pcase-dolist (`(,artgroup . ,artids) (ids-by-group articles)) + (let ((artlist (sort (mapcar #'cdr artids) #'<))) + (unless + (gnus-check-backend-function 'request-expire-articles artgroup) + (error "Group %s does not support article expiration" artgroup)) + (unless (gnus-check-server (gnus-find-method-for-group artgroup)) + (error "Couldn't open server for group %s" artgroup)) + (setq not-deleted + (append + (mapcar (lambda (art) (car (rassq art artids))) + (gnus-request-expire-articles artlist artgroup + force)) + not-deleted)))) + (sort (delq nil not-deleted) #'<)))) (deffoo nnselect-warp-to-article () commit 4f6583ab8a6f1f8e2329bf0b683277101447948d Author: Andrew G Cohen Date: Fri Mar 4 16:08:32 2022 +0800 ; Fetch the nnselect-rescan parameter from the topic or group * lisp/gnus/nnselect.el (nnselect-request-scan-group): Allow the nnselect-rescan parameter to be set in the topic or the group. diff --git a/lisp/gnus/nnselect.el b/lisp/gnus/nnselect.el index f5be477d26..b9072d4cb3 100644 --- a/lisp/gnus/nnselect.el +++ b/lisp/gnus/nnselect.el @@ -744,7 +744,7 @@ If this variable is nil, or if the provided function returns nil, (deffoo nnselect-request-scan (group _method) (when (and group - (gnus-group-get-parameter (nnselect-add-prefix group) + (gnus-group-find-parameter (nnselect-add-prefix group) 'nnselect-rescan t)) (nnselect-request-group-scan group)))