aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoakim Verona2012-12-11 12:02:20 +0100
committerJoakim Verona2012-12-11 12:02:20 +0100
commit5ccd4f20470d8e216ca3eae26339100a5eab52f1 (patch)
tree70caca485fbaef0dcce16a811908c4b9b121ee1e
parentc0b95835acf65071ac1d740d15f7bcaa55c2a04b (diff)
parentc6afe371b0218154957bbef17c3f8bda5377b7c8 (diff)
downloademacs-5ccd4f20470d8e216ca3eae26339100a5eab52f1.tar.gz
emacs-5ccd4f20470d8e216ca3eae26339100a5eab52f1.zip
some conflict resolution
-rw-r--r--ChangeLog24
-rw-r--r--configure.ac22
-rw-r--r--doc/lispref/ChangeLog6
-rw-r--r--doc/lispref/internals.texi88
-rw-r--r--etc/NEWS6
-rw-r--r--lib-src/ChangeLog9
-rw-r--r--lib-src/makefile.w32-in10
-rw-r--r--lib/makefile.w32-in5
-rw-r--r--lisp/ChangeLog52
-rw-r--r--lisp/calc/calc-forms.el33
-rw-r--r--lisp/calc/calc.el4
-rw-r--r--lisp/hi-lock.el95
-rw-r--r--lisp/makefile.w32-in2
-rw-r--r--lisp/net/rcirc.el9
-rw-r--r--lisp/progmodes/f90.el33
-rw-r--r--lisp/subr.el30
-rw-r--r--nt/ChangeLog12
-rw-r--r--nt/config.nt19
-rw-r--r--nt/emacs.rc4
-rw-r--r--src/ChangeLog160
-rw-r--r--src/Makefile.in25
-rw-r--r--src/buffer.c46
-rw-r--r--src/buffer.h19
-rw-r--r--src/deps.mk1
-rw-r--r--src/emacs.c14
-rw-r--r--src/fringe.c2
-rw-r--r--src/indent.c4
-rw-r--r--src/inotify.c438
-rw-r--r--src/insdel.c9
-rw-r--r--src/keyboard.c57
-rw-r--r--src/lisp.h10
-rw-r--r--src/makefile.w32-in21
-rw-r--r--src/termhooks.h5
-rw-r--r--src/unexw32.c16
-rw-r--r--src/w32console.c3
-rw-r--r--src/w32fns.c7
-rw-r--r--src/w32gui.h3
-rw-r--r--src/w32inevt.c74
-rw-r--r--src/w32notify.c631
-rw-r--r--src/w32proc.c19
-rw-r--r--src/w32term.c134
-rw-r--r--src/w32term.h15
-rw-r--r--src/w32xfns.c10
-rw-r--r--src/window.c81
-rw-r--r--src/window.h12
-rw-r--r--src/xdisp.c47
-rw-r--r--test/ChangeLog8
-rw-r--r--test/automated/f90.el18
-rw-r--r--test/automated/inotify-test.el60
49 files changed, 2209 insertions, 203 deletions
diff --git a/ChangeLog b/ChangeLog
index eb572b26b16..05bc063624b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
12012-12-11 Juanma Barranquero <lekktu@gmail.com>
2
3 * lib/makefile.w32-in (SIG2STR_H): New macro.
4 ($(BLD)/sig2str.$(O)): Update dependencies.
5
62012-12-10 Paul Eggert <eggert@cs.ucla.edu>
7
8 * configure.ac (HAVE_INOTIFY): Speed up configure-time test.
9 There's no need to test for any of three inotify functions,
10 since we use all three. Check for just the first one.
11
122012-12-10 Daniel Colascione <dancol@dancol.org>
13
14 * .bzrignore: add src/emacs.res.
15
16 * configure.ac (W32_RES, W32_RES_LINK, WINDRES): Teach the cygw32
17 build how to compile Windows resource files; use these variables
18 to tell src/Makefile.in how and whether to compile resources.
19
202012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
21
22 * configure.ac (inotify): New option.
23 (HAVE_INOTIFY): Test for inotify.
24
12012-12-09 Andreas Schwab <schwab@linux-m68k.org> 252012-12-09 Andreas Schwab <schwab@linux-m68k.org>
2 26
3 * configure.ac: Fix source command in .gdbinit. 27 * configure.ac: Fix source command in .gdbinit.
diff --git a/configure.ac b/configure.ac
index e649b6725e9..5b889cb2d8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,6 +185,7 @@ OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
185OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) 185OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
186OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) 186OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
187OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) 187OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
188OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support])
188 189
189OPTION_DEFAULT_OFF([xwidgets],[enable use of some gtk widgets it Emacs buffers]) 190OPTION_DEFAULT_OFF([xwidgets],[enable use of some gtk widgets it Emacs buffers])
190 191
@@ -1607,6 +1608,8 @@ AC_SUBST(LIB_STANDARD)
1607HAVE_W32=no 1608HAVE_W32=no
1608W32_OBJ= 1609W32_OBJ=
1609W32_LIBS= 1610W32_LIBS=
1611W32_RES=
1612W32_RES_LINK=
1610if test "${with_w32}" != no; then 1613if test "${with_w32}" != no; then
1611 if test "${opsys}" != "cygwin"; then 1614 if test "${opsys}" != "cygwin"; then
1612 AC_MSG_ERROR([Using w32 with an autotools build is only supported for Cygwin.]) 1615 AC_MSG_ERROR([Using w32 with an autotools build is only supported for Cygwin.])
@@ -1615,13 +1618,21 @@ if test "${with_w32}" != no; then
1615 [AC_MSG_ERROR([`--with-w32' was specified, but windows.h 1618 [AC_MSG_ERROR([`--with-w32' was specified, but windows.h
1616 cannot be found.])]) 1619 cannot be found.])])
1617 AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.]) 1620 AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.])
1621 AC_CHECK_TOOL(WINDRES, [windres],
1622 [AC_MSG_ERROR([No resource compiler found.])])
1618 W32_OBJ="w32fns.o w32menu.o w32reg.o w32font.o w32term.o" 1623 W32_OBJ="w32fns.o w32menu.o w32reg.o w32font.o w32term.o"
1619 W32_OBJ="$W32_OBJ w32xfns.o w32select.o w32uniscribe.o" 1624 W32_OBJ="$W32_OBJ w32xfns.o w32select.o w32uniscribe.o"
1620 W32_LIBS="$W32_LIBS -lkernel32 -luser32 -lgdi32 -lole32 -lcomdlg32" 1625 W32_LIBS="$W32_LIBS -lkernel32 -luser32 -lgdi32 -lole32 -lcomdlg32"
1621 W32_LIBS="$W32_LIBS -lusp10 -lcomctl32 -lwinspool" 1626 W32_LIBS="$W32_LIBS -lusp10 -lcomctl32 -lwinspool"
1627 W32_RES="emacs.res"
1628 # Tell the linker that emacs.res is an object (which we compile from
1629 # the rc file), not a linker script.
1630 W32_RES_LINK="-Wl,-bpe-i386 -Wl,emacs.res"
1622fi 1631fi
1623AC_SUBST(W32_OBJ) 1632AC_SUBST(W32_OBJ)
1624AC_SUBST(W32_LIBS) 1633AC_SUBST(W32_LIBS)
1634AC_SUBST(W32_RES)
1635AC_SUBST(W32_RES_LINK)
1625 1636
1626if test "${HAVE_W32}" = "yes"; then 1637if test "${HAVE_W32}" = "yes"; then
1627 window_system=w32 1638 window_system=w32
@@ -2236,6 +2247,17 @@ fi
2236AC_SUBST(LIBGNUTLS_LIBS) 2247AC_SUBST(LIBGNUTLS_LIBS)
2237AC_SUBST(LIBGNUTLS_CFLAGS) 2248AC_SUBST(LIBGNUTLS_CFLAGS)
2238 2249
2250dnl inotify is only available on GNU/Linux.
2251if test "${with_inotify}" = "yes"; then
2252 AC_CHECK_HEADERS(sys/inotify.h)
2253 if test "$ac_cv_header_sys_inotify_h" = yes ; then
2254 AC_CHECK_FUNC(inotify_init1)
2255 fi
2256fi
2257if test "$ac_cv_func_inotify_init1" = yes; then
2258 AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.])
2259fi
2260
2239dnl Do not put whitespace before the #include statements below. 2261dnl Do not put whitespace before the #include statements below.
2240dnl Older compilers (eg sunos4 cc) choke on it. 2262dnl Older compilers (eg sunos4 cc) choke on it.
2241HAVE_XAW3D=no 2263HAVE_XAW3D=no
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog
index 05716cd77b3..43d737b618f 100644
--- a/doc/lispref/ChangeLog
+++ b/doc/lispref/ChangeLog
@@ -1,3 +1,9 @@
12012-12-11 Paul Eggert <eggert@cs.ucla.edu>
2
3 * internals.texi (C Integer Types): New section.
4 This follows up and records an email in
5 <http://lists.gnu.org/archive/html/emacs-devel/2012-07/msg00496.html>.
6
12012-12-10 Stefan Monnier <monnier@iro.umontreal.ca> 72012-12-10 Stefan Monnier <monnier@iro.umontreal.ca>
2 8
3 * control.texi (Pattern maching case statement): New node. 9 * control.texi (Pattern maching case statement): New node.
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index 830a00ec9e6..025042a6869 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -16,6 +16,7 @@ internal aspects of GNU Emacs that may be of interest to C programmers.
16* Memory Usage:: Info about total size of Lisp objects made so far. 16* Memory Usage:: Info about total size of Lisp objects made so far.
17* Writing Emacs Primitives:: Writing C code for Emacs. 17* Writing Emacs Primitives:: Writing C code for Emacs.
18* Object Internals:: Data formats of buffers, windows, processes. 18* Object Internals:: Data formats of buffers, windows, processes.
19* C Integer Types:: How C integer types are used inside Emacs.
19@end menu 20@end menu
20 21
21@node Building Emacs 22@node Building Emacs
@@ -1531,4 +1532,91 @@ Symbol indicating the type of process: @code{real}, @code{network},
1531 1532
1532@end table 1533@end table
1533 1534
1535@node C Integer Types
1536@section C Integer Types
1537@cindex integer types (C programming language)
1538
1539Here are some guidelines for use of integer types in the Emacs C
1540source code. These guidelines sometimes give competing advice; common
1541sense is advised.
1542
1543@itemize @bullet
1544@item
1545Avoid arbitrary limits. For example, avoid @code{int len = strlen
1546(s);} unless the length of @code{s} is required for other reasons to
1547fit in @code{int} range.
1548
1549@item
1550Do not assume that signed integer arithmetic wraps around on overflow.
1551This is no longer true of Emacs porting targets: signed integer
1552overflow has undefined behavior in practice, and can dump core or
1553even cause earlier or later code to behave ``illogically''. Unsigned
1554overflow does wrap around reliably, modulo a power of two.
1555
1556@item
1557Prefer signed types to unsigned, as code gets confusing when signed
1558and unsigned types are combined. Many other guidelines assume that
1559types are signed; in the rarer cases where unsigned types are needed,
1560similar advice may apply to the unsigned counterparts (e.g.,
1561@code{size_t} instead of @code{ptrdiff_t}, or @code{uintptr_t} instead
1562of @code{intptr_t}).
1563
1564@item
1565Prefer @code{int} for Emacs character codes, in the range 0 ..@: 0x3FFFFF.
1566
1567@item
1568Prefer @code{ptrdiff_t} for sizes, i.e., for integers bounded by the
1569maximum size of any individual C object or by the maximum number of
1570elements in any C array. This is part of Emacs's general preference
1571for signed types. Using @code{ptrdiff_t} limits objects to
1572@code{PTRDIFF_MAX} bytes, but larger objects would cause trouble
1573anyway since they would break pointer subtraction, so this does not
1574impose an arbitrary limit.
1575
1576@item
1577Prefer @code{intptr_t} for internal representations of pointers, or
1578for integers bounded only by the number of objects that can exist at
1579any given time or by the total number of bytes that can be allocated.
1580Currently Emacs sometimes uses other types when @code{intptr_t} would
1581be better; fixing this is lower priority, as the code works as-is on
1582Emacs's current porting targets.
1583
1584@item
1585Prefer the Emacs-defined type @code{EMACS_INT} for representing values
1586converted to or from Emacs Lisp fixnums, as fixnum arithmetic is based
1587on @code{EMACS_INT}.
1588
1589@item
1590When representing a system value (such as a file size or a count of
1591seconds since the Epoch), prefer the corresponding system type (e.g.,
1592@code{off_t}, @code{time_t}). Do not assume that a system type is
1593signed, unless this assumption is known to be safe. For example,
1594although @code{off_t} is always signed, @code{time_t} need not be.
1595
1596@item
1597Prefer the Emacs-defined type @code{printmax_t} for representing
1598values that might be any signed integer value that can be printed,
1599using a @code{printf}-family function.
1600
1601@item
1602Prefer @code{intmax_t} for representing values that might be any
1603signed integer value.
1604
1605@item
1606In bitfields, prefer @code{unsigned int} or @code{signed int} to
1607@code{int}, as @code{int} is less portable: it might be signed, and
1608might not be. Single-bit bit fields are invariably @code{unsigned
1609int} so that their values are 0 and 1.
1610
1611@item
1612In C, Emacs commonly uses @code{bool}, 1, and 0 for boolean values.
1613Using @code{bool} for booleans can make programs easier to read and a
1614bit faster than using @code{int}. Although it is also OK to use
1615@code{int}, this older style is gradually being phased out. When
1616using @code{bool}, respect the limitations of the replacement
1617implementation of @code{bool}, as documented in the source file
1618@file{lib/stdbool.in.h}, so that Emacs remains portable to pre-C99
1619platforms.
1620@end itemize
1621
1534@c FIXME Mention src/globals.h somewhere in this file? 1622@c FIXME Mention src/globals.h somewhere in this file?
diff --git a/etc/NEWS b/etc/NEWS
index c7622b09b6b..77e7e47b8a3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -133,6 +133,12 @@ spurious warnings about an unused var.
133 133
134* Lisp changes in Emacs 24.4 134* Lisp changes in Emacs 24.4
135 135
136** Support for filesystem notifications.
137Emacs now supports notifications of filesystem changes, such as
138creation, modification, and deletion of files. This requires the
139'inotify' API on GNU/Linux systems. On MS-Windows systems, this is
140supported for Windows XP and newer versions.
141
136** Face changes 142** Face changes
137 143
138*** The `face-spec-set' is now analogous to `setq' for face specs. 144*** The `face-spec-set' is now analogous to `setq' for face specs.
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog
index 480ddabd44a..866e76ad24f 100644
--- a/lib-src/ChangeLog
+++ b/lib-src/ChangeLog
@@ -1,3 +1,12 @@
12012-12-11 Juanma Barranquero <lekktu@gmail.com>
2
3 * makefile.w32-in (SYSWAIT_H): Update dependencies.
4
52012-12-10 Eli Zaretskii <eliz@gnu.org>
6
7 * makefile.w32-in (obj): Add w32notify.o. Add missing X and Unix
8 sources.
9
12012-12-02 Kevin Ryde <user42@zip.com.au> 102012-12-02 Kevin Ryde <user42@zip.com.au>
2 11
3 * etags.c (Lisp_functions): Skip (defvar foo) declarations unless 12 * etags.c (Lisp_functions): Skip (defvar foo) declarations unless
diff --git a/lib-src/makefile.w32-in b/lib-src/makefile.w32-in
index cbd29f32cfe..24be44e22f2 100644
--- a/lib-src/makefile.w32-in
+++ b/lib-src/makefile.w32-in
@@ -123,10 +123,13 @@ $(BLD)/profile.exe: $(PROFILEOBJS)
123# 123#
124obj = dosfns.o msdos.o \ 124obj = dosfns.o msdos.o \
125 xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ 125 xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \
126 fontset.o menu.o \ 126 fontset.o menu.o dbusbind.o cygw32.o \
127 w32.o w32console.o w32fns.o w32heap.o w32inevt.o cygw32.o \ 127 nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \
128 w32.o w32console.o w32fns.o w32heap.o w32inevt.o w32notify.o \
128 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ 129 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
129 font.o w32font.o w32uniscribe.o \ 130 w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \
131 xsettings.o xgselect.o termcap.o \
132 font.o w32font.o w32uniscribe.o w32notify.o \
130 dispnew.o frame.o scroll.o xdisp.o window.o bidi.o \ 133 dispnew.o frame.o scroll.o xdisp.o window.o bidi.o \
131 charset.o coding.o category.o ccl.o character.o chartab.o \ 134 charset.o coding.o category.o ccl.o character.o chartab.o \
132 cm.o term.o terminal.o xfaces.o \ 135 cm.o term.o terminal.o xfaces.o \
@@ -375,6 +378,7 @@ SYSTIME_H = $(SRC)/systime.h \
375 $(NT_INC)/sys/time.h \ 378 $(NT_INC)/sys/time.h \
376 $(GNU_LIB)/timespec.h 379 $(GNU_LIB)/timespec.h
377SYSWAIT_H = $(SRC)/syswait.h \ 380SYSWAIT_H = $(SRC)/syswait.h \
381 $(NT_INC)/stdbool.h \
378 $(NT_INC)/sys/wait.h 382 $(NT_INC)/sys/wait.h
379 383
380$(BLD)/ctags.$(O) : \ 384$(BLD)/ctags.$(O) : \
diff --git a/lib/makefile.w32-in b/lib/makefile.w32-in
index b27e21032b3..1482d686acb 100644
--- a/lib/makefile.w32-in
+++ b/lib/makefile.w32-in
@@ -103,6 +103,8 @@ U64_H = $(GNU_LIB)/u64.h \
103 $(NT_INC)/stdint.h 103 $(NT_INC)/stdint.h
104SHA512_H = $(GNU_LIB)/sha512.h \ 104SHA512_H = $(GNU_LIB)/sha512.h \
105 $(U64_H) 105 $(U64_H)
106SIG2STR_H = $(GNU_LIB)/sig2str.h \
107 $(GNU_LIB)/intprops.h
106STAT_TIME_H = $(GNU_LIB)/stat-time.h \ 108STAT_TIME_H = $(GNU_LIB)/stat-time.h \
107 $(NT_INC)/sys/stat.h 109 $(NT_INC)/sys/stat.h
108 110
@@ -243,8 +245,7 @@ $(BLD)/filemode.$(O) : \
243$(BLD)/sig2str.$(O) : \ 245$(BLD)/sig2str.$(O) : \
244 $(GNU_LIB)/sig2str.c \ 246 $(GNU_LIB)/sig2str.c \
245 $(CONFIG_H) \ 247 $(CONFIG_H) \
246 $(GNU_LIB)/sig2str.h \ 248 $(SIG2STR_H)
247 $(GNU_LIB)/intprops.h
248 249
249 250
250# The following dependencies are for supporting parallel builds, where 251# The following dependencies are for supporting parallel builds, where
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 787bfb7563b..17dc012fdab 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,11 +1,59 @@
12012-12-11 Eli Zaretskii <eliz@gnu.org>
2
3 * makefile.w32-in (compile4-SH): Fix a typo that caused term
4 subdirectory be skipped.
5
62012-12-11 Glenn Morris <rgm@gnu.org>
7
8 * net/rcirc.el (rcirc-urls, rcirc-condition-filter): Doc fixes.
9
10 * progmodes/f90.el (f90-line-continued, f90-indent-region):
11 Treat preprocessor lines embedded in continuations like comments.
12 (f90-indent-line): Special-case preprocessor lines. (Bug#13138)
13
142012-12-11 Jay Belanger <jay.p.belanger@gmail.com>
15
16 * calc/calc.el (calc-standard-date-formats): Add more date
17 formats.
18 * calc/calc-forms.el (math-parse-iso-date): New function.
19 (math-parse-date): Use `math-parse-iso-date' when appropriate.
20 (math-parse-iso-date-validate): Add extra error checking.
21 (calc-date-notation): Add ability to access new date formats.
22
232012-12-10 Stefan Monnier <monnier@iro.umontreal.ca>
24
25 * hi-lock.el (hi-lock--regexps-at-point): Fix boundary case for
26 font-lock as well as when there's no text-property.
27
282012-12-10 Jambunathan K <kjambunathan@gmail.com>
29
30 * hi-lock.el: Refine the choice of default face.
31 (hi-lock-keyword->face): New function. Use it wherever we used
32 cadadadr instead.
33 (hi-lock--regexps-at-point): Ignore faces that can't come from hi-lock.
34 (hi-lock--last-face): Remove var.
35 (hi-lock--unused-faces): New var to replace it.
36 (hi-lock-read-face-name): Use/maintain it.
37 (hi-lock-unface-buffer): Maintain it. Fix error for the C-u case.
38 (hi-lock-set-pattern): Ignore new rule if it has the same regexp even
39 if it has another face.
40
412012-12-10 Eli Zaretskii <eliz@gnu.org>
42
43 * subr.el (w32notify-handle-event): New function.
44 (inotify-handle-event): Doc fix.
45
462012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
47
48 * subr.el (inotify-event-p, inotify-handle-event): New functions.
49
12012-12-10 Dani Moncayo <dmoncayo@gmail.com> 502012-12-10 Dani Moncayo <dmoncayo@gmail.com>
2 51
3 * simple.el (just-one-space): Doc fix. 52 * simple.el (just-one-space): Doc fix.
4 53
52012-12-10 Eli Zaretskii <eliz@gnu.org> 542012-12-10 Eli Zaretskii <eliz@gnu.org>
6 55
7 * textmodes/texinfo.el (texinfo-enable-quote-envs): Add 56 * textmodes/texinfo.el (texinfo-enable-quote-envs): Add "smallexample".
8 "smallexample".
9 57
102012-12-10 Le Wang <l26wang@gmail.com> 582012-12-10 Le Wang <l26wang@gmail.com>
11 59
diff --git a/lisp/calc/calc-forms.el b/lisp/calc/calc-forms.el
index 5ce76b14d72..7cfca261fa3 100644
--- a/lisp/calc/calc-forms.el
+++ b/lisp/calc/calc-forms.el
@@ -82,13 +82,13 @@
82 (calc-wrapper 82 (calc-wrapper
83 (if (string-match-p "\\`\\s-*\\'" fmt) 83 (if (string-match-p "\\`\\s-*\\'" fmt)
84 (setq fmt "1")) 84 (setq fmt "1"))
85 (if (string-match "\\` *[0-9] *\\'" fmt) 85 (if (string-match "\\` *\\([0-9]\\|10\\|11\\) *\\'" fmt)
86 (setq fmt (nth (string-to-number fmt) calc-standard-date-formats))) 86 (setq fmt (nth (string-to-number fmt) calc-standard-date-formats)))
87 (or (string-match "[a-zA-Z]" fmt) 87 (or (string-match "[a-zA-Z]" fmt)
88 (error "Bad date format specifier")) 88 (error "Bad date format specifier"))
89 (and arg 89 (and arg
90 (>= (setq arg (prefix-numeric-value arg)) 0) 90 (>= (setq arg (prefix-numeric-value arg)) 0)
91 (<= arg 9) 91 (<= arg 11)
92 (setq calc-standard-date-formats 92 (setq calc-standard-date-formats
93 (copy-sequence calc-standard-date-formats)) 93 (copy-sequence calc-standard-date-formats))
94 (setcar (nthcdr arg calc-standard-date-formats) fmt)) 94 (setcar (nthcdr arg calc-standard-date-formats) fmt))
@@ -918,6 +918,8 @@ as measured in the integer number of days before December 31, 1 BC (Gregorian)."
918 (catch 'syntax 918 (catch 'syntax
919 (or (math-parse-standard-date math-pd-str t) 919 (or (math-parse-standard-date math-pd-str t)
920 (math-parse-standard-date math-pd-str nil) 920 (math-parse-standard-date math-pd-str nil)
921 (and (or (memq 'IYYY calc-date-format) (memq 'Iww calc-date-format))
922 (math-parse-iso-date math-pd-str))
921 (and (string-match "\\`[^-+/0-9a-zA-Z]*\\([-+]?[0-9]+\\.?[0-9]*\\([eE][-+]?[0-9]+\\)?\\)[^-+/0-9a-zA-Z]*\\'" math-pd-str) 923 (and (string-match "\\`[^-+/0-9a-zA-Z]*\\([-+]?[0-9]+\\.?[0-9]*\\([eE][-+]?[0-9]+\\)?\\)[^-+/0-9a-zA-Z]*\\'" math-pd-str)
922 (list 'date (math-read-number (math-match-substring math-pd-str 1)))) 924 (list 'date (math-read-number (math-match-substring math-pd-str 1))))
923 (let ((case-fold-search t) 925 (let ((case-fold-search t)
@@ -1085,6 +1087,8 @@ as measured in the integer number of days before December 31, 1 BC (Gregorian)."
1085(defun math-parse-iso-date-validate (isoyear isoweek isoweekday hour minute second) 1087(defun math-parse-iso-date-validate (isoyear isoweek isoweekday hour minute second)
1086 (if (or (< isoweek 1) (> isoweek 53)) 1088 (if (or (< isoweek 1) (> isoweek 53))
1087 (throw 'syntax "Week value is out of range")) 1089 (throw 'syntax "Week value is out of range"))
1090 (if (or (< isoweekday 1) (> isoweekday 7))
1091 (throw 'syntax "Weekday value is out of range"))
1088 (and hour 1092 (and hour
1089 (progn 1093 (progn
1090 (if (or (< hour 0) (> hour 23)) 1094 (if (or (< hour 0) (> hour 23))
@@ -1290,6 +1294,31 @@ as measured in the integer number of days before December 31, 1 BC (Gregorian)."
1290 (setq day (math-add day (1- yearday)))) 1294 (setq day (math-add day (1- yearday))))
1291 day)))))) 1295 day))))))
1292 1296
1297(defun math-parse-iso-date (math-pd-str)
1298 "Parse MATH-PD-STR as an ISO week date, or return nil."
1299 (let ((case-fold-search t)
1300 (isoyear nil) (isoweek nil) (isoweekday nil)
1301 (hour nil) (minute nil) (second nil))
1302 ;; Extract the time, if any.
1303 (if (string-match "T[^0-9]*\\([0-9][0-9]\\)[^0-9]*\\([0-9][0-9]\\)?[^0-9]*\\([0-9][0-9]\\(\\.[0-9]+\\)?\\)?" math-pd-str)
1304 (progn
1305 (setq hour (string-to-number (math-match-substring math-pd-str 1))
1306 minute (math-match-substring math-pd-str 2)
1307 second (math-match-substring math-pd-str 3)
1308 math-pd-str (substring math-pd-str 0 (match-beginning 0)))
1309 (if (equal minute "")
1310 (setq minute 0)
1311 (setq minute (string-to-number minute)))
1312 (if (equal second "")
1313 (setq second 0)
1314 (setq second (math-read-number second)))))
1315 ;; Next, the year, week and weekday
1316 (if (string-match "\\(-?[0-9]*\\)[^0-9]*W\\([0-9][0-9]\\)[^0-9]*\\([0-9]\\)[^0-9]*\\'" math-pd-str)
1317 (progn
1318 (setq isoyear (string-to-number (math-match-substring math-pd-str 1))
1319 isoweek (string-to-number (math-match-substring math-pd-str 2))
1320 isoweekday (string-to-number (math-match-substring math-pd-str 3)))
1321 (math-parse-iso-date-validate isoyear isoweek isoweekday hour minute second)))))
1293 1322
1294(defun calcFunc-now (&optional zone) 1323(defun calcFunc-now (&optional zone)
1295 (let ((date (let ((calc-date-format nil)) 1324 (let ((date (let ((calc-date-format nil))
diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index 58eabf9bcec..b89cfbbda36 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -787,7 +787,9 @@ If nil, selections displayed but ignored.")
787 "M-D-Y< H:mm:SSpp>" 787 "M-D-Y< H:mm:SSpp>"
788 "D-M-Y< h:mm:SS>" 788 "D-M-Y< h:mm:SS>"
789 "j<, h:mm:SS>" 789 "j<, h:mm:SS>"
790 "YYddd< hh:mm:ss>")) 790 "YYddd< hh:mm:ss>"
791 "ZYYY-MM-DD Www< hh:mm>"
792 "IYYY-Iww-w< Thh:mm:ss>"))
791 793
792(defcalcmodevar calc-autorange-units nil 794(defcalcmodevar calc-autorange-units nil
793 "If non-nil, automatically set unit prefixes to keep units in a reasonable range.") 795 "If non-nil, automatically set unit prefixes to keep units in a reasonable range.")
diff --git a/lisp/hi-lock.el b/lisp/hi-lock.el
index de875c72593..2ae328a09e8 100644
--- a/lisp/hi-lock.el
+++ b/lisp/hi-lock.el
@@ -462,6 +462,9 @@ updated as you type."
462 (unless hi-lock-mode (hi-lock-mode 1)) 462 (unless hi-lock-mode (hi-lock-mode 1))
463 (hi-lock-set-pattern regexp face)) 463 (hi-lock-set-pattern regexp face))
464 464
465(defun hi-lock-keyword->face (keyword)
466 (cadr (cadr (cadr keyword)))) ; Keyword looks like (REGEXP (0 'FACE) ...).
467
465(declare-function x-popup-menu "menu.c" (position menu)) 468(declare-function x-popup-menu "menu.c" (position menu))
466 469
467(defun hi-lock--regexps-at-point () 470(defun hi-lock--regexps-at-point ()
@@ -470,23 +473,39 @@ updated as you type."
470 ;; choice of regexp. 473 ;; choice of regexp.
471 (let ((regexp (get-char-property (point) 'hi-lock-overlay-regexp))) 474 (let ((regexp (get-char-property (point) 'hi-lock-overlay-regexp)))
472 (when regexp (push regexp regexps))) 475 (when regexp (push regexp regexps)))
473 ;; With font-locking on, check if the cursor is on an highlighted text. 476 ;; With font-locking on, check if the cursor is on a highlighted text.
474 ;; Checking for hi-lock face is a good heuristic. FIXME: use "hi-lock-". 477 (let ((face-after (get-text-property (point) 'face))
475 (and (string-match "\\`hi-" (face-name (face-at-point))) 478 (face-before
476 (let* ((hi-text 479 (unless (bobp) (get-text-property (1- (point)) 'face)))
477 (buffer-substring-no-properties 480 (faces (mapcar #'hi-lock-keyword->face
478 (previous-single-property-change (point) 'face) 481 hi-lock-interactive-patterns)))
479 (next-single-property-change (point) 'face)))) 482 (unless (memq face-before faces) (setq face-before nil))
480 ;; Compute hi-lock patterns that match the 483 (unless (memq face-after faces) (setq face-after nil))
481 ;; highlighted text at point. Use this later in 484 (when (and face-before face-after (not (eq face-before face-after)))
482 ;; during completing-read. 485 (setq face-before nil))
483 (dolist (hi-lock-pattern hi-lock-interactive-patterns) 486 (when (or face-after face-before)
484 (let ((regexp (car hi-lock-pattern))) 487 (let* ((hi-text
485 (if (string-match regexp hi-text) 488 (buffer-substring-no-properties
486 (push regexp regexps)))))) 489 (if face-before
490 (or (previous-single-property-change (point) 'face)
491 (point-min))
492 (point))
493 (if face-after
494 (or (next-single-property-change (point) 'face)
495 (point-max))
496 (point)))))
497 ;; Compute hi-lock patterns that match the
498 ;; highlighted text at point. Use this later in
499 ;; during completing-read.
500 (dolist (hi-lock-pattern hi-lock-interactive-patterns)
501 (let ((regexp (car hi-lock-pattern)))
502 (if (string-match regexp hi-text)
503 (push regexp regexps)))))))
487 regexps)) 504 regexps))
488 505
489(defvar-local hi-lock--last-face nil) 506(defvar-local hi-lock--unused-faces nil
507 "List of faces that is not used and is available for highlighting new text.
508Face names from this list come from `hi-lock-face-defaults'.")
490 509
491;;;###autoload 510;;;###autoload
492(defalias 'unhighlight-regexp 'hi-lock-unface-buffer) 511(defalias 'unhighlight-regexp 'hi-lock-unface-buffer)
@@ -514,7 +533,7 @@ then remove all hi-lock highlighting."
514 (list (car pattern) 533 (list (car pattern)
515 (format 534 (format
516 "%s (%s)" (car pattern) 535 "%s (%s)" (car pattern)
517 (cadr (cadr (cadr pattern)))) 536 (hi-lock-keyword->face pattern))
518 (cons nil nil) 537 (cons nil nil)
519 (car pattern))) 538 (car pattern)))
520 hi-lock-interactive-patterns)))) 539 hi-lock-interactive-patterns))))
@@ -541,16 +560,14 @@ then remove all hi-lock highlighting."
541 (dolist (keyword (if (eq regexp t) hi-lock-interactive-patterns 560 (dolist (keyword (if (eq regexp t) hi-lock-interactive-patterns
542 (list (assoc regexp hi-lock-interactive-patterns)))) 561 (list (assoc regexp hi-lock-interactive-patterns))))
543 (when keyword 562 (when keyword
544 (let ((face (cadr (cadr (cadr keyword))))) 563 (let ((face (hi-lock-keyword->face keyword)))
545 ;; Make `face' the next one to use by default. 564 ;; Make `face' the next one to use by default.
546 (setq hi-lock--last-face 565 (add-to-list 'hi-lock--unused-faces (face-name face)))
547 (cadr (member (symbol-name face)
548 (reverse hi-lock-face-defaults)))))
549 (font-lock-remove-keywords nil (list keyword)) 566 (font-lock-remove-keywords nil (list keyword))
550 (setq hi-lock-interactive-patterns 567 (setq hi-lock-interactive-patterns
551 (delq keyword hi-lock-interactive-patterns)) 568 (delq keyword hi-lock-interactive-patterns))
552 (remove-overlays 569 (remove-overlays
553 nil nil 'hi-lock-overlay-regexp (hi-lock--hashcons regexp)) 570 nil nil 'hi-lock-overlay-regexp (hi-lock--hashcons (car keyword)))
554 (when font-lock-fontified (font-lock-fontify-buffer))))) 571 (when font-lock-fontified (font-lock-fontify-buffer)))))
555 572
556;;;###autoload 573;;;###autoload
@@ -608,27 +625,35 @@ not suitable."
608 "Return face for interactive highlighting. 625 "Return face for interactive highlighting.
609When `hi-lock-auto-select-face' is non-nil, just return the next face. 626When `hi-lock-auto-select-face' is non-nil, just return the next face.
610Otherwise, read face name from minibuffer with completion and history." 627Otherwise, read face name from minibuffer with completion and history."
611 (let ((default (or (cadr (member hi-lock--last-face hi-lock-face-defaults)) 628 (unless hi-lock-interactive-patterns
612 (car hi-lock-face-defaults)))) 629 (setq hi-lock--unused-faces hi-lock-face-defaults))
613 (setq hi-lock--last-face 630 (let* ((last-used-face
631 (when hi-lock-interactive-patterns
632 (face-name (hi-lock-keyword->face
633 (car hi-lock-interactive-patterns)))))
634 (defaults (append hi-lock--unused-faces
635 (cdr (member last-used-face hi-lock-face-defaults))
636 hi-lock-face-defaults))
637 face)
614 (if (and hi-lock-auto-select-face (not current-prefix-arg)) 638 (if (and hi-lock-auto-select-face (not current-prefix-arg))
615 default 639 (setq face (or (pop hi-lock--unused-faces) (car defaults)))
616 (completing-read 640 (setq face (completing-read
617 (format "Highlight using face (default %s): " default) 641 (format "Highlight using face (default %s): "
618 obarray 'facep t nil 'face-name-history 642 (car defaults))
619 (append (member default hi-lock-face-defaults) 643 obarray 'facep t nil 'face-name-history defaults))
620 hi-lock-face-defaults)))) 644 ;; Update list of un-used faces.
621 (unless (member hi-lock--last-face hi-lock-face-defaults) 645 (setq hi-lock--unused-faces (remove face hi-lock--unused-faces))
622 (setq hi-lock-face-defaults 646 ;; Grow the list of defaults.
623 (append hi-lock-face-defaults (list hi-lock--last-face)))) 647 (add-to-list 'hi-lock-face-defaults face t))
624 (intern hi-lock--last-face))) 648 (intern face)))
625 649
626(defun hi-lock-set-pattern (regexp face) 650(defun hi-lock-set-pattern (regexp face)
627 "Highlight REGEXP with face FACE." 651 "Highlight REGEXP with face FACE."
628 ;; Hashcons the regexp, so it can be passed to remove-overlays later. 652 ;; Hashcons the regexp, so it can be passed to remove-overlays later.
629 (setq regexp (hi-lock--hashcons regexp)) 653 (setq regexp (hi-lock--hashcons regexp))
630 (let ((pattern (list regexp (list 0 (list 'quote face) t)))) 654 (let ((pattern (list regexp (list 0 (list 'quote face) t))))
631 (unless (member pattern hi-lock-interactive-patterns) 655 ;; Refuse to highlight a text that is already highlighted.
656 (unless (assoc regexp hi-lock-interactive-patterns)
632 (push pattern hi-lock-interactive-patterns) 657 (push pattern hi-lock-interactive-patterns)
633 (if font-lock-mode 658 (if font-lock-mode
634 (progn 659 (progn
diff --git a/lisp/makefile.w32-in b/lisp/makefile.w32-in
index cb2cba466f6..b6beb6b292a 100644
--- a/lisp/makefile.w32-in
+++ b/lisp/makefile.w32-in
@@ -387,7 +387,7 @@ compile3-SH: autoloads compile0-SH
387 done 387 done
388 388
389compile4-SH: autoloads compile0-SH 389compile4-SH: autoloads compile0-SH
390 for dir in $(WINS_BASIC4) $(WINS_CEDET) terms obsolete; do \ 390 for dir in $(WINS_BASIC4) $(WINS_CEDET) term obsolete; do \
391 for el in $$dir/*.el; do \ 391 for el in $$dir/*.el; do \
392 if test -f $$el; \ 392 if test -f $$el; \
393 then \ 393 then \
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index fa5bc4a9822..16644b57549 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -406,8 +406,7 @@ will be killed."
406 "The channel or user associated with this buffer.") 406 "The channel or user associated with this buffer.")
407 407
408(defvar rcirc-urls nil 408(defvar rcirc-urls nil
409 "List of URLs seen in the current buffer and the position in 409 "List of URLs seen in the current buffer and their start positions.")
410the buffer where the URL starts.")
411(put 'rcirc-urls 'permanent-local t) 410(put 'rcirc-urls 'permanent-local t)
412 411
413(defvar rcirc-timeout-seconds 600 412(defvar rcirc-timeout-seconds 600
@@ -2393,9 +2392,11 @@ keywords when no KEYWORD is given."
2393 "\\)") 2392 "\\)")
2394 "Regexp matching URLs. Set to nil to disable URL features in rcirc.") 2393 "Regexp matching URLs. Set to nil to disable URL features in rcirc.")
2395 2394
2395;; cf cl-remove-if-not
2396(defun rcirc-condition-filter (condp lst) 2396(defun rcirc-condition-filter (condp lst)
2397 "Given a condition and a list, returns the list with elements 2397 "Remove all items not satisfying condition CONDP in list LST.
2398that do not satisfy the condition removed." 2398CONDP is a function that takes a list element as argument and returns
2399non-nil if that element should be included. Returns a new list."
2399 (delq nil (mapcar (lambda (x) (and (funcall condp x) x)) lst))) 2400 (delq nil (mapcar (lambda (x) (and (funcall condp x) x)) lst)))
2400 2401
2401(defun rcirc-browse-url (&optional arg) 2402(defun rcirc-browse-url (&optional arg)
diff --git a/lisp/progmodes/f90.el b/lisp/progmodes/f90.el
index f42952685d0..59dda170b77 100644
--- a/lisp/progmodes/f90.el
+++ b/lisp/progmodes/f90.el
@@ -1178,11 +1178,11 @@ and lies before point."
1178 1178
1179(defsubst f90-line-continued () 1179(defsubst f90-line-continued ()
1180 "Return t if the current line is a continued one. 1180 "Return t if the current line is a continued one.
1181This includes comment lines embedded in continued lines, but 1181This includes comment or preprocessor lines embedded in continued lines,
1182not the last line of a continued statement." 1182but not the last line of a continued statement."
1183 (save-excursion 1183 (save-excursion
1184 (beginning-of-line) 1184 (beginning-of-line)
1185 (while (and (looking-at "[ \t]*\\(!\\|$\\)") (zerop (forward-line -1)))) 1185 (while (and (looking-at "[ \t]*\\([!#]\\|$\\)") (zerop (forward-line -1))))
1186 (end-of-line) 1186 (end-of-line)
1187 (while (f90-in-comment) 1187 (while (f90-in-comment)
1188 (search-backward "!" (line-beginning-position)) 1188 (search-backward "!" (line-beginning-position))
@@ -1832,11 +1832,15 @@ after indenting."
1832 (f90-indent-line-no) 1832 (f90-indent-line-no)
1833 (setq no-line-number t) 1833 (setq no-line-number t)
1834 (skip-chars-forward " \t")) 1834 (skip-chars-forward " \t"))
1835 (if (looking-at "!") 1835 ;; FIXME This means f90-calculate-indent gives different answers
1836 (setq indent (f90-comment-indent)) 1836 ;; for comments and preprocessor lines to this function.
1837 (and f90-smart-end (looking-at "end") 1837 ;; Better to make f90-calculate-indent return the correct answer?
1838 (f90-match-end)) 1838 (cond ((looking-at "!") (setq indent (f90-comment-indent)))
1839 (setq indent (f90-calculate-indent))) 1839 ((looking-at "#") (setq indent 0))
1840 (t
1841 (and f90-smart-end (looking-at "end")
1842 (f90-match-end))
1843 (setq indent (f90-calculate-indent))))
1840 (or (= indent (current-column)) 1844 (or (= indent (current-column))
1841 (f90-indent-to indent no-line-number)) 1845 (f90-indent-to indent no-line-number))
1842 ;; If initial point was within line's indentation, 1846 ;; If initial point was within line's indentation,
@@ -1973,12 +1977,13 @@ If run in the middle of a line, the line is not broken."
1973 (f90-indent-to ind-curr)) 1977 (f90-indent-to ind-curr))
1974 (while (and (f90-line-continued) (zerop (forward-line 1)) 1978 (while (and (f90-line-continued) (zerop (forward-line 1))
1975 (< (point) end-region-mark)) 1979 (< (point) end-region-mark))
1976 (if (looking-at "[ \t]*!") 1980 (cond ((looking-at "[ \t]*#") (f90-indent-to 0))
1977 (f90-indent-to (f90-comment-indent)) 1981 ((looking-at "[ \t]*!") (f90-indent-to (f90-comment-indent)))
1978 (or (= (current-indentation) 1982 (t
1979 (+ ind-curr f90-continuation-indent)) 1983 (or (= (current-indentation)
1980 (f90-indent-to 1984 (+ ind-curr f90-continuation-indent))
1981 (+ ind-curr f90-continuation-indent) 'no-line-no))))) 1985 (f90-indent-to
1986 (+ ind-curr f90-continuation-indent) 'no-line-no))))))
1982 ;; Restore point, etc. 1987 ;; Restore point, etc.
1983 (setq f90-cache-position nil) 1988 (setq f90-cache-position nil)
1984 (goto-char save-point) 1989 (goto-char save-point)
diff --git a/lisp/subr.el b/lisp/subr.el
index e08277370a9..1e509036cd1 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4323,6 +4323,36 @@ convenience wrapper around `make-progress-reporter' and friends.
4323 nil ,@(cdr (cdr spec))))) 4323 nil ,@(cdr (cdr spec)))))
4324 4324
4325 4325
4326;;;; Support for watching filesystem events.
4327
4328(defun inotify-event-p (event)
4329 "Check if EVENT is an inotify event."
4330 (and (listp event)
4331 (>= (length event) 3)
4332 (eq (car event) 'file-inotify)))
4333
4334;;;###autoload
4335(defun inotify-handle-event (event)
4336 "Handle inotify file system monitoring event.
4337If EVENT is an inotify filewatch event, call its callback.
4338Otherwise, signal a `filewatch-error'."
4339 (interactive "e")
4340 (unless (inotify-event-p event)
4341 (signal 'filewatch-error (cons "Not a valid inotify event" event)))
4342 (funcall (nth 2 event) (nth 1 event)))
4343
4344(defun w32notify-handle-event (event)
4345 "Handle MS-Windows file system monitoring event.
4346If EVENT is an MS-Windows filewatch event, call its callback.
4347Otherwise, signal a `filewatch-error'."
4348 (interactive "e")
4349 (if (and (eq (car event) 'file-w32notify)
4350 (= (length event) 3))
4351 (funcall (nth 2 event) (nth 1 event))
4352 (signal 'filewatch-error
4353 (cons "Not a valid MS-Windows file-notify event" event))))
4354
4355
4326;;;; Comparing version strings. 4356;;;; Comparing version strings.
4327 4357
4328(defconst version-separator "." 4358(defconst version-separator "."
diff --git a/nt/ChangeLog b/nt/ChangeLog
index 35fcefe5b1b..ced3733da07 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -1,3 +1,15 @@
12012-12-11 Juanma Barranquero <lekktu@gmail.com>
2
3 * config.nt: Sync with autogen/config.in.
4 (HAVE_DECL_UNSETENV, HAVE_SIG2STR, VOID_UNSETENV): New macros.
5 (ULIMIT_BREAK_VALUE): Remove.
6
72012-12-10 Daniel Colascione <dancol@dancol.org>
8
9 * emacs.rc: Use forward slashes in relative paths in order to
10 avoid complaints from Cygwin. (Forward slashes work perfectly
11 well in the NT build.)
12
12012-12-09 Eli Zaretskii <eliz@gnu.org> 132012-12-09 Eli Zaretskii <eliz@gnu.org>
2 14
3 * inc/unistd.h (unsetenv): Provide a prototype. 15 * inc/unistd.h (unsetenv): Provide a prototype.
diff --git a/nt/config.nt b/nt/config.nt
index e83c9ff655f..789a1a8b2af 100644
--- a/nt/config.nt
+++ b/nt/config.nt
@@ -325,6 +325,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
325 */ 325 */
326#define HAVE_DECL_TZNAME 1 326#define HAVE_DECL_TZNAME 1
327 327
328/* Define to 1 if you have the declaration of `unsetenv', and to 0 if you
329 don't. */
330#undef HAVE_DECL_UNSETENV
331
328/* Define to 1 if you have the declaration of `__fpending', and to 0 if you 332/* Define to 1 if you have the declaration of `__fpending', and to 0 if you
329 don't. */ 333 don't. */
330#undef HAVE_DECL___FPENDING 334#undef HAVE_DECL___FPENDING
@@ -790,6 +794,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
790/* Define to 1 if you have the `shutdown' function. */ 794/* Define to 1 if you have the `shutdown' function. */
791#define HAVE_SHUTDOWN 1 795#define HAVE_SHUTDOWN 1
792 796
797/* Define to 1 if you have the `sig2str' function. */
798#undef HAVE_SIG2STR
799
793/* Define to 1 if 'sig_atomic_t' is a signed integer type. */ 800/* Define to 1 if 'sig_atomic_t' is a signed integer type. */
794#undef HAVE_SIGNED_SIG_ATOMIC_T 801#undef HAVE_SIGNED_SIG_ATOMIC_T
795 802
@@ -990,12 +997,12 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
990/* Define to 1 if you have the <unistd.h> header file. */ 997/* Define to 1 if you have the <unistd.h> header file. */
991#define HAVE_UNISTD_H 1 998#define HAVE_UNISTD_H 1
992 999
993/* Define to 1 if the system has the type 'unsigned long long int'. */
994#undef HAVE_UNSIGNED_LONG_LONG_INT
995
996/* Define to 1 if you have the `unsetenv' function. */ 1000/* Define to 1 if you have the `unsetenv' function. */
997#define HAVE_UNSETENV 1 1001#define HAVE_UNSETENV 1
998 1002
1003/* Define to 1 if the system has the type 'unsigned long long int'. */
1004#undef HAVE_UNSIGNED_LONG_LONG_INT
1005
999/* Define to 1 if you have the <util.h> header file. */ 1006/* Define to 1 if you have the <util.h> header file. */
1000#undef HAVE_UTIL_H 1007#undef HAVE_UTIL_H
1001 1008
@@ -1338,9 +1345,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1338 timespec. */ 1345 timespec. */
1339#undef TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC 1346#undef TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
1340 1347
1341/* Undocumented. */
1342#undef ULIMIT_BREAK_VALUE
1343
1344/* Define to 1 for Encore UMAX. */ 1348/* Define to 1 for Encore UMAX. */
1345#undef UMAX 1349#undef UMAX
1346 1350
@@ -1397,6 +1401,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1397/* Version number of package */ 1401/* Version number of package */
1398#define VERSION "24.3.50" 1402#define VERSION "24.3.50"
1399 1403
1404/* Define to 1 if unsetenv returns void instead of int. */
1405#undef VOID_UNSETENV
1406
1400/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type 1407/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type
1401 'wchar_t'. */ 1408 'wchar_t'. */
1402#undef WCHAR_T_SUFFIX 1409#undef WCHAR_T_SUFFIX
diff --git a/nt/emacs.rc b/nt/emacs.rc
index 72aa47212ac..da4283b6fd1 100644
--- a/nt/emacs.rc
+++ b/nt/emacs.rc
@@ -1,5 +1,5 @@
1Emacs ICON icons\emacs.ico 1Emacs ICON icons/emacs.ico
232649 CURSOR icons\hand.cur 232649 CURSOR icons/hand.cur
3#ifdef WIN64 3#ifdef WIN64
41 24 "emacs-x64.manifest" 41 24 "emacs-x64.manifest"
5#else 5#else
diff --git a/src/ChangeLog b/src/ChangeLog
index e7fc8179e07..9d9002ed77b 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,163 @@
12012-12-11 Dmitry Antipov <dmantipov@yandex.ru>
2
3 * buffer.c (Fset_buffer_multibyte): Do not force redisplay
4 if changed buffer is not shown in a window.
5 * insdel.c (prepare_to_modify_buffer): Likewise.
6 * window.c (replace_buffer_in_windows_safely): Do nothing
7 if buffer is not shown in a window.
8 (Fforce_window_update): Likewise if string or buffer argument
9 is passed.
10
112012-12-11 Eli Zaretskii <eliz@gnu.org>
12
13 * inotify.c (Finotify_add_watch): Rename decoded_file_name to
14 encoded_file_name, which is what it is.
15
162012-12-11 Dmitry Antipov <dmantipov@yandex.ru>
17
18 Consistently use marker_position and marker_byte_position.
19 * fringe.c (Ffringe_bitmaps_at_pos):
20 * indent.c (Fvertical_motion):
21 * insdel.c (prepare_to_modify_buffer):
22 * keyboard.c (make_lispy_position):
23 * window.c (Fwindow_end, Fpos_visible_in_window_p, unshow_buffer)
24 (window_scroll_pixel_based, displayed_window_lines)
25 (Fset_window_configuration):
26 * xdisp.c (message_dolog, with_echo_area_buffer_unwind_data)
27 (mark_window_display_accurate_1, redisplay_window, decode_mode_spec):
28 Replace direct access to marker fields with calls
29 to marker_position and/or marker_byte_position.
30
312012-12-11 Juanma Barranquero <lekktu@gmail.com>
32
33 * makefile.w32-in (SIG2STR_H): New macro.
34 (SYSWAIT_H, $(BLD)/emacs.$(O), $(BLD)/process.$(O))
35 ($(BLD)/w32notify.$(O)): Update dependencies.
36
372012-12-10 Daniel Colascione <dancol@dancol.org>
38
39 * w32term.c, keyboard.c: Fix build break in cygw32 by omitting
40 Windows file notification functionality unless WINDOWSNT.
41
42 * w32gui.h (hprevinst, lpCmdLine, nCmdShow): Remove unused
43 declarations.
44
45 * w32fns.c (cache_system_info): Initialize the global hinst
46 variable here so various initialization calls DTRT.
47
48 * unexw32.c (hprevinst, lpCmdLine, nCmdShow): Remove unused
49 variables.
50 (hinst): Remove unneeded extern declaration.
51 (_start): Remove initialization of above variables; remove
52 initialization of hinst, as cache_system_info now does that.
53
54 * emacs.c (main): Call cache_system_info early in startup; we
55 previously weren't calling it in Cygwin builds.
56
57 * Makefile.in (ntsource, WINDRES, W32_RES, W#@_RES_LINK): Teach
58 the autoconf build system how to compile a Windows resource file
59 and link it to Emacs.
60
612012-12-10 Dmitry Antipov <dmantipov@yandex.ru>
62
63 Per-buffer window counters.
64 * buffer.h (struct buffer): New member window_count.
65 (buffer_window_count): New function.
66 * buffer.c (Fget_buffer_create, Fmake_indirect_buffer):
67 Initialize window_count.
68 (Fkill_buffer): Verify window_count for the buffer being killed.
69 (modify_overlay): Do not force redisplay if buffer is not shown
70 in any window.
71 (init_buffer_once): Initialize window_count for buffer_defaults
72 and buffer_local_symbols.
73 * window.h (buffer_shared): Remove declaration.
74 (wset_buffer): Convert from inline ...
75 * window.c (wset_buffer): ... to an ordinary function.
76 (adjust_window_count): New function.
77 (make_parent_window): Use it.
78 * xdisp.c (buffer_shared): Remove.
79 (redisplay_internal, redisplay_window): Adjust users.
80 (buffer_shared_and_changed): Use per-buffer window counter.
81
822012-12-10 Eli Zaretskii <eliz@gnu.org>
83
84 Support for filesystem notifications on MS-Windows.
85 * w32proc.c (sys_select): If drain_message_queue returns non-zero,
86 and this is a TTY frame, signal the caller that keyboard input is
87 available.
88
89 * w32xfns.c (drain_message_queue): Now returns an int: an
90 indication whether any WM_EMACS_FILENOTIFY messages were found in
91 the queue.
92
93 * w32inevt.c (handle_file_notifications): New function.
94 (w32_console_read_socket): Call it to process file notifications.
95
96 * w32console.c (initialize_w32_display): Record the main thread ID
97 in dwMainThreadId.
98
99 * deps.mk (inotify.o): New dependency list.
100
101 * Makefile.in (SOME_MACHINE_OBJECTS): Add w32notify.o.
102
103 * w32term.h (WM_EMACS_FILENOTIFY): New custom message.
104 (WM_EMACS_END): Bump value by 1.
105 (notification_buffer_in_use, file_notifications)
106 (notifications_size, notifications_desc): Declare.
107 (w32_get_watch_object, lispy_file_action, globals_of_w32notify):
108 Add prototypes.
109
110 * w32term.c (lispy_file_action, queue_notifications): New functions.
111 (syms_of_w32term) <Qadded, Qremoved, Qmodified, Qrenamed_from>
112 <Qrenamed_to>: New symbols.
113 (w32_read_socket): Handle the WM_EMACS_FILENOTIFY message.
114
115 * w32notify.c: New file, implements file event notifications for
116 MS-Windows.
117
118 * w32fns.c (w32_wnd_proc): Handle the WM_EMACS_FILENOTIFY message
119 by posting it to the w32_read_socket queue.
120
121 * termhooks.h (enum event_kind) [HAVE_NTGUI]: Support
122 FILE_NOTIFY_EVENT.
123
124 * makefile.w32-in (OBJ2): Add $(BLD)/w32notify.$(O).
125 (GLOBAL_SOURCES): Add w32notify.c
126 ($(BLD)/w32notify.$(O)): New set of dependencies.
127
128 * lisp.h (syms_of_w32notify) [WINDOWSNT]: Add prototype.
129
130 * keyboard.c (kbd_buffer_get_event) [WINDOWSNT]: Handle
131 FILE_NOTIFY_EVENT.
132 (syms_of_keyboard) [HAVE_NTGUI] <Qfile_notify>: New symbol.
133 (keys_of_keyboard) [WINDOWSNT]: Bind file-notify to
134 w32notify-handle-event by default.
135
136 * emacs.c (main) [WINDOWSNT]: Call globals_of_w32notify and
137 syms_of_w32notify.
138
1392012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
140
141 Support for filesystem notifications on GNU/Linux via inotify.
142 * termhooks.h (enum event_kind) [HAVE_INOTIFY]: Add
143 FILE_NOTIFY_EVENT.
144
145 * lisp.h (syms_of_inotify) [HAVE_INOTIFY]: Add prototype.
146
147 * keyboard.c (Qfile_inotify) [HAVE_INOTIFY]: New variable.
148 (syms_of_keyboard): DEFSYM it.
149 (kbd_buffer_get_event) [HAVE_INOTIFY]: Generate FILE_NOTIFY_EVENT.
150 (make_lispy_event): Support FILE_NOTIFY_EVENT by generating
151 Qfile_inotify events.
152 (keys_of_keyboard) [HAVE_INOTIFY]: Bind file-inotify events in
153 special-event-map to inotify-handle-event.
154
155 * emacs.c (main) [HAVE_INOTIFY]: Call syms_of_inotify.
156
157 * Makefile.in (base_obj): Add inotify.o.
158
159 * inotify.c: New file.
160
12012-12-10 Jan Djärv <jan.h.d@swipnet.se> 1612012-12-10 Jan Djärv <jan.h.d@swipnet.se>
2 162
3 * nsterm.m (fd_handler:): FD_ZERO fds (Bug#13103). 163 * nsterm.m (fd_handler:): FD_ZERO fds (Bug#13103).
diff --git a/src/Makefile.in b/src/Makefile.in
index 88e1fc544d0..fe3a15f193a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -28,9 +28,11 @@ SHELL = /bin/sh
28# Here are the things that we expect ../configure to edit. 28# Here are the things that we expect ../configure to edit.
29# We use $(srcdir) explicitly in dependencies so as not to depend on VPATH. 29# We use $(srcdir) explicitly in dependencies so as not to depend on VPATH.
30srcdir = @srcdir@ 30srcdir = @srcdir@
31ntsource = $(srcdir)/../nt
31abs_builddir = @abs_builddir@ 32abs_builddir = @abs_builddir@
32VPATH = $(srcdir) 33VPATH = $(srcdir)
33CC = @CC@ 34CC = @CC@
35WINDRES = @WINDRES@
34CFLAGS = @CFLAGS@ 36CFLAGS = @CFLAGS@
35CPPFLAGS = @CPPFLAGS@ 37CPPFLAGS = @CPPFLAGS@
36LDFLAGS = @LDFLAGS@ 38LDFLAGS = @LDFLAGS@
@@ -276,6 +278,13 @@ W32_OBJ=@W32_OBJ@
276## --lwinspool if HAVE_W32, else empty. 278## --lwinspool if HAVE_W32, else empty.
277W32_LIBS=@W32_LIBS@ 279W32_LIBS=@W32_LIBS@
278 280
281## emacs.res if HAVE_W32
282W32_RES=@W32_RES@
283## If HAVE_W32, compiler arguments for including
284## the resource file in the binary.
285## XXX -Wl,-b -Wl,pe-i386 -Wl,emacs.res
286W32_RES_LINK=@W32_RES_LINK@
287
279## Empty if !HAVE_X_WINDOWS 288## Empty if !HAVE_X_WINDOWS
280## xfont.o ftfont.o xftfont.o ftxfont.o if HAVE_XFT 289## xfont.o ftfont.o xftfont.o ftxfont.o if HAVE_XFT
281## xfont.o ftfont.o ftxfont.o if HAVE_FREETYPE 290## xfont.o ftfont.o ftxfont.o if HAVE_FREETYPE
@@ -339,7 +348,6 @@ ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
339 @$(MKDEPDIR) 348 @$(MKDEPDIR)
340 $(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $< 349 $(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $<
341 350
342
343## lastfile must follow all files whose initialized data areas should 351## lastfile must follow all files whose initialized data areas should
344## be dumped as pure by dump-emacs. 352## be dumped as pure by dump-emacs.
345base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ 353base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
@@ -354,7 +362,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
354 syntax.o $(UNEXEC_OBJ) bytecode.o \ 362 syntax.o $(UNEXEC_OBJ) bytecode.o \
355 process.o gnutls.o callproc.o \ 363 process.o gnutls.o callproc.o \
356 region-cache.o sound.o atimer.o \ 364 region-cache.o sound.o atimer.o \
357 doprnt.o intervals.o textprop.o composite.o xml.o \ 365 doprnt.o intervals.o textprop.o composite.o xml.o inotify.o \
358 xwidget.o \ 366 xwidget.o \
359 profiler.o \ 367 profiler.o \
360 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ 368 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
@@ -370,7 +378,7 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \
370 xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ 378 xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \
371 fontset.o dbusbind.o cygw32.o \ 379 fontset.o dbusbind.o cygw32.o \
372 nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \ 380 nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \
373 w32.o w32console.o w32fns.o w32heap.o w32inevt.o \ 381 w32.o w32console.o w32fns.o w32heap.o w32inevt.o w32notify.o \
374 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ 382 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
375 w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \ 383 w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \
376 xsettings.o xgselect.o termcap.o 384 xsettings.o xgselect.o termcap.o
@@ -476,9 +484,11 @@ $(obj) $(otherobj): globals.h
476$(lib)/libgnu.a: $(config_h) 484$(lib)/libgnu.a: $(config_h)
477 cd $(lib) && $(MAKE) libgnu.a 485 cd $(lib) && $(MAKE) libgnu.a
478 486
479temacs$(EXEEXT): $(START_FILES) stamp-oldxmenu $(obj) $(otherobj) $(lib)/libgnu.a 487temacs$(EXEEXT): $(START_FILES) stamp-oldxmenu $(obj) $(otherobj) \
488 $(lib)/libgnu.a $(W32_RES)
480 $(CC) $(LD_FIRSTFLAG) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(TEMACS_LDFLAGS2) \ 489 $(CC) $(LD_FIRSTFLAG) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(TEMACS_LDFLAGS2) \
481 -o temacs $(START_FILES) $(obj) $(otherobj) $(lib)/libgnu.a $(LIBES) 490 -o temacs $(START_FILES) $(obj) $(otherobj) $(lib)/libgnu.a $(LIBES) \
491 $(W32_RES_LINK)
482 test "$(CANNOT_DUMP)" = "yes" || \ 492 test "$(CANNOT_DUMP)" = "yes" || \
483 test "X$(PAXCTL)" = X || $(PAXCTL) -r temacs$(EXEEXT) 493 test "X$(PAXCTL)" = X || $(PAXCTL) -r temacs$(EXEEXT)
484 494
@@ -519,11 +529,14 @@ $(OLDXMENU): $(OLDXMENU_TARGET)
519 529
520doc.o: buildobj.h 530doc.o: buildobj.h
521 531
532emacs.res: $(ntsource)/emacs.rc \
533 $(ntsource)/icons/emacs.ico \
534 $(ntsource)/emacs-x86.manifest
535 $(WINDRES) -O COFF -o $@ $(ntsource)/emacs.rc
522 536
523ns-app: emacs$(EXEEXT) 537ns-app: emacs$(EXEEXT)
524 cd ../nextstep && $(MAKE) $(MFLAGS) all 538 cd ../nextstep && $(MAKE) $(MFLAGS) all
525 539
526
527.PHONY: mostlyclean clean bootstrap-clean distclean maintainer-clean 540.PHONY: mostlyclean clean bootstrap-clean distclean maintainer-clean
528.PHONY: versionclean extraclean frc 541.PHONY: versionclean extraclean frc
529 542
diff --git a/src/buffer.c b/src/buffer.c
index 6e2191dc22f..748422df73a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -547,6 +547,8 @@ even if it is dead. The return value is never nil. */)
547 b->base_buffer = NULL; 547 b->base_buffer = NULL;
548 /* No one shares the text with us now. */ 548 /* No one shares the text with us now. */
549 b->indirections = 0; 549 b->indirections = 0;
550 /* No one shows us now. */
551 b->window_count = 0;
550 552
551 BUF_GAP_SIZE (b) = 20; 553 BUF_GAP_SIZE (b) = 20;
552 block_input (); 554 block_input ();
@@ -794,6 +796,8 @@ CLONE nil means the indirect buffer's state is reset to default values. */)
794 b->indirections = -1; 796 b->indirections = -1;
795 /* Notify base buffer that we share the text now. */ 797 /* Notify base buffer that we share the text now. */
796 b->base_buffer->indirections++; 798 b->base_buffer->indirections++;
799 /* Always -1 for an indirect buffer. */
800 b->window_count = -1;
797 801
798 b->pt = b->base_buffer->pt; 802 b->pt = b->base_buffer->pt;
799 b->begv = b->base_buffer->begv; 803 b->begv = b->base_buffer->begv;
@@ -1929,10 +1933,16 @@ cleaning up all windows currently displaying the buffer to be killed. */)
1929 eassert (b->indirections == -1); 1933 eassert (b->indirections == -1);
1930 b->base_buffer->indirections--; 1934 b->base_buffer->indirections--;
1931 eassert (b->base_buffer->indirections >= 0); 1935 eassert (b->base_buffer->indirections >= 0);
1936 /* Make sure that we wasn't confused. */
1937 eassert (b->window_count == -1);
1932 } 1938 }
1933 else 1939 else
1934 /* No one shares our buffer text, can free it. */ 1940 {
1935 free_buffer_text (b); 1941 /* Make sure that no one shows us. */
1942 eassert (b->window_count == 0);
1943 /* No one shares our buffer text, can free it. */
1944 free_buffer_text (b);
1945 }
1936 1946
1937 if (b->newline_cache) 1947 if (b->newline_cache)
1938 { 1948 {
@@ -2681,10 +2691,11 @@ current buffer is cleared. */)
2681 2691
2682 UNGCPRO; 2692 UNGCPRO;
2683 2693
2684 /* Changing the multibyteness of a buffer means that all windows
2685 showing that buffer must be updated thoroughly. */
2686 current_buffer->prevent_redisplay_optimizations_p = 1; 2694 current_buffer->prevent_redisplay_optimizations_p = 1;
2687 ++windows_or_buffers_changed; 2695
2696 /* If buffer is shown in a window, let redisplay consider other windows. */
2697 if (buffer_window_count (current_buffer))
2698 ++windows_or_buffers_changed;
2688 2699
2689 /* Copy this buffer's new multibyte status 2700 /* Copy this buffer's new multibyte status
2690 into all of its indirect buffers. */ 2701 into all of its indirect buffers. */
@@ -3880,17 +3891,17 @@ modify_overlay (struct buffer *buf, ptrdiff_t start, ptrdiff_t end)
3880 3891
3881 BUF_COMPUTE_UNCHANGED (buf, start, end); 3892 BUF_COMPUTE_UNCHANGED (buf, start, end);
3882 3893
3883 /* If this is a buffer not in the selected window, 3894 /* If BUF is visible, consider updating the display if ... */
3884 we must do other windows. */ 3895 if (buffer_window_count (buf) > 0)
3885 if (buf != XBUFFER (XWINDOW (selected_window)->buffer)) 3896 {
3886 windows_or_buffers_changed = 1; 3897 /* ... it's visible in other window than selected, */
3887 /* If multiple windows show this buffer, we must do other windows. */ 3898 if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
3888 else if (buffer_shared > 1) 3899 windows_or_buffers_changed = 1;
3889 windows_or_buffers_changed = 1; 3900 /* ... or if we modify an overlay at the end of the buffer
3890 /* If we modify an overlay at the end of the buffer, we cannot 3901 and so we cannot be sure that window end is still valid. */
3891 be sure that window end is still valid. */ 3902 else if (end >= ZV && start <= ZV)
3892 else if (end >= ZV && start <= ZV) 3903 windows_or_buffers_changed = 1;
3893 windows_or_buffers_changed = 1; 3904 }
3894 3905
3895 ++BUF_OVERLAY_MODIFF (buf); 3906 ++BUF_OVERLAY_MODIFF (buf);
3896} 3907}
@@ -5125,6 +5136,9 @@ init_buffer_once (void)
5125 /* No one will share the text with these buffers, but let's play it safe. */ 5136 /* No one will share the text with these buffers, but let's play it safe. */
5126 buffer_defaults.indirections = 0; 5137 buffer_defaults.indirections = 0;
5127 buffer_local_symbols.indirections = 0; 5138 buffer_local_symbols.indirections = 0;
5139 /* Likewise no one will display them. */
5140 buffer_defaults.window_count = 0;
5141 buffer_local_symbols.window_count = 0;
5128 set_buffer_intervals (&buffer_defaults, NULL); 5142 set_buffer_intervals (&buffer_defaults, NULL);
5129 set_buffer_intervals (&buffer_local_symbols, NULL); 5143 set_buffer_intervals (&buffer_local_symbols, NULL);
5130 /* This is not strictly necessary, but let's make them initialized. */ 5144 /* This is not strictly necessary, but let's make them initialized. */
diff --git a/src/buffer.h b/src/buffer.h
index 1129840bd47..d838d3767ef 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -770,11 +770,15 @@ struct buffer
770 In an ordinary buffer, it is 0. */ 770 In an ordinary buffer, it is 0. */
771 struct buffer *base_buffer; 771 struct buffer *base_buffer;
772 772
773 /* In an indirect buffer, this is -1. In an ordinary buffer, 773 /* In an indirect buffer, this is -1. In an ordinary buffer,
774 it's the number of indirect buffers that share our text; 774 it's the number of indirect buffers that share our text;
775 zero means that we're the only owner of this text. */ 775 zero means that we're the only owner of this text. */
776 int indirections; 776 int indirections;
777 777
778 /* Number of windows showing this buffer. Always -1 for
779 an indirect buffer since it counts as its base buffer. */
780 int window_count;
781
778 /* A non-zero value in slot IDX means that per-buffer variable 782 /* A non-zero value in slot IDX means that per-buffer variable
779 with index IDX has a local value in this buffer. The index IDX 783 with index IDX has a local value in this buffer. The index IDX
780 for a buffer-local variable is stored in that variable's slot 784 for a buffer-local variable is stored in that variable's slot
@@ -1173,7 +1177,18 @@ BUF_FETCH_MULTIBYTE_CHAR (struct buffer *buf, ptrdiff_t pos)
1173 + pos + BUF_BEG_ADDR (buf) - BEG_BYTE); 1177 + pos + BUF_BEG_ADDR (buf) - BEG_BYTE);
1174 return STRING_CHAR (p); 1178 return STRING_CHAR (p);
1175} 1179}
1176 1180
1181/* Return number of windows showing B. */
1182
1183BUFFER_INLINE int
1184buffer_window_count (struct buffer *b)
1185{
1186 if (b->base_buffer)
1187 b = b->base_buffer;
1188 eassert (b->window_count >= 0);
1189 return b->window_count;
1190}
1191
1177/* Overlays */ 1192/* Overlays */
1178 1193
1179/* Return the marker that stands for where OV starts in the buffer. */ 1194/* Return the marker that stands for where OV starts in the buffer. */
diff --git a/src/deps.mk b/src/deps.mk
index c7316a24dad..beca5f7c6bc 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -128,6 +128,7 @@ image.o: image.c frame.h window.h dispextern.h blockinput.h atimer.h \
128indent.o: indent.c frame.h window.h indent.h buffer.h lisp.h $(config_h) \ 128indent.o: indent.c frame.h window.h indent.h buffer.h lisp.h $(config_h) \
129 termchar.h termopts.h disptab.h region-cache.h character.h category.h \ 129 termchar.h termopts.h disptab.h region-cache.h character.h category.h \
130 keyboard.h systime.h coding.h $(INTERVALS_H) globals.h 130 keyboard.h systime.h coding.h $(INTERVALS_H) globals.h
131inotify.o: inotify.c lisp.h coding.h process.h keyboard.h frame.h termhooks.h
131insdel.o: insdel.c window.h buffer.h $(INTERVALS_H) blockinput.h character.h \ 132insdel.o: insdel.c window.h buffer.h $(INTERVALS_H) blockinput.h character.h \
132 atimer.h systime.h region-cache.h lisp.h globals.h $(config_h) 133 atimer.h systime.h region-cache.h lisp.h globals.h $(config_h)
133keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \ 134keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \
diff --git a/src/emacs.c b/src/emacs.c
index bd6654aa8cf..4d8e0be7470 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -41,6 +41,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
41#if defined WINDOWSNT || defined HAVE_NTGUI 41#if defined WINDOWSNT || defined HAVE_NTGUI
42#include "w32select.h" 42#include "w32select.h"
43#include "w32font.h" 43#include "w32font.h"
44#include "w32common.h"
44#endif 45#endif
45 46
46#if defined HAVE_NTGUI && defined CYGWIN 47#if defined HAVE_NTGUI && defined CYGWIN
@@ -736,6 +737,13 @@ main (int argc, char **argv)
736 } 737 }
737#endif 738#endif
738 739
740#if defined WINDOWSNT || defined HAVE_NTGUI
741 /* Set global variables used to detect Windows version. Do this as
742 early as possible. (unexw32.c calls this function as well, but
743 the additional call here is harmless.) */
744 cache_system_info ();
745#endif
746
739#ifdef RUN_TIME_REMAP 747#ifdef RUN_TIME_REMAP
740 if (initialized) 748 if (initialized)
741 run_time_remap (argv[0]); 749 run_time_remap (argv[0]);
@@ -1290,6 +1298,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1290 1298
1291#ifdef WINDOWSNT 1299#ifdef WINDOWSNT
1292 globals_of_w32 (); 1300 globals_of_w32 ();
1301 globals_of_w32notify ();
1293 /* Initialize environment from registry settings. */ 1302 /* Initialize environment from registry settings. */
1294 init_environment (argv); 1303 init_environment (argv);
1295 init_ntproc (dumping); /* must precede init_editfns. */ 1304 init_ntproc (dumping); /* must precede init_editfns. */
@@ -1448,12 +1457,17 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1448 syms_of_gnutls (); 1457 syms_of_gnutls ();
1449#endif 1458#endif
1450 1459
1460#ifdef HAVE_INOTIFY
1461 syms_of_inotify ();
1462#endif /* HAVE_INOTIFY */
1463
1451#ifdef HAVE_DBUS 1464#ifdef HAVE_DBUS
1452 syms_of_dbusbind (); 1465 syms_of_dbusbind ();
1453#endif /* HAVE_DBUS */ 1466#endif /* HAVE_DBUS */
1454 1467
1455#ifdef WINDOWSNT 1468#ifdef WINDOWSNT
1456 syms_of_ntterm (); 1469 syms_of_ntterm ();
1470 syms_of_w32notify ();
1457#endif /* WINDOWSNT */ 1471#endif /* WINDOWSNT */
1458 1472
1459 syms_of_profiler (); 1473 syms_of_profiler ();
diff --git a/src/fringe.c b/src/fringe.c
index a126292e1ff..ce31fd01763 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -1744,7 +1744,7 @@ Return nil if POS is not visible in WINDOW. */)
1744 else if (w == XWINDOW (selected_window)) 1744 else if (w == XWINDOW (selected_window))
1745 textpos = PT; 1745 textpos = PT;
1746 else 1746 else
1747 textpos = XMARKER (w->pointm)->charpos; 1747 textpos = marker_position (w->pointm);
1748 1748
1749 row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); 1749 row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
1750 row = row_containing_pos (w, textpos, row, NULL, 0); 1750 row = row_containing_pos (w, textpos, row, NULL, 0);
diff --git a/src/indent.c b/src/indent.c
index 327526eae2d..3dbf372cf17 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -1991,8 +1991,8 @@ whether or not it is currently displayed in some window. */)
1991 { 1991 {
1992 /* Set the window's buffer temporarily to the current buffer. */ 1992 /* Set the window's buffer temporarily to the current buffer. */
1993 old_buffer = w->buffer; 1993 old_buffer = w->buffer;
1994 old_charpos = XMARKER (w->pointm)->charpos; 1994 old_charpos = marker_position (w->pointm);
1995 old_bytepos = XMARKER (w->pointm)->bytepos; 1995 old_bytepos = marker_byte_position (w->pointm);
1996 wset_buffer (w, Fcurrent_buffer ()); 1996 wset_buffer (w, Fcurrent_buffer ());
1997 set_marker_both (w->pointm, w->buffer, 1997 set_marker_both (w->pointm, w->buffer,
1998 BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer)); 1998 BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer));
diff --git a/src/inotify.c b/src/inotify.c
new file mode 100644
index 00000000000..17104c89064
--- /dev/null
+++ b/src/inotify.c
@@ -0,0 +1,438 @@
1/* Inotify support for Emacs
2
3Copyright (C) 2012
4 Free Software Foundation, Inc.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21#include <config.h>
22
23#ifdef HAVE_INOTIFY
24
25#include "lisp.h"
26#include "coding.h"
27#include "process.h"
28#include "keyboard.h"
29#include "character.h"
30#include "frame.h" /* Required for termhooks.h. */
31#include "termhooks.h"
32
33static Lisp_Object Qaccess; /* IN_ACCESS */
34static Lisp_Object Qattrib; /* IN_ATTRIB */
35static Lisp_Object Qclose_write; /* IN_CLOSE_WRITE */
36static Lisp_Object Qclose_nowrite; /* IN_CLOSE_NOWRITE */
37static Lisp_Object Qcreate; /* IN_CREATE */
38static Lisp_Object Qdelete; /* IN_DELETE */
39static Lisp_Object Qdelete_self; /* IN_DELETE_SELF */
40static Lisp_Object Qmodify; /* IN_MODIFY */
41static Lisp_Object Qmove_self; /* IN_MOVE_SELF */
42static Lisp_Object Qmoved_from; /* IN_MOVED_FROM */
43static Lisp_Object Qmoved_to; /* IN_MOVED_TO */
44static Lisp_Object Qopen; /* IN_OPEN */
45
46static Lisp_Object Qall_events; /* IN_ALL_EVENTS */
47static Lisp_Object Qmove; /* IN_MOVE */
48static Lisp_Object Qclose; /* IN_CLOSE */
49
50static Lisp_Object Qdont_follow; /* IN_DONT_FOLLOW */
51static Lisp_Object Qexcl_unlink; /* IN_EXCL_UNLINK */
52static Lisp_Object Qmask_add; /* IN_MASK_ADD */
53static Lisp_Object Qoneshot; /* IN_ONESHOT */
54static Lisp_Object Qonlydir; /* IN_ONLYDIR */
55
56static Lisp_Object Qignored; /* IN_IGNORED */
57static Lisp_Object Qisdir; /* IN_ISDIR */
58static Lisp_Object Qq_overflow; /* IN_Q_OVERFLOW */
59static Lisp_Object Qunmount; /* IN_UNMOUNT */
60
61#include <sys/inotify.h>
62#include <sys/ioctl.h>
63
64/* Ignore bits that might be undefined on old GNU/Linux systems. */
65#ifndef IN_EXCL_UNLINK
66# define IN_EXCL_UNLINK 0
67#endif
68#ifndef IN_DONT_FOLLOW
69# define IN_DONT_FOLLOW 0
70#endif
71#ifndef IN_ONLYDIR
72# define IN_ONLYDIR 0
73#endif
74
75enum { uninitialized = -100 };
76/* File handle for inotify. */
77static int inotifyfd = uninitialized;
78
79/* Assoc list of files being watched.
80 Format:
81 (watch-descriptor . callback)
82 */
83static Lisp_Object watch_list;
84
85static Lisp_Object
86make_watch_descriptor (int wd)
87{
88 /* TODO replace this with a Misc Object! */
89 return make_number (wd);
90}
91
92static Lisp_Object
93mask_to_aspects (uint32_t mask) {
94 Lisp_Object aspects = Qnil;
95 if (mask & IN_ACCESS)
96 aspects = Fcons (Qaccess, aspects);
97 if (mask & IN_ATTRIB)
98 aspects = Fcons (Qattrib, aspects);
99 if (mask & IN_CLOSE_WRITE)
100 aspects = Fcons (Qclose_write, aspects);
101 if (mask & IN_CLOSE_NOWRITE)
102 aspects = Fcons (Qclose_nowrite, aspects);
103 if (mask & IN_CREATE)
104 aspects = Fcons (Qcreate, aspects);
105 if (mask & IN_DELETE)
106 aspects = Fcons (Qdelete, aspects);
107 if (mask & IN_DELETE_SELF)
108 aspects = Fcons (Qdelete_self, aspects);
109 if (mask & IN_MODIFY)
110 aspects = Fcons (Qmodify, aspects);
111 if (mask & IN_MOVE_SELF)
112 aspects = Fcons (Qmove_self, aspects);
113 if (mask & IN_MOVED_FROM)
114 aspects = Fcons (Qmoved_from, aspects);
115 if (mask & IN_MOVED_TO)
116 aspects = Fcons (Qmoved_to, aspects);
117 if (mask & IN_OPEN)
118 aspects = Fcons (Qopen, aspects);
119 if (mask & IN_IGNORED)
120 aspects = Fcons (Qignored, aspects);
121 if (mask & IN_ISDIR)
122 aspects = Fcons (Qisdir, aspects);
123 if (mask & IN_Q_OVERFLOW)
124 aspects = Fcons (Qq_overflow, aspects);
125 if (mask & IN_UNMOUNT)
126 aspects = Fcons (Qunmount, aspects);
127 return aspects;
128}
129
130static Lisp_Object
131inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const *ev)
132{
133 Lisp_Object name = Qnil;
134 if (ev->len > 0)
135 {
136 size_t const len = strlen (ev->name);
137 name = make_unibyte_string (ev->name, min (len, ev->len));
138 name = DECODE_FILE (name);
139 }
140
141 return list2 (list4 (make_watch_descriptor (ev->wd),
142 mask_to_aspects (ev->mask),
143 make_number (ev->cookie),
144 name),
145 XCDR (watch_object));
146}
147
148/* This callback is called when the FD is available for read. The inotify
149 events are read from FD and converted into input_events. */
150static void
151inotify_callback (int fd, void *_)
152{
153 struct input_event event;
154 Lisp_Object watch_object;
155 int to_read;
156 char *buffer;
157 ssize_t n;
158 size_t i;
159
160 to_read = 0;
161 if (ioctl (fd, FIONREAD, &to_read) == -1)
162 report_file_error ("Error while trying to retrieve file system events",
163 Qnil);
164 buffer = xmalloc (to_read);
165 n = read (fd, buffer, to_read);
166 if (n < 0)
167 {
168 xfree (buffer);
169 report_file_error ("Error while trying to read file system events",
170 Qnil);
171 }
172
173 EVENT_INIT (event);
174 event.kind = FILE_NOTIFY_EVENT;
175 event.arg = Qnil;
176
177 i = 0;
178 while (i < (size_t)n)
179 {
180 struct inotify_event *ev = (struct inotify_event*)&buffer[i];
181
182 watch_object = Fassoc (make_watch_descriptor (ev->wd), watch_list);
183 if (!NILP (watch_object))
184 {
185 event.arg = inotifyevent_to_event (watch_object, ev);
186
187 /* If event was removed automatically: Drop it from watch list. */
188 if (ev->mask & IN_IGNORED)
189 watch_list = Fdelete (watch_object, watch_list);
190 }
191
192 i += sizeof (*ev) + ev->len;
193 }
194
195 if (!NILP (event.arg))
196 kbd_buffer_store_event (&event);
197
198 xfree (buffer);
199}
200
201static uint32_t
202symbol_to_inotifymask (Lisp_Object symb)
203{
204 if (EQ (symb, Qaccess))
205 return IN_ACCESS;
206 else if (EQ (symb, Qattrib))
207 return IN_ATTRIB;
208 else if (EQ (symb, Qclose_write))
209 return IN_CLOSE_WRITE;
210 else if (EQ (symb, Qclose_nowrite))
211 return IN_CLOSE_NOWRITE;
212 else if (EQ (symb, Qcreate))
213 return IN_CREATE;
214 else if (EQ (symb, Qdelete))
215 return IN_DELETE;
216 else if (EQ (symb, Qdelete_self))
217 return IN_DELETE_SELF;
218 else if (EQ (symb, Qmodify))
219 return IN_MODIFY;
220 else if (EQ (symb, Qmove_self))
221 return IN_MOVE_SELF;
222 else if (EQ (symb, Qmoved_from))
223 return IN_MOVED_FROM;
224 else if (EQ (symb, Qmoved_to))
225 return IN_MOVED_TO;
226 else if (EQ (symb, Qopen))
227 return IN_OPEN;
228 else if (EQ (symb, Qmove))
229 return IN_MOVE;
230 else if (EQ (symb, Qclose))
231 return IN_CLOSE;
232
233 else if (EQ (symb, Qdont_follow))
234 return IN_DONT_FOLLOW;
235 else if (EQ (symb, Qexcl_unlink))
236 return IN_EXCL_UNLINK;
237 else if (EQ (symb, Qmask_add))
238 return IN_MASK_ADD;
239 else if (EQ (symb, Qoneshot))
240 return IN_ONESHOT;
241 else if (EQ (symb, Qonlydir))
242 return IN_ONLYDIR;
243
244 else if (EQ (symb, Qt) || EQ (symb, Qall_events))
245 return IN_ALL_EVENTS;
246 else
247 signal_error ("Unknown aspect", symb);
248}
249
250static uint32_t
251aspect_to_inotifymask (Lisp_Object aspect)
252{
253 if (CONSP (aspect))
254 {
255 Lisp_Object x = aspect;
256 uint32_t mask = 0;
257 while (CONSP (x))
258 {
259 mask |= symbol_to_inotifymask (XCAR (x));
260 x = XCDR (x);
261 }
262 return mask;
263 }
264 else
265 return symbol_to_inotifymask (aspect);
266}
267
268DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0,
269 doc: /* Add a watch for FILE-NAME to inotify.
270
271A WATCH-DESCRIPTOR is returned on success. ASPECT might be one of the following
272symbols or a list of those symbols:
273
274access
275attrib
276close-write
277close-nowrite
278create
279delete
280delete-self
281modify
282move-self
283moved-from
284moved-to
285open
286
287all-events or t
288move
289close
290
291The following symbols can also be added to a list of aspects
292
293dont-follow
294excl-unlink
295mask-add
296oneshot
297onlydir
298
299Watching a directory is not recursive. CALLBACK gets called in case of an
300event. It gets passed a single argument EVENT which contains an event structure
301of the format
302
303(WATCH-DESCRIPTOR ASPECTS COOKIE NAME)
304
305WATCH-DESCRIPTOR is the same object that was returned by this function. It can
306be tested for equality using `equal'. ASPECTS describes the event. It is a
307list of ASPECT symbols described above and can also contain one of the following
308symbols
309
310ignored
311isdir
312q-overflow
313unmount
314
315COOKIE is an object that can be compared using `equal' to identify two matching
316renames (moved-from and moved-to).
317
318If a directory is watched then NAME is the name of file that caused the event.
319
320See inotify(7) and inotify_add_watch(2) for further information. The inotify fd
321is managed internally and there is no corresponding inotify_init. Use
322`inotify-rm-watch' to remove a watch.
323 */)
324 (Lisp_Object file_name, Lisp_Object aspect, Lisp_Object callback)
325{
326 uint32_t mask;
327 Lisp_Object watch_object;
328 Lisp_Object encoded_file_name;
329 Lisp_Object watch_descriptor;
330 int watchdesc = -1;
331
332 CHECK_STRING (file_name);
333
334 if (inotifyfd == uninitialized)
335 {
336 inotifyfd = inotify_init1 (IN_NONBLOCK|IN_CLOEXEC);
337 if (inotifyfd == -1)
338 {
339 inotifyfd = uninitialized;
340 report_file_error ("File watching feature (inotify) is not available",
341 Qnil);
342 }
343 watch_list = Qnil;
344 add_read_fd (inotifyfd, &inotify_callback, NULL);
345 }
346
347 mask = aspect_to_inotifymask (aspect);
348 encoded_file_name = ENCODE_FILE (file_name);
349 watchdesc = inotify_add_watch (inotifyfd, SSDATA (encoded_file_name), mask);
350 if (watchdesc == -1)
351 report_file_error ("Could not add watch for file", Fcons (file_name, Qnil));
352
353 watch_descriptor = make_watch_descriptor (watchdesc);
354
355 /* Delete existing watch object. */
356 watch_object = Fassoc (watch_descriptor, watch_list);
357 if (!NILP (watch_object))
358 watch_list = Fdelete (watch_object, watch_list);
359
360 /* Store watch object in watch list. */
361 watch_object = Fcons (watch_descriptor, callback);
362 watch_list = Fcons (watch_object, watch_list);
363
364 return watch_descriptor;
365}
366
367DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0,
368 doc: /* Remove an existing WATCH-DESCRIPTOR.
369
370WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'.
371
372See inotify_rm_watch(2) for more information.
373 */)
374 (Lisp_Object watch_descriptor)
375{
376 Lisp_Object watch_object;
377 int wd = XINT (watch_descriptor);
378
379 if (inotify_rm_watch (inotifyfd, wd) == -1)
380 report_file_error ("Could not rm watch", Fcons (watch_descriptor,
381 Qnil));
382
383 /* Remove watch descriptor from watch list. */
384 watch_object = Fassoc (watch_descriptor, watch_list);
385 if (!NILP (watch_object))
386 watch_list = Fdelete (watch_object, watch_list);
387
388 /* Cleanup if no more files are watched. */
389 if (NILP (watch_list))
390 {
391 close (inotifyfd);
392 delete_read_fd (inotifyfd);
393 inotifyfd = uninitialized;
394 }
395
396 return Qt;
397}
398
399void
400syms_of_inotify (void)
401{
402 DEFSYM (Qaccess, "access");
403 DEFSYM (Qattrib, "attrib");
404 DEFSYM (Qclose_write, "close-write");
405 DEFSYM (Qclose_nowrite, "close-nowrite");
406 DEFSYM (Qcreate, "create");
407 DEFSYM (Qdelete, "delete");
408 DEFSYM (Qdelete_self, "delete-self");
409 DEFSYM (Qmodify, "modify");
410 DEFSYM (Qmove_self, "move-self");
411 DEFSYM (Qmoved_from, "moved-from");
412 DEFSYM (Qmoved_to, "moved-to");
413 DEFSYM (Qopen, "open");
414
415 DEFSYM (Qall_events, "all-events");
416 DEFSYM (Qmove, "move");
417 DEFSYM (Qclose, "close");
418
419 DEFSYM (Qdont_follow, "dont-follow");
420 DEFSYM (Qexcl_unlink, "excl-unlink");
421 DEFSYM (Qmask_add, "mask-add");
422 DEFSYM (Qoneshot, "oneshot");
423 DEFSYM (Qonlydir, "onlydir");
424
425 DEFSYM (Qignored, "ignored");
426 DEFSYM (Qisdir, "isdir");
427 DEFSYM (Qq_overflow, "q-overflow");
428 DEFSYM (Qunmount, "unmount");
429
430 defsubr (&Sinotify_add_watch);
431 defsubr (&Sinotify_rm_watch);
432
433 staticpro (&watch_list);
434
435 Fprovide (intern_c_string ("inotify"), Qnil);
436}
437
438#endif /* HAVE_INOTIFY */
diff --git a/src/insdel.c b/src/insdel.c
index 892ca3d5216..74e938c4b8c 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1800,9 +1800,10 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
1800 if (!NILP (BVAR (current_buffer, read_only))) 1800 if (!NILP (BVAR (current_buffer, read_only)))
1801 Fbarf_if_buffer_read_only (); 1801 Fbarf_if_buffer_read_only ();
1802 1802
1803 /* Let redisplay consider other windows than selected_window 1803 /* If we're modifying the buffer other than shown in a selected window,
1804 if modifying another buffer. */ 1804 let redisplay consider other windows if this buffer is visible. */
1805 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer) 1805 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer
1806 && buffer_window_count (current_buffer))
1806 ++windows_or_buffers_changed; 1807 ++windows_or_buffers_changed;
1807 1808
1808 if (buffer_intervals (current_buffer)) 1809 if (buffer_intervals (current_buffer))
@@ -1854,7 +1855,7 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
1854 : (!NILP (Vselect_active_regions) 1855 : (!NILP (Vselect_active_regions)
1855 && !NILP (Vtransient_mark_mode)))) 1856 && !NILP (Vtransient_mark_mode))))
1856 { 1857 {
1857 ptrdiff_t b = XMARKER (BVAR (current_buffer, mark))->charpos; 1858 ptrdiff_t b = marker_position (BVAR (current_buffer, mark));
1858 ptrdiff_t e = PT; 1859 ptrdiff_t e = PT;
1859 if (b < e) 1860 if (b < e)
1860 Vsaved_region_selection = make_buffer_string (b, e, 0); 1861 Vsaved_region_selection = make_buffer_string (b, e, 0);
diff --git a/src/keyboard.c b/src/keyboard.c
index 9b5e0c5865d..313c57fbe51 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -313,6 +313,9 @@ static Lisp_Object Qfunction_key;
313Lisp_Object Qmouse_click; 313Lisp_Object Qmouse_click;
314#ifdef HAVE_NTGUI 314#ifdef HAVE_NTGUI
315Lisp_Object Qlanguage_change; 315Lisp_Object Qlanguage_change;
316#ifdef WINDOWSNT
317Lisp_Object Qfile_w32notify;
318#endif
316#endif 319#endif
317static Lisp_Object Qdrag_n_drop; 320static Lisp_Object Qdrag_n_drop;
318static Lisp_Object Qsave_session; 321static Lisp_Object Qsave_session;
@@ -322,6 +325,9 @@ static Lisp_Object Qdbus_event;
322#ifdef HAVE_XWIDGETS 325#ifdef HAVE_XWIDGETS
323Lisp_Object Qxwidget_event; 326Lisp_Object Qxwidget_event;
324#endif 327#endif
328#ifdef HAVE_INOTIFY
329static Lisp_Object Qfile_inotify;
330#endif /* HAVE_INOTIFY */
325static Lisp_Object Qconfig_changed_event; 331static Lisp_Object Qconfig_changed_event;
326 332
327/* Lisp_Object Qmouse_movement; - also an event header */ 333/* Lisp_Object Qmouse_movement; - also an event header */
@@ -3907,6 +3913,18 @@ kbd_buffer_get_event (KBOARD **kbp,
3907 kbd_fetch_ptr = event + 1; 3913 kbd_fetch_ptr = event + 1;
3908 } 3914 }
3909#endif 3915#endif
3916#ifdef WINDOWSNT
3917 else if (event->kind == FILE_NOTIFY_EVENT)
3918 {
3919 /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK). */
3920 obj = Fcons (Qfile_w32notify,
3921 list2 (list3 (make_number (event->code),
3922 XCAR (event->arg),
3923 XCDR (event->arg)),
3924 event->frame_or_window));
3925 kbd_fetch_ptr = event + 1;
3926 }
3927#endif
3910 else if (event->kind == SAVE_SESSION_EVENT) 3928 else if (event->kind == SAVE_SESSION_EVENT)
3911 { 3929 {
3912 obj = Fcons (Qsave_session, Fcons (event->arg, Qnil)); 3930 obj = Fcons (Qsave_session, Fcons (event->arg, Qnil));
@@ -3970,6 +3988,12 @@ kbd_buffer_get_event (KBOARD **kbp,
3970 obj = make_lispy_event (event); 3988 obj = make_lispy_event (event);
3971 kbd_fetch_ptr = event + 1; 3989 kbd_fetch_ptr = event + 1;
3972 } 3990 }
3991#ifdef HAVE_INOTIFY
3992 else if (event->kind == FILE_NOTIFY_EVENT)
3993 {
3994 obj = make_lispy_event (event);
3995 kbd_fetch_ptr = event + 1;
3996 }
3973#endif 3997#endif
3974 else if (event->kind == CONFIG_CHANGED_EVENT) 3998 else if (event->kind == CONFIG_CHANGED_EVENT)
3975 { 3999 {
@@ -5123,7 +5147,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
5123 string_info = Fcons (string, make_number (charpos)); 5147 string_info = Fcons (string, make_number (charpos));
5124 textpos = (w == XWINDOW (selected_window) 5148 textpos = (w == XWINDOW (selected_window)
5125 && current_buffer == XBUFFER (w->buffer)) 5149 && current_buffer == XBUFFER (w->buffer))
5126 ? PT : XMARKER (w->pointm)->charpos; 5150 ? PT : marker_position (w->pointm);
5127 5151
5128 xret = wx; 5152 xret = wx;
5129 yret = wy; 5153 yret = wy;
@@ -5883,13 +5907,23 @@ make_lispy_event (struct input_event *event)
5883 return Fcons (Qdbus_event, event->arg); 5907 return Fcons (Qdbus_event, event->arg);
5884 } 5908 }
5885#endif /* HAVE_DBUS */ 5909#endif /* HAVE_DBUS */
5910
5886#ifdef HAVE_XWIDGETS 5911#ifdef HAVE_XWIDGETS
5887 case XWIDGET_EVENT: 5912 case XWIDGET_EVENT:
5888 { 5913 {
5889 printf("cool, an xwidget event arrived in make_lispy_event!\n"); 5914 printf("cool, an xwidget event arrived in make_lispy_event!\n");
5890 return Fcons (Qxwidget_event,event->arg); 5915 return Fcons (Qxwidget_event,event->arg);
5891 } 5916 }
5892#endif 5917#endif /* HAVE_XWIDGETS */
5918
5919
5920#ifdef HAVE_INOTIFY
5921 case FILE_NOTIFY_EVENT:
5922 {
5923 return Fcons (Qfile_inotify, event->arg);
5924 }
5925#endif /* HAVE_INOTIFY */
5926
5893 case CONFIG_CHANGED_EVENT: 5927 case CONFIG_CHANGED_EVENT:
5894 return Fcons (Qconfig_changed_event, 5928 return Fcons (Qconfig_changed_event,
5895 Fcons (event->arg, 5929 Fcons (event->arg,
@@ -11349,6 +11383,10 @@ syms_of_keyboard (void)
11349 DEFSYM (Qlanguage_change, "language-change"); 11383 DEFSYM (Qlanguage_change, "language-change");
11350#endif 11384#endif
11351 11385
11386#ifdef WINDOWSNT
11387 DEFSYM (Qfile_w32notify, "file-w32notify");
11388#endif
11389
11352#ifdef HAVE_DBUS 11390#ifdef HAVE_DBUS
11353 DEFSYM (Qdbus_event, "dbus-event"); 11391 DEFSYM (Qdbus_event, "dbus-event");
11354#endif 11392#endif
@@ -11356,7 +11394,11 @@ syms_of_keyboard (void)
11356#ifdef HAVE_XWIDGETS 11394#ifdef HAVE_XWIDGETS
11357 Qxwidget_event = intern ("xwidget-event"); 11395 Qxwidget_event = intern ("xwidget-event");
11358 staticpro (&Qxwidget_event); 11396 staticpro (&Qxwidget_event);
11359#endif 11397#endif /* HAVE_XWIDGETS */
11398#ifdef HAVE_INOTIFY
11399 DEFSYM (Qfile_inotify, "file-inotify");
11400#endif /* HAVE_INOTIFY */
11401
11360 DEFSYM (QCenable, ":enable"); 11402 DEFSYM (QCenable, ":enable");
11361 DEFSYM (QCvisible, ":visible"); 11403 DEFSYM (QCvisible, ":visible");
11362 DEFSYM (QChelp, ":help"); 11404 DEFSYM (QChelp, ":help");
@@ -12113,11 +12155,20 @@ keys_of_keyboard (void)
12113 "dbus-handle-event"); 12155 "dbus-handle-event");
12114#endif 12156#endif
12115 12157
12158#ifdef HAVE_INOTIFY
12159 /* Define a special event which is raised for inotify callback
12160 functions. */
12161 initial_define_lispy_key (Vspecial_event_map, "file-inotify",
12162 "inotify-handle-event");
12163#endif /* HAVE_INOTIFY */
12164
12116 initial_define_lispy_key (Vspecial_event_map, "config-changed-event", 12165 initial_define_lispy_key (Vspecial_event_map, "config-changed-event",
12117 "ignore"); 12166 "ignore");
12118#if defined (WINDOWSNT) 12167#if defined (WINDOWSNT)
12119 initial_define_lispy_key (Vspecial_event_map, "language-change", 12168 initial_define_lispy_key (Vspecial_event_map, "language-change",
12120 "ignore"); 12169 "ignore");
12170 initial_define_lispy_key (Vspecial_event_map, "file-w32notify",
12171 "w32notify-handle-event");
12121#endif 12172#endif
12122} 12173}
12123 12174
diff --git a/src/lisp.h b/src/lisp.h
index 269022f5dfd..9422ae740c9 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3521,6 +3521,16 @@ extern void syms_of_fontset (void);
3521extern Lisp_Object Qfont_param; 3521extern Lisp_Object Qfont_param;
3522#endif 3522#endif
3523 3523
3524#ifdef WINDOWSNT
3525/* Defined on w32notify.c. */
3526extern void syms_of_w32notify (void);
3527#endif
3528
3529/* Defined in inotify.c */
3530#ifdef HAVE_INOTIFY
3531extern void syms_of_inotify (void);
3532#endif
3533
3524/* Defined in xfaces.c. */ 3534/* Defined in xfaces.c. */
3525extern Lisp_Object Qdefault, Qtool_bar, Qfringe; 3535extern Lisp_Object Qdefault, Qtool_bar, Qfringe;
3526extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor; 3536extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor;
diff --git a/src/makefile.w32-in b/src/makefile.w32-in
index a296f6eb393..facf79cf849 100644
--- a/src/makefile.w32-in
+++ b/src/makefile.w32-in
@@ -134,6 +134,7 @@ OBJ2 = $(BLD)/sysdep.$(O) \
134 $(BLD)/w32menu.$(O) \ 134 $(BLD)/w32menu.$(O) \
135 $(BLD)/w32reg.$(O) \ 135 $(BLD)/w32reg.$(O) \
136 $(BLD)/w32font.$(O) \ 136 $(BLD)/w32font.$(O) \
137 $(BLD)/w32notify.$(O) \
137 $(BLD)/w32uniscribe.$(O) 138 $(BLD)/w32uniscribe.$(O)
138 139
139LIBS = $(TLIB0) \ 140LIBS = $(TLIB0) \
@@ -209,7 +210,7 @@ GLOBAL_SOURCES = dosfns.c msdos.c \
209 fontset.c menu.c dbusbind.c \ 210 fontset.c menu.c dbusbind.c \
210 w32.c w32console.c w32fns.c w32heap.c w32inevt.c cygw32.c \ 211 w32.c w32console.c w32fns.c w32heap.c w32inevt.c cygw32.c \
211 w32menu.c w32proc.c w32reg.c w32select.c w32term.c w32xfns.c \ 212 w32menu.c w32proc.c w32reg.c w32select.c w32term.c w32xfns.c \
212 font.c w32font.c w32uniscribe.c \ 213 font.c w32font.c w32uniscribe.c w32notify.c \
213 dispnew.c frame.c scroll.c xdisp.c window.c bidi.c \ 214 dispnew.c frame.c scroll.c xdisp.c window.c bidi.c \
214 charset.c coding.c category.c ccl.c character.c chartab.c \ 215 charset.c coding.c category.c ccl.c character.c chartab.c \
215 cm.c term.c terminal.c xfaces.c \ 216 cm.c term.c terminal.c xfaces.c \
@@ -461,6 +462,8 @@ U64_H = $(GNU_LIB)/u64.h \
461 $(NT_INC)/stdint.h 462 $(NT_INC)/stdint.h
462SHA512_H = $(GNU_LIB)/sha512.h \ 463SHA512_H = $(GNU_LIB)/sha512.h \
463 $(U64_H) 464 $(U64_H)
465SIG2STR_H = $(GNU_LIB)/sig2str.h \
466 $(GNU_LIB)/intprops.h
464SOCKET_H = $(NT_INC)/sys/socket.h \ 467SOCKET_H = $(NT_INC)/sys/socket.h \
465 $(SRC)/w32.h 468 $(SRC)/w32.h
466STAT_TIME_H = $(GNU_LIB)/stat-time.h \ 469STAT_TIME_H = $(GNU_LIB)/stat-time.h \
@@ -471,6 +474,7 @@ SYSTTY_H = $(SRC)/systty.h \
471 $(NT_INC)/sys/ioctl.h \ 474 $(NT_INC)/sys/ioctl.h \
472 $(NT_INC)/unistd.h 475 $(NT_INC)/unistd.h
473SYSWAIT_H = $(SRC)/syswait.h \ 476SYSWAIT_H = $(SRC)/syswait.h \
477 $(NT_INC)/stdbool.h \
474 $(NT_INC)/sys/wait.h 478 $(NT_INC)/sys/wait.h
475TERMHOOKS_H = $(SRC)/termhooks.h \ 479TERMHOOKS_H = $(SRC)/termhooks.h \
476 $(SYSTIME_H) 480 $(SYSTIME_H)
@@ -799,6 +803,7 @@ $(BLD)/emacs.$(O) : \
799 $(SRC)/keymap.h \ 803 $(SRC)/keymap.h \
800 $(SRC)/unexec.h \ 804 $(SRC)/unexec.h \
801 $(SRC)/w32.h \ 805 $(SRC)/w32.h \
806 $(SRC)/w32common.h \
802 $(SRC)/w32heap.h \ 807 $(SRC)/w32heap.h \
803 $(SRC)/w32select.h \ 808 $(SRC)/w32select.h \
804 $(NT_INC)/sys/file.h \ 809 $(NT_INC)/sys/file.h \
@@ -1287,11 +1292,13 @@ $(BLD)/process.$(O) : \
1287 $(CHARACTER_H) \ 1292 $(CHARACTER_H) \
1288 $(CODING_H) \ 1293 $(CODING_H) \
1289 $(CONFIG_H) \ 1294 $(CONFIG_H) \
1295 $(C_CTYPE_H) \
1290 $(DISPEXTERN_H) \ 1296 $(DISPEXTERN_H) \
1291 $(FRAME_H) \ 1297 $(FRAME_H) \
1292 $(KEYBOARD_H) \ 1298 $(KEYBOARD_H) \
1293 $(LISP_H) \ 1299 $(LISP_H) \
1294 $(PROCESS_H) \ 1300 $(PROCESS_H) \
1301 $(SIG2STR_H) \
1295 $(SOCKET_H) \ 1302 $(SOCKET_H) \
1296 $(SYSSIGNAL_H) \ 1303 $(SYSSIGNAL_H) \
1297 $(SYSTIME_H) \ 1304 $(SYSTIME_H) \
@@ -1693,6 +1700,18 @@ $(BLD)/w32uniscribe.$(O) : \
1693 $(W32FONT_H) \ 1700 $(W32FONT_H) \
1694 $(W32TERM_H) 1701 $(W32TERM_H)
1695 1702
1703$(BLD)/w32notify.$(O) : \
1704 $(SRC)/w32notify.c \
1705 $(SRC)/w32.h \
1706 $(SRC)/w32common.h \
1707 $(CODING_H) \
1708 $(CONFIG_H) \
1709 $(FRAME_H) \
1710 $(KEYBOARD_H) \
1711 $(LISP_H) \
1712 $(TERMHOOKS_H) \
1713 $(W32TERM_H)
1714
1696# Each object file depends on stamp_BLD, because in parallel builds we must 1715# Each object file depends on stamp_BLD, because in parallel builds we must
1697# make sure $(BLD) exists before starting compilations. 1716# make sure $(BLD) exists before starting compilations.
1698# 1717#
diff --git a/src/termhooks.h b/src/termhooks.h
index d4b472cfb24..79af2f91feb 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -213,7 +213,12 @@ enum event_kind
213#ifdef HAVE_XWIDGETS 213#ifdef HAVE_XWIDGETS
214 /* events generated by xwidgets*/ 214 /* events generated by xwidgets*/
215 , XWIDGET_EVENT 215 , XWIDGET_EVENT
216
217#if defined (HAVE_INOTIFY) || defined (HAVE_NTGUI)
218 /* File or directory was changed. */
219 , FILE_NOTIFY_EVENT
216#endif 220#endif
221
217}; 222};
218 223
219/* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT 224/* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT
diff --git a/src/unexw32.c b/src/unexw32.c
index 1e591a78b73..ee1deb5f92e 100644
--- a/src/unexw32.c
+++ b/src/unexw32.c
@@ -85,13 +85,6 @@ DWORD_PTR extra_bss_size_static = 0;
85 85
86PIMAGE_SECTION_HEADER heap_section; 86PIMAGE_SECTION_HEADER heap_section;
87 87
88#ifdef HAVE_NTGUI
89extern HINSTANCE hinst;
90HINSTANCE hprevinst = NULL;
91LPSTR lpCmdLine = "";
92int nCmdShow = 0;
93#endif /* HAVE_NTGUI */
94
95/* Startup code for running on NT. When we are running as the dumped 88/* Startup code for running on NT. When we are running as the dumped
96 version, we need to bootstrap our heap and .bss section into our 89 version, we need to bootstrap our heap and .bss section into our
97 address space before we can actually hand off control to the startup 90 address space before we can actually hand off control to the startup
@@ -121,15 +114,6 @@ _start (void)
121 /* Prevent Emacs from being locked up (eg. in batch mode) when 114 /* Prevent Emacs from being locked up (eg. in batch mode) when
122 accessing devices that aren't mounted (eg. removable media drives). */ 115 accessing devices that aren't mounted (eg. removable media drives). */
123 SetErrorMode (SEM_FAILCRITICALERRORS); 116 SetErrorMode (SEM_FAILCRITICALERRORS);
124
125 /* Invoke the NT CRT startup routine now that our housecleaning
126 is finished. */
127#ifdef HAVE_NTGUI
128 /* determine WinMain args like crt0.c does */
129 hinst = GetModuleHandle (NULL);
130 lpCmdLine = GetCommandLine ();
131 nCmdShow = SW_SHOWDEFAULT;
132#endif
133 mainCRTStartup (); 117 mainCRTStartup ();
134} 118}
135 119
diff --git a/src/w32console.c b/src/w32console.c
index f0574689bf1..f201ff190c2 100644
--- a/src/w32console.c
+++ b/src/w32console.c
@@ -746,6 +746,9 @@ initialize_w32_display (struct terminal *term)
746 else 746 else
747 w32_console_unicode_input = 0; 747 w32_console_unicode_input = 0;
748 748
749 /* This is needed by w32notify.c:send_notifications. */
750 dwMainThreadId = GetCurrentThreadId ();
751
749 /* Setup w32_display_info structure for this frame. */ 752 /* Setup w32_display_info structure for this frame. */
750 753
751 w32_initialize_display_info (build_string ("Console")); 754 w32_initialize_display_info (build_string ("Console"));
diff --git a/src/w32fns.c b/src/w32fns.c
index 1b8483479a1..f69fbe05a6d 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -1821,7 +1821,6 @@ static LRESULT CALLBACK w32_wnd_proc (HWND, UINT, WPARAM, LPARAM);
1821static BOOL 1821static BOOL
1822w32_init_class (HINSTANCE hinst) 1822w32_init_class (HINSTANCE hinst)
1823{ 1823{
1824
1825 if (w32_unicode_gui) 1824 if (w32_unicode_gui)
1826 { 1825 {
1827 WNDCLASSW uwc; 1826 WNDCLASSW uwc;
@@ -3957,6 +3956,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
3957 3956
3958 return retval; 3957 return retval;
3959 } 3958 }
3959 case WM_EMACS_FILENOTIFY:
3960 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3961 return 1;
3960 3962
3961 default: 3963 default:
3962 /* Check for messages registered at runtime. */ 3964 /* Check for messages registered at runtime. */
@@ -7024,6 +7026,9 @@ cache_system_info (void)
7024 DWORD data; 7026 DWORD data;
7025 } version; 7027 } version;
7026 7028
7029 /* Cache the module handle of Emacs itself. */
7030 hinst = GetModuleHandle (NULL);
7031
7027 /* Cache the version of the operating system. */ 7032 /* Cache the version of the operating system. */
7028 version.data = GetVersion (); 7033 version.data = GetVersion ();
7029 w32_major_version = version.info.major; 7034 w32_major_version = version.info.major;
diff --git a/src/w32gui.h b/src/w32gui.h
index 0da8de97f23..fe2bb2334b5 100644
--- a/src/w32gui.h
+++ b/src/w32gui.h
@@ -79,9 +79,6 @@ typedef struct _XImage
79#define FACE_DEFAULT (~0) 79#define FACE_DEFAULT (~0)
80 80
81extern HINSTANCE hinst; 81extern HINSTANCE hinst;
82extern HINSTANCE hprevinst;
83extern LPSTR lpCmdLine;
84extern int nCmdShow;
85 82
86/* Bit Gravity */ 83/* Bit Gravity */
87 84
diff --git a/src/w32inevt.c b/src/w32inevt.c
index 899a6fb89bf..2cbf31efda3 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -576,6 +576,74 @@ maybe_generate_resize_event (void)
576 0, 0, 0); 576 0, 0, 0);
577} 577}
578 578
579static int
580handle_file_notifications (struct input_event *hold_quit)
581{
582 BYTE *p = file_notifications;
583 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
584 const DWORD min_size
585 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
586 struct input_event inev;
587 int nevents = 0;
588
589 /* We cannot process notification before Emacs is fully initialized,
590 since we need the UTF-16LE coding-system to be set up. */
591 if (!initialized)
592 {
593 notification_buffer_in_use = 0;
594 return nevents;
595 }
596
597 enter_crit ();
598 if (notification_buffer_in_use)
599 {
600 DWORD info_size = notifications_size;
601 Lisp_Object cs = intern ("utf-16le");
602 Lisp_Object obj = w32_get_watch_object (notifications_desc);
603
604 /* notifications_size could be zero when the buffer of
605 notifications overflowed on the OS level, or when the
606 directory being watched was itself deleted. Do nothing in
607 that case. */
608 if (info_size
609 && !NILP (obj) && CONSP (obj))
610 {
611 Lisp_Object callback = XCDR (obj);
612
613 EVENT_INIT (inev);
614
615 while (info_size >= min_size)
616 {
617 Lisp_Object utf_16_fn
618 = make_unibyte_string ((char *)fni->FileName,
619 fni->FileNameLength);
620 /* Note: mule-conf is preloaded, so utf-16le must
621 already be defined at this point. */
622 Lisp_Object fname
623 = code_convert_string_norecord (utf_16_fn, cs, 0);
624 Lisp_Object action = lispy_file_action (fni->Action);
625
626 inev.kind = FILE_NOTIFY_EVENT;
627 inev.code = (ptrdiff_t)XINT (XIL ((EMACS_INT)notifications_desc));
628 inev.timestamp = GetTickCount ();
629 inev.modifiers = 0;
630 inev.frame_or_window = callback;
631 inev.arg = Fcons (action, fname);
632 kbd_buffer_store_event_hold (&inev, hold_quit);
633
634 if (!fni->NextEntryOffset)
635 break;
636 p += fni->NextEntryOffset;
637 fni = (PFILE_NOTIFY_INFORMATION)p;
638 info_size -= fni->NextEntryOffset;
639 }
640 }
641 notification_buffer_in_use = 0;
642 }
643 leave_crit ();
644 return nevents;
645}
646
579/* Here's an overview of how Emacs input works in non-GUI sessions on 647/* Here's an overview of how Emacs input works in non-GUI sessions on
580 MS-Windows. (For description of the GUI input, see the commentary 648 MS-Windows. (For description of the GUI input, see the commentary
581 before w32_msg_pump in w32fns.c.) 649 before w32_msg_pump in w32fns.c.)
@@ -619,12 +687,16 @@ w32_console_read_socket (struct terminal *terminal,
619 687
620 for (;;) 688 for (;;)
621 { 689 {
690 int nfnotify = handle_file_notifications (hold_quit);
691
622 nev = fill_queue (0); 692 nev = fill_queue (0);
623 if (nev <= 0) 693 if (nev <= 0)
624 { 694 {
625 /* If nev == -1, there was some kind of error 695 /* If nev == -1, there was some kind of error
626 If nev == 0 then waitp must be zero and no events were available 696 If nev == 0 then no events were available
627 so return. */ 697 so return. */
698 if (nfnotify)
699 nev = 0;
628 break; 700 break;
629 } 701 }
630 702
diff --git a/src/w32notify.c b/src/w32notify.c
new file mode 100644
index 00000000000..3095103484a
--- /dev/null
+++ b/src/w32notify.c
@@ -0,0 +1,631 @@
1/* Filesystem notifications support for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 2012 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19/* Written by Eli Zaretskii <eliz@gnu.org>.
20
21 Design overview:
22
23 For each watch request, we launch a separate worker thread. The
24 worker thread runs the watch_worker function, which issues an
25 asynchronous call to ReadDirectoryChangesW, and then waits in
26 SleepEx for that call to complete. Waiting in SleepEx puts the
27 thread in an "alertable" state, so it wakes up when either (a) the
28 call to ReadDirectoryChangesW completes, or (b) the main thread
29 instructs the worker thread to terminate by sending it an APC, see
30 below.
31
32 When the ReadDirectoryChangesW call completes, its completion
33 routine watch_completion is automatically called. watch_completion
34 stashes the received file events in a buffer used to communicate
35 them to the main thread (using a critical section, so that several
36 threads could use the same buffer), posts a special message,
37 WM_EMACS_FILENOTIFY, to the Emacs's message queue, and returns.
38 That causes the SleepEx function call inside watch_worker to
39 return, and watch_worker then issues another call to
40 ReadDirectoryChangesW. (Except when it does not, see below.)
41
42 In a GUI session, The WM_EMACS_FILENOTIFY message, posted to the
43 message queue gets dispatched to the main Emacs window procedure,
44 which queues it for processing by w32_read_socket. When
45 w32_read_socket sees this message, it accesses the buffer with file
46 notifications (using a critical section), extracts the information,
47 converts it to a series of FILE_NOTIFY_EVENT events, and stuffs
48 them into the input event queue to be processed by keyboard.c input
49 machinery (read_char via a call to kbd_buffer_get_event).
50
51 In a non-GUI session, we send the WM_EMACS_FILENOTIFY message to
52 the main (a.k.a. "Lisp") thread instead, since there are no window
53 procedures in console programs. That message wakes up
54 MsgWaitForMultipleObjects inside sys_select, which then signals to
55 its caller that some keyboard input is available. This causes
56 w32_console_read_socket to be called, which accesses the buffer
57 with file notifications and stuffs them into the input event queue
58 for keyboard.c to process.
59
60 When the FILE_NOTIFY_EVENT event is processed by keyboard.c's
61 kbd_buffer_get_event, it is converted to a Lispy event that can be
62 bound to a command. The default binding is w32notify-handle-event,
63 defined on subr.el.
64
65 After w32_read_socket or w32_console_read_socket are done
66 processing the notifications, they reset a flag signaling to all
67 watch worker threads that the notifications buffer is available for
68 more input.
69
70 When the watch is removed by a call to w32notify-rm-watch, the main
71 thread requests that the worker thread terminates by queuing an APC
72 for the worker thread. The APC specifies the watch_end function to
73 be called. watch_end calls CancelIo on the outstanding
74 ReadDirectoryChangesW call and closes the handle on which the
75 watched directory was open. When watch_end returns, the
76 watch_completion function is called one last time with the
77 ERROR_OPERATION_ABORTED status, which causes it to clean up and set
78 a flag telling watch_worker to exit without issuing another
79 ReadDirectoryChangesW call. Since watch_worker is the thread
80 procedure of the worker thread, exiting it causes the thread to
81 exit. The main thread waits for some time for the worker thread to
82 exit, and if it doesn't, terminates it forcibly. */
83
84#include <stddef.h>
85#include <errno.h>
86
87/* must include CRT headers *before* config.h */
88#include <config.h>
89
90#include <windows.h>
91
92#include "lisp.h"
93#include "w32term.h" /* for enter_crit/leave_crit and WM_EMACS_FILENOTIFY */
94#include "w32common.h" /* for OS version data */
95#include "w32.h" /* for w32_strerror */
96#include "coding.h"
97#include "keyboard.h"
98#include "frame.h" /* needed by termhooks.h */
99#include "termhooks.h" /* for FILE_NOTIFY_EVENT */
100
101#define DIRWATCH_SIGNATURE 0x01233210
102
103struct notification {
104 BYTE *buf; /* buffer for ReadDirectoryChangesW */
105 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
106 BOOL subtree; /* whether to watch subdirectories */
107 DWORD filter; /* bit mask for events to watch */
108 char *watchee; /* the file we are interested in */
109 HANDLE dir; /* handle to the watched directory */
110 HANDLE thr; /* handle to the thread that watches */
111 volatile int terminate; /* if non-zero, request for the thread to terminate */
112 unsigned signature;
113};
114
115/* Used for communicating notifications to the main thread. */
116volatile int notification_buffer_in_use;
117BYTE file_notifications[16384];
118DWORD notifications_size;
119void *notifications_desc;
120
121static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize;
122static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time;
123static Lisp_Object Qsecurity_desc, Qsubtree, watch_list;
124
125/* Signal to the main thread that we have file notifications for it to
126 process. */
127static void
128send_notifications (BYTE *info, DWORD info_size, void *desc,
129 volatile int *terminate)
130{
131 int done = 0;
132 FRAME_PTR f = SELECTED_FRAME ();
133
134 /* A single buffer is used to communicate all notifications to the
135 main thread. Since both the main thread and several watcher
136 threads could be active at the same time, we use a critical area
137 and an "in-use" flag to synchronize them. A watcher thread can
138 only put its notifications in the buffer if it acquires the
139 critical area and finds the "in-use" flag reset. The main thread
140 resets the flag after it is done processing notifications.
141
142 FIXME: is there a better way of dealing with this? */
143 while (!done && !*terminate)
144 {
145 enter_crit ();
146 if (!notification_buffer_in_use)
147 {
148 if (info_size)
149 memcpy (file_notifications, info, info_size);
150 notifications_size = info_size;
151 notifications_desc = desc;
152 /* If PostMessage fails, the message queue is full. If that
153 happens, the last thing they will worry about is file
154 notifications. So we effectively discard the
155 notification in that case. */
156 if ((FRAME_TERMCAP_P (f)
157 /* We send the message to the main (a.k.a. "Lisp")
158 thread, where it will wake up MsgWaitForMultipleObjects
159 inside sys_select, causing it to report that there's
160 some keyboard input available. This will in turn cause
161 w32_console_read_socket to be called, which will pick
162 up the file notifications. */
163 && PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0))
164 || (FRAME_W32_P (f)
165 && PostMessage (FRAME_W32_WINDOW (f),
166 WM_EMACS_FILENOTIFY, 0, 0)))
167 notification_buffer_in_use = 1;
168 done = 1;
169 }
170 leave_crit ();
171 if (!done)
172 Sleep (5);
173 }
174}
175
176/* An APC routine to cancel outstanding directory watch. Invoked by
177 the main thread via QueueUserAPC. This is needed because only the
178 thread that issued the ReadDirectoryChangesW call can call CancelIo
179 to cancel that. (CancelIoEx is only available since Vista, so we
180 cannot use it on XP.) */
181VOID CALLBACK
182watch_end (ULONG_PTR arg)
183{
184 HANDLE hdir = (HANDLE)arg;
185
186 if (hdir && hdir != INVALID_HANDLE_VALUE)
187 {
188 CancelIo (hdir);
189 CloseHandle (hdir);
190 }
191}
192
193/* A completion routine (a.k.a. "APC function") for handling events
194 read by ReadDirectoryChangesW. Called by the OS when the thread
195 which issued the asynchronous ReadDirectoryChangesW call is in the
196 "alertable state", i.e. waiting inside SleepEx call. */
197VOID CALLBACK
198watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
199{
200 struct notification *dirwatch;
201
202 /* Who knows what happened? Perhaps the OVERLAPPED structure was
203 freed by someone already? In any case, we cannot do anything
204 with this request, so just punt and skip it. FIXME: should we
205 raise the 'terminate' flag in this case? */
206 if (!io_info)
207 return;
208
209 /* We have a pointer to our dirwatch structure conveniently stashed
210 away in the hEvent member of the OVERLAPPED struct. According to
211 MSDN documentation of ReadDirectoryChangesW: "The hEvent member
212 of the OVERLAPPED structure is not used by the system, so you can
213 use it yourself." */
214 dirwatch = (struct notification *)io_info->hEvent;
215 if (status == ERROR_OPERATION_ABORTED)
216 {
217 /* We've been called because the main thread told us to issue
218 CancelIo on the directory we watch, and watch_end did so.
219 The directory handle is already closed. We should clean up
220 and exit, signalling to the thread worker routine not to
221 issue another call to ReadDirectoryChangesW. Note that we
222 don't free the dirwatch object itself nor the memory consumed
223 by its buffers; this is done by the main thread in
224 remove_watch. Calling malloc/free from a thread other than
225 the main thread is a no-no. */
226 dirwatch->dir = NULL;
227 dirwatch->terminate = 1;
228 }
229 else
230 {
231 /* Tell the main thread we have notifications for it. */
232 send_notifications (dirwatch->buf, bytes_ret, dirwatch,
233 &dirwatch->terminate);
234 }
235}
236
237/* Worker routine for the watch thread. */
238static DWORD WINAPI
239watch_worker (LPVOID arg)
240{
241 struct notification *dirwatch = (struct notification *)arg;
242
243 do {
244 BOOL status;
245 DWORD sleep_result;
246 DWORD bytes_ret = 0;
247
248 if (dirwatch->dir)
249 {
250 status = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, 16384,
251 dirwatch->subtree, dirwatch->filter,
252 &bytes_ret,
253 dirwatch->io_info, watch_completion);
254 if (!status)
255 {
256 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ()));
257 /* We cannot remove the dirwatch object from watch_list,
258 because we are in a separate thread. For the same
259 reason, we also cannot free memory consumed by the
260 buffers allocated for the dirwatch object. So we close
261 the directory handle, but do not free the object itself
262 or its buffers. We also don't touch the signature.
263 This way, remove_watch can still identify the object,
264 remove it, and free its memory. */
265 CloseHandle (dirwatch->dir);
266 dirwatch->dir = NULL;
267 return 1;
268 }
269 }
270 /* Sleep indefinitely until awoken by the I/O completion, which
271 could be either a change notification or a cancellation of the
272 watch. */
273 sleep_result = SleepEx (INFINITE, TRUE);
274 } while (!dirwatch->terminate);
275
276 return 0;
277}
278
279/* Launch a thread to watch changes to FILE in a directory open on
280 handle HDIR. */
281static struct notification *
282start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
283{
284 struct notification *dirwatch = xzalloc (sizeof (struct notification));
285 HANDLE thr;
286
287 dirwatch->signature = DIRWATCH_SIGNATURE;
288 dirwatch->buf = xmalloc (16384);
289 dirwatch->io_info = xzalloc (sizeof(OVERLAPPED));
290 /* Stash a pointer to dirwatch structure for use by the completion
291 routine. According to MSDN documentation of ReadDirectoryChangesW:
292 "The hEvent member of the OVERLAPPED structure is not used by the
293 system, so you can use it yourself." */
294 dirwatch->io_info->hEvent = dirwatch;
295 dirwatch->subtree = subdirs;
296 dirwatch->filter = flags;
297 dirwatch->watchee = xstrdup (file);
298 dirwatch->terminate = 0;
299 dirwatch->dir = hdir;
300
301 /* See w32proc.c where it calls CreateThread for the story behind
302 the 2nd and 5th argument in the call to CreateThread. */
303 dirwatch->thr = CreateThread (NULL, 64 * 1024, watch_worker, (void *)dirwatch,
304 0x00010000, NULL);
305
306 if (!dirwatch->thr)
307 {
308 xfree (dirwatch->buf);
309 xfree (dirwatch->io_info);
310 xfree (dirwatch->watchee);
311 xfree (dirwatch);
312 dirwatch = NULL;
313 }
314 return dirwatch;
315}
316
317/* Called from the main thread to start watching FILE in PARENT_DIR,
318 subject to FLAGS. If SUBDIRS is TRUE, watch the subdirectories of
319 PARENT_DIR as well. Value is a pointer to 'struct notification'
320 used by the thread that watches the changes. */
321static struct notification *
322add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
323{
324 HANDLE hdir;
325 struct notification *dirwatch = NULL;
326
327 if (!file || !*file)
328 return NULL;
329
330 hdir = CreateFile (parent_dir,
331 FILE_LIST_DIRECTORY,
332 /* FILE_SHARE_DELETE doesn't preclude other
333 processes from deleting files inside
334 parent_dir. */
335 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
336 NULL, OPEN_EXISTING,
337 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
338 NULL);
339 if (hdir == INVALID_HANDLE_VALUE)
340 return NULL;
341
342 if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL)
343 CloseHandle (hdir);
344
345 return dirwatch;
346}
347
348/* Stop watching a directory specified by a pointer to its dirwatch object. */
349static int
350remove_watch (struct notification *dirwatch)
351{
352 if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE)
353 {
354 int i;
355 BOOL status;
356 DWORD exit_code, err;
357
358 /* Only the thread that issued the outstanding I/O call can call
359 CancelIo on it. (CancelIoEx is available only since Vista.)
360 So we need to queue an APC for the worker thread telling it
361 to terminate. */
362 if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir))
363 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ()));
364 /* We also set the terminate flag, for when the thread is
365 waiting on the critical section that never gets acquired.
366 FIXME: is there a cleaner method? Using SleepEx there is a
367 no-no, as that will lead to recursive APC invocations and
368 stack overflow. */
369 dirwatch->terminate = 1;
370 /* Wait for the thread to exit. FIXME: is there a better method
371 that is not overly complex? */
372 for (i = 0; i < 50; i++)
373 {
374 if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code))
375 && exit_code == STILL_ACTIVE))
376 break;
377 Sleep (10);
378 }
379 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
380 || exit_code == STILL_ACTIVE)
381 {
382 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
383 {
384 TerminateThread (dirwatch->thr, 0);
385 if (dirwatch->dir)
386 CloseHandle (dirwatch->dir);
387 }
388 }
389
390 /* Clean up. */
391 if (dirwatch->thr)
392 {
393 CloseHandle (dirwatch->thr);
394 dirwatch->thr = NULL;
395 }
396 xfree (dirwatch->buf);
397 xfree (dirwatch->io_info);
398 xfree (dirwatch->watchee);
399 xfree (dirwatch);
400
401 return 0;
402 }
403 else
404 {
405 DebPrint (("Unknown dirwatch object!\n"));
406 return -1;
407 }
408}
409
410static DWORD
411filter_list_to_flags (Lisp_Object filter_list)
412{
413 DWORD flags = 0;
414
415 if (NILP (filter_list))
416 return flags;
417
418 if (!NILP (Fmember (Qfile_name, filter_list)))
419 flags |= FILE_NOTIFY_CHANGE_FILE_NAME;
420 if (!NILP (Fmember (Qdirectory_name, filter_list)))
421 flags |= FILE_NOTIFY_CHANGE_DIR_NAME;
422 if (!NILP (Fmember (Qattributes, filter_list)))
423 flags |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
424 if (!NILP (Fmember (Qsize, filter_list)))
425 flags |= FILE_NOTIFY_CHANGE_SIZE;
426 if (!NILP (Fmember (Qlast_write_time, filter_list)))
427 flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
428 if (!NILP (Fmember (Qlast_access_time, filter_list)))
429 flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
430 if (!NILP (Fmember (Qcreation_time, filter_list)))
431 flags |= FILE_NOTIFY_CHANGE_CREATION;
432 if (!NILP (Fmember (Qsecurity_desc, filter_list)))
433 flags |= FILE_NOTIFY_CHANGE_SECURITY;
434
435 return flags;
436}
437
438DEFUN ("w32notify-add-watch", Fw32notify_add_watch,
439 Sw32notify_add_watch, 3, 3, 0,
440 doc: /* Add a watch for filesystem events pertaining to FILE.
441
442This arranges for filesystem events pertaining to FILE to be reported
443to Emacs. Use `w32notify-rm-watch' to cancel the watch.
444
445Value is a descriptor for the added watch, or nil if the file
446cannot be watched.
447
448FILTER is a list of conditions for reporting an event. It can include
449the following symbols:
450
451 'file-name' -- report file creation, deletion, or renaming
452 'directory-name' -- report directory creation, deletion, or renaming
453 'attributes' -- report changes in attributes
454 'size' -- report changes in file-size
455 'last-write-time' -- report changes in last-write time
456 'last-access-time' -- report changes in last-access time
457 'creation-time' -- report changes in creation time
458 'security-desc' -- report changes in security descriptor
459
460If FILE is a directory, and FILTER includes 'subtree', then all the
461subdirectories will also be watched and changes in them reported.
462
463When any event happens that satisfies the conditions specified by
464FILTER, Emacs will call the CALLBACK function passing it a single
465argument EVENT, which is of the form
466
467 (DESCRIPTOR ACTION FILE)
468
469DESCRIPTOR is the same object as the one returned by this function.
470ACTION is the description of the event. It could be any one of the
471following:
472
473 'added' -- FILE was added
474 'removed' -- FILE was deleted
475 'modified' -- FILE's contents or its attributes were modified
476 'renamed-from' -- a file was renamed whose old name was FILE
477 'renamed-to' -- a file was renamed and its new name is FILE
478
479FILE is the name of the file whose event is being reported. */)
480 (Lisp_Object file, Lisp_Object filter, Lisp_Object callback)
481{
482 Lisp_Object encoded_file, watch_object, watch_descriptor;
483 char parent_dir[MAX_PATH], *basename;
484 size_t fn_len;
485 DWORD flags;
486 BOOL subdirs = FALSE;
487 struct notification *dirwatch = NULL;
488 Lisp_Object lisp_errstr;
489 char *errstr;
490
491 CHECK_LIST (filter);
492
493 /* The underlying features are available only since XP. */
494 if (os_subtype == OS_9X
495 || (w32_major_version == 5 && w32_major_version < 1))
496 {
497 errno = ENOSYS;
498 report_file_error ("Watching filesystem events is not supported",
499 Qnil);
500 }
501
502 /* We need a full absolute file name of FILE, and we need to remove
503 any trailing slashes from it, so that GetFullPathName below gets
504 the basename part correctly. */
505 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
506 encoded_file = ENCODE_FILE (file);
507
508 fn_len = GetFullPathName (SDATA (encoded_file), MAX_PATH, parent_dir,
509 &basename);
510 if (!fn_len)
511 {
512 errstr = w32_strerror (0);
513 errno = EINVAL;
514 if (!NILP (Vlocale_coding_system))
515 lisp_errstr
516 = code_convert_string_norecord (build_unibyte_string (errstr),
517 Vlocale_coding_system, 0);
518 else
519 lisp_errstr = build_string (errstr);
520 report_file_error ("GetFullPathName failed",
521 Fcons (lisp_errstr, Fcons (file, Qnil)));
522 }
523 /* We need the parent directory without the slash that follows it.
524 If BASENAME is NULL, the argument was the root directory on its
525 drive. */
526 if (basename)
527 basename[-1] = '\0';
528 else
529 subdirs = TRUE;
530
531 if (!NILP (Fmember (Qsubtree, filter)))
532 subdirs = TRUE;
533
534 flags = filter_list_to_flags (filter);
535
536 dirwatch = add_watch (parent_dir, basename, subdirs, flags);
537 if (!dirwatch)
538 {
539 DWORD err = GetLastError ();
540
541 errno = EINVAL;
542 if (err)
543 {
544 errstr = w32_strerror (err);
545 if (!NILP (Vlocale_coding_system))
546 lisp_errstr
547 = code_convert_string_norecord (build_unibyte_string (errstr),
548 Vlocale_coding_system, 0);
549 else
550 lisp_errstr = build_string (errstr);
551 report_file_error ("Cannot watch file",
552 Fcons (lisp_errstr, Fcons (file, Qnil)));
553 }
554 else
555 report_file_error ("Cannot watch file", Fcons (file, Qnil));
556 }
557 /* Store watch object in watch list. */
558 watch_descriptor = XIL ((EMACS_INT)dirwatch);
559 watch_object = Fcons (watch_descriptor, callback);
560 watch_list = Fcons (watch_object, watch_list);
561
562 return watch_descriptor;
563}
564
565DEFUN ("w32notify-rm-watch", Fw32notify_rm_watch,
566 Sw32notify_rm_watch, 1, 1, 0,
567 doc: /* Remove an existing watch specified by its WATCH-DESCRIPTOR.
568
569WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */)
570 (Lisp_Object watch_descriptor)
571{
572 Lisp_Object watch_object;
573 struct notification *dirwatch;
574 int status = -1;
575
576 /* Remove the watch object from watch list. Do this before freeing
577 the object, do that even if we fail to free it, watch_list is
578 kept free of junk. */
579 watch_object = Fassoc (watch_descriptor, watch_list);
580 if (!NILP (watch_object))
581 {
582 watch_list = Fdelete (watch_object, watch_list);
583 dirwatch = (struct notification *)XLI (watch_descriptor);
584 if (w32_valid_pointer_p (dirwatch, sizeof(struct notification)))
585 status = remove_watch (dirwatch);
586 }
587
588 if (status == -1)
589 report_file_error ("Invalid watch descriptor", Fcons (watch_descriptor,
590 Qnil));
591
592 return Qnil;
593}
594
595Lisp_Object
596w32_get_watch_object (void *desc)
597{
598 Lisp_Object descriptor = XIL ((EMACS_INT)desc);
599
600 /* This is called from the input queue handling code, inside a
601 critical section, so we cannot possibly QUIT if watch_list is not
602 in the right condition. */
603 return NILP (watch_list) ? Qnil : assoc_no_quit (descriptor, watch_list);
604}
605
606void
607globals_of_w32notify (void)
608{
609 watch_list = Qnil;
610}
611
612void
613syms_of_w32notify (void)
614{
615 DEFSYM (Qfile_name, "file-name");
616 DEFSYM (Qdirectory_name, "directory-name");
617 DEFSYM (Qattributes, "attributes");
618 DEFSYM (Qsize, "size");
619 DEFSYM (Qlast_write_time, "last-write-time");
620 DEFSYM (Qlast_access_time, "last-access-time");
621 DEFSYM (Qcreation_time, "creation-time");
622 DEFSYM (Qsecurity_desc, "security-desc");
623 DEFSYM (Qsubtree, "subtree");
624
625 defsubr (&Sw32notify_add_watch);
626 defsubr (&Sw32notify_rm_watch);
627
628 staticpro (&watch_list);
629
630 Fprovide (intern_c_string ("w32notify"), Qnil);
631}
diff --git a/src/w32proc.c b/src/w32proc.c
index d888200c556..ddc6826df98 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -2018,7 +2018,24 @@ count_children:
2018 (*) Note that MsgWaitForMultipleObjects above is an 2018 (*) Note that MsgWaitForMultipleObjects above is an
2019 internal dispatch point for messages that are sent to 2019 internal dispatch point for messages that are sent to
2020 windows created by this thread. */ 2020 windows created by this thread. */
2021 drain_message_queue (); 2021 if (drain_message_queue ()
2022 /* If drain_message_queue returns non-zero, that means
2023 we received a WM_EMACS_FILENOTIFY message. If this
2024 is a TTY frame, we must signal the caller that keyboard
2025 input is available, so that w32_console_read_socket
2026 will be called to pick up the notifications. If we
2027 don't do that, file notifications will only work when
2028 the Emacs TTY frame has focus. */
2029 && FRAME_TERMCAP_P (SELECTED_FRAME ())
2030 /* they asked for stdin reads */
2031 && FD_ISSET (0, &orfds)
2032 /* the stdin handle is valid */
2033 && keyboard_handle)
2034 {
2035 FD_SET (0, rfds);
2036 if (nr == 0)
2037 nr = 1;
2038 }
2022 } 2039 }
2023 else if (active >= nh) 2040 else if (active >= nh)
2024 { 2041 {
diff --git a/src/w32term.c b/src/w32term.c
index e26777543fb..7c53097e313 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -246,6 +246,8 @@ static void x_check_font (struct frame *, struct font *);
246#endif 246#endif
247 247
248static Lisp_Object Qvendor_specific_keysyms; 248static Lisp_Object Qvendor_specific_keysyms;
249static Lisp_Object Qadded, Qremoved, Qmodified;
250static Lisp_Object Qrenamed_from, Qrenamed_to;
249 251
250 252
251/*********************************************************************** 253/***********************************************************************
@@ -3204,6 +3206,124 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
3204} 3206}
3205 3207
3206 3208
3209/* File event notifications (see w32notify.c). */
3210
3211Lisp_Object
3212lispy_file_action (DWORD action)
3213{
3214 static char unknown_fmt[] = "unknown-action(%d)";
3215 Lisp_Object retval;
3216
3217 switch (action)
3218 {
3219 case FILE_ACTION_ADDED:
3220 retval = Qadded;
3221 break;
3222 case FILE_ACTION_REMOVED:
3223 retval = Qremoved;
3224 break;
3225 case FILE_ACTION_MODIFIED:
3226 retval = Qmodified;
3227 break;
3228 case FILE_ACTION_RENAMED_OLD_NAME:
3229 retval = Qrenamed_from;
3230 break;
3231 case FILE_ACTION_RENAMED_NEW_NAME:
3232 retval = Qrenamed_to;
3233 break;
3234 default:
3235 {
3236 char buf[sizeof(unknown_fmt) - 1 + INT_STRLEN_BOUND (DWORD)];
3237
3238 sprintf (buf, unknown_fmt, action);
3239 retval = intern (buf);
3240 }
3241 break;
3242 }
3243
3244 return retval;
3245}
3246
3247#ifdef WINDOWSNT
3248/* Put file notifications into the Emacs input event queue. This
3249 function runs when the WM_EMACS_FILENOTIFY message arrives from a
3250 watcher thread. */
3251static void
3252queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f,
3253 int *evcount)
3254{
3255 BYTE *p = file_notifications;
3256 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
3257 const DWORD min_size
3258 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
3259 Lisp_Object frame;
3260
3261 /* We cannot process notification before Emacs is fully initialized,
3262 since we need the UTF-16LE coding-system to be set up. */
3263 if (!initialized)
3264 {
3265 notification_buffer_in_use = 0;
3266 return;
3267 }
3268
3269 XSETFRAME (frame, f);
3270
3271 enter_crit ();
3272 if (notification_buffer_in_use)
3273 {
3274 DWORD info_size = notifications_size;
3275 Lisp_Object cs = intern ("utf-16le");
3276 Lisp_Object obj = w32_get_watch_object (notifications_desc);
3277
3278 /* notifications_size could be zero when the buffer of
3279 notifications overflowed on the OS level, or when the
3280 directory being watched was itself deleted. Do nothing in
3281 that case. */
3282 if (info_size
3283 && !NILP (obj) && CONSP (obj))
3284 {
3285 Lisp_Object callback = XCDR (obj);
3286
3287 while (info_size >= min_size)
3288 {
3289 Lisp_Object utf_16_fn
3290 = make_unibyte_string ((char *)fni->FileName,
3291 fni->FileNameLength);
3292 /* Note: mule-conf is preloaded, so utf-16le must
3293 already be defined at this point. */
3294 Lisp_Object fname
3295 = code_convert_string_norecord (utf_16_fn, cs, 0);
3296 Lisp_Object action = lispy_file_action (fni->Action);
3297
3298 event->kind = FILE_NOTIFY_EVENT;
3299 event->code
3300 = (ptrdiff_t)XINT (XIL ((EMACS_INT)notifications_desc));
3301 event->timestamp = msg->msg.time;
3302 event->modifiers = 0;
3303 event->frame_or_window = callback;
3304 event->arg = Fcons (action, fname);
3305 kbd_buffer_store_event (event);
3306 (*evcount)++;
3307
3308 if (!fni->NextEntryOffset)
3309 break;
3310 p += fni->NextEntryOffset;
3311 fni = (PFILE_NOTIFY_INFORMATION)p;
3312 info_size -= fni->NextEntryOffset;
3313 }
3314 }
3315 notification_buffer_in_use = 0;
3316 }
3317 else
3318 DebPrint (("We were promised notifications, but in-use flag is zero!\n"));
3319 leave_crit ();
3320
3321 /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */
3322 event->kind = NO_EVENT;
3323}
3324#endif
3325
3326
3207/* Function to report a mouse movement to the mainstream Emacs code. 3327/* Function to report a mouse movement to the mainstream Emacs code.
3208 The input handler calls this. 3328 The input handler calls this.
3209 3329
@@ -4836,6 +4956,14 @@ w32_read_socket (struct terminal *terminal,
4836 check_visibility = 1; 4956 check_visibility = 1;
4837 break; 4957 break;
4838 4958
4959#ifdef WINDOWSNT
4960 case WM_EMACS_FILENOTIFY:
4961 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4962 if (f)
4963 queue_notifications (&inev, &msg, f, &count);
4964 break;
4965#endif
4966
4839 default: 4967 default:
4840 /* Check for messages registered at runtime. */ 4968 /* Check for messages registered at runtime. */
4841 if (msg.msg.message == msh_mousewheel) 4969 if (msg.msg.message == msh_mousewheel)
@@ -6503,6 +6631,12 @@ syms_of_w32term (void)
6503 6631
6504 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); 6632 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
6505 6633
6634 DEFSYM (Qadded, "added");
6635 DEFSYM (Qremoved, "removed");
6636 DEFSYM (Qmodified, "modified");
6637 DEFSYM (Qrenamed_from, "renamed-from");
6638 DEFSYM (Qrenamed_to, "renamed-to");
6639
6506 DEFVAR_INT ("w32-num-mouse-buttons", 6640 DEFVAR_INT ("w32-num-mouse-buttons",
6507 w32_num_mouse_buttons, 6641 w32_num_mouse_buttons,
6508 doc: /* Number of physical mouse buttons. */); 6642 doc: /* Number of physical mouse buttons. */);
diff --git a/src/w32term.h b/src/w32term.h
index af1a79e21c9..35842e60c16 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -602,7 +602,8 @@ do { \
602#define WM_EMACS_PAINT (WM_EMACS_START + 20) 602#define WM_EMACS_PAINT (WM_EMACS_START + 20)
603#define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 21) 603#define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 21)
604#define WM_EMACS_INPUT_READY (WM_EMACS_START + 22) 604#define WM_EMACS_INPUT_READY (WM_EMACS_START + 22)
605#define WM_EMACS_END (WM_EMACS_START + 23) 605#define WM_EMACS_FILENOTIFY (WM_EMACS_START + 23)
606#define WM_EMACS_END (WM_EMACS_START + 24)
606 607
607#define WND_FONTWIDTH_INDEX (0) 608#define WND_FONTWIDTH_INDEX (0)
608#define WND_LINEHEIGHT_INDEX (4) 609#define WND_LINEHEIGHT_INDEX (4)
@@ -652,7 +653,7 @@ extern void deselect_palette (struct frame * f, HDC hdc);
652extern HDC get_frame_dc (struct frame * f); 653extern HDC get_frame_dc (struct frame * f);
653extern int release_frame_dc (struct frame * f, HDC hDC); 654extern int release_frame_dc (struct frame * f, HDC hDC);
654 655
655extern void drain_message_queue (void); 656extern int drain_message_queue (void);
656 657
657extern BOOL get_next_msg (W32Msg *, BOOL); 658extern BOOL get_next_msg (W32Msg *, BOOL);
658extern BOOL post_msg (W32Msg *); 659extern BOOL post_msg (W32Msg *);
@@ -662,10 +663,17 @@ extern BOOL parse_button (int, int, int *, int *);
662 663
663extern void w32_sys_ring_bell (struct frame *f); 664extern void w32_sys_ring_bell (struct frame *f);
664extern void x_delete_display (struct w32_display_info *dpyinfo); 665extern void x_delete_display (struct w32_display_info *dpyinfo);
666
667extern volatile int notification_buffer_in_use;
668extern BYTE file_notifications[16384];
669extern DWORD notifications_size;
670extern void *notifications_desc;
671extern Lisp_Object w32_get_watch_object (void *);
672extern Lisp_Object lispy_file_action (DWORD);
673
665extern void w32_initialize_display_info (Lisp_Object); 674extern void w32_initialize_display_info (Lisp_Object);
666extern void initialize_w32_display (struct terminal *); 675extern void initialize_w32_display (struct terminal *);
667 676
668
669/* Keypad command key support. W32 doesn't have virtual keys defined 677/* Keypad command key support. W32 doesn't have virtual keys defined
670 for the function keys on the keypad (they are mapped to the standard 678 for the function keys on the keypad (they are mapped to the standard
671 function keys), so we define our own. */ 679 function keys), so we define our own. */
@@ -759,6 +767,7 @@ extern void syms_of_w32fns (void);
759 767
760extern void globals_of_w32menu (void); 768extern void globals_of_w32menu (void);
761extern void globals_of_w32fns (void); 769extern void globals_of_w32fns (void);
770extern void globals_of_w32notify (void);
762 771
763#ifdef CYGWIN 772#ifdef CYGWIN
764extern int w32_message_fd; 773extern int w32_message_fd;
diff --git a/src/w32xfns.c b/src/w32xfns.c
index cb452571665..8820edda6c2 100644
--- a/src/w32xfns.c
+++ b/src/w32xfns.c
@@ -315,16 +315,22 @@ prepend_msg (W32Msg *lpmsg)
315 return (TRUE); 315 return (TRUE);
316} 316}
317 317
318/* Process all messages in the current thread's queue. */ 318/* Process all messages in the current thread's queue. Value is 1 if
319void 319 one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */
320int
320drain_message_queue (void) 321drain_message_queue (void)
321{ 322{
322 MSG msg; 323 MSG msg;
324 int retval = 0;
325
323 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) 326 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
324 { 327 {
328 if (msg.message == WM_EMACS_FILENOTIFY)
329 retval = 1;
325 TranslateMessage (&msg); 330 TranslateMessage (&msg);
326 DispatchMessage (&msg); 331 DispatchMessage (&msg);
327 } 332 }
333 return retval;
328} 334}
329 335
330/* x_sync is a no-op on W32. */ 336/* x_sync is a no-op on W32. */
diff --git a/src/window.c b/src/window.c
index 0340044ca21..4631a898d3e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -271,6 +271,35 @@ decode_valid_window (register Lisp_Object window)
271 return w; 271 return w;
272} 272}
273 273
274/* Called when W's buffer slot is changed. ARG -1 means that W is about to
275 cease its buffer, and 1 means that W is about to set up the new one. */
276
277static void
278adjust_window_count (struct window *w, int arg)
279{
280 eassert (eabs (arg) == 1);
281 if (BUFFERP (w->buffer))
282 {
283 struct buffer *b = XBUFFER (w->buffer);
284
285 if (b->base_buffer)
286 b = b->base_buffer;
287 b->window_count += arg;
288 eassert (b->window_count >= 0);
289 }
290}
291
292/* Set W's buffer slot to VAL and recompute number
293 of windows showing VAL if it is a buffer. */
294
295void
296wset_buffer (struct window *w, Lisp_Object val)
297{
298 adjust_window_count (w, -1);
299 w->buffer = val;
300 adjust_window_count (w, 1);
301}
302
274/* Build a frequently used 4-integer (X Y W H) list. */ 303/* Build a frequently used 4-integer (X Y W H) list. */
275 304
276static Lisp_Object 305static Lisp_Object
@@ -1464,6 +1493,7 @@ if it isn't already recorded. */)
1464 && !noninteractive) 1493 && !noninteractive)
1465 { 1494 {
1466 struct text_pos startp; 1495 struct text_pos startp;
1496 ptrdiff_t charpos = marker_position (w->start);
1467 struct it it; 1497 struct it it;
1468 struct buffer *old_buffer = NULL; 1498 struct buffer *old_buffer = NULL;
1469 void *itdata = NULL; 1499 void *itdata = NULL;
@@ -1481,9 +1511,9 @@ if it isn't already recorded. */)
1481 `-l' containing a call to `rmail' with subsequent other 1511 `-l' containing a call to `rmail' with subsequent other
1482 commands. At the end, W->start happened to be BEG, while 1512 commands. At the end, W->start happened to be BEG, while
1483 rmail had already narrowed the buffer. */ 1513 rmail had already narrowed the buffer. */
1484 if (XMARKER (w->start)->charpos < BEGV) 1514 if (charpos < BEGV)
1485 SET_TEXT_POS (startp, BEGV, BEGV_BYTE); 1515 SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
1486 else if (XMARKER (w->start)->charpos > ZV) 1516 else if (charpos > ZV)
1487 SET_TEXT_POS (startp, ZV, ZV_BYTE); 1517 SET_TEXT_POS (startp, ZV, ZV_BYTE);
1488 else 1518 else
1489 SET_TEXT_POS_FROM_MARKER (startp, w->start); 1519 SET_TEXT_POS_FROM_MARKER (startp, w->start);
@@ -1606,7 +1636,7 @@ display row, and VPOS is the row number (0-based) containing POS. */)
1606 else if (w == XWINDOW (selected_window)) 1636 else if (w == XWINDOW (selected_window))
1607 posint = PT; 1637 posint = PT;
1608 else 1638 else
1609 posint = XMARKER (w->pointm)->charpos; 1639 posint = marker_position (w->pointm);
1610 1640
1611 /* If position is above window start or outside buffer boundaries, 1641 /* If position is above window start or outside buffer boundaries,
1612 or if window start is out of range, position is not visible. */ 1642 or if window start is out of range, position is not visible. */
@@ -1952,7 +1982,7 @@ unshow_buffer (register struct window *w)
1952 && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->buffer))) 1982 && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->buffer)))
1953 temp_set_point_both (b, 1983 temp_set_point_both (b,
1954 clip_to_bounds (BUF_BEGV (b), 1984 clip_to_bounds (BUF_BEGV (b),
1955 XMARKER (w->pointm)->charpos, 1985 marker_position (w->pointm),
1956 BUF_ZV (b)), 1986 BUF_ZV (b)),
1957 clip_to_bounds (BUF_BEGV_BYTE (b), 1987 clip_to_bounds (BUF_BEGV_BYTE (b),
1958 marker_byte_position (w->pointm), 1988 marker_byte_position (w->pointm),
@@ -2959,22 +2989,24 @@ replace_buffer_in_windows (Lisp_Object buffer)
2959 call1 (Qreplace_buffer_in_windows, buffer); 2989 call1 (Qreplace_buffer_in_windows, buffer);
2960} 2990}
2961 2991
2962 2992/* If BUFFER is shown in a window, safely replace it with some other
2963/* Safely replace BUFFER with some other buffer in all windows of all 2993 buffer in all windows of all frames, even those on other keyboards. */
2964 frames, even those on other keyboards. */
2965 2994
2966void 2995void
2967replace_buffer_in_windows_safely (Lisp_Object buffer) 2996replace_buffer_in_windows_safely (Lisp_Object buffer)
2968{ 2997{
2969 Lisp_Object tail, frame; 2998 if (buffer_window_count (XBUFFER (buffer)))
2999 {
3000 Lisp_Object tail, frame;
2970 3001
2971 /* A single call to window_loop won't do the job because it only 3002 /* A single call to window_loop won't do the job because it only
2972 considers frames on the current keyboard. So loop manually over 3003 considers frames on the current keyboard. So loop manually over
2973 frames, and handle each one. */ 3004 frames, and handle each one. */
2974 FOR_EACH_FRAME (tail, frame) 3005 FOR_EACH_FRAME (tail, frame)
2975 window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame); 3006 window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
3007 }
2976} 3008}
2977 3009
2978/* If *ROWS or *COLS are too small a size for FRAME, set them to the 3010/* If *ROWS or *COLS are too small a size for FRAME, set them to the
2979 minimum allowable size. */ 3011 minimum allowable size. */
2980 3012
@@ -3309,11 +3341,11 @@ displaying that buffer. */)
3309 3341
3310 if (STRINGP (object)) 3342 if (STRINGP (object))
3311 object = Fget_buffer (object); 3343 object = Fget_buffer (object);
3312 if (BUFFERP (object) && BUFFER_LIVE_P (XBUFFER (object))) 3344 if (BUFFERP (object) && BUFFER_LIVE_P (XBUFFER (object))
3345 && buffer_window_count (XBUFFER (object)))
3313 { 3346 {
3314 /* Walk all windows looking for buffer, and force update 3347 /* If buffer is live and shown in at least one window, find
3315 of each of those windows. */ 3348 all windows showing this buffer and force update of them. */
3316
3317 object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible); 3349 object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
3318 return NILP (object) ? Qnil : Qt; 3350 return NILP (object) ? Qnil : Qt;
3319 } 3351 }
@@ -3392,6 +3424,8 @@ make_parent_window (Lisp_Object window, int horflag)
3392 memcpy ((char *) p + sizeof (struct vectorlike_header), 3424 memcpy ((char *) p + sizeof (struct vectorlike_header),
3393 (char *) o + sizeof (struct vectorlike_header), 3425 (char *) o + sizeof (struct vectorlike_header),
3394 word_size * VECSIZE (struct window)); 3426 word_size * VECSIZE (struct window));
3427 /* P's buffer slot may change from nil to a buffer. */
3428 adjust_window_count (p, 1);
3395 XSETWINDOW (parent, p); 3429 XSETWINDOW (parent, p);
3396 3430
3397 p->sequence_number = ++sequence_number; 3431 p->sequence_number = ++sequence_number;
@@ -4589,7 +4623,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
4589 /* Set the window start, and set up the window for redisplay. */ 4623 /* Set the window start, and set up the window for redisplay. */
4590 set_marker_restricted (w->start, make_number (pos), 4624 set_marker_restricted (w->start, make_number (pos),
4591 w->buffer); 4625 w->buffer);
4592 bytepos = XMARKER (w->start)->bytepos; 4626 bytepos = marker_byte_position (w->start);
4593 w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n'); 4627 w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n');
4594 w->update_mode_line = 1; 4628 w->update_mode_line = 1;
4595 w->last_modified = 0; 4629 w->last_modified = 0;
@@ -5089,6 +5123,7 @@ displayed_window_lines (struct window *w)
5089{ 5123{
5090 struct it it; 5124 struct it it;
5091 struct text_pos start; 5125 struct text_pos start;
5126 ptrdiff_t charpos = marker_position (w->start);
5092 int height = window_box_height (w); 5127 int height = window_box_height (w);
5093 struct buffer *old_buffer; 5128 struct buffer *old_buffer;
5094 int bottom_y; 5129 int bottom_y;
@@ -5105,9 +5140,9 @@ displayed_window_lines (struct window *w)
5105 /* In case W->start is out of the accessible range, do something 5140 /* In case W->start is out of the accessible range, do something
5106 reasonable. This happens in Info mode when Info-scroll-down 5141 reasonable. This happens in Info mode when Info-scroll-down
5107 calls (recenter -1) while W->start is 1. */ 5142 calls (recenter -1) while W->start is 1. */
5108 if (XMARKER (w->start)->charpos < BEGV) 5143 if (charpos < BEGV)
5109 SET_TEXT_POS (start, BEGV, BEGV_BYTE); 5144 SET_TEXT_POS (start, BEGV, BEGV_BYTE);
5110 else if (XMARKER (w->start)->charpos > ZV) 5145 else if (charpos > ZV)
5111 SET_TEXT_POS (start, ZV, ZV_BYTE); 5146 SET_TEXT_POS (start, ZV, ZV_BYTE);
5112 else 5147 else
5113 SET_TEXT_POS_FROM_MARKER (start, w->start); 5148 SET_TEXT_POS_FROM_MARKER (start, w->start);
@@ -5535,7 +5570,7 @@ the return value is nil. Otherwise the value is t. */)
5535 && WINDOWP (selected_window) 5570 && WINDOWP (selected_window)
5536 && EQ (XWINDOW (selected_window)->buffer, new_current_buffer) 5571 && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
5537 && !EQ (selected_window, data->current_window)) 5572 && !EQ (selected_window, data->current_window))
5538 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos; 5573 old_point = marker_position (XWINDOW (data->current_window)->pointm);
5539 else 5574 else
5540 old_point = PT; 5575 old_point = PT;
5541 else 5576 else
@@ -5550,7 +5585,7 @@ the return value is nil. Otherwise the value is t. */)
5550 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer) 5585 if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
5551 /* If current_window = selected_window, its point is in BUF_PT. */ 5586 /* If current_window = selected_window, its point is in BUF_PT. */
5552 && !EQ (selected_window, data->current_window)) 5587 && !EQ (selected_window, data->current_window))
5553 old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos; 5588 old_point = marker_position (XWINDOW (data->current_window)->pointm);
5554 else 5589 else
5555 old_point = BUF_PT (XBUFFER (new_current_buffer)); 5590 old_point = BUF_PT (XBUFFER (new_current_buffer));
5556 } 5591 }
diff --git a/src/window.h b/src/window.h
index 2a12226c0aa..f4f42a25af4 100644
--- a/src/window.h
+++ b/src/window.h
@@ -351,11 +351,6 @@ struct window
351/* Most code should use these functions to set Lisp fields in struct 351/* Most code should use these functions to set Lisp fields in struct
352 window. */ 352 window. */
353WINDOW_INLINE void 353WINDOW_INLINE void
354wset_buffer (struct window *w, Lisp_Object val)
355{
356 w->buffer = val;
357}
358WINDOW_INLINE void
359wset_frame (struct window *w, Lisp_Object val) 354wset_frame (struct window *w, Lisp_Object val)
360{ 355{
361 w->frame = val; 356 w->frame = val;
@@ -947,11 +942,6 @@ extern int windows_or_buffers_changed;
947 942
948extern int cursor_type_changed; 943extern int cursor_type_changed;
949 944
950/* Number of windows displaying the selected buffer. Normally this is
951 1, but it can be more. */
952
953extern int buffer_shared;
954
955/* If *ROWS or *COLS are too small a size for FRAME, set them to the 945/* If *ROWS or *COLS are too small a size for FRAME, set them to the
956 minimum allowable size. */ 946 minimum allowable size. */
957 947
@@ -997,6 +987,8 @@ extern int window_body_cols (struct window *w);
997extern void temp_output_buffer_show (Lisp_Object); 987extern void temp_output_buffer_show (Lisp_Object);
998extern void replace_buffer_in_windows (Lisp_Object); 988extern void replace_buffer_in_windows (Lisp_Object);
999extern void replace_buffer_in_windows_safely (Lisp_Object); 989extern void replace_buffer_in_windows_safely (Lisp_Object);
990/* This looks like a setter, but it is a bit special. */
991extern void wset_buffer (struct window *, Lisp_Object);
1000extern void init_window_once (void); 992extern void init_window_once (void);
1001extern void init_window (void); 993extern void init_window (void);
1002extern void syms_of_window (void); 994extern void syms_of_window (void);
diff --git a/src/xdisp.c b/src/xdisp.c
index e1b12b8464c..ccd0bb07487 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -517,11 +517,6 @@ Lisp_Object Qmenu_bar_update_hook;
517 517
518static int overlay_arrow_seen; 518static int overlay_arrow_seen;
519 519
520/* Number of windows showing the buffer of the selected
521 window (or another buffer with the same base buffer). */
522
523int buffer_shared;
524
525/* Vector containing glyphs for an ellipsis `...'. */ 520/* Vector containing glyphs for an ellipsis `...'. */
526 521
527static Lisp_Object default_invis_vector[3]; 522static Lisp_Object default_invis_vector[3];
@@ -9554,7 +9549,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
9554 del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0); 9549 del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0);
9555 } 9550 }
9556 } 9551 }
9557 BEGV = XMARKER (oldbegv)->charpos; 9552 BEGV = marker_position (oldbegv);
9558 BEGV_BYTE = marker_byte_position (oldbegv); 9553 BEGV_BYTE = marker_byte_position (oldbegv);
9559 9554
9560 if (zv_at_end) 9555 if (zv_at_end)
@@ -9564,7 +9559,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
9564 } 9559 }
9565 else 9560 else
9566 { 9561 {
9567 ZV = XMARKER (oldzv)->charpos; 9562 ZV = marker_position (oldzv);
9568 ZV_BYTE = marker_byte_position (oldzv); 9563 ZV_BYTE = marker_byte_position (oldzv);
9569 } 9564 }
9570 9565
@@ -9573,8 +9568,8 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
9573 else 9568 else
9574 /* We can't do Fgoto_char (oldpoint) because it will run some 9569 /* We can't do Fgoto_char (oldpoint) because it will run some
9575 Lisp code. */ 9570 Lisp code. */
9576 TEMP_SET_PT_BOTH (XMARKER (oldpoint)->charpos, 9571 TEMP_SET_PT_BOTH (marker_position (oldpoint),
9577 XMARKER (oldpoint)->bytepos); 9572 marker_byte_position (oldpoint));
9578 9573
9579 UNGCPRO; 9574 UNGCPRO;
9580 unchain_marker (XMARKER (oldpoint)); 9575 unchain_marker (XMARKER (oldpoint));
@@ -10146,8 +10141,8 @@ with_echo_area_buffer_unwind_data (struct window *w)
10146 { 10141 {
10147 XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i; 10142 XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i;
10148 ASET (vector, i, w->buffer); ++i; 10143 ASET (vector, i, w->buffer); ++i;
10149 ASET (vector, i, make_number (XMARKER (w->pointm)->charpos)); ++i; 10144 ASET (vector, i, make_number (marker_position (w->pointm))); ++i;
10150 ASET (vector, i, make_number (XMARKER (w->pointm)->bytepos)); ++i; 10145 ASET (vector, i, make_number (marker_byte_position (w->pointm))); ++i;
10151 } 10146 }
10152 else 10147 else
10153 { 10148 {
@@ -10948,9 +10943,8 @@ echo_area_display (int update_frame_p)
10948static int 10943static int
10949buffer_shared_and_changed (void) 10944buffer_shared_and_changed (void)
10950{ 10945{
10951 /* The variable buffer_shared is set in redisplay_window and 10946 return (buffer_window_count (current_buffer) > 1
10952 indicates that we redisplay a buffer in different windows. */ 10947 && UNCHANGED_MODIFIED < MODIFF);
10953 return (buffer_shared > 1 && UNCHANGED_MODIFIED < MODIFF);
10954} 10948}
10955 10949
10956/* Nonzero if W doesn't reflect the actual state of current buffer due 10950/* Nonzero if W doesn't reflect the actual state of current buffer due
@@ -13531,10 +13525,6 @@ redisplay_internal (void)
13531 FOR_EACH_FRAME (tail, frame) 13525 FOR_EACH_FRAME (tail, frame)
13532 XFRAME (frame)->updated_p = 0; 13526 XFRAME (frame)->updated_p = 0;
13533 13527
13534 /* Recompute # windows showing selected buffer. This will be
13535 incremented each time such a window is displayed. */
13536 buffer_shared = 0;
13537
13538 FOR_EACH_FRAME (tail, frame) 13528 FOR_EACH_FRAME (tail, frame)
13539 { 13529 {
13540 struct frame *f = XFRAME (frame); 13530 struct frame *f = XFRAME (frame);
@@ -13872,7 +13862,7 @@ mark_window_display_accurate_1 (struct window *w, int accurate_p)
13872 if (w == XWINDOW (selected_window)) 13862 if (w == XWINDOW (selected_window))
13873 w->last_point = BUF_PT (b); 13863 w->last_point = BUF_PT (b);
13874 else 13864 else
13875 w->last_point = XMARKER (w->pointm)->charpos; 13865 w->last_point = marker_position (w->pointm);
13876 } 13866 }
13877 } 13867 }
13878 13868
@@ -15629,26 +15619,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
15629 if (mode_line_update_needed (w)) 15619 if (mode_line_update_needed (w))
15630 update_mode_line = 1; 15620 update_mode_line = 1;
15631 15621
15632 /* Count number of windows showing the selected buffer. An indirect
15633 buffer counts as its base buffer. */
15634 if (!just_this_one_p)
15635 {
15636 struct buffer *current_base, *window_base;
15637 current_base = current_buffer;
15638 window_base = XBUFFER (XWINDOW (selected_window)->buffer);
15639 if (current_base->base_buffer)
15640 current_base = current_base->base_buffer;
15641 if (window_base->base_buffer)
15642 window_base = window_base->base_buffer;
15643 if (current_base == window_base)
15644 buffer_shared++;
15645 }
15646
15647 /* Point refers normally to the selected window. For any other 15622 /* Point refers normally to the selected window. For any other
15648 window, set up appropriate value. */ 15623 window, set up appropriate value. */
15649 if (!EQ (window, selected_window)) 15624 if (!EQ (window, selected_window))
15650 { 15625 {
15651 ptrdiff_t new_pt = XMARKER (w->pointm)->charpos; 15626 ptrdiff_t new_pt = marker_position (w->pointm);
15652 ptrdiff_t new_pt_byte = marker_byte_position (w->pointm); 15627 ptrdiff_t new_pt_byte = marker_byte_position (w->pointm);
15653 if (new_pt < BEGV) 15628 if (new_pt < BEGV)
15654 { 15629 {
@@ -21656,7 +21631,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
21656 if (mode_line_target == MODE_LINE_TITLE) 21631 if (mode_line_target == MODE_LINE_TITLE)
21657 return ""; 21632 return "";
21658 21633
21659 startpos = XMARKER (w->start)->charpos; 21634 startpos = marker_position (w->start);
21660 startpos_byte = marker_byte_position (w->start); 21635 startpos_byte = marker_byte_position (w->start);
21661 height = WINDOW_TOTAL_LINES (w); 21636 height = WINDOW_TOTAL_LINES (w);
21662 21637
diff --git a/test/ChangeLog b/test/ChangeLog
index 21f0f29b73b..142dfcb42fd 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,11 @@
12012-12-11 Glenn Morris <rgm@gnu.org>
2
3 * automated/f90.el (f90-test-bug13138): New test.
4
52012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
6
7 * automated/inotify-test.el: New test.
8
12012-12-02 Chong Yidong <cyd@gnu.org> 92012-12-02 Chong Yidong <cyd@gnu.org>
2 10
3 * automated/ruby-mode-tests.el 11 * automated/ruby-mode-tests.el
diff --git a/test/automated/f90.el b/test/automated/f90.el
index 25b77f07ad3..7f412568ae3 100644
--- a/test/automated/f90.el
+++ b/test/automated/f90.el
@@ -154,5 +154,23 @@ end module modname")
154 (f90-indent-line) 154 (f90-indent-line)
155 (should (= 0 (current-indentation))))) 155 (should (= 0 (current-indentation)))))
156 156
157(ert-deftest f90-test-bug13138 ()
158 "Test for http://debbugs.gnu.org/13138 ."
159 (with-temp-buffer
160 (f90-mode)
161 (insert "program prog
162 integer :: i = &
163#ifdef foo
164 & 1
165#else
166 & 2
167#endif
168
169 write(*,*) i
170end program prog")
171 (goto-char (point-min))
172 (forward-line 2)
173 (f90-indent-subprogram)
174 (should (= 0 (current-indentation)))))
157 175
158;;; f90.el ends here 176;;; f90.el ends here
diff --git a/test/automated/inotify-test.el b/test/automated/inotify-test.el
new file mode 100644
index 00000000000..edda7ef0418
--- /dev/null
+++ b/test/automated/inotify-test.el
@@ -0,0 +1,60 @@
1;;; inotify-tests.el --- Test suite for inotify. -*- lexical-binding: t -*-
2
3;; Copyright (C) 2012 Free Software Foundation, Inc.
4
5;; Author: Rüdiger Sonderfeld <ruediger@c-plusplus.de>
6;; Keywords: internal
7;; Human-Keywords: internal
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software: you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23
24;;; Code:
25
26(require 'ert)
27
28(when (featurep 'inotify)
29
30 ;; (ert-deftest filewatch-file-watch-aspects-check ()
31 ;; "Test whether `file-watch' properly checks the aspects."
32 ;; (let ((temp-file (make-temp-file "filewatch-aspects")))
33 ;; (should (stringp temp-file))
34 ;; (should-error (file-watch temp-file 'wrong nil)
35 ;; :type 'error)
36 ;; (should-error (file-watch temp-file '(modify t) nil)
37 ;; :type 'error)
38 ;; (should-error (file-watch temp-file '(modify all-modify) nil)
39 ;; :type 'error)
40 ;; (should-error (file-watch temp-file '(access wrong modify) nil)
41 ;; :type 'error)))
42
43 (ert-deftest inotify-file-watch-simple ()
44 "Test if watching a normal file works."
45 (let ((temp-file (make-temp-file "inotify-simple"))
46 (events 0))
47 (let ((wd
48 (inotify-add-watch temp-file t (lambda (ev)
49 (setq events (1+ events))))))
50 (unwind-protect
51 (progn
52 (with-temp-file temp-file
53 (insert "Foo\n"))
54 (sit-for 5) ;; Hacky. Wait for 5s until events are processed
55 (should (> events 0)))
56 (inotify-rm-watch wd)))))
57)
58
59(provide 'inotify-tests)
60;;; inotify-tests.el ends here.