diff options
| author | Michael R. Mauger | 2017-04-02 18:10:57 -0400 |
|---|---|---|
| committer | Michael R. Mauger | 2017-04-02 18:10:57 -0400 |
| commit | 77083e2d34ba5559ae2899d3b03cf08c2e6c5ad4 (patch) | |
| tree | 27da92c2a61d664b700860c2d527a4d36000ca37 /src | |
| parent | c5a31f8292c94d19b80a3dbe0b3026693cc1090e (diff) | |
| parent | 8e394a7f35c2ba9297d222faa2689e177f268924 (diff) | |
| download | emacs-77083e2d34ba5559ae2899d3b03cf08c2e6c5ad4.tar.gz emacs-77083e2d34ba5559ae2899d3b03cf08c2e6c5ad4.zip | |
Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.in | 25 | ||||
| -rw-r--r-- | src/editfns.c | 2 | ||||
| -rw-r--r-- | src/fns.c | 121 | ||||
| -rw-r--r-- | src/gtkutil.c | 83 | ||||
| -rw-r--r-- | src/inotify.c | 432 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/xdisp.c | 20 | ||||
| -rw-r--r-- | src/xterm.c | 22 |
8 files changed, 457 insertions, 249 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 60aa6866718..5a3d0bd0445 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -347,15 +347,14 @@ am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) | |||
| 347 | am__v_at_0 = @ | 347 | am__v_at_0 = @ |
| 348 | am__v_at_1 = | 348 | am__v_at_1 = |
| 349 | 349 | ||
| 350 | DEPDIR=deps | ||
| 351 | AUTO_DEPEND = @AUTO_DEPEND@ | 350 | AUTO_DEPEND = @AUTO_DEPEND@ |
| 352 | 351 | DEPDIR = deps | |
| 353 | ifeq ($(AUTO_DEPEND),yes) | 352 | ifeq ($(AUTO_DEPEND),yes) |
| 354 | DEPFLAGS = -MMD -MF ${DEPDIR}/$*.d -MP | 353 | DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP |
| 355 | MKDEPDIR = ${MKDIR_P} ${DEPDIR} | 354 | -include $(ALLOBJS:%.o=$(DEPDIR)/%.d) |
| 356 | else | 355 | else |
| 357 | DEPFLAGS = | 356 | DEPFLAGS = |
| 358 | MKDEPDIR = : | 357 | include $(srcdir)/deps.mk |
| 359 | endif | 358 | endif |
| 360 | 359 | ||
| 361 | # Flags that might be in WARN_CFLAGS but are not valid for Objective C. | 360 | # Flags that might be in WARN_CFLAGS but are not valid for Objective C. |
| @@ -383,10 +382,8 @@ ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ | |||
| 383 | 382 | ||
| 384 | .SUFFIXES: .m | 383 | .SUFFIXES: .m |
| 385 | .c.o: | 384 | .c.o: |
| 386 | @$(MKDEPDIR) | ||
| 387 | $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $< | 385 | $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $< |
| 388 | .m.o: | 386 | .m.o: |
| 389 | @$(MKDEPDIR) | ||
| 390 | $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $< | 387 | $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $< |
| 391 | 388 | ||
| 392 | ## lastfile must follow all files whose initialized data areas should | 389 | ## lastfile must follow all files whose initialized data areas should |
| @@ -650,8 +647,7 @@ mostlyclean: | |||
| 650 | rm -f globals.h gl-stamp | 647 | rm -f globals.h gl-stamp |
| 651 | rm -f *.res *.tmp | 648 | rm -f *.res *.tmp |
| 652 | clean: mostlyclean | 649 | clean: mostlyclean |
| 653 | rm -f emacs-*.*.*$(EXEEXT) emacs$(EXEEXT) | 650 | rm -f emacs-*.*.*$(EXEEXT) emacs$(EXEEXT) $(DEPDIR)/* |
| 654 | -rm -rf $(DEPDIR) | ||
| 655 | 651 | ||
| 656 | ## bootstrap-clean is used to clean up just before a bootstrap. | 652 | ## bootstrap-clean is used to clean up just before a bootstrap. |
| 657 | ## It should remove all files generated during a compilation/bootstrap, | 653 | ## It should remove all files generated during a compilation/bootstrap, |
| @@ -666,6 +662,7 @@ bootstrap-clean: clean | |||
| 666 | 662 | ||
| 667 | distclean: bootstrap-clean | 663 | distclean: bootstrap-clean |
| 668 | rm -f Makefile lisp.mk | 664 | rm -f Makefile lisp.mk |
| 665 | rm -fr $(DEPDIR) | ||
| 669 | 666 | ||
| 670 | maintainer-clean: distclean | 667 | maintainer-clean: distclean |
| 671 | rm -f TAGS | 668 | rm -f TAGS |
| @@ -755,11 +752,3 @@ else | |||
| 755 | endif | 752 | endif |
| 756 | @: Compile some files earlier to speed up further compilation. | 753 | @: Compile some files earlier to speed up further compilation. |
| 757 | $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)" | 754 | $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)" |
| 758 | |||
| 759 | ifeq ($(AUTO_DEPEND),yes) | ||
| 760 | -include $(ALLOBJS:%.o=${DEPDIR}/%.d) | ||
| 761 | else | ||
| 762 | include $(srcdir)/deps.mk | ||
| 763 | endif | ||
| 764 | |||
| 765 | ### Makefile.in ends here | ||
diff --git a/src/editfns.c b/src/editfns.c index 65c0c721d11..2dafd8e7b1b 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -4356,7 +4356,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4356 | sprintf_buf[0] = XINT (args[n]); | 4356 | sprintf_buf[0] = XINT (args[n]); |
| 4357 | sprintf_bytes = prec != 0; | 4357 | sprintf_bytes = prec != 0; |
| 4358 | } | 4358 | } |
| 4359 | else if (conversion == 'd') | 4359 | else if (conversion == 'd' || conversion == 'i') |
| 4360 | { | 4360 | { |
| 4361 | /* For float, maybe we should use "%1.0f" | 4361 | /* For float, maybe we should use "%1.0f" |
| 4362 | instead so it also works for values outside | 4362 | instead so it also works for values outside |
| @@ -38,7 +38,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 38 | 38 | ||
| 39 | static void sort_vector_copy (Lisp_Object, ptrdiff_t, | 39 | static void sort_vector_copy (Lisp_Object, ptrdiff_t, |
| 40 | Lisp_Object *restrict, Lisp_Object *restrict); | 40 | Lisp_Object *restrict, Lisp_Object *restrict); |
| 41 | static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); | 41 | enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; |
| 42 | static bool internal_equal (Lisp_Object, Lisp_Object, | ||
| 43 | enum equal_kind, int, Lisp_Object); | ||
| 42 | 44 | ||
| 43 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, | 45 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, |
| 44 | doc: /* Return the argument unchanged. */ | 46 | doc: /* Return the argument unchanged. */ |
| @@ -1377,7 +1379,7 @@ The value is actually the tail of LIST whose car is ELT. */) | |||
| 1377 | FOR_EACH_TAIL (tail) | 1379 | FOR_EACH_TAIL (tail) |
| 1378 | { | 1380 | { |
| 1379 | Lisp_Object tem = XCAR (tail); | 1381 | Lisp_Object tem = XCAR (tail); |
| 1380 | if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil)) | 1382 | if (FLOATP (tem) && equal_no_quit (elt, tem)) |
| 1381 | return tail; | 1383 | return tail; |
| 1382 | } | 1384 | } |
| 1383 | CHECK_LIST_END (tail, list); | 1385 | CHECK_LIST_END (tail, list); |
| @@ -1428,7 +1430,8 @@ The value is actually the first element of LIST whose car equals KEY. */) | |||
| 1428 | } | 1430 | } |
| 1429 | 1431 | ||
| 1430 | /* Like Fassoc but never report an error and do not allow quits. | 1432 | /* Like Fassoc but never report an error and do not allow quits. |
| 1431 | Use only on objects known to be non-circular lists. */ | 1433 | Use only on keys and lists known to be non-circular, and on keys |
| 1434 | that are not too deep and are not window configurations. */ | ||
| 1432 | 1435 | ||
| 1433 | Lisp_Object | 1436 | Lisp_Object |
| 1434 | assoc_no_quit (Lisp_Object key, Lisp_Object list) | 1437 | assoc_no_quit (Lisp_Object key, Lisp_Object list) |
| @@ -1437,7 +1440,7 @@ assoc_no_quit (Lisp_Object key, Lisp_Object list) | |||
| 1437 | { | 1440 | { |
| 1438 | Lisp_Object car = XCAR (list); | 1441 | Lisp_Object car = XCAR (list); |
| 1439 | if (CONSP (car) | 1442 | if (CONSP (car) |
| 1440 | && (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key)))) | 1443 | && (EQ (XCAR (car), key) || equal_no_quit (XCAR (car), key))) |
| 1441 | return car; | 1444 | return car; |
| 1442 | } | 1445 | } |
| 1443 | return Qnil; | 1446 | return Qnil; |
| @@ -2085,7 +2088,7 @@ Floating-point numbers of equal value are `eql', but they may not be `eq'. */) | |||
| 2085 | (Lisp_Object obj1, Lisp_Object obj2) | 2088 | (Lisp_Object obj1, Lisp_Object obj2) |
| 2086 | { | 2089 | { |
| 2087 | if (FLOATP (obj1)) | 2090 | if (FLOATP (obj1)) |
| 2088 | return internal_equal (obj1, obj2, 0, 0, Qnil) ? Qt : Qnil; | 2091 | return equal_no_quit (obj1, obj2) ? Qt : Qnil; |
| 2089 | else | 2092 | else |
| 2090 | return EQ (obj1, obj2) ? Qt : Qnil; | 2093 | return EQ (obj1, obj2) ? Qt : Qnil; |
| 2091 | } | 2094 | } |
| @@ -2098,31 +2101,50 @@ Vectors and strings are compared element by element. | |||
| 2098 | Numbers are compared by value, but integers cannot equal floats. | 2101 | Numbers are compared by value, but integers cannot equal floats. |
| 2099 | (Use `=' if you want integers and floats to be able to be equal.) | 2102 | (Use `=' if you want integers and floats to be able to be equal.) |
| 2100 | Symbols must match exactly. */) | 2103 | Symbols must match exactly. */) |
| 2101 | (register Lisp_Object o1, Lisp_Object o2) | 2104 | (Lisp_Object o1, Lisp_Object o2) |
| 2102 | { | 2105 | { |
| 2103 | return internal_equal (o1, o2, 0, 0, Qnil) ? Qt : Qnil; | 2106 | return internal_equal (o1, o2, EQUAL_PLAIN, 0, Qnil) ? Qt : Qnil; |
| 2104 | } | 2107 | } |
| 2105 | 2108 | ||
| 2106 | DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, | 2109 | DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, |
| 2107 | doc: /* Return t if two Lisp objects have similar structure and contents. | 2110 | doc: /* Return t if two Lisp objects have similar structure and contents. |
| 2108 | This is like `equal' except that it compares the text properties | 2111 | This is like `equal' except that it compares the text properties |
| 2109 | of strings. (`equal' ignores text properties.) */) | 2112 | of strings. (`equal' ignores text properties.) */) |
| 2110 | (register Lisp_Object o1, Lisp_Object o2) | 2113 | (Lisp_Object o1, Lisp_Object o2) |
| 2111 | { | 2114 | { |
| 2112 | return internal_equal (o1, o2, 0, 1, Qnil) ? Qt : Qnil; | 2115 | return (internal_equal (o1, o2, EQUAL_INCLUDING_PROPERTIES, 0, Qnil) |
| 2116 | ? Qt : Qnil); | ||
| 2113 | } | 2117 | } |
| 2114 | 2118 | ||
| 2115 | /* DEPTH is current depth of recursion. Signal an error if it | 2119 | /* Return true if O1 and O2 are equal. Do not quit or check for cycles. |
| 2116 | gets too deep. | 2120 | Use this only on arguments that are cycle-free and not too large and |
| 2117 | PROPS means compare string text properties too. */ | 2121 | are not window configurations. */ |
| 2122 | |||
| 2123 | bool | ||
| 2124 | equal_no_quit (Lisp_Object o1, Lisp_Object o2) | ||
| 2125 | { | ||
| 2126 | return internal_equal (o1, o2, EQUAL_NO_QUIT, 0, Qnil); | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | /* Return true if O1 and O2 are equal. EQUAL_KIND specifies what kind | ||
| 2130 | of equality test to use: if it is EQUAL_NO_QUIT, do not check for | ||
| 2131 | cycles or large arguments or quits; if EQUAL_PLAIN, do ordinary | ||
| 2132 | Lisp equality; and if EQUAL_INCLUDING_PROPERTIES, do | ||
| 2133 | equal-including-properties. | ||
| 2134 | |||
| 2135 | If DEPTH is the current depth of recursion; signal an error if it | ||
| 2136 | gets too deep. HT is a hash table used to detect cycles; if nil, | ||
| 2137 | it has not been allocated yet. But ignore the last two arguments | ||
| 2138 | if EQUAL_KIND == EQUAL_NO_QUIT. */ | ||
| 2118 | 2139 | ||
| 2119 | static bool | 2140 | static bool |
| 2120 | internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | 2141 | internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, |
| 2121 | Lisp_Object ht) | 2142 | int depth, Lisp_Object ht) |
| 2122 | { | 2143 | { |
| 2123 | tail_recurse: | 2144 | tail_recurse: |
| 2124 | if (depth > 10) | 2145 | if (depth > 10) |
| 2125 | { | 2146 | { |
| 2147 | eassert (equal_kind != EQUAL_NO_QUIT); | ||
| 2126 | if (depth > 200) | 2148 | if (depth > 200) |
| 2127 | error ("Stack overflow in equal"); | 2149 | error ("Stack overflow in equal"); |
| 2128 | if (NILP (ht)) | 2150 | if (NILP (ht)) |
| @@ -2138,7 +2160,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2138 | { /* `o1' was seen already. */ | 2160 | { /* `o1' was seen already. */ |
| 2139 | Lisp_Object o2s = HASH_VALUE (h, i); | 2161 | Lisp_Object o2s = HASH_VALUE (h, i); |
| 2140 | if (!NILP (Fmemq (o2, o2s))) | 2162 | if (!NILP (Fmemq (o2, o2s))) |
| 2141 | return 1; | 2163 | return true; |
| 2142 | else | 2164 | else |
| 2143 | set_hash_value_slot (h, i, Fcons (o2, o2s)); | 2165 | set_hash_value_slot (h, i, Fcons (o2, o2s)); |
| 2144 | } | 2166 | } |
| @@ -2150,9 +2172,9 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2150 | } | 2172 | } |
| 2151 | 2173 | ||
| 2152 | if (EQ (o1, o2)) | 2174 | if (EQ (o1, o2)) |
| 2153 | return 1; | 2175 | return true; |
| 2154 | if (XTYPE (o1) != XTYPE (o2)) | 2176 | if (XTYPE (o1) != XTYPE (o2)) |
| 2155 | return 0; | 2177 | return false; |
| 2156 | 2178 | ||
| 2157 | switch (XTYPE (o1)) | 2179 | switch (XTYPE (o1)) |
| 2158 | { | 2180 | { |
| @@ -2166,31 +2188,42 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2166 | } | 2188 | } |
| 2167 | 2189 | ||
| 2168 | case Lisp_Cons: | 2190 | case Lisp_Cons: |
| 2169 | { | 2191 | if (equal_kind == EQUAL_NO_QUIT) |
| 2192 | for (; CONSP (o1); o1 = XCDR (o1)) | ||
| 2193 | { | ||
| 2194 | if (! CONSP (o2)) | ||
| 2195 | return false; | ||
| 2196 | if (! equal_no_quit (XCAR (o1), XCAR (o2))) | ||
| 2197 | return false; | ||
| 2198 | o2 = XCDR (o2); | ||
| 2199 | if (EQ (XCDR (o1), o2)) | ||
| 2200 | return true; | ||
| 2201 | } | ||
| 2202 | else | ||
| 2170 | FOR_EACH_TAIL (o1) | 2203 | FOR_EACH_TAIL (o1) |
| 2171 | { | 2204 | { |
| 2172 | if (! CONSP (o2)) | 2205 | if (! CONSP (o2)) |
| 2173 | return false; | 2206 | return false; |
| 2174 | if (! internal_equal (XCAR (o1), XCAR (o2), depth + 1, props, ht)) | 2207 | if (! internal_equal (XCAR (o1), XCAR (o2), |
| 2208 | equal_kind, depth + 1, ht)) | ||
| 2175 | return false; | 2209 | return false; |
| 2176 | o2 = XCDR (o2); | 2210 | o2 = XCDR (o2); |
| 2177 | if (EQ (XCDR (o1), o2)) | 2211 | if (EQ (XCDR (o1), o2)) |
| 2178 | return true; | 2212 | return true; |
| 2179 | } | 2213 | } |
| 2180 | depth++; | 2214 | depth++; |
| 2181 | goto tail_recurse; | 2215 | goto tail_recurse; |
| 2182 | } | ||
| 2183 | 2216 | ||
| 2184 | case Lisp_Misc: | 2217 | case Lisp_Misc: |
| 2185 | if (XMISCTYPE (o1) != XMISCTYPE (o2)) | 2218 | if (XMISCTYPE (o1) != XMISCTYPE (o2)) |
| 2186 | return 0; | 2219 | return false; |
| 2187 | if (OVERLAYP (o1)) | 2220 | if (OVERLAYP (o1)) |
| 2188 | { | 2221 | { |
| 2189 | if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), | 2222 | if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), |
| 2190 | depth + 1, props, ht) | 2223 | equal_kind, depth + 1, ht) |
| 2191 | || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), | 2224 | || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), |
| 2192 | depth + 1, props, ht)) | 2225 | equal_kind, depth + 1, ht)) |
| 2193 | return 0; | 2226 | return false; |
| 2194 | o1 = XOVERLAY (o1)->plist; | 2227 | o1 = XOVERLAY (o1)->plist; |
| 2195 | o2 = XOVERLAY (o2)->plist; | 2228 | o2 = XOVERLAY (o2)->plist; |
| 2196 | depth++; | 2229 | depth++; |
| @@ -2212,20 +2245,23 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2212 | actually checks that the objects have the same type as well as the | 2245 | actually checks that the objects have the same type as well as the |
| 2213 | same size. */ | 2246 | same size. */ |
| 2214 | if (ASIZE (o2) != size) | 2247 | if (ASIZE (o2) != size) |
| 2215 | return 0; | 2248 | return false; |
| 2216 | /* Boolvectors are compared much like strings. */ | 2249 | /* Boolvectors are compared much like strings. */ |
| 2217 | if (BOOL_VECTOR_P (o1)) | 2250 | if (BOOL_VECTOR_P (o1)) |
| 2218 | { | 2251 | { |
| 2219 | EMACS_INT size = bool_vector_size (o1); | 2252 | EMACS_INT size = bool_vector_size (o1); |
| 2220 | if (size != bool_vector_size (o2)) | 2253 | if (size != bool_vector_size (o2)) |
| 2221 | return 0; | 2254 | return false; |
| 2222 | if (memcmp (bool_vector_data (o1), bool_vector_data (o2), | 2255 | if (memcmp (bool_vector_data (o1), bool_vector_data (o2), |
| 2223 | bool_vector_bytes (size))) | 2256 | bool_vector_bytes (size))) |
| 2224 | return 0; | 2257 | return false; |
| 2225 | return 1; | 2258 | return true; |
| 2226 | } | 2259 | } |
| 2227 | if (WINDOW_CONFIGURATIONP (o1)) | 2260 | if (WINDOW_CONFIGURATIONP (o1)) |
| 2228 | return compare_window_configurations (o1, o2, 0); | 2261 | { |
| 2262 | eassert (equal_kind != EQUAL_NO_QUIT); | ||
| 2263 | return compare_window_configurations (o1, o2, false); | ||
| 2264 | } | ||
| 2229 | 2265 | ||
| 2230 | /* Aside from them, only true vectors, char-tables, compiled | 2266 | /* Aside from them, only true vectors, char-tables, compiled |
| 2231 | functions, and fonts (font-spec, font-entity, font-object) | 2267 | functions, and fonts (font-spec, font-entity, font-object) |
| @@ -2234,7 +2270,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2234 | { | 2270 | { |
| 2235 | if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) | 2271 | if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) |
| 2236 | < PVEC_COMPILED) | 2272 | < PVEC_COMPILED) |
| 2237 | return 0; | 2273 | return false; |
| 2238 | size &= PSEUDOVECTOR_SIZE_MASK; | 2274 | size &= PSEUDOVECTOR_SIZE_MASK; |
| 2239 | } | 2275 | } |
| 2240 | for (i = 0; i < size; i++) | 2276 | for (i = 0; i < size; i++) |
| @@ -2242,29 +2278,30 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2242 | Lisp_Object v1, v2; | 2278 | Lisp_Object v1, v2; |
| 2243 | v1 = AREF (o1, i); | 2279 | v1 = AREF (o1, i); |
| 2244 | v2 = AREF (o2, i); | 2280 | v2 = AREF (o2, i); |
| 2245 | if (!internal_equal (v1, v2, depth + 1, props, ht)) | 2281 | if (!internal_equal (v1, v2, equal_kind, depth + 1, ht)) |
| 2246 | return 0; | 2282 | return false; |
| 2247 | } | 2283 | } |
| 2248 | return 1; | 2284 | return true; |
| 2249 | } | 2285 | } |
| 2250 | break; | 2286 | break; |
| 2251 | 2287 | ||
| 2252 | case Lisp_String: | 2288 | case Lisp_String: |
| 2253 | if (SCHARS (o1) != SCHARS (o2)) | 2289 | if (SCHARS (o1) != SCHARS (o2)) |
| 2254 | return 0; | 2290 | return false; |
| 2255 | if (SBYTES (o1) != SBYTES (o2)) | 2291 | if (SBYTES (o1) != SBYTES (o2)) |
| 2256 | return 0; | 2292 | return false; |
| 2257 | if (memcmp (SDATA (o1), SDATA (o2), SBYTES (o1))) | 2293 | if (memcmp (SDATA (o1), SDATA (o2), SBYTES (o1))) |
| 2258 | return 0; | 2294 | return false; |
| 2259 | if (props && !compare_string_intervals (o1, o2)) | 2295 | if (equal_kind == EQUAL_INCLUDING_PROPERTIES |
| 2260 | return 0; | 2296 | && !compare_string_intervals (o1, o2)) |
| 2261 | return 1; | 2297 | return false; |
| 2298 | return true; | ||
| 2262 | 2299 | ||
| 2263 | default: | 2300 | default: |
| 2264 | break; | 2301 | break; |
| 2265 | } | 2302 | } |
| 2266 | 2303 | ||
| 2267 | return 0; | 2304 | return false; |
| 2268 | } | 2305 | } |
| 2269 | 2306 | ||
| 2270 | 2307 | ||
diff --git a/src/gtkutil.c b/src/gtkutil.c index 3a00e362221..63f01436413 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c | |||
| @@ -783,33 +783,55 @@ xg_set_geometry (struct frame *f) | |||
| 783 | { | 783 | { |
| 784 | if (f->size_hint_flags & (USPosition | PPosition)) | 784 | if (f->size_hint_flags & (USPosition | PPosition)) |
| 785 | { | 785 | { |
| 786 | int left = f->left_pos; | 786 | if (x_gtk_use_window_move) |
| 787 | int xneg = f->size_hint_flags & XNegative; | 787 | { |
| 788 | int top = f->top_pos; | 788 | /* Handle negative positions without consulting |
| 789 | int yneg = f->size_hint_flags & YNegative; | 789 | gtk_window_parse_geometry (Bug#25851). The position will |
| 790 | char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)]; | 790 | be off by scrollbar width + window manager decorations. */ |
| 791 | guint id; | 791 | if (f->size_hint_flags & XNegative) |
| 792 | 792 | f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f)) | |
| 793 | if (xneg) | 793 | - FRAME_PIXEL_WIDTH (f) + f->left_pos); |
| 794 | left = -left; | 794 | |
| 795 | if (yneg) | 795 | if (f->size_hint_flags & YNegative) |
| 796 | top = -top; | 796 | f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f)) |
| 797 | 797 | - FRAME_PIXEL_HEIGHT (f) + f->top_pos); | |
| 798 | sprintf (geom_str, "=%dx%d%c%d%c%d", | 798 | |
| 799 | FRAME_PIXEL_WIDTH (f), | 799 | gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), |
| 800 | FRAME_PIXEL_HEIGHT (f), | 800 | f->left_pos, f->top_pos); |
| 801 | (xneg ? '-' : '+'), left, | 801 | |
| 802 | (yneg ? '-' : '+'), top); | 802 | /* Reset size hint flags. */ |
| 803 | 803 | f->size_hint_flags &= ~ (XNegative | YNegative); | |
| 804 | /* Silence warning about visible children. */ | 804 | } |
| 805 | id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | 805 | else |
| 806 | | G_LOG_FLAG_RECURSION, my_log_handler, NULL); | 806 | { |
| 807 | 807 | int left = f->left_pos; | |
| 808 | if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), | 808 | int xneg = f->size_hint_flags & XNegative; |
| 809 | geom_str)) | 809 | int top = f->top_pos; |
| 810 | fprintf (stderr, "Failed to parse: '%s'\n", geom_str); | 810 | int yneg = f->size_hint_flags & YNegative; |
| 811 | 811 | char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)]; | |
| 812 | g_log_remove_handler ("Gtk", id); | 812 | guint id; |
| 813 | |||
| 814 | if (xneg) | ||
| 815 | left = -left; | ||
| 816 | if (yneg) | ||
| 817 | top = -top; | ||
| 818 | |||
| 819 | sprintf (geom_str, "=%dx%d%c%d%c%d", | ||
| 820 | FRAME_PIXEL_WIDTH (f), | ||
| 821 | FRAME_PIXEL_HEIGHT (f), | ||
| 822 | (xneg ? '-' : '+'), left, | ||
| 823 | (yneg ? '-' : '+'), top); | ||
| 824 | |||
| 825 | /* Silence warning about visible children. */ | ||
| 826 | id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | ||
| 827 | | G_LOG_FLAG_RECURSION, my_log_handler, NULL); | ||
| 828 | |||
| 829 | if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), | ||
| 830 | geom_str)) | ||
| 831 | fprintf (stderr, "Failed to parse: '%s'\n", geom_str); | ||
| 832 | |||
| 833 | g_log_remove_handler ("Gtk", id); | ||
| 834 | } | ||
| 813 | } | 835 | } |
| 814 | } | 836 | } |
| 815 | 837 | ||
| @@ -1406,6 +1428,13 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position) | |||
| 1406 | else if (win_gravity == StaticGravity) | 1428 | else if (win_gravity == StaticGravity) |
| 1407 | size_hints.win_gravity = GDK_GRAVITY_STATIC; | 1429 | size_hints.win_gravity = GDK_GRAVITY_STATIC; |
| 1408 | 1430 | ||
| 1431 | if (x_gtk_use_window_move) | ||
| 1432 | { | ||
| 1433 | if (flags & PPosition) hint_flags |= GDK_HINT_POS; | ||
| 1434 | if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS; | ||
| 1435 | if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE; | ||
| 1436 | } | ||
| 1437 | |||
| 1409 | if (user_position) | 1438 | if (user_position) |
| 1410 | { | 1439 | { |
| 1411 | hint_flags &= ~GDK_HINT_POS; | 1440 | hint_flags &= ~GDK_HINT_POS; |
diff --git a/src/inotify.c b/src/inotify.c index 61ef6153286..290701349ef 100644 --- a/src/inotify.c +++ b/src/inotify.c | |||
| @@ -41,24 +41,40 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 41 | #ifndef IN_ONLYDIR | 41 | #ifndef IN_ONLYDIR |
| 42 | # define IN_ONLYDIR 0 | 42 | # define IN_ONLYDIR 0 |
| 43 | #endif | 43 | #endif |
| 44 | #define INOTIFY_DEFAULT_MASK (IN_ALL_EVENTS | IN_EXCL_UNLINK) | ||
| 44 | 45 | ||
| 45 | /* File handle for inotify. */ | 46 | /* File handle for inotify. */ |
| 46 | static int inotifyfd = -1; | 47 | static int inotifyfd = -1; |
| 47 | 48 | ||
| 48 | /* Assoc list of files being watched. | 49 | /* Alist of files being watched. We want the returned descriptor to |
| 49 | Format: (watch-descriptor name callback) | 50 | be unique for every watch, but inotify returns the same descriptor |
| 50 | */ | 51 | WD for multiple calls to inotify_add_watch with the same file. |
| 52 | Supply a nonnegative integer ID, so that WD and ID together | ||
| 53 | uniquely identify a watch/file combination. | ||
| 54 | |||
| 55 | For the same reason, we also need to store the watch's mask and we | ||
| 56 | can't allow the following flags to be used. | ||
| 57 | |||
| 58 | IN_EXCL_UNLINK | ||
| 59 | IN_MASK_ADD | ||
| 60 | IN_ONESHOT | ||
| 61 | IN_ONLYDIR | ||
| 62 | |||
| 63 | Each element of this list is of the form (DESCRIPTOR . WATCHES) | ||
| 64 | where no two DESCRIPTOR values are the same. DESCRIPTOR represents | ||
| 65 | the inotify watch descriptor and WATCHES is a list with elements of | ||
| 66 | the form (ID FILENAME CALLBACK MASK), where ID is the integer | ||
| 67 | described above, FILENAME names the file being watched, CALLBACK is | ||
| 68 | invoked when the event occurs, and MASK represents the aspects | ||
| 69 | being watched. The WATCHES list is sorted by ID. Although | ||
| 70 | DESCRIPTOR and MASK are ordinarily integers, they are conses when | ||
| 71 | representing integers outside of fixnum range. */ | ||
| 72 | |||
| 51 | static Lisp_Object watch_list; | 73 | static Lisp_Object watch_list; |
| 52 | 74 | ||
| 53 | static Lisp_Object | 75 | static Lisp_Object |
| 54 | make_watch_descriptor (int wd) | 76 | mask_to_aspects (uint32_t mask) |
| 55 | { | 77 | { |
| 56 | /* TODO replace this with a Misc Object! */ | ||
| 57 | return make_number (wd); | ||
| 58 | } | ||
| 59 | |||
| 60 | static Lisp_Object | ||
| 61 | mask_to_aspects (uint32_t mask) { | ||
| 62 | Lisp_Object aspects = Qnil; | 78 | Lisp_Object aspects = Qnil; |
| 63 | if (mask & IN_ACCESS) | 79 | if (mask & IN_ACCESS) |
| 64 | aspects = Fcons (Qaccess, aspects); | 80 | aspects = Fcons (Qaccess, aspects); |
| @@ -95,77 +111,6 @@ mask_to_aspects (uint32_t mask) { | |||
| 95 | return aspects; | 111 | return aspects; |
| 96 | } | 112 | } |
| 97 | 113 | ||
| 98 | static Lisp_Object | ||
| 99 | inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const *ev) | ||
| 100 | { | ||
| 101 | Lisp_Object name = Qnil; | ||
| 102 | if (ev->len > 0) | ||
| 103 | { | ||
| 104 | size_t const len = strlen (ev->name); | ||
| 105 | name = make_unibyte_string (ev->name, min (len, ev->len)); | ||
| 106 | name = DECODE_FILE (name); | ||
| 107 | } | ||
| 108 | else | ||
| 109 | name = XCAR (XCDR (watch_object)); | ||
| 110 | |||
| 111 | return list2 (list4 (make_watch_descriptor (ev->wd), | ||
| 112 | mask_to_aspects (ev->mask), | ||
| 113 | name, | ||
| 114 | make_number (ev->cookie)), | ||
| 115 | Fnth (make_number (2), watch_object)); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* This callback is called when the FD is available for read. The inotify | ||
| 119 | events are read from FD and converted into input_events. */ | ||
| 120 | static void | ||
| 121 | inotify_callback (int fd, void *_) | ||
| 122 | { | ||
| 123 | struct input_event event; | ||
| 124 | Lisp_Object watch_object; | ||
| 125 | int to_read; | ||
| 126 | char *buffer; | ||
| 127 | ssize_t n; | ||
| 128 | size_t i; | ||
| 129 | |||
| 130 | to_read = 0; | ||
| 131 | if (ioctl (fd, FIONREAD, &to_read) == -1) | ||
| 132 | report_file_notify_error ("Error while retrieving file system events", | ||
| 133 | Qnil); | ||
| 134 | buffer = xmalloc (to_read); | ||
| 135 | n = read (fd, buffer, to_read); | ||
| 136 | if (n < 0) | ||
| 137 | { | ||
| 138 | xfree (buffer); | ||
| 139 | report_file_notify_error ("Error while reading file system events", Qnil); | ||
| 140 | } | ||
| 141 | |||
| 142 | EVENT_INIT (event); | ||
| 143 | event.kind = FILE_NOTIFY_EVENT; | ||
| 144 | |||
| 145 | i = 0; | ||
| 146 | while (i < (size_t)n) | ||
| 147 | { | ||
| 148 | struct inotify_event *ev = (struct inotify_event *) &buffer[i]; | ||
| 149 | |||
| 150 | watch_object = Fassoc (make_watch_descriptor (ev->wd), watch_list); | ||
| 151 | if (!NILP (watch_object)) | ||
| 152 | { | ||
| 153 | event.arg = inotifyevent_to_event (watch_object, ev); | ||
| 154 | |||
| 155 | /* If event was removed automatically: Drop it from watch list. */ | ||
| 156 | if (ev->mask & IN_IGNORED) | ||
| 157 | watch_list = Fdelete (watch_object, watch_list); | ||
| 158 | |||
| 159 | if (!NILP (event.arg)) | ||
| 160 | kbd_buffer_store_event (&event); | ||
| 161 | } | ||
| 162 | |||
| 163 | i += sizeof (*ev) + ev->len; | ||
| 164 | } | ||
| 165 | |||
| 166 | xfree (buffer); | ||
| 167 | } | ||
| 168 | |||
| 169 | static uint32_t | 114 | static uint32_t |
| 170 | symbol_to_inotifymask (Lisp_Object symb) | 115 | symbol_to_inotifymask (Lisp_Object symb) |
| 171 | { | 116 | { |
| @@ -200,14 +145,6 @@ symbol_to_inotifymask (Lisp_Object symb) | |||
| 200 | 145 | ||
| 201 | else if (EQ (symb, Qdont_follow)) | 146 | else if (EQ (symb, Qdont_follow)) |
| 202 | return IN_DONT_FOLLOW; | 147 | return IN_DONT_FOLLOW; |
| 203 | else if (EQ (symb, Qexcl_unlink)) | ||
| 204 | return IN_EXCL_UNLINK; | ||
| 205 | else if (EQ (symb, Qmask_add)) | ||
| 206 | return IN_MASK_ADD; | ||
| 207 | else if (EQ (symb, Qoneshot)) | ||
| 208 | return IN_ONESHOT; | ||
| 209 | else if (EQ (symb, Qonlydir)) | ||
| 210 | return IN_ONLYDIR; | ||
| 211 | 148 | ||
| 212 | else if (EQ (symb, Qt) || EQ (symb, Qall_events)) | 149 | else if (EQ (symb, Qt) || EQ (symb, Qall_events)) |
| 213 | return IN_ALL_EVENTS; | 150 | return IN_ALL_EVENTS; |
| @@ -221,21 +158,204 @@ symbol_to_inotifymask (Lisp_Object symb) | |||
| 221 | static uint32_t | 158 | static uint32_t |
| 222 | aspect_to_inotifymask (Lisp_Object aspect) | 159 | aspect_to_inotifymask (Lisp_Object aspect) |
| 223 | { | 160 | { |
| 224 | if (CONSP (aspect)) | 161 | if (CONSP (aspect) || NILP (aspect)) |
| 225 | { | 162 | { |
| 226 | Lisp_Object x = aspect; | 163 | Lisp_Object x = aspect; |
| 227 | uint32_t mask = 0; | 164 | uint32_t mask = 0; |
| 228 | while (CONSP (x)) | 165 | FOR_EACH_TAIL (x) |
| 229 | { | 166 | mask |= symbol_to_inotifymask (XCAR (x)); |
| 230 | mask |= symbol_to_inotifymask (XCAR (x)); | 167 | CHECK_LIST_END (x, aspect); |
| 231 | x = XCDR (x); | ||
| 232 | } | ||
| 233 | return mask; | 168 | return mask; |
| 234 | } | 169 | } |
| 235 | else | 170 | else |
| 236 | return symbol_to_inotifymask (aspect); | 171 | return symbol_to_inotifymask (aspect); |
| 237 | } | 172 | } |
| 238 | 173 | ||
| 174 | static Lisp_Object | ||
| 175 | inotifyevent_to_event (Lisp_Object watch, struct inotify_event const *ev) | ||
| 176 | { | ||
| 177 | Lisp_Object name; | ||
| 178 | uint32_t mask; | ||
| 179 | CONS_TO_INTEGER (Fnth (make_number (3), watch), uint32_t, mask); | ||
| 180 | |||
| 181 | if (! (mask & ev->mask)) | ||
| 182 | return Qnil; | ||
| 183 | |||
| 184 | if (ev->len > 0) | ||
| 185 | { | ||
| 186 | size_t const len = strlen (ev->name); | ||
| 187 | name = make_unibyte_string (ev->name, min (len, ev->len)); | ||
| 188 | name = DECODE_FILE (name); | ||
| 189 | } | ||
| 190 | else | ||
| 191 | name = XCAR (XCDR (watch)); | ||
| 192 | |||
| 193 | return list2 (list4 (Fcons (INTEGER_TO_CONS (ev->wd), XCAR (watch)), | ||
| 194 | mask_to_aspects (ev->mask), | ||
| 195 | name, | ||
| 196 | INTEGER_TO_CONS (ev->cookie)), | ||
| 197 | Fnth (make_number (2), watch)); | ||
| 198 | } | ||
| 199 | |||
| 200 | /* Add a new watch to watch-descriptor WD watching FILENAME and using | ||
| 201 | CALLBACK. Returns a cons (DESCRIPTOR . ID) uniquely identifying the | ||
| 202 | new watch. */ | ||
| 203 | static Lisp_Object | ||
| 204 | add_watch (int wd, Lisp_Object filename, | ||
| 205 | Lisp_Object aspect, Lisp_Object callback) | ||
| 206 | { | ||
| 207 | Lisp_Object descriptor = INTEGER_TO_CONS (wd); | ||
| 208 | Lisp_Object tail = assoc_no_quit (descriptor, watch_list); | ||
| 209 | Lisp_Object watch, watch_id; | ||
| 210 | uint32_t imask = aspect_to_inotifymask (aspect); | ||
| 211 | Lisp_Object mask = INTEGER_TO_CONS (imask); | ||
| 212 | |||
| 213 | EMACS_INT id = 0; | ||
| 214 | if (NILP (tail)) | ||
| 215 | { | ||
| 216 | tail = list1 (descriptor); | ||
| 217 | watch_list = Fcons (tail, watch_list); | ||
| 218 | } | ||
| 219 | else | ||
| 220 | { | ||
| 221 | /* Assign a watch ID that is not already in use, by looking | ||
| 222 | for a gap in the existing sorted list. */ | ||
| 223 | for (; ! NILP (XCDR (tail)); tail = XCDR (tail), id++) | ||
| 224 | if (!EQ (XCAR (XCAR (XCDR (tail))), make_number (id))) | ||
| 225 | break; | ||
| 226 | if (MOST_POSITIVE_FIXNUM < id) | ||
| 227 | emacs_abort (); | ||
| 228 | } | ||
| 229 | |||
| 230 | /* Insert the newly-assigned ID into the previously-discovered gap, | ||
| 231 | which is possibly at the end of the list. Inserting it there | ||
| 232 | keeps the list sorted. */ | ||
| 233 | watch_id = make_number (id); | ||
| 234 | watch = list4 (watch_id, filename, callback, mask); | ||
| 235 | XSETCDR (tail, Fcons (watch, XCDR (tail))); | ||
| 236 | |||
| 237 | return Fcons (descriptor, watch_id); | ||
| 238 | } | ||
| 239 | |||
| 240 | /* Find the watch list element (if any) matching DESCRIPTOR. Return | ||
| 241 | nil if not found. If found, return t if the first element matches | ||
| 242 | DESCRIPTOR; otherwise, return the cons whose cdr matches | ||
| 243 | DESCRIPTOR. This lets the caller easily remove the element | ||
| 244 | matching DESCRIPTOR without having to search for it again, and | ||
| 245 | without calling Fdelete (which might quit). */ | ||
| 246 | |||
| 247 | static Lisp_Object | ||
| 248 | find_descriptor (Lisp_Object descriptor) | ||
| 249 | { | ||
| 250 | Lisp_Object tail, prevtail = Qt; | ||
| 251 | for (tail = watch_list; !NILP (tail); prevtail = tail, tail = XCDR (tail)) | ||
| 252 | if (equal_no_quit (XCAR (XCAR (tail)), descriptor)) | ||
| 253 | return prevtail; | ||
| 254 | return Qnil; | ||
| 255 | } | ||
| 256 | |||
| 257 | /* Remove all watches associated with the watch list element after | ||
| 258 | PREVTAIL, or after the first element if PREVTAIL is t. If INVALID_P | ||
| 259 | is true, the descriptor is already invalid, i.e., it received a | ||
| 260 | IN_IGNORED event. In this case skip calling inotify_rm_watch. */ | ||
| 261 | static void | ||
| 262 | remove_descriptor (Lisp_Object prevtail, bool invalid_p) | ||
| 263 | { | ||
| 264 | Lisp_Object tail = CONSP (prevtail) ? XCDR (prevtail) : watch_list; | ||
| 265 | |||
| 266 | int inotify_errno = 0; | ||
| 267 | if (! invalid_p) | ||
| 268 | { | ||
| 269 | int wd; | ||
| 270 | CONS_TO_INTEGER (XCAR (XCAR (tail)), int, wd); | ||
| 271 | if (inotify_rm_watch (inotifyfd, wd) != 0) | ||
| 272 | inotify_errno = errno; | ||
| 273 | } | ||
| 274 | |||
| 275 | if (CONSP (prevtail)) | ||
| 276 | XSETCDR (prevtail, XCDR (tail)); | ||
| 277 | else | ||
| 278 | { | ||
| 279 | watch_list = XCDR (tail); | ||
| 280 | if (NILP (watch_list)) | ||
| 281 | { | ||
| 282 | delete_read_fd (inotifyfd); | ||
| 283 | emacs_close (inotifyfd); | ||
| 284 | inotifyfd = -1; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | if (inotify_errno != 0) | ||
| 289 | { | ||
| 290 | errno = inotify_errno; | ||
| 291 | report_file_notify_error ("Could not rm watch", XCAR (tail)); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | /* Remove watch associated with (descriptor, id). */ | ||
| 296 | static void | ||
| 297 | remove_watch (Lisp_Object descriptor, Lisp_Object id) | ||
| 298 | { | ||
| 299 | Lisp_Object prevtail = find_descriptor (descriptor); | ||
| 300 | if (NILP (prevtail)) | ||
| 301 | return; | ||
| 302 | |||
| 303 | Lisp_Object elt = XCAR (CONSP (prevtail) ? XCDR (prevtail) : watch_list); | ||
| 304 | for (Lisp_Object prev = elt; !NILP (XCDR (prev)); prev = XCDR (prev)) | ||
| 305 | if (EQ (id, XCAR (XCAR (XCDR (prev))))) | ||
| 306 | { | ||
| 307 | XSETCDR (prev, XCDR (XCDR (prev))); | ||
| 308 | if (NILP (XCDR (elt))) | ||
| 309 | remove_descriptor (prevtail, false); | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | /* This callback is called when the FD is available for read. The inotify | ||
| 315 | events are read from FD and converted into input_events. */ | ||
| 316 | static void | ||
| 317 | inotify_callback (int fd, void *_) | ||
| 318 | { | ||
| 319 | int to_read; | ||
| 320 | if (ioctl (fd, FIONREAD, &to_read) < 0) | ||
| 321 | report_file_notify_error ("Error while retrieving file system events", | ||
| 322 | Qnil); | ||
| 323 | USE_SAFE_ALLOCA; | ||
| 324 | char *buffer = SAFE_ALLOCA (to_read); | ||
| 325 | ssize_t n = read (fd, buffer, to_read); | ||
| 326 | if (n < 0) | ||
| 327 | report_file_notify_error ("Error while reading file system events", Qnil); | ||
| 328 | |||
| 329 | struct input_event event; | ||
| 330 | EVENT_INIT (event); | ||
| 331 | event.kind = FILE_NOTIFY_EVENT; | ||
| 332 | |||
| 333 | for (ssize_t i = 0; i < n; ) | ||
| 334 | { | ||
| 335 | struct inotify_event *ev = (struct inotify_event *) &buffer[i]; | ||
| 336 | Lisp_Object descriptor = INTEGER_TO_CONS (ev->wd); | ||
| 337 | Lisp_Object prevtail = find_descriptor (descriptor); | ||
| 338 | |||
| 339 | if (! NILP (prevtail)) | ||
| 340 | { | ||
| 341 | Lisp_Object tail = CONSP (prevtail) ? XCDR (prevtail) : watch_list; | ||
| 342 | for (Lisp_Object watches = XCDR (XCAR (tail)); ! NILP (watches); | ||
| 343 | watches = XCDR (watches)) | ||
| 344 | { | ||
| 345 | event.arg = inotifyevent_to_event (XCAR (watches), ev); | ||
| 346 | if (!NILP (event.arg)) | ||
| 347 | kbd_buffer_store_event (&event); | ||
| 348 | } | ||
| 349 | /* If event was removed automatically: Drop it from watch list. */ | ||
| 350 | if (ev->mask & IN_IGNORED) | ||
| 351 | remove_descriptor (prevtail, true); | ||
| 352 | } | ||
| 353 | i += sizeof (*ev) + ev->len; | ||
| 354 | } | ||
| 355 | |||
| 356 | SAFE_FREE (); | ||
| 357 | } | ||
| 358 | |||
| 239 | DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0, | 359 | DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0, |
| 240 | doc: /* Add a watch for FILE-NAME to inotify. | 360 | doc: /* Add a watch for FILE-NAME to inotify. |
| 241 | 361 | ||
| @@ -264,10 +384,6 @@ close | |||
| 264 | The following symbols can also be added to a list of aspects: | 384 | The following symbols can also be added to a list of aspects: |
| 265 | 385 | ||
| 266 | dont-follow | 386 | dont-follow |
| 267 | excl-unlink | ||
| 268 | mask-add | ||
| 269 | oneshot | ||
| 270 | onlydir | ||
| 271 | 387 | ||
| 272 | Watching a directory is not recursive. CALLBACK is passed a single argument | 388 | Watching a directory is not recursive. CALLBACK is passed a single argument |
| 273 | EVENT which contains an event structure of the format | 389 | EVENT which contains an event structure of the format |
| @@ -289,47 +405,56 @@ If a directory is watched then NAME is the name of file that caused the event. | |||
| 289 | COOKIE is an object that can be compared using `equal' to identify two matching | 405 | COOKIE is an object that can be compared using `equal' to identify two matching |
| 290 | renames (moved-from and moved-to). | 406 | renames (moved-from and moved-to). |
| 291 | 407 | ||
| 292 | See inotify(7) and inotify_add_watch(2) for further information. The inotify fd | 408 | See inotify(7) and inotify_add_watch(2) for further information. The |
| 293 | is managed internally and there is no corresponding inotify_init. Use | 409 | inotify fd is managed internally and there is no corresponding |
| 294 | `inotify-rm-watch' to remove a watch. | 410 | inotify_init. Use `inotify-rm-watch' to remove a watch. |
| 295 | */) | 411 | |
| 296 | (Lisp_Object file_name, Lisp_Object aspect, Lisp_Object callback) | 412 | Also note, that the following inotify bit-masks can not be used, due |
| 413 | to the fact that descriptors are shared across different callers. | ||
| 414 | |||
| 415 | IN_EXCL_UNLINK | ||
| 416 | IN_MASK_ADD | ||
| 417 | IN_ONESHOT | ||
| 418 | IN_ONLYDIR */) | ||
| 419 | (Lisp_Object filename, Lisp_Object aspect, Lisp_Object callback) | ||
| 297 | { | 420 | { |
| 298 | uint32_t mask; | ||
| 299 | Lisp_Object watch_object; | ||
| 300 | Lisp_Object encoded_file_name; | 421 | Lisp_Object encoded_file_name; |
| 301 | Lisp_Object watch_descriptor; | 422 | bool dont_follow = (CONSP (aspect) |
| 302 | int watchdesc = -1; | 423 | ? ! NILP (Fmemq (Qdont_follow, aspect)) |
| 424 | : EQ (Qdont_follow, aspect)); | ||
| 425 | int wd = -1; | ||
| 426 | uint32_t mask = (INOTIFY_DEFAULT_MASK | ||
| 427 | | (dont_follow ? IN_DONT_FOLLOW : 0)); | ||
| 303 | 428 | ||
| 304 | CHECK_STRING (file_name); | 429 | CHECK_STRING (filename); |
| 305 | 430 | ||
| 306 | if (inotifyfd < 0) | 431 | if (inotifyfd < 0) |
| 307 | { | 432 | { |
| 308 | inotifyfd = inotify_init1 (IN_NONBLOCK|IN_CLOEXEC); | 433 | inotifyfd = inotify_init1 (IN_NONBLOCK | IN_CLOEXEC); |
| 309 | if (inotifyfd < 0) | 434 | if (inotifyfd < 0) |
| 310 | report_file_notify_error ("File watching is not available", Qnil); | 435 | report_file_notify_error ("File watching is not available", Qnil); |
| 311 | watch_list = Qnil; | 436 | watch_list = Qnil; |
| 312 | add_read_fd (inotifyfd, &inotify_callback, NULL); | 437 | add_read_fd (inotifyfd, &inotify_callback, NULL); |
| 313 | } | 438 | } |
| 314 | 439 | ||
| 315 | mask = aspect_to_inotifymask (aspect); | 440 | encoded_file_name = ENCODE_FILE (filename); |
| 316 | encoded_file_name = ENCODE_FILE (file_name); | 441 | wd = inotify_add_watch (inotifyfd, SSDATA (encoded_file_name), mask); |
| 317 | watchdesc = inotify_add_watch (inotifyfd, SSDATA (encoded_file_name), mask); | 442 | if (wd < 0) |
| 318 | if (watchdesc == -1) | 443 | report_file_notify_error ("Could not add watch for file", filename); |
| 319 | report_file_notify_error ("Could not add watch for file", file_name); | ||
| 320 | |||
| 321 | watch_descriptor = make_watch_descriptor (watchdesc); | ||
| 322 | 444 | ||
| 323 | /* Delete existing watch object. */ | 445 | return add_watch (wd, filename, aspect, callback); |
| 324 | watch_object = Fassoc (watch_descriptor, watch_list); | 446 | } |
| 325 | if (!NILP (watch_object)) | ||
| 326 | watch_list = Fdelete (watch_object, watch_list); | ||
| 327 | |||
| 328 | /* Store watch object in watch list. */ | ||
| 329 | watch_object = list3 (watch_descriptor, encoded_file_name, callback); | ||
| 330 | watch_list = Fcons (watch_object, watch_list); | ||
| 331 | 447 | ||
| 332 | return watch_descriptor; | 448 | static bool |
| 449 | valid_watch_descriptor (Lisp_Object wd) | ||
| 450 | { | ||
| 451 | return (CONSP (wd) | ||
| 452 | && (RANGED_INTEGERP (0, XCAR (wd), INT_MAX) | ||
| 453 | || (CONSP (XCAR (wd)) | ||
| 454 | && RANGED_INTEGERP ((MOST_POSITIVE_FIXNUM >> 16) + 1, | ||
| 455 | XCAR (XCAR (wd)), INT_MAX >> 16) | ||
| 456 | && RANGED_INTEGERP (0, XCDR (XCAR (wd)), (1 << 16) - 1))) | ||
| 457 | && NATNUMP (XCDR (wd))); | ||
| 333 | } | 458 | } |
| 334 | 459 | ||
| 335 | DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0, | 460 | DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0, |
| @@ -337,28 +462,18 @@ DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0, | |||
| 337 | 462 | ||
| 338 | WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'. | 463 | WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'. |
| 339 | 464 | ||
| 340 | See inotify_rm_watch(2) for more information. | 465 | See inotify_rm_watch(2) for more information. */) |
| 341 | */) | ||
| 342 | (Lisp_Object watch_descriptor) | 466 | (Lisp_Object watch_descriptor) |
| 343 | { | 467 | { |
| 344 | Lisp_Object watch_object; | ||
| 345 | int wd = XINT (watch_descriptor); | ||
| 346 | 468 | ||
| 347 | if (inotify_rm_watch (inotifyfd, wd) == -1) | 469 | Lisp_Object descriptor, id; |
| 348 | report_file_notify_error ("Could not rm watch", watch_descriptor); | ||
| 349 | 470 | ||
| 350 | /* Remove watch descriptor from watch list. */ | 471 | if (! valid_watch_descriptor (watch_descriptor)) |
| 351 | watch_object = Fassoc (watch_descriptor, watch_list); | 472 | report_file_notify_error ("Invalid descriptor ", watch_descriptor); |
| 352 | if (!NILP (watch_object)) | ||
| 353 | watch_list = Fdelete (watch_object, watch_list); | ||
| 354 | 473 | ||
| 355 | /* Cleanup if no more files are watched. */ | 474 | descriptor = XCAR (watch_descriptor); |
| 356 | if (NILP (watch_list)) | 475 | id = XCDR (watch_descriptor); |
| 357 | { | 476 | remove_watch (descriptor, id); |
| 358 | emacs_close (inotifyfd); | ||
| 359 | delete_read_fd (inotifyfd); | ||
| 360 | inotifyfd = -1; | ||
| 361 | } | ||
| 362 | 477 | ||
| 363 | return Qt; | 478 | return Qt; |
| 364 | } | 479 | } |
| @@ -374,10 +489,29 @@ reason. Removing the watch by calling `inotify-rm-watch' also makes | |||
| 374 | it invalid. */) | 489 | it invalid. */) |
| 375 | (Lisp_Object watch_descriptor) | 490 | (Lisp_Object watch_descriptor) |
| 376 | { | 491 | { |
| 377 | Lisp_Object watch_object = Fassoc (watch_descriptor, watch_list); | 492 | if (! valid_watch_descriptor (watch_descriptor)) |
| 378 | return NILP (watch_object) ? Qnil : Qt; | 493 | return Qnil; |
| 494 | Lisp_Object tail = assoc_no_quit (XCAR (watch_descriptor), watch_list); | ||
| 495 | if (NILP (tail)) | ||
| 496 | return Qnil; | ||
| 497 | Lisp_Object watch = assq_no_quit (XCDR (watch_descriptor), XCDR (tail)); | ||
| 498 | return ! NILP (watch) ? Qt : Qnil; | ||
| 379 | } | 499 | } |
| 380 | 500 | ||
| 501 | #ifdef INOTIFY_DEBUG | ||
| 502 | DEFUN ("inotify-watch-list", Finotify_watch_list, Sinotify_watch_list, 0, 0, 0, | ||
| 503 | doc: /* Return a copy of the internal watch_list. */) | ||
| 504 | { | ||
| 505 | return Fcopy_sequence (watch_list); | ||
| 506 | } | ||
| 507 | |||
| 508 | DEFUN ("inotify-allocated-p", Finotify_allocated_p, Sinotify_allocated_p, 0, 0, 0, | ||
| 509 | doc: /* Return non-nil, if a inotify instance is allocated. */) | ||
| 510 | { | ||
| 511 | return inotifyfd < 0 ? Qnil : Qt; | ||
| 512 | } | ||
| 513 | #endif | ||
| 514 | |||
| 381 | void | 515 | void |
| 382 | syms_of_inotify (void) | 516 | syms_of_inotify (void) |
| 383 | { | 517 | { |
| @@ -400,10 +534,6 @@ syms_of_inotify (void) | |||
| 400 | DEFSYM (Qclose, "close"); /* IN_CLOSE */ | 534 | DEFSYM (Qclose, "close"); /* IN_CLOSE */ |
| 401 | 535 | ||
| 402 | DEFSYM (Qdont_follow, "dont-follow"); /* IN_DONT_FOLLOW */ | 536 | DEFSYM (Qdont_follow, "dont-follow"); /* IN_DONT_FOLLOW */ |
| 403 | DEFSYM (Qexcl_unlink, "excl-unlink"); /* IN_EXCL_UNLINK */ | ||
| 404 | DEFSYM (Qmask_add, "mask-add"); /* IN_MASK_ADD */ | ||
| 405 | DEFSYM (Qoneshot, "oneshot"); /* IN_ONESHOT */ | ||
| 406 | DEFSYM (Qonlydir, "onlydir"); /* IN_ONLYDIR */ | ||
| 407 | 537 | ||
| 408 | DEFSYM (Qignored, "ignored"); /* IN_IGNORED */ | 538 | DEFSYM (Qignored, "ignored"); /* IN_IGNORED */ |
| 409 | DEFSYM (Qisdir, "isdir"); /* IN_ISDIR */ | 539 | DEFSYM (Qisdir, "isdir"); /* IN_ISDIR */ |
| @@ -414,6 +544,10 @@ syms_of_inotify (void) | |||
| 414 | defsubr (&Sinotify_rm_watch); | 544 | defsubr (&Sinotify_rm_watch); |
| 415 | defsubr (&Sinotify_valid_p); | 545 | defsubr (&Sinotify_valid_p); |
| 416 | 546 | ||
| 547 | #ifdef INOTIFY_DEBUG | ||
| 548 | defsubr (&Sinotify_watch_list); | ||
| 549 | defsubr (&Sinotify_allocated_p); | ||
| 550 | #endif | ||
| 417 | staticpro (&watch_list); | 551 | staticpro (&watch_list); |
| 418 | 552 | ||
| 419 | Fprovide (intern_c_string ("inotify"), Qnil); | 553 | Fprovide (intern_c_string ("inotify"), Qnil); |
diff --git a/src/lisp.h b/src/lisp.h index 4b9cd3c4702..3125bd2a5dd 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3376,6 +3376,7 @@ extern Lisp_Object merge (Lisp_Object, Lisp_Object, Lisp_Object); | |||
| 3376 | extern Lisp_Object do_yes_or_no_p (Lisp_Object); | 3376 | extern Lisp_Object do_yes_or_no_p (Lisp_Object); |
| 3377 | extern Lisp_Object concat2 (Lisp_Object, Lisp_Object); | 3377 | extern Lisp_Object concat2 (Lisp_Object, Lisp_Object); |
| 3378 | extern Lisp_Object concat3 (Lisp_Object, Lisp_Object, Lisp_Object); | 3378 | extern Lisp_Object concat3 (Lisp_Object, Lisp_Object, Lisp_Object); |
| 3379 | extern bool equal_no_quit (Lisp_Object, Lisp_Object); | ||
| 3379 | extern Lisp_Object nconc2 (Lisp_Object, Lisp_Object); | 3380 | extern Lisp_Object nconc2 (Lisp_Object, Lisp_Object); |
| 3380 | extern Lisp_Object assq_no_quit (Lisp_Object, Lisp_Object); | 3381 | extern Lisp_Object assq_no_quit (Lisp_Object, Lisp_Object); |
| 3381 | extern Lisp_Object assoc_no_quit (Lisp_Object, Lisp_Object); | 3382 | extern Lisp_Object assoc_no_quit (Lisp_Object, Lisp_Object); |
diff --git a/src/xdisp.c b/src/xdisp.c index 82668494927..af086d17eb8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -2716,6 +2716,7 @@ init_iterator (struct it *it, struct window *w, | |||
| 2716 | if (face_change) | 2716 | if (face_change) |
| 2717 | { | 2717 | { |
| 2718 | face_change = false; | 2718 | face_change = false; |
| 2719 | XFRAME (w->frame)->face_change = 0; | ||
| 2719 | free_all_realized_faces (Qnil); | 2720 | free_all_realized_faces (Qnil); |
| 2720 | } | 2721 | } |
| 2721 | else if (XFRAME (w->frame)->face_change) | 2722 | else if (XFRAME (w->frame)->face_change) |
| @@ -14132,21 +14133,16 @@ redisplay_internal (void) | |||
| 14132 | Therefore, we must redisplay this frame. */ | 14133 | Therefore, we must redisplay this frame. */ |
| 14133 | if (!f_redisplay_flag && f->redisplay) | 14134 | if (!f_redisplay_flag && f->redisplay) |
| 14134 | goto retry_frame; | 14135 | goto retry_frame; |
| 14135 | |||
| 14136 | /* In some case (e.g., window resize), we notice | 14136 | /* In some case (e.g., window resize), we notice |
| 14137 | only during window updating that the window | 14137 | only during window updating that the window |
| 14138 | content changed unpredictably (e.g., a GTK | 14138 | content changed unpredictably (e.g., a GTK |
| 14139 | scrollbar moved) and that our previous estimation | 14139 | scrollbar moved, or some Lisp hook that winds up |
| 14140 | of the frame content was garbage. We have to | 14140 | calling adjust_frame_glyphs) and that our |
| 14141 | start over. These cases should be rare, so going | 14141 | previous estimation of the frame content was |
| 14142 | all the way back to the top of redisplay should | 14142 | garbage. We have to start over. These cases |
| 14143 | be good enough. | 14143 | should be rare, so going all the way back to the |
| 14144 | 14144 | top of redisplay should be good enough. */ | |
| 14145 | Why FRAME_WINDOW_P? See | 14145 | if (FRAME_GARBAGED_P (f)) |
| 14146 | https://lists.gnu.org/archive/html/emacs-devel/2016-10/msg00957.html | ||
| 14147 | |||
| 14148 | */ | ||
| 14149 | if (FRAME_GARBAGED_P (f) && FRAME_WINDOW_P (f)) | ||
| 14150 | goto retry; | 14146 | goto retry; |
| 14151 | 14147 | ||
| 14152 | /* Prevent various kinds of signals during display | 14148 | /* Prevent various kinds of signals during display |
diff --git a/src/xterm.c b/src/xterm.c index 7856793f8dc..4f9eff6c5e6 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -10056,11 +10056,26 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_ | |||
| 10056 | f->size_hint_flags |= YNegative; | 10056 | f->size_hint_flags |= YNegative; |
| 10057 | f->win_gravity = NorthWestGravity; | 10057 | f->win_gravity = NorthWestGravity; |
| 10058 | } | 10058 | } |
| 10059 | |||
| 10059 | x_calc_absolute_position (f); | 10060 | x_calc_absolute_position (f); |
| 10060 | 10061 | ||
| 10061 | block_input (); | 10062 | block_input (); |
| 10062 | x_wm_set_size_hint (f, 0, false); | 10063 | x_wm_set_size_hint (f, 0, false); |
| 10063 | 10064 | ||
| 10065 | #ifdef USE_GTK | ||
| 10066 | if (x_gtk_use_window_move) | ||
| 10067 | { | ||
| 10068 | /* When a position change was requested and the outer GTK widget | ||
| 10069 | has been realized already, leave it to gtk_window_move to DTRT | ||
| 10070 | and return. Used for Bug#25851 and Bug#25943. */ | ||
| 10071 | if (change_gravity != 0 && FRAME_GTK_OUTER_WIDGET (f)) | ||
| 10072 | gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), | ||
| 10073 | f->left_pos, f->top_pos); | ||
| 10074 | unblock_input (); | ||
| 10075 | return; | ||
| 10076 | } | ||
| 10077 | #endif /* USE_GTK */ | ||
| 10078 | |||
| 10064 | modified_left = f->left_pos; | 10079 | modified_left = f->left_pos; |
| 10065 | modified_top = f->top_pos; | 10080 | modified_top = f->top_pos; |
| 10066 | 10081 | ||
| @@ -12905,4 +12920,11 @@ state. | |||
| 12905 | Set this variable only if your window manager cannot handle the | 12920 | Set this variable only if your window manager cannot handle the |
| 12906 | transition between the various maximization states. */); | 12921 | transition between the various maximization states. */); |
| 12907 | x_frame_normalize_before_maximize = false; | 12922 | x_frame_normalize_before_maximize = false; |
| 12923 | |||
| 12924 | DEFVAR_BOOL ("x-gtk-use-window-move", x_gtk_use_window_move, | ||
| 12925 | doc: /* Non-nil means rely on gtk_window_move to set frame positions. | ||
| 12926 | If this variable is t, the GTK build uses the function gtk_window_move | ||
| 12927 | to set or store frame positions and disables some time consuming frame | ||
| 12928 | position adjustments. */); | ||
| 12929 | x_gtk_use_window_move = false; | ||
| 12908 | } | 12930 | } |