diff options
| author | Joakim Verona | 2012-12-11 12:02:20 +0100 |
|---|---|---|
| committer | Joakim Verona | 2012-12-11 12:02:20 +0100 |
| commit | 5ccd4f20470d8e216ca3eae26339100a5eab52f1 (patch) | |
| tree | 70caca485fbaef0dcce16a811908c4b9b121ee1e | |
| parent | c0b95835acf65071ac1d740d15f7bcaa55c2a04b (diff) | |
| parent | c6afe371b0218154957bbef17c3f8bda5377b7c8 (diff) | |
| download | emacs-5ccd4f20470d8e216ca3eae26339100a5eab52f1.tar.gz emacs-5ccd4f20470d8e216ca3eae26339100a5eab52f1.zip | |
some conflict resolution
49 files changed, 2209 insertions, 203 deletions
| @@ -1,3 +1,27 @@ | |||
| 1 | 2012-12-11 Juanma Barranquero <lekktu@gmail.com> | ||
| 2 | |||
| 3 | * lib/makefile.w32-in (SIG2STR_H): New macro. | ||
| 4 | ($(BLD)/sig2str.$(O)): Update dependencies. | ||
| 5 | |||
| 6 | 2012-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 | |||
| 12 | 2012-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 | |||
| 20 | 2012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de> | ||
| 21 | |||
| 22 | * configure.ac (inotify): New option. | ||
| 23 | (HAVE_INOTIFY): Test for inotify. | ||
| 24 | |||
| 1 | 2012-12-09 Andreas Schwab <schwab@linux-m68k.org> | 25 | 2012-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]) | |||
| 185 | OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) | 185 | OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) |
| 186 | OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) | 186 | OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) |
| 187 | OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) | 187 | OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) |
| 188 | OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support]) | ||
| 188 | 189 | ||
| 189 | OPTION_DEFAULT_OFF([xwidgets],[enable use of some gtk widgets it Emacs buffers]) | 190 | OPTION_DEFAULT_OFF([xwidgets],[enable use of some gtk widgets it Emacs buffers]) |
| 190 | 191 | ||
| @@ -1607,6 +1608,8 @@ AC_SUBST(LIB_STANDARD) | |||
| 1607 | HAVE_W32=no | 1608 | HAVE_W32=no |
| 1608 | W32_OBJ= | 1609 | W32_OBJ= |
| 1609 | W32_LIBS= | 1610 | W32_LIBS= |
| 1611 | W32_RES= | ||
| 1612 | W32_RES_LINK= | ||
| 1610 | if test "${with_w32}" != no; then | 1613 | if 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" | ||
| 1622 | fi | 1631 | fi |
| 1623 | AC_SUBST(W32_OBJ) | 1632 | AC_SUBST(W32_OBJ) |
| 1624 | AC_SUBST(W32_LIBS) | 1633 | AC_SUBST(W32_LIBS) |
| 1634 | AC_SUBST(W32_RES) | ||
| 1635 | AC_SUBST(W32_RES_LINK) | ||
| 1625 | 1636 | ||
| 1626 | if test "${HAVE_W32}" = "yes"; then | 1637 | if test "${HAVE_W32}" = "yes"; then |
| 1627 | window_system=w32 | 1638 | window_system=w32 |
| @@ -2236,6 +2247,17 @@ fi | |||
| 2236 | AC_SUBST(LIBGNUTLS_LIBS) | 2247 | AC_SUBST(LIBGNUTLS_LIBS) |
| 2237 | AC_SUBST(LIBGNUTLS_CFLAGS) | 2248 | AC_SUBST(LIBGNUTLS_CFLAGS) |
| 2238 | 2249 | ||
| 2250 | dnl inotify is only available on GNU/Linux. | ||
| 2251 | if 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 | ||
| 2256 | fi | ||
| 2257 | if test "$ac_cv_func_inotify_init1" = yes; then | ||
| 2258 | AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.]) | ||
| 2259 | fi | ||
| 2260 | |||
| 2239 | dnl Do not put whitespace before the #include statements below. | 2261 | dnl Do not put whitespace before the #include statements below. |
| 2240 | dnl Older compilers (eg sunos4 cc) choke on it. | 2262 | dnl Older compilers (eg sunos4 cc) choke on it. |
| 2241 | HAVE_XAW3D=no | 2263 | HAVE_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 @@ | |||
| 1 | 2012-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 | |||
| 1 | 2012-12-10 Stefan Monnier <monnier@iro.umontreal.ca> | 7 | 2012-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 | |||
| 1539 | Here are some guidelines for use of integer types in the Emacs C | ||
| 1540 | source code. These guidelines sometimes give competing advice; common | ||
| 1541 | sense is advised. | ||
| 1542 | |||
| 1543 | @itemize @bullet | ||
| 1544 | @item | ||
| 1545 | Avoid arbitrary limits. For example, avoid @code{int len = strlen | ||
| 1546 | (s);} unless the length of @code{s} is required for other reasons to | ||
| 1547 | fit in @code{int} range. | ||
| 1548 | |||
| 1549 | @item | ||
| 1550 | Do not assume that signed integer arithmetic wraps around on overflow. | ||
| 1551 | This is no longer true of Emacs porting targets: signed integer | ||
| 1552 | overflow has undefined behavior in practice, and can dump core or | ||
| 1553 | even cause earlier or later code to behave ``illogically''. Unsigned | ||
| 1554 | overflow does wrap around reliably, modulo a power of two. | ||
| 1555 | |||
| 1556 | @item | ||
| 1557 | Prefer signed types to unsigned, as code gets confusing when signed | ||
| 1558 | and unsigned types are combined. Many other guidelines assume that | ||
| 1559 | types are signed; in the rarer cases where unsigned types are needed, | ||
| 1560 | similar advice may apply to the unsigned counterparts (e.g., | ||
| 1561 | @code{size_t} instead of @code{ptrdiff_t}, or @code{uintptr_t} instead | ||
| 1562 | of @code{intptr_t}). | ||
| 1563 | |||
| 1564 | @item | ||
| 1565 | Prefer @code{int} for Emacs character codes, in the range 0 ..@: 0x3FFFFF. | ||
| 1566 | |||
| 1567 | @item | ||
| 1568 | Prefer @code{ptrdiff_t} for sizes, i.e., for integers bounded by the | ||
| 1569 | maximum size of any individual C object or by the maximum number of | ||
| 1570 | elements in any C array. This is part of Emacs's general preference | ||
| 1571 | for signed types. Using @code{ptrdiff_t} limits objects to | ||
| 1572 | @code{PTRDIFF_MAX} bytes, but larger objects would cause trouble | ||
| 1573 | anyway since they would break pointer subtraction, so this does not | ||
| 1574 | impose an arbitrary limit. | ||
| 1575 | |||
| 1576 | @item | ||
| 1577 | Prefer @code{intptr_t} for internal representations of pointers, or | ||
| 1578 | for integers bounded only by the number of objects that can exist at | ||
| 1579 | any given time or by the total number of bytes that can be allocated. | ||
| 1580 | Currently Emacs sometimes uses other types when @code{intptr_t} would | ||
| 1581 | be better; fixing this is lower priority, as the code works as-is on | ||
| 1582 | Emacs's current porting targets. | ||
| 1583 | |||
| 1584 | @item | ||
| 1585 | Prefer the Emacs-defined type @code{EMACS_INT} for representing values | ||
| 1586 | converted to or from Emacs Lisp fixnums, as fixnum arithmetic is based | ||
| 1587 | on @code{EMACS_INT}. | ||
| 1588 | |||
| 1589 | @item | ||
| 1590 | When representing a system value (such as a file size or a count of | ||
| 1591 | seconds 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 | ||
| 1593 | signed, unless this assumption is known to be safe. For example, | ||
| 1594 | although @code{off_t} is always signed, @code{time_t} need not be. | ||
| 1595 | |||
| 1596 | @item | ||
| 1597 | Prefer the Emacs-defined type @code{printmax_t} for representing | ||
| 1598 | values that might be any signed integer value that can be printed, | ||
| 1599 | using a @code{printf}-family function. | ||
| 1600 | |||
| 1601 | @item | ||
| 1602 | Prefer @code{intmax_t} for representing values that might be any | ||
| 1603 | signed integer value. | ||
| 1604 | |||
| 1605 | @item | ||
| 1606 | In bitfields, prefer @code{unsigned int} or @code{signed int} to | ||
| 1607 | @code{int}, as @code{int} is less portable: it might be signed, and | ||
| 1608 | might not be. Single-bit bit fields are invariably @code{unsigned | ||
| 1609 | int} so that their values are 0 and 1. | ||
| 1610 | |||
| 1611 | @item | ||
| 1612 | In C, Emacs commonly uses @code{bool}, 1, and 0 for boolean values. | ||
| 1613 | Using @code{bool} for booleans can make programs easier to read and a | ||
| 1614 | bit faster than using @code{int}. Although it is also OK to use | ||
| 1615 | @code{int}, this older style is gradually being phased out. When | ||
| 1616 | using @code{bool}, respect the limitations of the replacement | ||
| 1617 | implementation of @code{bool}, as documented in the source file | ||
| 1618 | @file{lib/stdbool.in.h}, so that Emacs remains portable to pre-C99 | ||
| 1619 | platforms. | ||
| 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? |
| @@ -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. | ||
| 137 | Emacs now supports notifications of filesystem changes, such as | ||
| 138 | creation, modification, and deletion of files. This requires the | ||
| 139 | 'inotify' API on GNU/Linux systems. On MS-Windows systems, this is | ||
| 140 | supported 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 @@ | |||
| 1 | 2012-12-11 Juanma Barranquero <lekktu@gmail.com> | ||
| 2 | |||
| 3 | * makefile.w32-in (SYSWAIT_H): Update dependencies. | ||
| 4 | |||
| 5 | 2012-12-10 Eli Zaretskii <eliz@gnu.org> | ||
| 6 | |||
| 7 | * makefile.w32-in (obj): Add w32notify.o. Add missing X and Unix | ||
| 8 | sources. | ||
| 9 | |||
| 1 | 2012-12-02 Kevin Ryde <user42@zip.com.au> | 10 | 2012-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 | # |
| 124 | obj = dosfns.o msdos.o \ | 124 | obj = 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 |
| 377 | SYSWAIT_H = $(SRC)/syswait.h \ | 380 | SYSWAIT_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 |
| 104 | SHA512_H = $(GNU_LIB)/sha512.h \ | 104 | SHA512_H = $(GNU_LIB)/sha512.h \ |
| 105 | $(U64_H) | 105 | $(U64_H) |
| 106 | SIG2STR_H = $(GNU_LIB)/sig2str.h \ | ||
| 107 | $(GNU_LIB)/intprops.h | ||
| 106 | STAT_TIME_H = $(GNU_LIB)/stat-time.h \ | 108 | STAT_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 @@ | |||
| 1 | 2012-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 | |||
| 6 | 2012-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 | |||
| 14 | 2012-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 | |||
| 23 | 2012-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 | |||
| 28 | 2012-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 | |||
| 41 | 2012-12-10 Eli Zaretskii <eliz@gnu.org> | ||
| 42 | |||
| 43 | * subr.el (w32notify-handle-event): New function. | ||
| 44 | (inotify-handle-event): Doc fix. | ||
| 45 | |||
| 46 | 2012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de> | ||
| 47 | |||
| 48 | * subr.el (inotify-event-p, inotify-handle-event): New functions. | ||
| 49 | |||
| 1 | 2012-12-10 Dani Moncayo <dmoncayo@gmail.com> | 50 | 2012-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 | ||
| 5 | 2012-12-10 Eli Zaretskii <eliz@gnu.org> | 54 | 2012-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 | ||
| 10 | 2012-12-10 Le Wang <l26wang@gmail.com> | 58 | 2012-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. | ||
| 508 | Face 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. |
| 609 | When `hi-lock-auto-select-face' is non-nil, just return the next face. | 626 | When `hi-lock-auto-select-face' is non-nil, just return the next face. |
| 610 | Otherwise, read face name from minibuffer with completion and history." | 627 | Otherwise, 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 | ||
| 389 | compile4-SH: autoloads compile0-SH | 389 | compile4-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.") |
| 410 | the 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. |
| 2398 | that do not satisfy the condition removed." | 2398 | CONDP is a function that takes a list element as argument and returns |
| 2399 | non-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. |
| 1181 | This includes comment lines embedded in continued lines, but | 1181 | This includes comment or preprocessor lines embedded in continued lines, |
| 1182 | not the last line of a continued statement." | 1182 | but 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. | ||
| 4337 | If EVENT is an inotify filewatch event, call its callback. | ||
| 4338 | Otherwise, 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. | ||
| 4346 | If EVENT is an MS-Windows filewatch event, call its callback. | ||
| 4347 | Otherwise, 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 @@ | |||
| 1 | 2012-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 | |||
| 7 | 2012-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 | |||
| 1 | 2012-12-09 Eli Zaretskii <eliz@gnu.org> | 13 | 2012-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 @@ | |||
| 1 | Emacs ICON icons\emacs.ico | 1 | Emacs ICON icons/emacs.ico |
| 2 | 32649 CURSOR icons\hand.cur | 2 | 32649 CURSOR icons/hand.cur |
| 3 | #ifdef WIN64 | 3 | #ifdef WIN64 |
| 4 | 1 24 "emacs-x64.manifest" | 4 | 1 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 @@ | |||
| 1 | 2012-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 | |||
| 11 | 2012-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 | |||
| 16 | 2012-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 | |||
| 31 | 2012-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 | |||
| 37 | 2012-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 | |||
| 61 | 2012-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 | |||
| 82 | 2012-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 | |||
| 139 | 2012-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 | |||
| 1 | 2012-12-10 Jan Djärv <jan.h.d@swipnet.se> | 161 | 2012-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. |
| 30 | srcdir = @srcdir@ | 30 | srcdir = @srcdir@ |
| 31 | ntsource = $(srcdir)/../nt | ||
| 31 | abs_builddir = @abs_builddir@ | 32 | abs_builddir = @abs_builddir@ |
| 32 | VPATH = $(srcdir) | 33 | VPATH = $(srcdir) |
| 33 | CC = @CC@ | 34 | CC = @CC@ |
| 35 | WINDRES = @WINDRES@ | ||
| 34 | CFLAGS = @CFLAGS@ | 36 | CFLAGS = @CFLAGS@ |
| 35 | CPPFLAGS = @CPPFLAGS@ | 37 | CPPFLAGS = @CPPFLAGS@ |
| 36 | LDFLAGS = @LDFLAGS@ | 38 | LDFLAGS = @LDFLAGS@ |
| @@ -276,6 +278,13 @@ W32_OBJ=@W32_OBJ@ | |||
| 276 | ## --lwinspool if HAVE_W32, else empty. | 278 | ## --lwinspool if HAVE_W32, else empty. |
| 277 | W32_LIBS=@W32_LIBS@ | 279 | W32_LIBS=@W32_LIBS@ |
| 278 | 280 | ||
| 281 | ## emacs.res if HAVE_W32 | ||
| 282 | W32_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 | ||
| 286 | W32_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. |
| 345 | base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ | 353 | base_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 | ||
| 479 | temacs$(EXEEXT): $(START_FILES) stamp-oldxmenu $(obj) $(otherobj) $(lib)/libgnu.a | 487 | temacs$(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 | ||
| 520 | doc.o: buildobj.h | 530 | doc.o: buildobj.h |
| 521 | 531 | ||
| 532 | emacs.res: $(ntsource)/emacs.rc \ | ||
| 533 | $(ntsource)/icons/emacs.ico \ | ||
| 534 | $(ntsource)/emacs-x86.manifest | ||
| 535 | $(WINDRES) -O COFF -o $@ $(ntsource)/emacs.rc | ||
| 522 | 536 | ||
| 523 | ns-app: emacs$(EXEEXT) | 537 | ns-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 | |||
| 1183 | BUFFER_INLINE int | ||
| 1184 | buffer_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 \ | |||
| 128 | indent.o: indent.c frame.h window.h indent.h buffer.h lisp.h $(config_h) \ | 128 | indent.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 |
| 131 | inotify.o: inotify.c lisp.h coding.h process.h keyboard.h frame.h termhooks.h | ||
| 131 | insdel.o: insdel.c window.h buffer.h $(INTERVALS_H) blockinput.h character.h \ | 132 | insdel.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) |
| 133 | keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \ | 134 | keyboard.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 | |||
| 3 | Copyright (C) 2012 | ||
| 4 | Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | This file is part of GNU Emacs. | ||
| 7 | |||
| 8 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 9 | it under the terms of the GNU General Public License as published by | ||
| 10 | the Free Software Foundation, either version 3 of the License, or | ||
| 11 | (at your option) any later version. | ||
| 12 | |||
| 13 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | GNU General Public License for more details. | ||
| 17 | |||
| 18 | You should have received a copy of the GNU General Public License | ||
| 19 | along 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 | |||
| 33 | static Lisp_Object Qaccess; /* IN_ACCESS */ | ||
| 34 | static Lisp_Object Qattrib; /* IN_ATTRIB */ | ||
| 35 | static Lisp_Object Qclose_write; /* IN_CLOSE_WRITE */ | ||
| 36 | static Lisp_Object Qclose_nowrite; /* IN_CLOSE_NOWRITE */ | ||
| 37 | static Lisp_Object Qcreate; /* IN_CREATE */ | ||
| 38 | static Lisp_Object Qdelete; /* IN_DELETE */ | ||
| 39 | static Lisp_Object Qdelete_self; /* IN_DELETE_SELF */ | ||
| 40 | static Lisp_Object Qmodify; /* IN_MODIFY */ | ||
| 41 | static Lisp_Object Qmove_self; /* IN_MOVE_SELF */ | ||
| 42 | static Lisp_Object Qmoved_from; /* IN_MOVED_FROM */ | ||
| 43 | static Lisp_Object Qmoved_to; /* IN_MOVED_TO */ | ||
| 44 | static Lisp_Object Qopen; /* IN_OPEN */ | ||
| 45 | |||
| 46 | static Lisp_Object Qall_events; /* IN_ALL_EVENTS */ | ||
| 47 | static Lisp_Object Qmove; /* IN_MOVE */ | ||
| 48 | static Lisp_Object Qclose; /* IN_CLOSE */ | ||
| 49 | |||
| 50 | static Lisp_Object Qdont_follow; /* IN_DONT_FOLLOW */ | ||
| 51 | static Lisp_Object Qexcl_unlink; /* IN_EXCL_UNLINK */ | ||
| 52 | static Lisp_Object Qmask_add; /* IN_MASK_ADD */ | ||
| 53 | static Lisp_Object Qoneshot; /* IN_ONESHOT */ | ||
| 54 | static Lisp_Object Qonlydir; /* IN_ONLYDIR */ | ||
| 55 | |||
| 56 | static Lisp_Object Qignored; /* IN_IGNORED */ | ||
| 57 | static Lisp_Object Qisdir; /* IN_ISDIR */ | ||
| 58 | static Lisp_Object Qq_overflow; /* IN_Q_OVERFLOW */ | ||
| 59 | static 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 | |||
| 75 | enum { uninitialized = -100 }; | ||
| 76 | /* File handle for inotify. */ | ||
| 77 | static int inotifyfd = uninitialized; | ||
| 78 | |||
| 79 | /* Assoc list of files being watched. | ||
| 80 | Format: | ||
| 81 | (watch-descriptor . callback) | ||
| 82 | */ | ||
| 83 | static Lisp_Object watch_list; | ||
| 84 | |||
| 85 | static Lisp_Object | ||
| 86 | make_watch_descriptor (int wd) | ||
| 87 | { | ||
| 88 | /* TODO replace this with a Misc Object! */ | ||
| 89 | return make_number (wd); | ||
| 90 | } | ||
| 91 | |||
| 92 | static Lisp_Object | ||
| 93 | mask_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 | |||
| 130 | static Lisp_Object | ||
| 131 | inotifyevent_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. */ | ||
| 150 | static void | ||
| 151 | inotify_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 | |||
| 201 | static uint32_t | ||
| 202 | symbol_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 | |||
| 250 | static uint32_t | ||
| 251 | aspect_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 | |||
| 268 | DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0, | ||
| 269 | doc: /* Add a watch for FILE-NAME to inotify. | ||
| 270 | |||
| 271 | A WATCH-DESCRIPTOR is returned on success. ASPECT might be one of the following | ||
| 272 | symbols or a list of those symbols: | ||
| 273 | |||
| 274 | access | ||
| 275 | attrib | ||
| 276 | close-write | ||
| 277 | close-nowrite | ||
| 278 | create | ||
| 279 | delete | ||
| 280 | delete-self | ||
| 281 | modify | ||
| 282 | move-self | ||
| 283 | moved-from | ||
| 284 | moved-to | ||
| 285 | open | ||
| 286 | |||
| 287 | all-events or t | ||
| 288 | move | ||
| 289 | close | ||
| 290 | |||
| 291 | The following symbols can also be added to a list of aspects | ||
| 292 | |||
| 293 | dont-follow | ||
| 294 | excl-unlink | ||
| 295 | mask-add | ||
| 296 | oneshot | ||
| 297 | onlydir | ||
| 298 | |||
| 299 | Watching a directory is not recursive. CALLBACK gets called in case of an | ||
| 300 | event. It gets passed a single argument EVENT which contains an event structure | ||
| 301 | of the format | ||
| 302 | |||
| 303 | (WATCH-DESCRIPTOR ASPECTS COOKIE NAME) | ||
| 304 | |||
| 305 | WATCH-DESCRIPTOR is the same object that was returned by this function. It can | ||
| 306 | be tested for equality using `equal'. ASPECTS describes the event. It is a | ||
| 307 | list of ASPECT symbols described above and can also contain one of the following | ||
| 308 | symbols | ||
| 309 | |||
| 310 | ignored | ||
| 311 | isdir | ||
| 312 | q-overflow | ||
| 313 | unmount | ||
| 314 | |||
| 315 | COOKIE is an object that can be compared using `equal' to identify two matching | ||
| 316 | renames (moved-from and moved-to). | ||
| 317 | |||
| 318 | If a directory is watched then NAME is the name of file that caused the event. | ||
| 319 | |||
| 320 | See inotify(7) and inotify_add_watch(2) for further information. The inotify fd | ||
| 321 | is 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 | |||
| 367 | DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0, | ||
| 368 | doc: /* Remove an existing WATCH-DESCRIPTOR. | ||
| 369 | |||
| 370 | WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'. | ||
| 371 | |||
| 372 | See 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 | |||
| 399 | void | ||
| 400 | syms_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; | |||
| 313 | Lisp_Object Qmouse_click; | 313 | Lisp_Object Qmouse_click; |
| 314 | #ifdef HAVE_NTGUI | 314 | #ifdef HAVE_NTGUI |
| 315 | Lisp_Object Qlanguage_change; | 315 | Lisp_Object Qlanguage_change; |
| 316 | #ifdef WINDOWSNT | ||
| 317 | Lisp_Object Qfile_w32notify; | ||
| 318 | #endif | ||
| 316 | #endif | 319 | #endif |
| 317 | static Lisp_Object Qdrag_n_drop; | 320 | static Lisp_Object Qdrag_n_drop; |
| 318 | static Lisp_Object Qsave_session; | 321 | static Lisp_Object Qsave_session; |
| @@ -322,6 +325,9 @@ static Lisp_Object Qdbus_event; | |||
| 322 | #ifdef HAVE_XWIDGETS | 325 | #ifdef HAVE_XWIDGETS |
| 323 | Lisp_Object Qxwidget_event; | 326 | Lisp_Object Qxwidget_event; |
| 324 | #endif | 327 | #endif |
| 328 | #ifdef HAVE_INOTIFY | ||
| 329 | static Lisp_Object Qfile_inotify; | ||
| 330 | #endif /* HAVE_INOTIFY */ | ||
| 325 | static Lisp_Object Qconfig_changed_event; | 331 | static 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); | |||
| 3521 | extern Lisp_Object Qfont_param; | 3521 | extern Lisp_Object Qfont_param; |
| 3522 | #endif | 3522 | #endif |
| 3523 | 3523 | ||
| 3524 | #ifdef WINDOWSNT | ||
| 3525 | /* Defined on w32notify.c. */ | ||
| 3526 | extern void syms_of_w32notify (void); | ||
| 3527 | #endif | ||
| 3528 | |||
| 3529 | /* Defined in inotify.c */ | ||
| 3530 | #ifdef HAVE_INOTIFY | ||
| 3531 | extern void syms_of_inotify (void); | ||
| 3532 | #endif | ||
| 3533 | |||
| 3524 | /* Defined in xfaces.c. */ | 3534 | /* Defined in xfaces.c. */ |
| 3525 | extern Lisp_Object Qdefault, Qtool_bar, Qfringe; | 3535 | extern Lisp_Object Qdefault, Qtool_bar, Qfringe; |
| 3526 | extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor; | 3536 | extern 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 | ||
| 139 | LIBS = $(TLIB0) \ | 140 | LIBS = $(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 |
| 462 | SHA512_H = $(GNU_LIB)/sha512.h \ | 463 | SHA512_H = $(GNU_LIB)/sha512.h \ |
| 463 | $(U64_H) | 464 | $(U64_H) |
| 465 | SIG2STR_H = $(GNU_LIB)/sig2str.h \ | ||
| 466 | $(GNU_LIB)/intprops.h | ||
| 464 | SOCKET_H = $(NT_INC)/sys/socket.h \ | 467 | SOCKET_H = $(NT_INC)/sys/socket.h \ |
| 465 | $(SRC)/w32.h | 468 | $(SRC)/w32.h |
| 466 | STAT_TIME_H = $(GNU_LIB)/stat-time.h \ | 469 | STAT_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 |
| 473 | SYSWAIT_H = $(SRC)/syswait.h \ | 476 | SYSWAIT_H = $(SRC)/syswait.h \ |
| 477 | $(NT_INC)/stdbool.h \ | ||
| 474 | $(NT_INC)/sys/wait.h | 478 | $(NT_INC)/sys/wait.h |
| 475 | TERMHOOKS_H = $(SRC)/termhooks.h \ | 479 | TERMHOOKS_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 | ||
| 86 | PIMAGE_SECTION_HEADER heap_section; | 86 | PIMAGE_SECTION_HEADER heap_section; |
| 87 | 87 | ||
| 88 | #ifdef HAVE_NTGUI | ||
| 89 | extern HINSTANCE hinst; | ||
| 90 | HINSTANCE hprevinst = NULL; | ||
| 91 | LPSTR lpCmdLine = ""; | ||
| 92 | int 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); | |||
| 1821 | static BOOL | 1821 | static BOOL |
| 1822 | w32_init_class (HINSTANCE hinst) | 1822 | w32_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 | ||
| 81 | extern HINSTANCE hinst; | 81 | extern HINSTANCE hinst; |
| 82 | extern HINSTANCE hprevinst; | ||
| 83 | extern LPSTR lpCmdLine; | ||
| 84 | extern 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 | ||
| 579 | static int | ||
| 580 | handle_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 103 | struct 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. */ | ||
| 116 | volatile int notification_buffer_in_use; | ||
| 117 | BYTE file_notifications[16384]; | ||
| 118 | DWORD notifications_size; | ||
| 119 | void *notifications_desc; | ||
| 120 | |||
| 121 | static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize; | ||
| 122 | static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; | ||
| 123 | static Lisp_Object Qsecurity_desc, Qsubtree, watch_list; | ||
| 124 | |||
| 125 | /* Signal to the main thread that we have file notifications for it to | ||
| 126 | process. */ | ||
| 127 | static void | ||
| 128 | send_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.) */ | ||
| 181 | VOID CALLBACK | ||
| 182 | watch_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. */ | ||
| 197 | VOID CALLBACK | ||
| 198 | watch_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. */ | ||
| 238 | static DWORD WINAPI | ||
| 239 | watch_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. */ | ||
| 281 | static struct notification * | ||
| 282 | start_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. */ | ||
| 321 | static struct notification * | ||
| 322 | add_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. */ | ||
| 349 | static int | ||
| 350 | remove_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 | |||
| 410 | static DWORD | ||
| 411 | filter_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 | |||
| 438 | DEFUN ("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 | |||
| 442 | This arranges for filesystem events pertaining to FILE to be reported | ||
| 443 | to Emacs. Use `w32notify-rm-watch' to cancel the watch. | ||
| 444 | |||
| 445 | Value is a descriptor for the added watch, or nil if the file | ||
| 446 | cannot be watched. | ||
| 447 | |||
| 448 | FILTER is a list of conditions for reporting an event. It can include | ||
| 449 | the 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 | |||
| 460 | If FILE is a directory, and FILTER includes 'subtree', then all the | ||
| 461 | subdirectories will also be watched and changes in them reported. | ||
| 462 | |||
| 463 | When any event happens that satisfies the conditions specified by | ||
| 464 | FILTER, Emacs will call the CALLBACK function passing it a single | ||
| 465 | argument EVENT, which is of the form | ||
| 466 | |||
| 467 | (DESCRIPTOR ACTION FILE) | ||
| 468 | |||
| 469 | DESCRIPTOR is the same object as the one returned by this function. | ||
| 470 | ACTION is the description of the event. It could be any one of the | ||
| 471 | following: | ||
| 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 | |||
| 479 | FILE 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 | |||
| 565 | DEFUN ("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 | |||
| 569 | WATCH-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 | |||
| 595 | Lisp_Object | ||
| 596 | w32_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 | |||
| 606 | void | ||
| 607 | globals_of_w32notify (void) | ||
| 608 | { | ||
| 609 | watch_list = Qnil; | ||
| 610 | } | ||
| 611 | |||
| 612 | void | ||
| 613 | syms_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 | ||
| 248 | static Lisp_Object Qvendor_specific_keysyms; | 248 | static Lisp_Object Qvendor_specific_keysyms; |
| 249 | static Lisp_Object Qadded, Qremoved, Qmodified; | ||
| 250 | static 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 | |||
| 3211 | Lisp_Object | ||
| 3212 | lispy_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. */ | ||
| 3251 | static void | ||
| 3252 | queue_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); | |||
| 652 | extern HDC get_frame_dc (struct frame * f); | 653 | extern HDC get_frame_dc (struct frame * f); |
| 653 | extern int release_frame_dc (struct frame * f, HDC hDC); | 654 | extern int release_frame_dc (struct frame * f, HDC hDC); |
| 654 | 655 | ||
| 655 | extern void drain_message_queue (void); | 656 | extern int drain_message_queue (void); |
| 656 | 657 | ||
| 657 | extern BOOL get_next_msg (W32Msg *, BOOL); | 658 | extern BOOL get_next_msg (W32Msg *, BOOL); |
| 658 | extern BOOL post_msg (W32Msg *); | 659 | extern BOOL post_msg (W32Msg *); |
| @@ -662,10 +663,17 @@ extern BOOL parse_button (int, int, int *, int *); | |||
| 662 | 663 | ||
| 663 | extern void w32_sys_ring_bell (struct frame *f); | 664 | extern void w32_sys_ring_bell (struct frame *f); |
| 664 | extern void x_delete_display (struct w32_display_info *dpyinfo); | 665 | extern void x_delete_display (struct w32_display_info *dpyinfo); |
| 666 | |||
| 667 | extern volatile int notification_buffer_in_use; | ||
| 668 | extern BYTE file_notifications[16384]; | ||
| 669 | extern DWORD notifications_size; | ||
| 670 | extern void *notifications_desc; | ||
| 671 | extern Lisp_Object w32_get_watch_object (void *); | ||
| 672 | extern Lisp_Object lispy_file_action (DWORD); | ||
| 673 | |||
| 665 | extern void w32_initialize_display_info (Lisp_Object); | 674 | extern void w32_initialize_display_info (Lisp_Object); |
| 666 | extern void initialize_w32_display (struct terminal *); | 675 | extern 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 | ||
| 760 | extern void globals_of_w32menu (void); | 768 | extern void globals_of_w32menu (void); |
| 761 | extern void globals_of_w32fns (void); | 769 | extern void globals_of_w32fns (void); |
| 770 | extern void globals_of_w32notify (void); | ||
| 762 | 771 | ||
| 763 | #ifdef CYGWIN | 772 | #ifdef CYGWIN |
| 764 | extern int w32_message_fd; | 773 | extern 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 |
| 319 | void | 319 | one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */ |
| 320 | int | ||
| 320 | drain_message_queue (void) | 321 | drain_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 | |||
| 277 | static void | ||
| 278 | adjust_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 | |||
| 295 | void | ||
| 296 | wset_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 | ||
| 276 | static Lisp_Object | 305 | static 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 | ||
| 2966 | void | 2995 | void |
| 2967 | replace_buffer_in_windows_safely (Lisp_Object buffer) | 2996 | replace_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. */ |
| 353 | WINDOW_INLINE void | 353 | WINDOW_INLINE void |
| 354 | wset_buffer (struct window *w, Lisp_Object val) | ||
| 355 | { | ||
| 356 | w->buffer = val; | ||
| 357 | } | ||
| 358 | WINDOW_INLINE void | ||
| 359 | wset_frame (struct window *w, Lisp_Object val) | 354 | wset_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 | ||
| 948 | extern int cursor_type_changed; | 943 | extern 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 | |||
| 953 | extern 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); | |||
| 997 | extern void temp_output_buffer_show (Lisp_Object); | 987 | extern void temp_output_buffer_show (Lisp_Object); |
| 998 | extern void replace_buffer_in_windows (Lisp_Object); | 988 | extern void replace_buffer_in_windows (Lisp_Object); |
| 999 | extern void replace_buffer_in_windows_safely (Lisp_Object); | 989 | extern void replace_buffer_in_windows_safely (Lisp_Object); |
| 990 | /* This looks like a setter, but it is a bit special. */ | ||
| 991 | extern void wset_buffer (struct window *, Lisp_Object); | ||
| 1000 | extern void init_window_once (void); | 992 | extern void init_window_once (void); |
| 1001 | extern void init_window (void); | 993 | extern void init_window (void); |
| 1002 | extern void syms_of_window (void); | 994 | extern 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 | ||
| 518 | static int overlay_arrow_seen; | 518 | static 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 | |||
| 523 | int buffer_shared; | ||
| 524 | |||
| 525 | /* Vector containing glyphs for an ellipsis `...'. */ | 520 | /* Vector containing glyphs for an ellipsis `...'. */ |
| 526 | 521 | ||
| 527 | static Lisp_Object default_invis_vector[3]; | 522 | static 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) | |||
| 10948 | static int | 10943 | static int |
| 10949 | buffer_shared_and_changed (void) | 10944 | buffer_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 @@ | |||
| 1 | 2012-12-11 Glenn Morris <rgm@gnu.org> | ||
| 2 | |||
| 3 | * automated/f90.el (f90-test-bug13138): New test. | ||
| 4 | |||
| 5 | 2012-12-10 Rüdiger Sonderfeld <ruediger@c-plusplus.de> | ||
| 6 | |||
| 7 | * automated/inotify-test.el: New test. | ||
| 8 | |||
| 1 | 2012-12-02 Chong Yidong <cyd@gnu.org> | 9 | 2012-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 | ||
| 170 | end 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. | ||