aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael R. Mauger2017-04-02 18:10:57 -0400
committerMichael R. Mauger2017-04-02 18:10:57 -0400
commit77083e2d34ba5559ae2899d3b03cf08c2e6c5ad4 (patch)
tree27da92c2a61d664b700860c2d527a4d36000ca37 /src
parentc5a31f8292c94d19b80a3dbe0b3026693cc1090e (diff)
parent8e394a7f35c2ba9297d222faa2689e177f268924 (diff)
downloademacs-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.in25
-rw-r--r--src/editfns.c2
-rw-r--r--src/fns.c121
-rw-r--r--src/gtkutil.c83
-rw-r--r--src/inotify.c432
-rw-r--r--src/lisp.h1
-rw-r--r--src/xdisp.c20
-rw-r--r--src/xterm.c22
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@)
347am__v_at_0 = @ 347am__v_at_0 = @
348am__v_at_1 = 348am__v_at_1 =
349 349
350DEPDIR=deps
351AUTO_DEPEND = @AUTO_DEPEND@ 350AUTO_DEPEND = @AUTO_DEPEND@
352 351DEPDIR = deps
353ifeq ($(AUTO_DEPEND),yes) 352ifeq ($(AUTO_DEPEND),yes)
354DEPFLAGS = -MMD -MF ${DEPDIR}/$*.d -MP 353 DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP
355MKDEPDIR = ${MKDIR_P} ${DEPDIR} 354 -include $(ALLOBJS:%.o=$(DEPDIR)/%.d)
356else 355else
357DEPFLAGS = 356 DEPFLAGS =
358MKDEPDIR = : 357 include $(srcdir)/deps.mk
359endif 358endif
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
652clean: mostlyclean 649clean: 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
667distclean: bootstrap-clean 663distclean: bootstrap-clean
668 rm -f Makefile lisp.mk 664 rm -f Makefile lisp.mk
665 rm -fr $(DEPDIR)
669 666
670maintainer-clean: distclean 667maintainer-clean: distclean
671 rm -f TAGS 668 rm -f TAGS
@@ -755,11 +752,3 @@ else
755endif 752endif
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
759ifeq ($(AUTO_DEPEND),yes)
760-include $(ALLOBJS:%.o=${DEPDIR}/%.d)
761else
762include $(srcdir)/deps.mk
763endif
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
diff --git a/src/fns.c b/src/fns.c
index 10653558eb5..de7fc1b47fc 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -38,7 +38,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
38 38
39static void sort_vector_copy (Lisp_Object, ptrdiff_t, 39static void sort_vector_copy (Lisp_Object, ptrdiff_t,
40 Lisp_Object *restrict, Lisp_Object *restrict); 40 Lisp_Object *restrict, Lisp_Object *restrict);
41static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); 41enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES };
42static bool internal_equal (Lisp_Object, Lisp_Object,
43 enum equal_kind, int, Lisp_Object);
42 44
43DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, 45DEFUN ("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
1433Lisp_Object 1436Lisp_Object
1434assoc_no_quit (Lisp_Object key, Lisp_Object list) 1437assoc_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.
2098Numbers are compared by value, but integers cannot equal floats. 2101Numbers 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.)
2100Symbols must match exactly. */) 2103Symbols 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
2106DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, 2109DEFUN ("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.
2108This is like `equal' except that it compares the text properties 2111This is like `equal' except that it compares the text properties
2109of strings. (`equal' ignores text properties.) */) 2112of 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
2123bool
2124equal_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
2119static bool 2140static bool
2120internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, 2141internal_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. */
46static int inotifyfd = -1; 47static 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
51static Lisp_Object watch_list; 73static Lisp_Object watch_list;
52 74
53static Lisp_Object 75static Lisp_Object
54make_watch_descriptor (int wd) 76mask_to_aspects (uint32_t mask)
55{ 77{
56 /* TODO replace this with a Misc Object! */
57 return make_number (wd);
58}
59
60static Lisp_Object
61mask_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
98static Lisp_Object
99inotifyevent_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. */
120static void
121inotify_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
169static uint32_t 114static uint32_t
170symbol_to_inotifymask (Lisp_Object symb) 115symbol_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)
221static uint32_t 158static uint32_t
222aspect_to_inotifymask (Lisp_Object aspect) 159aspect_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
174static Lisp_Object
175inotifyevent_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. */
203static Lisp_Object
204add_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
247static Lisp_Object
248find_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. */
261static void
262remove_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). */
296static void
297remove_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. */
316static void
317inotify_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
239DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0, 359DEFUN ("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
264The following symbols can also be added to a list of aspects: 384The following symbols can also be added to a list of aspects:
265 385
266dont-follow 386dont-follow
267excl-unlink
268mask-add
269oneshot
270onlydir
271 387
272Watching a directory is not recursive. CALLBACK is passed a single argument 388Watching a directory is not recursive. CALLBACK is passed a single argument
273EVENT which contains an event structure of the format 389EVENT 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.
289COOKIE is an object that can be compared using `equal' to identify two matching 405COOKIE is an object that can be compared using `equal' to identify two matching
290renames (moved-from and moved-to). 406renames (moved-from and moved-to).
291 407
292See inotify(7) and inotify_add_watch(2) for further information. The inotify fd 408See inotify(7) and inotify_add_watch(2) for further information. The
293is managed internally and there is no corresponding inotify_init. Use 409inotify fd is managed internally and there is no corresponding
294`inotify-rm-watch' to remove a watch. 410inotify_init. Use `inotify-rm-watch' to remove a watch.
295 */) 411
296 (Lisp_Object file_name, Lisp_Object aspect, Lisp_Object callback) 412Also note, that the following inotify bit-masks can not be used, due
413to the fact that descriptors are shared across different callers.
414
415IN_EXCL_UNLINK
416IN_MASK_ADD
417IN_ONESHOT
418IN_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; 448static bool
449valid_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
335DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0, 460DEFUN ("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
338WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'. 463WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'.
339 464
340See inotify_rm_watch(2) for more information. 465See 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
374it invalid. */) 489it 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
502DEFUN ("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
508DEFUN ("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
381void 515void
382syms_of_inotify (void) 516syms_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);
3376extern Lisp_Object do_yes_or_no_p (Lisp_Object); 3376extern Lisp_Object do_yes_or_no_p (Lisp_Object);
3377extern Lisp_Object concat2 (Lisp_Object, Lisp_Object); 3377extern Lisp_Object concat2 (Lisp_Object, Lisp_Object);
3378extern Lisp_Object concat3 (Lisp_Object, Lisp_Object, Lisp_Object); 3378extern Lisp_Object concat3 (Lisp_Object, Lisp_Object, Lisp_Object);
3379extern bool equal_no_quit (Lisp_Object, Lisp_Object);
3379extern Lisp_Object nconc2 (Lisp_Object, Lisp_Object); 3380extern Lisp_Object nconc2 (Lisp_Object, Lisp_Object);
3380extern Lisp_Object assq_no_quit (Lisp_Object, Lisp_Object); 3381extern Lisp_Object assq_no_quit (Lisp_Object, Lisp_Object);
3381extern Lisp_Object assoc_no_quit (Lisp_Object, Lisp_Object); 3382extern 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.
12905Set this variable only if your window manager cannot handle the 12920Set this variable only if your window manager cannot handle the
12906transition between the various maximization states. */); 12921transition 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.
12926If this variable is t, the GTK build uses the function gtk_window_move
12927to set or store frame positions and disables some time consuming frame
12928position adjustments. */);
12929 x_gtk_use_window_move = false;
12908} 12930}