summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuan Fu <casouri@gmail.com>2022-06-14 15:59:46 -0700
committerYuan Fu <casouri@gmail.com>2022-06-14 15:59:46 -0700
commit98bfb240818bae14cd87a1ffeb8fae7cb7846e05 (patch)
tree16e8ab06875ed54e110cf98ccdbd7e78f15905c6 /src
parent184d212042ffa5a4f02c92085d9b6e8346d66e99 (diff)
parent787c4ad8b0776280305a220d6669c956d9ed8a5d (diff)
downloademacs-98bfb240818bae14cd87a1ffeb8fae7cb7846e05.tar.gz
Merge remote-tracking branch 'savannah/master' into feature/tree-sitter
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c8
-rw-r--r--src/atimer.c37
-rw-r--r--src/buffer.c97
-rw-r--r--src/bytecode.c6
-rw-r--r--src/callint.c35
-rw-r--r--src/ccl.c5
-rw-r--r--src/coding.c35
-rw-r--r--src/comp.c24
-rw-r--r--src/composite.c2
-rw-r--r--src/data.c18
-rw-r--r--src/dbusbind.c41
-rw-r--r--src/dispextern.h7
-rw-r--r--src/dispnew.c77
-rw-r--r--src/doc.c2
-rw-r--r--src/editfns.c2
-rw-r--r--src/emacs-module.c2
-rw-r--r--src/emacs.c167
-rw-r--r--src/eval.c106
-rw-r--r--src/fileio.c60
-rw-r--r--src/floatfns.c22
-rw-r--r--src/fns.c28
-rw-r--r--src/font.c4
-rw-r--r--src/frame.c45
-rw-r--r--src/frame.h25
-rw-r--r--src/ftcrfont.c33
-rw-r--r--src/ftfont.c30
-rw-r--r--src/gtkutil.c108
-rw-r--r--src/haiku_draw_support.cc83
-rw-r--r--src/haiku_io.c2
-rw-r--r--src/haiku_select.cc219
-rw-r--r--src/haiku_support.cc1068
-rw-r--r--src/haiku_support.h102
-rw-r--r--src/haikufns.c704
-rw-r--r--src/haikufont.c4
-rw-r--r--src/haikugui.h105
-rw-r--r--src/haikumenu.c67
-rw-r--r--src/haikuselect.c325
-rw-r--r--src/haikuselect.h28
-rw-r--r--src/haikuterm.c1050
-rw-r--r--src/haikuterm.h30
-rw-r--r--src/image.c174
-rw-r--r--src/indent.c4
-rw-r--r--src/intervals.c1
-rw-r--r--src/intervals.h2
-rw-r--r--src/json.c2
-rw-r--r--src/keyboard.c127
-rw-r--r--src/keyboard.h12
-rw-r--r--src/keymap.c15
-rw-r--r--src/lisp.h28
-rw-r--r--src/lread.c2219
-rw-r--r--src/menu.c6
-rw-r--r--src/minibuf.c33
-rw-r--r--src/nsfns.m752
-rw-r--r--src/nsfont.m3
-rw-r--r--src/nsmenu.m385
-rw-r--r--src/nsselect.m237
-rw-r--r--src/nsterm.h107
-rw-r--r--src/nsterm.m1050
-rw-r--r--src/nsxwidget.m3
-rw-r--r--src/pdumper.c11
-rw-r--r--src/pgtkfns.c53
-rw-r--r--src/pgtkmenu.c10
-rw-r--r--src/pgtkselect.c2
-rw-r--r--src/pgtkterm.c109
-rw-r--r--src/pgtkterm.h2
-rw-r--r--src/print.c948
-rw-r--r--src/process.c29
-rw-r--r--src/profiler.c4
-rw-r--r--src/regex-emacs.c21
-rw-r--r--src/sort.c2
-rw-r--r--src/sysstdio.h3
-rw-r--r--src/term.c2
-rw-r--r--src/termhooks.h16
-rw-r--r--src/terminal.c4
-rw-r--r--src/textprop.c2
-rw-r--r--src/tparam.h5
-rw-r--r--src/w32.c3
-rw-r--r--src/w32fns.c74
-rw-r--r--src/w32font.c23
-rw-r--r--src/w32menu.c13
-rw-r--r--src/w32notify.c30
-rw-r--r--src/w32proc.c17
-rw-r--r--src/w32term.c29
-rw-r--r--src/window.c192
-rw-r--r--src/window.h12
-rw-r--r--src/xdisp.c57
-rw-r--r--src/xfaces.c43
-rw-r--r--src/xfns.c444
-rw-r--r--src/xfont.c2
-rw-r--r--src/xftfont.c9
-rw-r--r--src/xgselect.c23
-rw-r--r--src/xgselect.h7
-rw-r--r--src/xmenu.c45
-rw-r--r--src/xrdb.c6
-rw-r--r--src/xselect.c343
-rw-r--r--src/xsettings.c202
-rw-r--r--src/xsettings.h5
-rw-r--r--src/xterm.c4116
-rw-r--r--src/xterm.h84
99 files changed, 12151 insertions, 4824 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 3c622d05ff1..14c3a4cb8d7 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -1036,9 +1036,12 @@ lisp_free (void *block)
return;
MALLOC_BLOCK_INPUT;
+#ifndef GC_MALLOC_CHECK
+ struct mem_node *m = mem_find (block);
+#endif
free (block);
#ifndef GC_MALLOC_CHECK
- mem_delete (mem_find (block));
+ mem_delete (m);
#endif
MALLOC_UNBLOCK_INPUT;
}
@@ -6197,6 +6200,7 @@ garbage_collect (void)
mark_pinned_objects ();
mark_pinned_symbols ();
+ mark_lread ();
mark_terminals ();
mark_kboards ();
mark_threads ();
@@ -6319,7 +6323,7 @@ where each entry has the form (NAME SIZE USED FREE), where:
to return them to the OS).
However, if there was overflow in pure space, and Emacs was dumped
-using the 'unexec' method, `garbage-collect' returns nil, because
+using the \"unexec\" method, `garbage-collect' returns nil, because
real GC can't be done.
Note that calling this function does not guarantee that absolutely all
diff --git a/src/atimer.c b/src/atimer.c
index 1c6c881fc02..18301120ffe 100644
--- a/src/atimer.c
+++ b/src/atimer.c
@@ -18,6 +18,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
+#ifdef WINDOWSNT
+#define raise(s) w32_raise(s)
+#endif
+
#include "lisp.h"
#include "keyboard.h"
#include "syssignal.h"
@@ -297,11 +301,6 @@ set_alarm (void)
{
if (atimers)
{
-#ifdef HAVE_SETITIMER
- struct itimerval it;
-#endif
- struct timespec now, interval;
-
#ifdef HAVE_ITIMERSPEC
if (0 <= timerfd || alarm_timer_ok)
{
@@ -337,20 +336,24 @@ set_alarm (void)
}
#endif
- /* Determine interval till the next timer is ripe.
- Don't set the interval to 0; this disables the timer. */
- now = current_timespec ();
- interval = (timespec_cmp (atimers->expiration, now) <= 0
- ? make_timespec (0, 1000 * 1000)
- : timespec_sub (atimers->expiration, now));
+ /* Determine interval till the next timer is ripe. */
+ struct timespec now = current_timespec ();
+ if (timespec_cmp (atimers->expiration, now) <= 0)
+ {
+ /* Timer is (over)due -- just trigger the signal right way. */
+ raise (SIGALRM);
+ }
+ else
+ {
+ struct timespec interval = timespec_sub (atimers->expiration, now);
#ifdef HAVE_SETITIMER
-
- memset (&it, 0, sizeof it);
- it.it_value = make_timeval (interval);
- setitimer (ITIMER_REAL, &it, 0);
-#endif /* not HAVE_SETITIMER */
- alarm (max (interval.tv_sec, 1));
+ struct itimerval it = {.it_value = make_timeval (interval)};
+ setitimer (ITIMER_REAL, &it, 0);
+#else
+ alarm (max (interval.tv_sec, 1));
+#endif
+ }
}
}
diff --git a/src/buffer.c b/src/buffer.c
index f8a7a4f5109..a0761f5b59a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1218,7 +1218,7 @@ is the default binding of the variable. */)
{
register Lisp_Object result = buffer_local_value (variable, buffer);
- if (EQ (result, Qunbound))
+ if (BASE_EQ (result, Qunbound))
xsignal1 (Qvoid_variable, variable);
return result;
@@ -1313,7 +1313,7 @@ buffer_lisp_local_variables (struct buffer *buf, bool clone)
if (buf != current_buffer)
val = XCDR (elt);
- result = Fcons (!clone && EQ (val, Qunbound)
+ result = Fcons (!clone && BASE_EQ (val, Qunbound)
? XCAR (elt)
: Fcons (XCAR (elt), val),
result);
@@ -1336,7 +1336,7 @@ buffer_local_variables_1 (struct buffer *buf, int offset, Lisp_Object sym)
{
sym = NILP (sym) ? PER_BUFFER_SYMBOL (offset) : sym;
Lisp_Object val = per_buffer_value (buf, offset);
- return EQ (val, Qunbound) ? sym : Fcons (sym, val);
+ return BASE_EQ (val, Qunbound) ? sym : Fcons (sym, val);
}
return Qnil;
}
@@ -1376,12 +1376,23 @@ No argument or nil as argument means use current buffer as BUFFER. */)
DEFUN ("buffer-modified-p", Fbuffer_modified_p, Sbuffer_modified_p,
0, 1, 0,
- doc: /* Return t if BUFFER was modified since its file was last read or saved.
-No argument or nil as argument means use current buffer as BUFFER. */)
+ doc: /* Return non-nil if BUFFER was modified since its file was last read or saved.
+No argument or nil as argument means use current buffer as BUFFER.
+
+If BUFFER was autosaved since it was last modified, this function
+returns the symbol `autosaved'. */)
(Lisp_Object buffer)
{
struct buffer *buf = decode_buffer (buffer);
- return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil;
+ if (BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf))
+ {
+ if (BUF_AUTOSAVE_MODIFF (buf) == BUF_MODIFF (buf))
+ return Qautosaved;
+ else
+ return Qt;
+ }
+ else
+ return Qnil;
}
DEFUN ("force-mode-line-update", Fforce_mode_line_update,
@@ -1436,6 +1447,11 @@ and `buffer-file-truename' are non-nil. */)
DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
Srestore_buffer_modified_p, 1, 1, 0,
doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line.
+A nil FLAG means to mark the buffer as unmodified. A non-nil FLAG
+means mark the buffer as modified. A special value of `autosaved'
+will mark the buffer as modified and also as autosaved since it was
+last modified.
+
This function also locks or unlocks the file visited by the buffer,
if both `buffer-file-truename' and `buffer-file-name' are non-nil.
@@ -1475,16 +1491,19 @@ state of the current buffer. Use with care. */)
recent-auto-save-p from t to nil.
Vice versa, if FLAG is non-nil and SAVE_MODIFF>=auto_save_modified
we risk changing recent-auto-save-p from nil to t. */
- SAVE_MODIFF = (NILP (flag)
- /* FIXME: This unavoidably sets recent-auto-save-p to nil. */
- ? MODIFF
- /* Let's try to preserve recent-auto-save-p. */
- : SAVE_MODIFF < MODIFF ? SAVE_MODIFF
- /* If SAVE_MODIFF == auto_save_modified == MODIFF,
- we can either decrease SAVE_MODIFF and auto_save_modified
- or increase MODIFF. */
- : modiff_incr (&MODIFF));
-
+ if (NILP (flag))
+ /* This unavoidably sets recent-auto-save-p to nil. */
+ SAVE_MODIFF = MODIFF;
+ else
+ {
+ /* If SAVE_MODIFF == auto_save_modified == MODIFF, we can either
+ decrease SAVE_MODIFF and auto_save_modified or increase
+ MODIFF. */
+ if (SAVE_MODIFF >= MODIFF)
+ SAVE_MODIFF = modiff_incr (&MODIFF);
+ if (EQ (flag, Qautosaved))
+ BUF_AUTOSAVE_MODIFF (b) = MODIFF;
+ }
return flag;
}
@@ -1499,6 +1518,18 @@ use current buffer as BUFFER. */)
return modiff_to_integer (BUF_MODIFF (decode_buffer (buffer)));
}
+DEFUN ("internal--set-buffer-modified-tick",
+ Finternal__set_buffer_modified_tick, Sinternal__set_buffer_modified_tick,
+ 1, 2, 0,
+ doc: /* Set BUFFER's tick counter to TICK.
+No argument or nil as argument means use current buffer as BUFFER. */)
+ (Lisp_Object tick, Lisp_Object buffer)
+{
+ CHECK_FIXNUM (tick);
+ BUF_MODIFF (decode_buffer (buffer)) = XFIXNUM (tick);
+ return Qnil;
+}
+
DEFUN ("buffer-chars-modified-tick", Fbuffer_chars_modified_tick,
Sbuffer_chars_modified_tick, 0, 1, 0,
doc: /* Return BUFFER's character-change tick counter.
@@ -1634,16 +1665,7 @@ exists, return the buffer `*scratch*' (creating it if necessary). */)
if (!NILP (notsogood))
return notsogood;
else
- {
- AUTO_STRING (scratch, "*scratch*");
- buf = Fget_buffer (scratch);
- if (NILP (buf))
- {
- buf = Fget_buffer_create (scratch, Qnil);
- Fset_buffer_major_mode (buf);
- }
- return buf;
- }
+ return safe_call (1, Qget_scratch_buffer_create);
}
/* The following function is a safe variant of Fother_buffer: It doesn't
@@ -1659,15 +1681,7 @@ other_buffer_safely (Lisp_Object buffer)
if (candidate_buffer (buf, buffer))
return buf;
- AUTO_STRING (scratch, "*scratch*");
- buf = Fget_buffer (scratch);
- if (NILP (buf))
- {
- buf = Fget_buffer_create (scratch, Qnil);
- Fset_buffer_major_mode (buf);
- }
-
- return buf;
+ return safe_call (1, Qget_scratch_buffer_create);
}
DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
@@ -4093,7 +4107,7 @@ buffer. */)
n_end = marker_position (OVERLAY_END (overlay));
/* If the overlay has changed buffers, do a thorough redisplay. */
- if (!EQ (buffer, obuffer))
+ if (!BASE_EQ (buffer, obuffer))
{
/* Redisplay where the overlay was. */
if (ob)
@@ -5552,6 +5566,7 @@ syms_of_buffer (void)
DEFSYM (Qbefore_change_functions, "before-change-functions");
DEFSYM (Qafter_change_functions, "after-change-functions");
DEFSYM (Qkill_buffer_query_functions, "kill-buffer-query-functions");
+ DEFSYM (Qget_scratch_buffer_create, "get-scratch-buffer-create");
DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar");
Fput (Qvertical_scroll_bar, Qchoice, list4 (Qnil, Qt, Qleft, Qright));
@@ -5583,8 +5598,11 @@ the mode line appears at the bottom. */);
&BVAR (current_buffer, header_line_format),
Qnil,
doc: /* Analogous to `mode-line-format', but controls the header line.
-The header line appears, optionally, at the top of a window;
-the mode line appears at the bottom. */);
+The header line appears, optionally, at the top of a window; the mode
+line appears at the bottom.
+
+Also see `header-line-indent-mode' if `display-line-number-mode' is
+used. */);
DEFVAR_PER_BUFFER ("mode-line-format", &BVAR (current_buffer, mode_line_format),
Qnil,
@@ -6418,6 +6436,7 @@ will run for `clone-indirect-buffer' calls as well. */);
defsubr (&Sforce_mode_line_update);
defsubr (&Sset_buffer_modified_p);
defsubr (&Sbuffer_modified_tick);
+ defsubr (&Sinternal__set_buffer_modified_tick);
defsubr (&Sbuffer_chars_modified_tick);
defsubr (&Srename_buffer);
defsubr (&Sother_buffer);
@@ -6452,5 +6471,7 @@ will run for `clone-indirect-buffer' calls as well. */);
defsubr (&Soverlay_put);
defsubr (&Srestore_buffer_modified_p);
+ DEFSYM (Qautosaved, "autosaved");
+
Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt);
}
diff --git a/src/bytecode.c b/src/bytecode.c
index 74b7d16affd..fa068e1ec6b 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -627,7 +627,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
Lisp_Object v1 = vectorp[op], v2;
if (!SYMBOLP (v1)
|| XSYMBOL (v1)->u.s.redirect != SYMBOL_PLAINVAL
- || (v2 = SYMBOL_VAL (XSYMBOL (v1)), EQ (v2, Qunbound)))
+ || (v2 = SYMBOL_VAL (XSYMBOL (v1)), BASE_EQ (v2, Qunbound)))
v2 = Fsymbol_value (v1);
PUSH (v2);
NEXT;
@@ -694,7 +694,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
/* Inline the most common case. */
if (SYMBOLP (sym)
- && !EQ (val, Qunbound)
+ && !BASE_EQ (val, Qunbound)
&& XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL
&& !SYMBOL_TRAPPED_WRITE_P (sym))
SET_SYMBOL_VAL (XSYMBOL (sym), val);
@@ -1209,7 +1209,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
Lisp_Object v2 = POP;
Lisp_Object v1 = TOP;
if (FIXNUMP (v1) && FIXNUMP (v2))
- TOP = BASE_EQ(v1, v2) ? Qt : Qnil;
+ TOP = BASE_EQ (v1, v2) ? Qt : Qnil;
else
TOP = arithcompare (v1, v2, ARITH_EQUAL);
NEXT;
diff --git a/src/callint.c b/src/callint.c
index 92bfaf8d397..8283c61da67 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -170,7 +170,7 @@ check_mark (bool for_region)
of VALUES to do its job. */
static void
-fix_command (Lisp_Object input, Lisp_Object values)
+fix_command (Lisp_Object input, Lisp_Object function, Lisp_Object values)
{
/* FIXME: Instead of this ugly hack, we should provide a way for an
interactive spec to return an expression/function that will re-build the
@@ -230,6 +230,37 @@ fix_command (Lisp_Object input, Lisp_Object values)
}
}
}
+
+ /* If the list contains a bunch of trailing nil values, and they are
+ optional, remove them from the list. This makes navigating the
+ history less confusing, since it doesn't contain a lot of
+ parameters that aren't used. */
+ if (CONSP (values))
+ {
+ Lisp_Object arity = Ffunc_arity (function);
+ /* We don't want to do this simplification if we have an &rest
+ function, because (cl-defun foo (a &optional (b 'zot)) ..)
+ etc. */
+ if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity)))
+ {
+ Lisp_Object final = Qnil;
+ ptrdiff_t final_i = 0, i = 0;
+ for (Lisp_Object tail = values;
+ CONSP (tail);
+ tail = XCDR (tail), ++i)
+ {
+ if (!NILP (XCAR (tail)))
+ {
+ final = tail;
+ final_i = i;
+ }
+ }
+
+ /* Chop the trailing optional values. */
+ if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1)
+ XSETCDR (final, Qnil);
+ }
+ }
}
/* Helper function to call `read-file-name' from C. */
@@ -340,7 +371,7 @@ invoke it (via an `interactive' spec that contains, for instance, an
Make a copy of the list of values, for the command history,
and turn them into things we can eval. */
Lisp_Object values = quotify_args (Fcopy_sequence (specs));
- fix_command (input, values);
+ fix_command (input, function, values);
call4 (intern ("add-to-history"), intern ("command-history"),
Fcons (function, values), Qnil, Qt);
}
diff --git a/src/ccl.c b/src/ccl.c
index a3121f72782..1a4f73500a3 100644
--- a/src/ccl.c
+++ b/src/ccl.c
@@ -35,6 +35,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "coding.h"
#include "keyboard.h"
+/* Avoid GCC 12 bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105784>. */
+#if GNUC_PREREQ (12, 0, 0)
+# pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value"
+#endif
+
/* Table of registered CCL programs. Each element is a vector of
NAME, CCL_PROG, RESOLVEDP, and UPDATEDP, where NAME (symbol) is the
name of the program, CCL_PROG (vector) is the compiled code of the
diff --git a/src/coding.c b/src/coding.c
index 2bed293d571..aa32efc3f61 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -6528,7 +6528,7 @@ detect_coding (struct coding_system *coding)
if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qundecided))
{
int c, i;
- struct coding_detection_info detect_info;
+ struct coding_detection_info detect_info = {0};
bool null_byte_found = 0, eight_bit_found = 0;
bool inhibit_nbd = inhibit_flag (coding->spec.undecided.inhibit_nbd,
inhibit_null_byte_detection);
@@ -6537,7 +6537,6 @@ detect_coding (struct coding_system *coding)
bool prefer_utf_8 = coding->spec.undecided.prefer_utf_8;
coding->head_ascii = 0;
- detect_info.checked = detect_info.found = detect_info.rejected = 0;
for (src = coding->source; src < src_end; src++)
{
c = *src;
@@ -6712,12 +6711,8 @@ detect_coding (struct coding_system *coding)
else if (XFIXNUM (CODING_ATTR_CATEGORY (CODING_ID_ATTRS (coding->id)))
== coding_category_utf_8_auto)
{
- Lisp_Object coding_systems;
- struct coding_detection_info detect_info;
-
- coding_systems
+ Lisp_Object coding_systems
= AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_bom);
- detect_info.found = detect_info.rejected = 0;
if (check_ascii (coding) == coding->src_bytes)
{
if (CONSP (coding_systems))
@@ -6725,6 +6720,7 @@ detect_coding (struct coding_system *coding)
}
else
{
+ struct coding_detection_info detect_info = {0};
if (CONSP (coding_systems)
&& detect_coding_utf_8 (coding, &detect_info))
{
@@ -6738,20 +6734,19 @@ detect_coding (struct coding_system *coding)
else if (XFIXNUM (CODING_ATTR_CATEGORY (CODING_ID_ATTRS (coding->id)))
== coding_category_utf_16_auto)
{
- Lisp_Object coding_systems;
- struct coding_detection_info detect_info;
-
- coding_systems
+ Lisp_Object coding_systems
= AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_bom);
- detect_info.found = detect_info.rejected = 0;
coding->head_ascii = 0;
- if (CONSP (coding_systems)
- && detect_coding_utf_16 (coding, &detect_info))
+ if (CONSP (coding_systems))
{
- if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
- found = XCAR (coding_systems);
- else if (detect_info.found & CATEGORY_MASK_UTF_16_BE)
- found = XCDR (coding_systems);
+ struct coding_detection_info detect_info = {0};
+ if (detect_coding_utf_16 (coding, &detect_info))
+ {
+ if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
+ found = XCAR (coding_systems);
+ else if (detect_info.found & CATEGORY_MASK_UTF_16_BE)
+ found = XCDR (coding_systems);
+ }
}
}
@@ -8639,7 +8634,7 @@ detect_coding_system (const unsigned char *src,
Lisp_Object val = Qnil;
struct coding_system coding;
ptrdiff_t id;
- struct coding_detection_info detect_info;
+ struct coding_detection_info detect_info = {0};
enum coding_category base_category;
bool null_byte_found = 0, eight_bit_found = 0;
@@ -8658,8 +8653,6 @@ detect_coding_system (const unsigned char *src,
coding.mode |= CODING_MODE_LAST_BLOCK;
coding.head_ascii = 0;
- detect_info.checked = detect_info.found = detect_info.rejected = 0;
-
/* At first, detect text-format if necessary. */
base_category = XFIXNUM (CODING_ATTR_CATEGORY (attrs));
if (base_category == coding_category_undecided)
diff --git a/src/comp.c b/src/comp.c
index 66a7ab789a8..c230536ac59 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -756,12 +756,12 @@ comp_hash_source_file (Lisp_Object filename)
DEFUN ("comp--subr-signature", Fcomp__subr_signature,
Scomp__subr_signature, 1, 1, 0,
- doc: /* Support function to 'hash_native_abi'.
+ doc: /* Support function to hash_native_abi.
For internal use. */)
(Lisp_Object subr)
{
return concat2 (Fsubr_name (subr),
- Fprin1_to_string (Fsubr_arity (subr), Qnil));
+ Fprin1_to_string (Fsubr_arity (subr), Qnil, Qnil));
}
/* Produce a key hashing Vcomp_subr_list. */
@@ -1707,7 +1707,7 @@ static gcc_jit_lvalue *
emit_lisp_obj_reloc_lval (Lisp_Object obj)
{
emit_comment (format_string ("l-value for lisp obj: %s",
- SSDATA (Fprin1_to_string (obj, Qnil))));
+ SSDATA (Fprin1_to_string (obj, Qnil, Qnil))));
imm_reloc_t reloc = obj_to_reloc (obj);
return gcc_jit_context_new_array_access (comp.ctxt,
@@ -1720,7 +1720,7 @@ static gcc_jit_rvalue *
emit_lisp_obj_rval (Lisp_Object obj)
{
emit_comment (format_string ("const lisp obj: %s",
- SSDATA (Fprin1_to_string (obj, Qnil))));
+ SSDATA (Fprin1_to_string (obj, Qnil, Qnil))));
if (NILP (obj))
{
@@ -1968,7 +1968,7 @@ emit_mvar_rval (Lisp_Object mvar)
SSDATA (
Fprin1_to_string (
NILP (func) ? value : CALL1I (comp-func-c-name, func),
- Qnil)));
+ Qnil, Qnil)));
}
if (FIXNUMP (value))
{
@@ -2471,7 +2471,7 @@ emit_limple_insn (Lisp_Object insn)
else if (EQ (op, Qsetimm))
{
/* Ex: (setimm #s(comp-mvar 9 1 t 3 nil) a). */
- emit_comment (SSDATA (Fprin1_to_string (arg[1], Qnil)));
+ emit_comment (SSDATA (Fprin1_to_string (arg[1], Qnil, Qnil)));
imm_reloc_t reloc = obj_to_reloc (arg[1]);
emit_frame_assignment (
arg[0],
@@ -2647,7 +2647,7 @@ emit_static_object (const char *name, Lisp_Object obj)
specbind (intern_c_string ("print-quoted"), Qt);
specbind (intern_c_string ("print-gensym"), Qt);
specbind (intern_c_string ("print-circle"), Qt);
- Lisp_Object str = Fprin1_to_string (obj, Qnil);
+ Lisp_Object str = Fprin1_to_string (obj, Qnil, Qnil);
unbind_to (count, Qnil);
ptrdiff_t len = SBYTES (str);
@@ -4262,7 +4262,7 @@ compile_function (Lisp_Object func)
{
Lisp_Object block_name = HASH_KEY (ht, i);
if (!EQ (block_name, Qentry)
- && !EQ (block_name, Qunbound))
+ && !BASE_EQ (block_name, Qunbound))
declare_block (block_name);
}
@@ -4275,7 +4275,7 @@ compile_function (Lisp_Object func)
for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (ht); i++)
{
Lisp_Object block_name = HASH_KEY (ht, i);
- if (!EQ (block_name, Qunbound))
+ if (!BASE_EQ (block_name, Qunbound))
{
Lisp_Object block = HASH_VALUE (ht, i);
Lisp_Object insns = CALL1I (comp-block-insns, block);
@@ -4890,12 +4890,12 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
struct Lisp_Hash_Table *func_h =
XHASH_TABLE (CALL1I (comp-ctxt-funcs-h, Vcomp_ctxt));
for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (func_h); i++)
- if (!EQ (HASH_VALUE (func_h, i), Qunbound))
+ if (!BASE_EQ (HASH_VALUE (func_h, i), Qunbound))
declare_function (HASH_VALUE (func_h, i));
/* Compile all functions. Can't be done before because the
relocation structs has to be already defined. */
for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (func_h); i++)
- if (!EQ (HASH_VALUE (func_h, i), Qunbound))
+ if (!BASE_EQ (HASH_VALUE (func_h, i), Qunbound))
compile_function (HASH_VALUE (func_h, i));
/* Work around bug#46495 (GCC PR99126). */
@@ -5342,7 +5342,7 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
are necessary exclusively during the first load. Once these
are collected we don't have to maintain them in the heap
forever. */
- Lisp_Object volatile data_ephemeral_vec;
+ Lisp_Object volatile data_ephemeral_vec = Qnil;
/* In case another load of the same CU is active on the stack
all ephemeral data is hold by that frame. Re-writing
'data_ephemeral_vec' would be not only a waste of cycles but
diff --git a/src/composite.c b/src/composite.c
index c2ade90d54a..4d69702171f 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -688,7 +688,7 @@ composition_gstring_cache_clear_font (Lisp_Object font_object)
{
Lisp_Object k = HASH_KEY (h, i);
- if (!EQ (k, Qunbound))
+ if (!BASE_EQ (k, Qunbound))
{
Lisp_Object gstring = HASH_VALUE (h, i);
diff --git a/src/data.c b/src/data.c
index 8dbb2902a72..2447ed72e4a 100644
--- a/src/data.c
+++ b/src/data.c
@@ -705,7 +705,7 @@ global value outside of any lexical scope. */)
default: emacs_abort ();
}
- return (EQ (valcontents, Qunbound) ? Qnil : Qt);
+ return (BASE_EQ (valcontents, Qunbound) ? Qnil : Qt);
}
/* It has been previously suggested to make this function an alias for
@@ -1591,7 +1591,7 @@ global value outside of any lexical scope. */)
Lisp_Object val;
val = find_symbol_value (symbol);
- if (!EQ (val, Qunbound))
+ if (!BASE_EQ (val, Qunbound))
return val;
xsignal1 (Qvoid_variable, symbol);
@@ -1618,7 +1618,7 @@ void
set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
enum Set_Internal_Bind bindflag)
{
- bool voide = EQ (newval, Qunbound);
+ bool voide = BASE_EQ (newval, Qunbound);
/* If restoring in a dead buffer, do nothing. */
/* if (BUFFERP (where) && NILP (XBUFFER (where)->name))
@@ -1945,15 +1945,15 @@ default_value (Lisp_Object symbol)
DEFUN ("default-boundp", Fdefault_boundp, Sdefault_boundp, 1, 1, 0,
doc: /* Return t if SYMBOL has a non-void default value.
-A variable may have a buffer-local or a `let'-bound local value. This
-function says whether the variable has a non-void value outside of the
-current context. Also see `default-value'. */)
+A variable may have a buffer-local value. This function says whether
+the variable has a non-void value outside of the current buffer
+context. Also see `default-value'. */)
(Lisp_Object symbol)
{
register Lisp_Object value;
value = default_value (symbol);
- return (EQ (value, Qunbound) ? Qnil : Qt);
+ return (BASE_EQ (value, Qunbound) ? Qnil : Qt);
}
DEFUN ("default-value", Fdefault_value, Sdefault_value, 1, 1, 0,
@@ -1964,7 +1964,7 @@ local bindings in certain buffers. */)
(Lisp_Object symbol)
{
Lisp_Object value = default_value (symbol);
- if (!EQ (value, Qunbound))
+ if (!BASE_EQ (value, Qunbound))
return value;
xsignal1 (Qvoid_variable, symbol);
@@ -2144,7 +2144,7 @@ See also `defvar-local'. */)
case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
case SYMBOL_PLAINVAL:
forwarded = 0; valcontents.value = SYMBOL_VAL (sym);
- if (EQ (valcontents.value, Qunbound))
+ if (BASE_EQ (valcontents.value, Qunbound))
valcontents.value = Qnil;
break;
case SYMBOL_LOCALIZED:
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 7cfdbbe23cf..943a4aff8e7 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1690,29 +1690,30 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
/* Loop over the registered functions. Construct an event. */
- while (!NILP (value))
+ for (; !NILP (value); value = CDR_SAFE (value))
{
key = CAR_SAFE (value);
+ Lisp_Object key_uname = CAR_SAFE (key);
/* key has the structure (UNAME SERVICE PATH HANDLER). */
- if (((uname == NULL)
- || (NILP (CAR_SAFE (key)))
- || (strcmp (uname, SSDATA (CAR_SAFE (key))) == 0))
- && ((path == NULL)
- || (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
- || (strcmp (path,
- SSDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
- == 0))
- && (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))))))
- {
- EVENT_INIT (event);
- event.kind = DBUS_EVENT;
- event.frame_or_window = Qnil;
- /* Handler. */
- event.arg
- = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args);
- break;
- }
- value = CDR_SAFE (value);
+ if (uname && !NILP (key_uname)
+ && strcmp (uname, SSDATA (key_uname)) != 0)
+ continue;
+ Lisp_Object key_service_etc = CDR_SAFE (key);
+ Lisp_Object key_path_etc = CDR_SAFE (key_service_etc);
+ Lisp_Object key_path = CAR_SAFE (key_path_etc);
+ if (path && !NILP (key_path)
+ && strcmp (path, SSDATA (key_path)) != 0)
+ continue;
+ Lisp_Object handler = CAR_SAFE (CDR_SAFE (key_path_etc));
+ if (NILP (handler))
+ continue;
+
+ /* Construct an event and exit the loop. */
+ EVENT_INIT (event);
+ event.kind = DBUS_EVENT;
+ event.frame_or_window = Qnil;
+ event.arg = Fcons (handler, args);
+ break;
}
if (NILP (value))
diff --git a/src/dispextern.h b/src/dispextern.h
index e9b19a7f135..c7399ca2998 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1075,6 +1075,9 @@ struct glyph_row
right-to-left paragraph. */
bool_bf reversed_p : 1;
+ /* Whether or not a stipple was drawn in this row at some point. */
+ bool_bf stipple_p : 1;
+
/* Continuation lines width at the start of the row. */
int continuation_lines_width;
@@ -3467,6 +3470,7 @@ extern void expose_frame (struct frame *, int, int, int, int);
extern bool gui_intersect_rectangles (const Emacs_Rectangle *,
const Emacs_Rectangle *,
Emacs_Rectangle *);
+extern void gui_consider_frame_title (Lisp_Object);
#endif /* HAVE_WINDOW_SYSTEM */
extern void note_mouse_highlight (struct frame *, int, int);
@@ -3612,6 +3616,9 @@ void gamma_correct (struct frame *, XColor *);
#ifdef HAVE_NTGUI
void gamma_correct (struct frame *, COLORREF *);
#endif
+#ifdef HAVE_HAIKU
+void gamma_correct (struct frame *, Emacs_Color *);
+#endif
#ifdef HAVE_WINDOW_SYSTEM
diff --git a/src/dispnew.c b/src/dispnew.c
index 1dd64be4ead..7a4d9f8710b 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -1837,7 +1837,18 @@ adjust_frame_glyphs (struct frame *f)
if (FRAME_WINDOW_P (f))
adjust_frame_glyphs_for_window_redisplay (f);
else
- adjust_frame_glyphs_for_frame_redisplay (f);
+ {
+ adjust_frame_glyphs_for_frame_redisplay (f);
+ eassert (FRAME_INITIAL_P (f)
+ || noninteractive
+ || !initialized
+ || (f->current_matrix
+ && f->current_matrix->nrows > 0
+ && f->current_matrix->rows
+ && f->desired_matrix
+ && f->desired_matrix->nrows > 0
+ && f->desired_matrix->rows));
+ }
/* Don't forget the buffer for decode_mode_spec. */
adjust_decode_mode_spec_buffer (f);
@@ -2119,6 +2130,19 @@ adjust_frame_glyphs_for_frame_redisplay (struct frame *f)
SET_FRAME_GARBAGED (f);
}
}
+ else if (!FRAME_INITIAL_P (f) && !noninteractive && initialized)
+ {
+ if (!f->desired_matrix->nrows || !f->desired_matrix->rows)
+ {
+ adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim);
+ SET_FRAME_GARBAGED (f);
+ }
+ if (!f->current_matrix->nrows || !f->current_matrix->rows)
+ {
+ adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
+ SET_FRAME_GARBAGED (f);
+ }
+ }
}
@@ -3907,7 +3931,8 @@ update_marginal_area (struct window *w, struct glyph_row *updated_row,
Value is true if display has changed. */
static bool
-update_text_area (struct window *w, struct glyph_row *updated_row, int vpos)
+update_text_area (struct window *w, struct glyph_row *updated_row, int vpos,
+ bool *partial_p)
{
struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
@@ -4013,6 +4038,13 @@ update_text_area (struct window *w, struct glyph_row *updated_row, int vpos)
{
x += desired_glyph->pixel_width;
++desired_glyph, ++current_glyph, ++i;
+
+ /* Say that only a partial update was performed of
+ the current row (i.e. not all the glyphs were
+ drawn). This is used to preserve the stipple_p
+ flag of the current row inside
+ update_window_line. */
+ *partial_p = true;
}
/* Consider the case that the current row contains "xxx
@@ -4084,9 +4116,15 @@ update_text_area (struct window *w, struct glyph_row *updated_row, int vpos)
rif->write_glyphs (w, updated_row, start,
TEXT_AREA, i - start_hpos);
changed_p = 1;
+ *partial_p = true;
}
}
+ /* This means we will draw from the start, so no partial update
+ is being performed. */
+ if (!i)
+ *partial_p = false;
+
/* Write the rest. */
if (i < desired_row->used[TEXT_AREA])
{
@@ -4159,7 +4197,9 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w)));
- bool changed_p = 0;
+
+ /* partial_p is true if not all of desired_row was drawn. */
+ bool changed_p = 0, partial_p = 0, was_stipple;
/* A row can be completely invisible in case a desired matrix was
built with a vscroll and then make_cursor_line_fully_visible shifts
@@ -4183,7 +4223,7 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
}
/* Update the display of the text area. */
- if (update_text_area (w, desired_row, vpos))
+ if (update_text_area (w, desired_row, vpos, &partial_p))
{
changed_p = 1;
if (current_row->mouse_face_p)
@@ -4212,7 +4252,17 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
}
/* Update current_row from desired_row. */
+ was_stipple = current_row->stipple_p;
make_current (w->desired_matrix, w->current_matrix, vpos);
+
+ /* If only a partial update was performed, any stipple already
+ displayed in MATRIX_ROW (w->current_matrix, vpos) might still be
+ there, so don't hurry to clear that flag if it's not in
+ desired_row. */
+
+ if (partial_p && was_stipple)
+ current_row->stipple_p = true;
+
return changed_p;
}
@@ -4392,7 +4442,6 @@ add_row_entry (struct glyph_row *row)
return entry;
}
-
/* Try to reuse part of the current display of W by scrolling lines.
HEADER_LINE_P means W has a header line.
@@ -4438,6 +4487,14 @@ scrolling_window (struct window *w, int tab_line_p)
struct glyph_row *d = MATRIX_ROW (desired_matrix, i);
struct glyph_row *c = MATRIX_ROW (current_matrix, i);
+ /* If there is a row with a stipple currently on the glass, give
+ up. Stipples look different depending on where on the
+ display they are drawn, so scrolling the display will produce
+ incorrect results. */
+
+ if (c->stipple_p)
+ return 0;
+
if (c->enabled_p
&& d->enabled_p
&& !d->redraw_fringe_bitmaps_p
@@ -4467,6 +4524,16 @@ scrolling_window (struct window *w, int tab_line_p)
first_old = first_new = i;
+ while (i < current_matrix->nrows - 1)
+ {
+ /* If there is a stipple after the first change, give up as
+ well. */
+ if (MATRIX_ROW (current_matrix, i)->stipple_p)
+ return 0;
+
+ ++i;
+ }
+
/* Set last_new to the index + 1 of the row that reaches the
bottom boundary in the desired matrix. Give up if we find a
disabled row before we reach the bottom boundary. */
diff --git a/src/doc.c b/src/doc.c
index 71e66853b08..14db3189f34 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -569,6 +569,8 @@ the same file name is found in the `doc-directory'. */)
if (p)
{
end = strchr (p, '\n');
+ if (!end)
+ error ("DOC file invalid at position %"pI"d", pos);
/* We used to skip files not in build_files, so that when a
function was defined several times in different files
diff --git a/src/editfns.c b/src/editfns.c
index 6cb684d4d85..17f0252969e 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3327,7 +3327,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
if (EQ (arg, args[n]))
{
Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
- spec->argument = arg = Fprin1_to_string (arg, noescape);
+ spec->argument = arg = Fprin1_to_string (arg, noescape, Qnil);
if (STRING_MULTIBYTE (arg) && ! multibyte)
{
multibyte = true;
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 0d3cce0276b..1c392d65df8 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -411,7 +411,7 @@ module_global_reference_p (emacs_value v, ptrdiff_t *n)
reference that's identical to some global reference. */
for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
{
- if (!EQ (HASH_KEY (h, i), Qunbound)
+ if (!BASE_EQ (HASH_KEY (h, i), Qunbound)
&& &XMODULE_GLOBAL_REFERENCE (HASH_VALUE (h, i))->value == v)
return true;
}
diff --git a/src/emacs.c b/src/emacs.c
index 9f20a1597c9..189692a02ea 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1409,7 +1409,7 @@ main (int argc, char **argv)
related to the GUI system, like -font, -geometry, and -title, and
then processes the rest of arguments whose priority is below
those that are related to the GUI system. The arguments
- porcessed by 'command-line' are removed from 'command-line-args';
+ processed by 'command-line' are removed from 'command-line-args';
the arguments processed by 'command-line-1' aren't, they are only
removed from 'command-line-args-left'.
@@ -1419,54 +1419,19 @@ main (int argc, char **argv)
should be explicitly recognized, ignored, and removed from
'command-line-args-left' in 'command-line-1'. */
+ bool only_version = false;
sort_args (argc, argv);
argc = 0;
while (argv[argc]) argc++;
skip_args = 0;
if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args))
- {
- const char *version, *copyright;
- if (initialized)
- {
- Lisp_Object tem, tem2;
- tem = Fsymbol_value (intern_c_string ("emacs-version"));
- tem2 = Fsymbol_value (intern_c_string ("emacs-copyright"));
- if (!STRINGP (tem))
- {
- fputs ("Invalid value of 'emacs-version'\n", stderr);
- exit (1);
- }
- if (!STRINGP (tem2))
- {
- fputs ("Invalid value of 'emacs-copyright'\n", stderr);
- exit (1);
- }
- else
- {
- version = SSDATA (tem);
- copyright = SSDATA (tem2);
- }
- }
- else
- {
- version = emacs_version;
- copyright = emacs_copyright;
- }
- printf (("%s %s\n"
- "%s\n"
- "%s comes with ABSOLUTELY NO WARRANTY.\n"
- "You may redistribute copies of %s\n"
- "under the terms of the GNU General Public License.\n"
- "For more information about these matters, "
- "see the file named COPYING.\n"),
- PACKAGE_NAME, version, copyright, PACKAGE_NAME, PACKAGE_NAME);
- exit (0);
- }
+ only_version = true;
#ifdef HAVE_PDUMPER
if (argmatch (argv, argc, "-fingerprint", "--fingerprint", 4,
- NULL, &skip_args))
+ NULL, &skip_args)
+ && !only_version)
{
if (initialized)
{
@@ -1491,7 +1456,8 @@ main (int argc, char **argv)
pdumper_record_wd (emacs_wd);
#endif
- if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
+ if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args)
+ && !only_version)
{
#ifdef WINDOWSNT
/* argv[] array is kept in its original ANSI codepage encoding,
@@ -1617,7 +1583,7 @@ main (int argc, char **argv)
inhibit_window_system = 0;
/* Handle the -t switch, which specifies filename to use as terminal. */
- while (1)
+ while (!only_version)
{
char *term;
if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args))
@@ -1655,7 +1621,8 @@ main (int argc, char **argv)
/* Handle the -batch switch, which means don't do interactive display. */
noninteractive = 0;
- if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args))
+ if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args)
+ || only_version)
{
noninteractive = 1;
Vundo_outer_limit = Qnil;
@@ -1672,7 +1639,8 @@ main (int argc, char **argv)
}
/* Handle the --help option, which gives a usage message. */
- if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args))
+ if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args)
+ && !only_version)
{
int i;
printf ("Usage: %s [OPTION-OR-FILENAME]...\n", argv[0]);
@@ -1693,20 +1661,27 @@ main (int argc, char **argv)
int sockfd = -1;
- if (argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, NULL, &skip_args)
- || argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, &dname_arg, &skip_args))
+ if (!only_version)
{
- daemon_type = 1; /* foreground */
- }
- else if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)
- || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg, &skip_args)
- || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10, NULL, &skip_args)
- || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10, &dname_arg, &skip_args))
- {
- daemon_type = 2; /* background */
+ if (argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, NULL,
+ &skip_args)
+ || argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, &dname_arg,
+ &skip_args))
+ {
+ daemon_type = 1; /* foreground */
+ }
+ else if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)
+ || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg,
+ &skip_args)
+ || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10, NULL,
+ &skip_args)
+ || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10,
+ &dname_arg, &skip_args))
+ {
+ daemon_type = 2; /* background */
+ }
}
-
if (daemon_type > 0)
{
#ifndef DOS_NT
@@ -1956,15 +1931,11 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
init_threads ();
init_eval ();
#ifdef HAVE_PGTK
- init_pgtkterm (); /* before init_atimer(). */
+ init_pgtkterm (); /* Must come before `init_atimer'. */
#endif
running_asynch_code = 0;
init_random ();
-
-#ifdef HAVE_PDUMPER
- if (dumped_with_pdumper_p ())
- init_xfaces ();
-#endif
+ init_xfaces ();
#if defined HAVE_JSON && !defined WINDOWSNT
init_json ();
@@ -1986,7 +1957,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
bool module_assertions
= argmatch (argv, argc, "-module-assertions", "--module-assertions", 15,
NULL, &skip_args);
- if (will_dump_p () && module_assertions)
+ if (will_dump_p () && module_assertions && !only_version)
{
fputs ("Module assertions are not supported during dumping\n", stderr);
exit (1);
@@ -2034,7 +2005,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
int count_before = skip_args;
/* Skip any number of -d options, but only use the last one. */
- while (1)
+ while (!only_version)
{
int count_before_this = skip_args;
@@ -2176,6 +2147,72 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */
init_fileio ();
init_lread ();
+
+ /* If "-version" was specified, produce version information and
+ exit. We do it here because the code below needs to call Lisp
+ primitives, which cannot be done safely before we call all the
+ init_FOO initialization functions above. */
+ if (only_version)
+ {
+ const char *version, *copyright;
+
+ if (initialized)
+ {
+ Lisp_Object tem = Fsymbol_value (intern_c_string ("emacs-version"));
+ Lisp_Object tem2 = Fsymbol_value (intern_c_string ("emacs-copyright"));
+ if (!STRINGP (tem))
+ {
+ fputs ("Invalid value of 'emacs-version'\n", stderr);
+ exit (1);
+ }
+ if (!STRINGP (tem2))
+ {
+ fputs ("Invalid value of 'emacs-copyright'\n", stderr);
+ exit (1);
+ }
+ else
+ {
+ version = SSDATA (tem);
+ copyright = SSDATA (tem2);
+ }
+ }
+ else
+ {
+ version = emacs_version;
+ copyright = emacs_copyright;
+ }
+ printf ("%s %s\n", PACKAGE_NAME, version);
+
+ if (initialized)
+ {
+ Lisp_Object rversion, rbranch, rtime;
+
+ rversion
+ = Fsymbol_value (intern_c_string ("emacs-repository-version"));
+ rbranch
+ = Fsymbol_value (intern_c_string ("emacs-repository-branch"));
+ rtime
+ = Fsymbol_value (intern_c_string ("emacs-build-time"));
+
+ if (!NILP (rversion) && !NILP (rbranch) && !NILP (rtime))
+ printf ("Development version %s on %s branch; build date %s.\n",
+ SSDATA (Fsubstring (rversion, make_fixnum (0),
+ make_fixnum (12))),
+ SSDATA (rbranch),
+ SSDATA (Fformat_time_string (build_string ("%Y-%m-%d"),
+ rtime, Qnil)));
+ }
+
+ printf (("%s\n"
+ "%s comes with ABSOLUTELY NO WARRANTY.\n"
+ "You may redistribute copies of %s\n"
+ "under the terms of the GNU General Public License.\n"
+ "For more information about these matters, "
+ "see the file named COPYING.\n"),
+ copyright, PACKAGE_NAME, PACKAGE_NAME);
+ exit (0);
+ }
+
#ifdef WINDOWSNT
/* Check to see if Emacs has been installed correctly. */
check_windows_init_file ();
@@ -2954,6 +2991,10 @@ shut_down_emacs (int sig, Lisp_Object stuff)
check_message_stack ();
}
+#ifdef HAVE_NATIVE_COMP
+ eln_load_path_final_clean_up ();
+#endif
+
#ifdef MSDOS
dos_cleanup ();
#endif
diff --git a/src/eval.c b/src/eval.c
index 3ec03de1376..45ddbab2a2c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -707,7 +707,7 @@ DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_valu
union specbinding *binding = default_toplevel_binding (symbol);
Lisp_Object value
= binding ? specpdl_old_value (binding) : Fdefault_value (symbol);
- if (!EQ (value, Qunbound))
+ if (!BASE_EQ (value, Qunbound))
return value;
xsignal1 (Qvoid_variable, symbol);
}
@@ -741,7 +741,9 @@ value. */)
and where the `foo` package only gets loaded when <foo-function>
is called, so the outer `let` incorrectly made the binding lexical
because the <foo-var> wasn't yet declared as dynamic at that point. */
- error ("Defining as dynamic an already lexical var");
+ xsignal2 (Qerror,
+ build_string ("Defining as dynamic an already lexical var"),
+ symbol);
XSYMBOL (symbol)->u.s.declared_special = true;
if (!NILP (doc))
@@ -754,6 +756,33 @@ value. */)
return Qnil;
}
+static Lisp_Object
+defvar (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring, bool eval)
+{
+ Lisp_Object tem;
+
+ CHECK_SYMBOL (sym);
+
+ tem = Fdefault_boundp (sym);
+
+ /* Do it before evaluating the initial value, for self-references. */
+ Finternal__define_uninitialized_variable (sym, docstring);
+
+ if (NILP (tem))
+ Fset_default (sym, eval ? eval_sub (initvalue) : initvalue);
+ else
+ { /* Check if there is really a global binding rather than just a let
+ binding that shadows the global unboundness of the var. */
+ union specbinding *binding = default_toplevel_binding (sym);
+ if (binding && BASE_EQ (specpdl_old_value (binding), Qunbound))
+ {
+ set_specpdl_old_value (binding,
+ eval ? eval_sub (initvalue) : initvalue);
+ }
+ }
+ return sym;
+}
+
DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0,
doc: /* Define SYMBOL as a variable, and return SYMBOL.
You are not required to define a variable in order to use it, but
@@ -768,12 +797,10 @@ value. If SYMBOL is buffer-local, its default value is what is set;
buffer-local values are not affected. If INITVALUE is missing,
SYMBOL's value is not set.
-If SYMBOL has a local binding, then this form affects the local
-binding. This is usually not what you want. Thus, if you need to
-load a file defining variables, with this form or with `defconst' or
-`defcustom', you should always load that file _outside_ any bindings
-for these variables. (`defconst' and `defcustom' behave similarly in
-this respect.)
+If SYMBOL is let-bound, then this form does not affect the local let
+binding but the toplevel default binding instead, like
+`set-toplevel-default-binding`.
+(`defcustom' behaves similarly in this respect.)
The optional argument DOCSTRING is a documentation string for the
variable.
@@ -784,7 +811,7 @@ To define a buffer-local variable, use `defvar-local'.
usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
(Lisp_Object args)
{
- Lisp_Object sym, tem, tail;
+ Lisp_Object sym, tail;
sym = XCAR (args);
tail = XCDR (args);
@@ -796,24 +823,8 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
if (!NILP (XCDR (tail)) && !NILP (XCDR (XCDR (tail))))
error ("Too many arguments");
Lisp_Object exp = XCAR (tail);
-
- tem = Fdefault_boundp (sym);
tail = XCDR (tail);
-
- /* Do it before evaluating the initial value, for self-references. */
- Finternal__define_uninitialized_variable (sym, CAR (tail));
-
- if (NILP (tem))
- Fset_default (sym, eval_sub (exp));
- else
- { /* Check if there is really a global binding rather than just a let
- binding that shadows the global unboundness of the var. */
- union specbinding *binding = default_toplevel_binding (sym);
- if (binding && EQ (specpdl_old_value (binding), Qunbound))
- {
- set_specpdl_old_value (binding, eval_sub (exp));
- }
- }
+ return defvar (sym, exp, CAR (tail), true);
}
else if (!NILP (Vinternal_interpreter_environment)
&& (SYMBOLP (sym) && !XSYMBOL (sym)->u.s.declared_special))
@@ -832,6 +843,14 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
return sym;
}
+DEFUN ("defvar-1", Fdefvar_1, Sdefvar_1, 2, 3, 0,
+ doc: /* Like `defvar' but as a function.
+More specifically behaves like (defvar SYM 'INITVALUE DOCSTRING). */)
+ (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring)
+{
+ return defvar (sym, initvalue, docstring, false);
+}
+
DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
doc: /* Define SYMBOL as a constant variable.
This declares that neither programs nor users should ever change the
@@ -861,9 +880,18 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING]) */)
error ("Too many arguments");
docstring = XCAR (XCDR (XCDR (args)));
}
+ tem = eval_sub (XCAR (XCDR (args)));
+ return Fdefconst_1 (sym, tem, docstring);
+}
+DEFUN ("defconst-1", Fdefconst_1, Sdefconst_1, 2, 3, 0,
+ doc: /* Like `defconst' but as a function.
+More specifically, behaves like (defconst SYM 'INITVALUE DOCSTRING). */)
+ (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring)
+{
+ CHECK_SYMBOL (sym);
+ Lisp_Object tem = initvalue;
Finternal__define_uninitialized_variable (sym, docstring);
- tem = eval_sub (XCAR (XCDR (args)));
if (!NILP (Vpurify_flag))
tem = Fpurecopy (tem);
Fset_default (sym, tem); /* FIXME: set-default-toplevel-value? */
@@ -1223,6 +1251,13 @@ unwind_to_catch (struct handler *catch, enum nonlocal_exit type,
set_poll_suppress_count (catch->poll_suppress_count);
unblock_input_to (catch->interrupt_input_blocked);
+#ifdef HAVE_X_WINDOWS
+ /* Restore the X error handler stack. This is important because
+ otherwise a display disconnect won't unwind the stack of error
+ traps to the right depth. */
+ x_unwind_errors_to (catch->x_error_handler_depth);
+#endif
+
do
{
/* Unwind the specpdl stack, and then restore the proper set of
@@ -1341,7 +1376,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
&& (SYMBOLP (XCAR (tem))
|| CONSP (XCAR (tem))))))
error ("Invalid condition handler: %s",
- SDATA (Fprin1_to_string (tem, Qt)));
+ SDATA (Fprin1_to_string (tem, Qt, Qnil)));
if (CONSP (tem) && EQ (XCAR (tem), QCsuccess))
success_handler = XCDR (tem);
else
@@ -1597,6 +1632,9 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
c->act_rec = get_act_rec (current_thread);
c->poll_suppress_count = poll_suppress_count;
c->interrupt_input_blocked = interrupt_input_blocked;
+#ifdef HAVE_X_WINDOWS
+ c->x_error_handler_depth = x_error_message_count;
+#endif
handlerlist = c;
return c;
}
@@ -2740,7 +2778,7 @@ run_hook_with_args (ptrdiff_t nargs, Lisp_Object *args,
sym = args[0];
val = find_symbol_value (sym);
- if (EQ (val, Qunbound) || NILP (val))
+ if (BASE_EQ (val, Qunbound) || NILP (val))
return ret;
else if (!CONSP (val) || FUNCTIONP (val))
{
@@ -2816,7 +2854,13 @@ apply1 (Lisp_Object fn, Lisp_Object arg)
}
DEFUN ("functionp", Ffunctionp, Sfunctionp, 1, 1, 0,
- doc: /* Return t if OBJECT is a function. */)
+ doc: /* Return t if OBJECT is a function.
+
+An object is a function if it is callable via `funcall'; this includes
+symbols with function bindings, but excludes macros and special forms.
+
+Ordinarily return nil if OBJECT is not a function, although t might be
+returned in rare cases. */)
(Lisp_Object object)
{
if (FUNCTIONP (object))
@@ -4338,9 +4382,11 @@ alist of active lexical bindings. */);
defsubr (&Sdefault_toplevel_value);
defsubr (&Sset_default_toplevel_value);
defsubr (&Sdefvar);
+ defsubr (&Sdefvar_1);
defsubr (&Sdefvaralias);
DEFSYM (Qdefvaralias, "defvaralias");
defsubr (&Sdefconst);
+ defsubr (&Sdefconst_1);
defsubr (&Sinternal__define_uninitialized_variable);
defsubr (&Smake_var_non_special);
defsubr (&Slet);
diff --git a/src/fileio.c b/src/fileio.c
index c418036fc6e..e29685e07bf 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2718,6 +2718,20 @@ This is what happens in interactive use with M-x. */)
: Qnil);
if (!NILP (symlink_target))
Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists);
+ else if (S_ISFIFO (file_st.st_mode))
+ {
+ /* If it's a FIFO, calling `copy-file' will hang if it's a
+ inter-file system move, so do it here. (It will signal
+ an error in that case, but it won't hang in any case.) */
+ if (!NILP (ok_if_already_exists))
+ barf_or_query_if_file_exists (newname, false,
+ "rename to it",
+ FIXNUMP (ok_if_already_exists),
+ false);
+ if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) != 0)
+ report_file_errno ("Renaming", list2 (file, newname), errno);
+ return Qnil;
+ }
else
Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt);
}
@@ -3884,6 +3898,10 @@ The optional third and fourth arguments BEG and END specify what portion
of the file to insert. These arguments count bytes in the file, not
characters in the buffer. If VISIT is non-nil, BEG and END must be nil.
+When inserting data from a special file (e.g., /dev/urandom), you
+can't specify VISIT or BEG, and END should be specified to avoid
+inserting unlimited data into the buffer.
+
If optional fifth argument REPLACE is non-nil, replace the current
buffer contents (in the accessible portion) with the file contents.
This is better than simply deleting and inserting the whole thing
@@ -3911,7 +3929,7 @@ by calling `format-decode', which see. */)
Lisp_Object handler, val, insval, orig_filename, old_undo;
Lisp_Object p;
ptrdiff_t total = 0;
- bool not_regular = 0;
+ bool regular = true;
int save_errno = 0;
char read_buf[READ_BUF_SIZE];
struct coding_system coding;
@@ -3934,6 +3952,7 @@ by calling `format-decode', which see. */)
/* SAME_AT_END_CHARPOS counts characters, because
restore_window_points needs the old character count. */
ptrdiff_t same_at_end_charpos = ZV;
+ bool seekable = true;
if (current_buffer->base_buffer && ! NILP (visit))
error ("Cannot do file visiting in an indirect buffer");
@@ -4007,7 +4026,8 @@ by calling `format-decode', which see. */)
least signal an error. */
if (!S_ISREG (st.st_mode))
{
- not_regular = 1;
+ regular = false;
+ seekable = lseek (fd, 0, SEEK_CUR) < 0;
if (! NILP (visit))
{
@@ -4015,7 +4035,12 @@ by calling `format-decode', which see. */)
goto notfound;
}
- if (! NILP (replace) || ! NILP (beg) || ! NILP (end))
+ if (!NILP (beg) && !seekable)
+ xsignal2 (Qfile_error,
+ build_string ("cannot use a start position in a non-seekable file/device"),
+ orig_filename);
+
+ if (!NILP (replace))
xsignal2 (Qfile_error,
build_string ("not a regular file"), orig_filename);
}
@@ -4037,7 +4062,7 @@ by calling `format-decode', which see. */)
end_offset = file_offset (end);
else
{
- if (not_regular)
+ if (!regular)
end_offset = TYPE_MAXIMUM (off_t);
else
{
@@ -4059,7 +4084,7 @@ by calling `format-decode', which see. */)
/* Check now whether the buffer will become too large,
in the likely case where the file's length is not changing.
This saves a lot of needless work before a buffer overflow. */
- if (! not_regular)
+ if (regular)
{
/* The likely offset where we will stop reading. We could read
more (or less), if the file grows (or shrinks) as we read it. */
@@ -4097,7 +4122,7 @@ by calling `format-decode', which see. */)
{
/* Don't try looking inside a file for a coding system
specification if it is not seekable. */
- if (! not_regular && ! NILP (Vset_auto_coding_function))
+ if (regular && !NILP (Vset_auto_coding_function))
{
/* Find a coding system specified in the heading two
lines or in the tailing several lines of the file.
@@ -4559,7 +4584,7 @@ by calling `format-decode', which see. */)
goto handled;
}
- if (! not_regular)
+ if (seekable || !NILP (end))
total = end_offset - beg_offset;
else
/* For a special file, all we can do is guess. */
@@ -4605,7 +4630,7 @@ by calling `format-decode', which see. */)
ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE);
ptrdiff_t this;
- if (not_regular)
+ if (!seekable && NILP (end))
{
Lisp_Object nbytes;
@@ -4656,7 +4681,7 @@ by calling `format-decode', which see. */)
For a special file, where TOTAL is just a buffer size,
so don't bother counting in HOW_MUCH.
(INSERTED is where we count the number of characters inserted.) */
- if (! not_regular)
+ if (seekable || !NILP (end))
how_much += this;
inserted += this;
}
@@ -4834,7 +4859,7 @@ by calling `format-decode', which see. */)
Funlock_file (BVAR (current_buffer, file_truename));
Funlock_file (filename);
}
- if (not_regular)
+ if (!regular)
xsignal2 (Qfile_error,
build_string ("not a regular file"), orig_filename);
}
@@ -5958,14 +5983,19 @@ do_auto_save_eh (Lisp_Object ignore)
DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
doc: /* Auto-save all buffers that need it.
-This is all buffers that have auto-saving enabled
-and are changed since last auto-saved.
-Auto-saving writes the buffer into a file
-so that your editing is not lost if the system crashes.
-This file is not the file you visited; that changes only when you save.
+This auto-saves all buffers that have auto-saving enabled and
+were changed since last auto-saved.
+
+Auto-saving writes the buffer into a file so that your edits are
+not lost if the system crashes.
+
+The auto-save file is not the file you visited; that changes only
+when you save.
+
Normally, run the normal hook `auto-save-hook' before saving.
A non-nil NO-MESSAGE argument means do not print any message if successful.
+
A non-nil CURRENT-ONLY argument means save only current buffer. */)
(Lisp_Object no_message, Lisp_Object current_only)
{
diff --git a/src/floatfns.c b/src/floatfns.c
index f2b3b13acd8..293184c70f1 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -29,14 +29,20 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
C99 and C11 require the following math.h functions in addition to
the C89 functions. Of these, Emacs currently exports only the
- starred ones to Lisp, since we haven't found a use for the others:
- acosh, atanh, cbrt, *copysign, erf, erfc, exp2, expm1, fdim, fma,
- fmax, fmin, fpclassify, hypot, ilogb, isfinite, isgreater,
- isgreaterequal, isinf, isless, islessequal, islessgreater, *isnan,
- isnormal, isunordered, lgamma, log1p, *log2 [via (log X 2)], *logb
- (approximately), lrint/llrint, lround/llround, nan, nearbyint,
- nextafter, nexttoward, remainder, remquo, *rint, round, scalbln,
- scalbn, signbit, tgamma, *trunc.
+ starred ones to Lisp, since we haven't found a use for the others.
+ Also, it uses the ones marked "+" internally:
+ acosh, atanh, cbrt, copysign (implemented by signbit), erf, erfc,
+ exp2, expm1, fdim, fma, fmax, fmin, fpclassify, hypot, +ilogb,
+ isfinite, isgreater, isgreaterequal, isinf, isless, islessequal,
+ islessgreater, *isnan, isnormal, isunordered, lgamma, log1p, *log2
+ [via (log X 2)], logb (approximately; implemented by frexp),
+ +lrint/llrint, +lround/llround, nan, nearbyint, nextafter,
+ nexttoward, remainder, remquo, *rint, round, scalbln, +scalbn,
+ +signbit, tgamma, *trunc.
+
+ The C standard also requires functions for float and long double
+ that are not listed above. Of these functions, Emacs uses only the
+ following internally: fabsf, powf, sprintf.
*/
#include <config.h>
diff --git a/src/fns.c b/src/fns.c
index 4673fde28c7..6094c00b27c 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2519,7 +2519,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
if (SYMBOL_WITH_POS_P (o2))
o2 = SYMBOL_WITH_POS_SYM (o2);
- if (EQ (o1, o2))
+ if (BASE_EQ (o1, o2))
return true;
if (XTYPE (o1) != XTYPE (o2))
return false;
@@ -4113,7 +4113,7 @@ hash_table_user_defined_call (ptrdiff_t nargs, Lisp_Object *args,
return unbind_to (count, Ffuncall (nargs, args));
}
-/* Ignore HT and compare KEY1 and KEY2 using 'eql'.
+/* Ignore H and compare KEY1 and KEY2 using 'eql'.
Value is true if KEY1 and KEY2 are the same. */
static Lisp_Object
@@ -4122,7 +4122,7 @@ cmpfn_eql (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h)
return Feql (key1, key2);
}
-/* Ignore HT and compare KEY1 and KEY2 using 'equal'.
+/* Ignore H and compare KEY1 and KEY2 using 'equal'.
Value is true if KEY1 and KEY2 are the same. */
static Lisp_Object
@@ -4132,7 +4132,7 @@ cmpfn_equal (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h)
}
-/* Given HT, compare KEY1 and KEY2 using HT->user_cmp_function.
+/* Given H, compare KEY1 and KEY2 using H->user_cmp_function.
Value is true if KEY1 and KEY2 are the same. */
static Lisp_Object
@@ -4143,8 +4143,7 @@ cmpfn_user_defined (Lisp_Object key1, Lisp_Object key2,
return hash_table_user_defined_call (ARRAYELTS (args), args, h);
}
-/* Ignore HT and return a hash code for KEY which uses 'eq' to compare
- keys. */
+/* Ignore H and return a hash code for KEY which uses 'eq' to compare keys. */
static Lisp_Object
hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h)
@@ -4154,7 +4153,7 @@ hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h)
return make_ufixnum (XHASH (key) ^ XTYPE (key));
}
-/* Ignore HT and return a hash code for KEY which uses 'equal' to compare keys.
+/* Ignore H and return a hash code for KEY which uses 'equal' to compare keys.
The hash code is at most INTMASK. */
static Lisp_Object
@@ -4163,7 +4162,7 @@ hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h)
return make_ufixnum (sxhash (key));
}
-/* Ignore HT and return a hash code for KEY which uses 'eql' to compare keys.
+/* Ignore H and return a hash code for KEY which uses 'eql' to compare keys.
The hash code is at most INTMASK. */
static Lisp_Object
@@ -4172,7 +4171,7 @@ hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h)
return (FLOATP (key) || BIGNUMP (key) ? hashfn_equal : hashfn_eq) (key, h);
}
-/* Given HT, return a hash code for KEY which uses a user-defined
+/* Given H, return a hash code for KEY which uses a user-defined
function to compare keys. */
Lisp_Object
@@ -4479,7 +4478,7 @@ hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value,
/* Store key/value in the key_and_value vector. */
i = h->next_free;
eassert (NILP (HASH_HASH (h, i)));
- eassert (EQ (Qunbound, (HASH_KEY (h, i))));
+ eassert (BASE_EQ (Qunbound, (HASH_KEY (h, i))));
h->next_free = HASH_NEXT (h, i);
set_hash_key_slot (h, i, key);
set_hash_value_slot (h, i, value);
@@ -5220,7 +5219,7 @@ FUNCTION is called with two arguments, KEY and VALUE.
for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
{
Lisp_Object k = HASH_KEY (h, i);
- if (!EQ (k, Qunbound))
+ if (!BASE_EQ (k, Qunbound))
call2 (function, k, HASH_VALUE (h, i));
}
@@ -5870,9 +5869,12 @@ from the absolute start of the buffer, disregarding the narrowing. */)
if (!NILP (absolute))
start = BEG_BYTE;
- /* Check that POSITION is in the accessible range of the buffer. */
- if (pos < BEGV || pos > ZV)
+ /* Check that POSITION is in the accessible range of the buffer, or,
+ if we're reporting absolute positions, in the buffer. */
+ if (NILP (absolute) && (pos < BEGV || pos > ZV))
args_out_of_range_3 (make_int (pos), make_int (BEGV), make_int (ZV));
+ else if (!NILP (absolute) && (pos < 1 || pos > Z))
+ args_out_of_range_3 (make_int (pos), make_int (1), make_int (Z));
return make_int (count_lines (start, CHAR_TO_BYTE (pos)) + 1);
}
diff --git a/src/font.c b/src/font.c
index 6297452d3e0..702536c1cab 100644
--- a/src/font.c
+++ b/src/font.c
@@ -731,7 +731,7 @@ font_put_extra (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
{
Lisp_Object prev = Qnil;
- if (EQ (val, Qunbound))
+ if (BASE_EQ (val, Qunbound))
return val;
while (CONSP (extra)
&& NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
@@ -745,7 +745,7 @@ font_put_extra (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
return val;
}
XSETCDR (slot, val);
- if (EQ (val, Qunbound))
+ if (BASE_EQ (val, Qunbound))
ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra));
return val;
}
diff --git a/src/frame.c b/src/frame.c
index 93028aa8958..c21461d49fe 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1572,6 +1572,19 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame)))
last_nonminibuf_frame = XFRAME (selected_frame);
+ /* If the selected window in the target frame is its mini-window, we move
+ to a different window, the most recently used one, unless there is a
+ valid active minibuffer in the mini-window. */
+ if (EQ (f->selected_window, f->minibuffer_window)
+ /* The following test might fail if the mini-window contains a
+ non-active minibuffer. */
+ && NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt)))
+ {
+ Lisp_Object w = call1 (Qget_mru_window, frame);
+ if (WINDOW_LIVE_P (w)) /* W can be nil in minibuffer-only frames. */
+ Fset_frame_selected_window (frame, w, Qnil);
+ }
+
Fselect_window (f->selected_window, norecord);
/* We want to make sure that the next event generates a frame-switch
@@ -1988,7 +2001,8 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
error ("Attempt to delete the only frame");
}
#ifdef HAVE_X_WINDOWS
- else if (x_dnd_in_progress && f == x_dnd_frame)
+ else if ((x_dnd_in_progress && f == x_dnd_frame)
+ || (x_dnd_waiting_for_finish && f == x_dnd_finish_frame))
error ("Attempt to delete the drop source frame");
#endif
#ifdef HAVE_HAIKU
@@ -2333,7 +2347,8 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
kset_default_minibuffer_frame (kb, Qnil);
}
- /* Cause frame titles to update--necessary if we now have just one frame. */
+ /* Cause frame titles to update--necessary if we now have just one
+ frame. */
if (!is_tooltip_frame)
update_mode_lines = 15;
@@ -3642,7 +3657,7 @@ DEFUN ("frame-fringe-width", Ffringe_width, Sfringe_width, 0, 1, 0,
DEFUN ("frame-child-frame-border-width", Fframe_child_frame_border_width, Sframe_child_frame_border_width, 0, 1, 0,
doc: /* Return width of FRAME's child-frame border in pixels.
- If FRAME's 'child-frame-border-width' parameter is nil, return FRAME's
+ If FRAME's `child-frame-border-width' parameter is nil, return FRAME's
internal border width instead. */)
(Lisp_Object frame)
{
@@ -4276,7 +4291,7 @@ gui_set_frame_parameters (struct frame *f, Lisp_Object alist)
}
/* Don't die if just one of these was set. */
- if (EQ (left, Qunbound))
+ if (BASE_EQ (left, Qunbound))
{
left_no_change = 1;
if (f->left_pos < 0)
@@ -4284,7 +4299,7 @@ gui_set_frame_parameters (struct frame *f, Lisp_Object alist)
else
XSETINT (left, f->left_pos);
}
- if (EQ (top, Qunbound))
+ if (BASE_EQ (top, Qunbound))
{
top_no_change = 1;
if (f->top_pos < 0)
@@ -5442,7 +5457,7 @@ gui_frame_get_and_record_arg (struct frame *f, Lisp_Object alist,
value = gui_display_get_arg (FRAME_DISPLAY_INFO (f), alist, param,
attribute, class, type);
- if (! NILP (value) && ! EQ (value, Qunbound))
+ if (! NILP (value) && ! BASE_EQ (value, Qunbound))
store_frame_param (f, param, value);
return value;
@@ -5463,7 +5478,7 @@ gui_default_parameter (struct frame *f, Lisp_Object alist, Lisp_Object prop,
Lisp_Object tem;
tem = gui_frame_get_arg (f, alist, prop, xprop, xclass, type);
- if (EQ (tem, Qunbound))
+ if (BASE_EQ (tem, Qunbound))
tem = deflt;
AUTO_FRAME_ARG (arg, prop, tem);
gui_set_frame_parameters (f, arg);
@@ -5725,9 +5740,9 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
height = gui_display_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
width = gui_display_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
- if (!EQ (width, Qunbound) || !EQ (height, Qunbound))
+ if (!BASE_EQ (width, Qunbound) || !BASE_EQ (height, Qunbound))
{
- if (!EQ (width, Qunbound))
+ if (!BASE_EQ (width, Qunbound))
{
if (CONSP (width) && EQ (XCAR (width), Qtext_pixels))
{
@@ -5763,7 +5778,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
}
}
- if (!EQ (height, Qunbound))
+ if (!BASE_EQ (height, Qunbound))
{
if (CONSP (height) && EQ (XCAR (height), Qtext_pixels))
{
@@ -5801,7 +5816,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
user_size = gui_display_get_arg (dpyinfo, parms, Quser_size, 0, 0,
RES_TYPE_NUMBER);
- if (!NILP (user_size) && !EQ (user_size, Qunbound))
+ if (!NILP (user_size) && !BASE_EQ (user_size, Qunbound))
window_prompting |= USSize;
else
window_prompting |= PSize;
@@ -5814,7 +5829,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
left = gui_display_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
user_position = gui_display_get_arg (dpyinfo, parms, Quser_position, 0, 0,
RES_TYPE_NUMBER);
- if (! EQ (top, Qunbound) || ! EQ (left, Qunbound))
+ if (! BASE_EQ (top, Qunbound) || ! BASE_EQ (left, Qunbound))
{
if (EQ (top, Qminus))
{
@@ -5837,7 +5852,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
else if (FLOATP (top))
f->top_pos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done,
&outer_done, 0);
- else if (EQ (top, Qunbound))
+ else if (BASE_EQ (top, Qunbound))
f->top_pos = 0;
else
{
@@ -5867,7 +5882,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
else if (FLOATP (left))
f->left_pos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done,
&outer_done, 0);
- else if (EQ (left, Qunbound))
+ else if (BASE_EQ (left, Qunbound))
f->left_pos = 0;
else
{
@@ -5876,7 +5891,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
window_prompting |= XNegative;
}
- if (!NILP (user_position) && ! EQ (user_position, Qunbound))
+ if (!NILP (user_position) && ! BASE_EQ (user_position, Qunbound))
window_prompting |= USPosition;
else
window_prompting |= PPosition;
diff --git a/src/frame.h b/src/frame.h
index 4942e640d27..458b6257e49 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -127,6 +127,7 @@ struct frame
/* This frame's selected window.
Each frame has its own window hierarchy
and one of the windows in it is selected within the frame.
+ This window may be the mini-window of the frame, if any.
The selected window of the selected frame is Emacs's selected window. */
Lisp_Object selected_window;
@@ -1292,8 +1293,28 @@ SET_FRAME_VISIBLE (struct frame *f, int v)
}
/* Set iconified status of frame F. */
-#define SET_FRAME_ICONIFIED(f, i) \
- (f)->iconified = (eassert (0 <= (i) && (i) <= 1), (i))
+INLINE void
+SET_FRAME_ICONIFIED (struct frame *f, int i)
+{
+#ifdef HAVE_WINDOW_SYSTEM
+ Lisp_Object frame;
+#endif
+
+ eassert (0 <= (i) && (i) <= 1);
+
+ f->iconified = i;
+
+#ifdef HAVE_WINDOW_SYSTEM
+ /* Iconifying a frame might cause the frame title to change if no
+ title was explicitly specified. Force the frame title to be
+ recomputed. */
+
+ XSETFRAME (frame, f);
+
+ if (FRAME_WINDOW_P (f))
+ gui_consider_frame_title (frame);
+#endif
+}
extern Lisp_Object selected_frame;
extern Lisp_Object old_selected_frame;
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 98a28af5f22..6bb41110d5c 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -37,6 +37,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "font.h"
#include "ftfont.h"
#include "pdumper.h"
+#ifdef HAVE_PGTK
+#include "xsettings.h"
+#endif
#ifdef USE_BE_CAIRO
#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
@@ -168,7 +171,12 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
cairo_matrix_t font_matrix, ctm;
cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size);
cairo_matrix_init_identity (&ctm);
+
+#ifdef HAVE_PGTK
+ cairo_font_options_t *options = xsettings_get_font_options ();
+#else
cairo_font_options_t *options = cairo_font_options_create ();
+#endif
#ifdef USE_BE_CAIRO
if (be_use_subpixel_antialiasing ())
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL);
@@ -624,6 +632,28 @@ ftcrfont_draw (struct glyph_string *s,
return len;
}
+#ifdef HAVE_PGTK
+/* Determine if FONT_OBJECT is a valid cached font for ENTITY by
+ comparing the options used to open it with the user's current
+ preferences specified via GSettings. */
+static bool
+ftcrfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
+ Lisp_Object entity)
+{
+ struct font_info *info = (struct font_info *) XFONT_OBJECT (font_object);
+
+ cairo_font_options_t *options = cairo_font_options_create ();
+ cairo_scaled_font_get_font_options (info->cr_scaled_font, options);
+ cairo_font_options_t *gsettings_options = xsettings_get_font_options ();
+
+ bool equal = cairo_font_options_equal (options, gsettings_options);
+ cairo_font_options_destroy (options);
+ cairo_font_options_destroy (gsettings_options);
+
+ return equal;
+}
+#endif
+
#ifdef HAVE_HARFBUZZ
static Lisp_Object
@@ -694,6 +724,9 @@ struct font_driver const ftcrfont_driver =
#endif
.filter_properties = ftfont_filter_properties,
.combining_capability = ftfont_combining_capability,
+#ifdef HAVE_PGTK
+ .cached_font_ok = ftcrfont_cached_font_ok
+#endif
};
#ifdef HAVE_HARFBUZZ
struct font_driver ftcrhbfont_driver;
diff --git a/src/ftfont.c b/src/ftfont.c
index 5797300d231..301a145b7ac 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -645,8 +645,29 @@ ftfont_get_open_type_spec (Lisp_Object otf_spec)
return spec;
}
+#if defined HAVE_XFT && defined FC_COLOR
+static bool
+xft_color_font_whitelisted_p (const char *family)
+{
+ Lisp_Object tem, name;
+
+ tem = Vxft_color_font_whitelist;
+
+ FOR_EACH_TAIL_SAFE (tem)
+ {
+ name = XCAR (tem);
+
+ if (STRINGP (name) && !strcmp (family, SSDATA (name)))
+ return true;
+ }
+
+ return false;
+}
+#endif
+
static FcPattern *
-ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
+ftfont_spec_pattern (Lisp_Object spec, char *otlayout,
+ struct OpenTypeSpec **otspec, const char **langname)
{
Lisp_Object tmp, extra;
FcPattern *pattern = NULL;
@@ -785,6 +806,8 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
/* We really don't like color fonts, they cause Xft crashes. See
Bug#30874. */
if (xft_ignore_color_fonts
+ && (NILP (AREF (spec, FONT_FAMILY_INDEX))
+ || NILP (Vxft_color_font_whitelist))
&& ! FcPatternAddBool (pattern, FC_COLOR, FcFalse))
goto err;
#endif
@@ -930,7 +953,12 @@ ftfont_list (struct frame *f, Lisp_Object spec)
returns them even when it shouldn't really do so, so we
need to manually skip them here (Bug#37786). */
FcBool b;
+ FcChar8 *str;
+
if (xft_ignore_color_fonts
+ && (FcPatternGetString (fontset->fonts[i], FC_FAMILY,
+ 0, &str) != FcResultMatch
+ || !xft_color_font_whitelisted_p ((char *) str))
&& FcPatternGetBool (fontset->fonts[i], FC_COLOR, 0, &b)
== FcResultMatch && b != FcFalse)
continue;
diff --git a/src/gtkutil.c b/src/gtkutil.c
index a2ab01d02c5..f2018bc01f5 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -736,67 +736,74 @@ xg_check_special_colors (struct frame *f,
const char *color_name,
Emacs_Color *color)
{
- bool success_p = 0;
- bool get_bg = strcmp ("gtk_selection_bg_color", color_name) == 0;
- bool get_fg = !get_bg && strcmp ("gtk_selection_fg_color", color_name) == 0;
+ bool success_p;
+ bool get_bg;
+ bool get_fg;
+#ifdef HAVE_GTK3
+ GtkStyleContext *gsty;
+ GdkRGBA col;
+ char buf[sizeof "rgb://rrrr/gggg/bbbb"];
+ int state;
+ GdkRGBA *c;
+ unsigned short r, g, b;
+#else
+ GtkStyle *gsty;
+ GdkColor *grgb;
+#endif
+
+ get_bg = !strcmp ("gtk_selection_bg_color", color_name);
+ get_fg = !get_bg && !strcmp ("gtk_selection_fg_color", color_name);
+ success_p = false;
- if (! FRAME_GTK_WIDGET (f) || ! (get_bg || get_fg))
+#ifdef HAVE_PGTK
+ while (FRAME_PARENT_FRAME (f))
+ f = FRAME_PARENT_FRAME (f);
+#endif
+
+ if (!FRAME_GTK_WIDGET (f) || !(get_bg || get_fg))
return success_p;
block_input ();
- {
#ifdef HAVE_GTK3
-#ifndef HAVE_PGTK
- GtkStyleContext *gsty
- = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
-#else
- GtkStyleContext *gsty
- = gtk_widget_get_style_context (FRAME_WIDGET (f));
-#endif
- GdkRGBA col;
- char buf[sizeof "rgb://rrrr/gggg/bbbb"];
- int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
- if (get_fg)
- gtk_style_context_get_color (gsty, state, &col);
- else
- {
- GdkRGBA *c;
- /* FIXME: Retrieving the background color is deprecated in
- GTK+ 3.16. New versions of GTK+ don't use the concept of a
- single background color any more, so we shouldn't query for
- it. */
- gtk_style_context_get (gsty, state,
- GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &c,
- NULL);
- col = *c;
- gdk_rgba_free (c);
- }
+ gsty = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
+ state = GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED;
- unsigned short
- r = col.red * 65535,
- g = col.green * 65535,
- b = col.blue * 65535;
+ if (get_fg)
+ gtk_style_context_get_color (gsty, state, &col);
+ else
+ {
+ /* FIXME: Retrieving the background color is deprecated in
+ GTK+ 3.16. New versions of GTK+ don't use the concept of a
+ single background color any more, so we shouldn't query for
+ it. */
+ gtk_style_context_get (gsty, state,
+ GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &c,
+ NULL);
+ col = *c;
+ gdk_rgba_free (c);
+ }
+
+ r = col.red * 65535;
+ g = col.green * 65535;
+ b = col.blue * 65535;
#ifndef HAVE_PGTK
- sprintf (buf, "rgb:%04x/%04x/%04x", r, g, b);
- success_p = x_parse_color (f, buf, color) != 0;
+ sprintf (buf, "rgb:%04x/%04x/%04x", r, g, b);
+ success_p = x_parse_color (f, buf, color) != 0;
#else
- sprintf (buf, "#%04x%04x%04x", r, g, b);
- success_p = pgtk_parse_color (f, buf, color) != 0;
+ sprintf (buf, "#%04x%04x%04x", r, g, b);
+ success_p = pgtk_parse_color (f, buf, color) != 0;
#endif
#else
- GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
- GdkColor *grgb = get_bg
- ? &gsty->bg[GTK_STATE_SELECTED]
- : &gsty->fg[GTK_STATE_SELECTED];
+ gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
+ grgb = (get_bg ? &gsty->bg[GTK_STATE_SELECTED]
+ : &gsty->fg[GTK_STATE_SELECTED]);
- color->red = grgb->red;
- color->green = grgb->green;
- color->blue = grgb->blue;
- color->pixel = grgb->pixel;
- success_p = 1;
+ color->red = grgb->red;
+ color->green = grgb->green;
+ color->blue = grgb->blue;
+ color->pixel = grgb->pixel;
+ success_p = 1;
#endif
-
- }
unblock_input ();
return success_p;
}
@@ -6395,6 +6402,9 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
if (!f)
return true;
+ if (popup_activated ())
+ return true;
+
#ifdef HAVE_XINPUT2
pending_keystroke_time
= FRAME_DISPLAY_INFO (f)->pending_keystroke_time;
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
index a8d46d000a3..f0cc084bb37 100644
--- a/src/haiku_draw_support.cc
+++ b/src/haiku_draw_support.cc
@@ -285,11 +285,32 @@ BView_DrawBitmap (void *view, void *bitmap, int x, int y,
BView *vw = get_view (view);
BBitmap *bm = (BBitmap *) bitmap;
- vw->PushState ();
vw->SetDrawingMode (B_OP_OVER);
vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
- vw->PopState ();
+ vw->SetDrawingMode (B_OP_COPY);
+}
+
+void
+BView_DrawBitmapTiled (void *view, void *bitmap, int x, int y,
+ int width, int height, int vx, int vy,
+ int vwidth, int vheight)
+{
+ BView *vw = get_view (view);
+ BBitmap *bm = (BBitmap *) bitmap;
+ BRect bounds = bm->Bounds ();
+
+ if (width == -1)
+ width = BE_RECT_WIDTH (bounds);
+
+ if (height == -1)
+ height = BE_RECT_HEIGHT (bounds);
+
+ vw->SetDrawingMode (B_OP_OVER);
+ vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
+ BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1),
+ B_TILE_BITMAP);
+ vw->SetDrawingMode (B_OP_COPY);
}
void
@@ -300,17 +321,22 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
BBitmap *bm = (BBitmap *) bitmap;
BBitmap bc (bm->Bounds (), B_RGBA32);
BRect rect (x, y, x + width - 1, y + height - 1);
+ uint32_t *bits;
+ size_t stride;
+ rgb_color low_color;
+ BRect bounds;
if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK)
return;
- uint32_t *bits = (uint32_t *) bc.Bits ();
- size_t stride = bc.BytesPerRow ();
+ bits = (uint32_t *) bc.Bits ();
+ stride = bc.BytesPerRow ();
if (bm->ColorSpace () == B_GRAY1)
{
- rgb_color low_color = vw->LowColor ();
- BRect bounds = bc.Bounds ();
+ low_color = vw->LowColor ();
+ bounds = bc.Bounds ();
+
for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
{
for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x)
@@ -323,10 +349,11 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
}
}
- vw->PushState ();
- vw->SetDrawingMode (bm->ColorSpace () == B_GRAY1 ? B_OP_OVER : B_OP_ERASE);
+ vw->SetDrawingMode ((bm->ColorSpace ()
+ == B_GRAY1)
+ ? B_OP_OVER : B_OP_ERASE);
vw->DrawBitmap (&bc, rect);
- vw->PopState ();
+ vw->SetDrawingMode (B_OP_COPY);
}
void
@@ -357,6 +384,7 @@ BView_DrawMask (void *src, void *view,
vw->SetDrawingMode (B_OP_OVER);
vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+ vw->SetDrawingMode (B_OP_COPY);
}
static BBitmap *
@@ -475,3 +503,40 @@ BView_InvertRect (void *view, int x, int y, int width, int height)
vw->InvertRect (BRect (x, y, x + width - 1, y + height - 1));
}
+
+static void
+be_draw_cross_on_pixmap_1 (BBitmap *bitmap, int x, int y, int width,
+ int height, uint32_t color)
+{
+ BBitmap dest (bitmap->Bounds (),
+ bitmap->ColorSpace (),
+ true, false);
+ BView view (bitmap->Bounds (), NULL, B_FOLLOW_NONE, 0);
+ rgb_color high_color;
+
+ rgb32_to_rgb_color (color, &high_color);
+ dest.ImportBits (bitmap);
+
+ if (!dest.Lock ())
+ return;
+
+ dest.AddChild (&view);
+
+ view.SetHighColor (high_color);
+ view.StrokeLine (BPoint (x, y),
+ BPoint (x + width - 1, y + height - 1));
+ view.StrokeLine (BPoint (x, y + height - 1),
+ BPoint (x + width - 1, y));
+ view.RemoveSelf ();
+ bitmap->ImportBits (&dest);
+}
+
+void
+be_draw_cross_on_pixmap (void *bitmap, int x, int y, int width,
+ int height, uint32_t color)
+{
+ BBitmap *target = (BBitmap *) bitmap;
+
+ be_draw_cross_on_pixmap_1 (target, x, y, width, height,
+ color);
+}
diff --git a/src/haiku_io.c b/src/haiku_io.c
index 5d0031ef712..d3455276855 100644
--- a/src/haiku_io.c
+++ b/src/haiku_io.c
@@ -105,6 +105,8 @@ haiku_len (enum haiku_event_type type)
return sizeof (struct haiku_menu_bar_left_event);
case SCROLL_BAR_PART_EVENT:
return sizeof (struct haiku_scroll_bar_part_event);
+ case SCREEN_CHANGED_EVENT:
+ return sizeof (struct haiku_screen_changed_event);
}
emacs_abort ();
diff --git a/src/haiku_select.cc b/src/haiku_select.cc
index a26a0049cbf..764001f62b0 100644
--- a/src/haiku_select.cc
+++ b/src/haiku_select.cc
@@ -28,29 +28,64 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "haikuselect.h"
+/* The clipboard object representing the primary selection. */
static BClipboard *primary = NULL;
+
+/* The clipboard object representing the secondary selection. */
static BClipboard *secondary = NULL;
+
+/* The clipboard object used by other programs, representing the
+ clipboard. */
static BClipboard *system_clipboard = NULL;
+
+/* The number of times the system clipboard has changed. */
static int64 count_clipboard = -1;
+
+/* The number of times the primary selection has changed. */
static int64 count_primary = -1;
+
+/* The number of times the secondary selection has changed. */
static int64 count_secondary = -1;
+static BClipboard *
+get_clipboard_object (enum haiku_clipboard clipboard)
+{
+ switch (clipboard)
+ {
+ case CLIPBOARD_PRIMARY:
+ return primary;
+
+ case CLIPBOARD_SECONDARY:
+ return secondary;
+
+ case CLIPBOARD_CLIPBOARD:
+ return system_clipboard;
+ }
+
+ abort ();
+}
+
static char *
-BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
+be_find_clipboard_data_1 (BClipboard *cb, const char *type, ssize_t *len)
{
+ BMessage *data;
+ const char *ptr;
+ ssize_t nbytes;
+ void *value;
+
if (!cb->Lock ())
- return 0;
+ return NULL;
+
+ data = cb->Data ();
- BMessage *dat = cb->Data ();
- if (!dat)
+ if (!data)
{
cb->Unlock ();
- return 0;
+ return NULL;
}
- const char *ptr;
- ssize_t bt;
- dat->FindData (type, B_MIME_TYPE, (const void **) &ptr, &bt);
+ data->FindData (type, B_MIME_TYPE, (const void **) &ptr,
+ &nbytes);
if (!ptr)
{
@@ -59,9 +94,9 @@ BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
}
if (len)
- *len = bt;
+ *len = nbytes;
- void *data = malloc (bt);
+ value = malloc (nbytes);
if (!data)
{
@@ -69,13 +104,14 @@ BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
return NULL;
}
- memcpy (data, ptr, bt);
+ memcpy (value, ptr, nbytes);
cb->Unlock ();
- return (char *) data;
+
+ return (char *) value;
}
static void
-BClipboard_get_targets (BClipboard *cb, char **buf, int buf_size)
+be_get_clipboard_targets_1 (BClipboard *cb, char **buf, int buf_size)
{
BMessage *data;
char *name;
@@ -122,142 +158,125 @@ BClipboard_get_targets (BClipboard *cb, char **buf, int buf_size)
}
static void
-BClipboard_set_data (BClipboard *cb, const char *type, const char *dat,
- ssize_t len, bool clear)
+be_set_clipboard_data_1 (BClipboard *cb, const char *type, const char *data,
+ ssize_t len, bool clear)
{
+ BMessage *message_data;
+
if (!cb->Lock ())
return;
if (clear)
cb->Clear ();
- BMessage *mdat = cb->Data ();
- if (!mdat)
+ message_data = cb->Data ();
+
+ if (!message_data)
{
cb->Unlock ();
return;
}
- if (dat)
+ if (data)
{
- if (mdat->ReplaceData (type, B_MIME_TYPE, dat, len)
+ if (message_data->ReplaceData (type, B_MIME_TYPE, data, len)
== B_NAME_NOT_FOUND)
- mdat->AddData (type, B_MIME_TYPE, dat, len);
+ message_data->AddData (type, B_MIME_TYPE, data, len);
}
else
- mdat->RemoveName (type);
+ message_data->RemoveName (type);
+
cb->Commit ();
cb->Unlock ();
}
-char *
-BClipboard_find_system_data (const char *type, ssize_t *len)
-{
- if (!system_clipboard)
- return 0;
-
- return BClipboard_find_data (system_clipboard, type, len);
-}
-
-char *
-BClipboard_find_primary_selection_data (const char *type, ssize_t *len)
-{
- if (!primary)
- return 0;
-
- return BClipboard_find_data (primary, type, len);
-}
-
-char *
-BClipboard_find_secondary_selection_data (const char *type, ssize_t *len)
-{
- if (!secondary)
- return 0;
-
- return BClipboard_find_data (secondary, type, len);
-}
-
-void
-BClipboard_set_system_data (const char *type, const char *data,
- ssize_t len, bool clear)
-{
- if (!system_clipboard)
- return;
-
- count_clipboard = system_clipboard->SystemCount ();
- BClipboard_set_data (system_clipboard, type, data, len, clear);
-}
-
void
-BClipboard_set_primary_selection_data (const char *type, const char *data,
- ssize_t len, bool clear)
+be_update_clipboard_count (enum haiku_clipboard id)
{
- if (!primary)
- return;
+ switch (id)
+ {
+ case CLIPBOARD_CLIPBOARD:
+ count_clipboard = system_clipboard->SystemCount ();
+ break;
- count_primary = primary->SystemCount ();
- BClipboard_set_data (primary, type, data, len, clear);
-}
+ case CLIPBOARD_PRIMARY:
+ count_primary = primary->SystemCount ();
+ break;
-void
-BClipboard_set_secondary_selection_data (const char *type, const char *data,
- ssize_t len, bool clear)
-{
- if (!secondary)
- return;
-
- count_secondary = secondary->SystemCount ();
- BClipboard_set_data (secondary, type, data, len, clear);
+ case CLIPBOARD_SECONDARY:
+ count_secondary = secondary->SystemCount ();
+ break;
+ }
}
-void
-BClipboard_free_data (void *ptr)
+char *
+be_find_clipboard_data (enum haiku_clipboard id, const char *type,
+ ssize_t *len)
{
- std::free (ptr);
+ return be_find_clipboard_data_1 (get_clipboard_object (id),
+ type, len);
}
void
-BClipboard_system_targets (char **buf, int len)
+be_set_clipboard_data (enum haiku_clipboard id, const char *type,
+ const char *data, ssize_t len, bool clear)
{
- BClipboard_get_targets (system_clipboard, buf, len);
-}
+ be_update_clipboard_count (id);
-void
-BClipboard_primary_targets (char **buf, int len)
-{
- BClipboard_get_targets (primary, buf, len);
+ be_set_clipboard_data_1 (get_clipboard_object (id), type,
+ data, len, clear);
}
void
-BClipboard_secondary_targets (char **buf, int len)
+be_get_clipboard_targets (enum haiku_clipboard id, char **targets,
+ int len)
{
- BClipboard_get_targets (secondary, buf, len);
+ be_get_clipboard_targets_1 (get_clipboard_object (id), targets,
+ len);
}
-bool
-BClipboard_owns_clipboard (void)
+static bool
+clipboard_owner_p (void)
{
return (count_clipboard >= 0
&& (count_clipboard + 1
== system_clipboard->SystemCount ()));
}
-bool
-BClipboard_owns_primary (void)
+static bool
+primary_owner_p (void)
{
return (count_primary >= 0
&& (count_primary + 1
== primary->SystemCount ()));
}
-bool
-BClipboard_owns_secondary (void)
+static bool
+secondary_owner_p (void)
{
return (count_secondary >= 0
&& (count_secondary + 1
== secondary->SystemCount ()));
}
+bool
+be_clipboard_owner_p (enum haiku_clipboard clipboard)
+{
+ switch (clipboard)
+ {
+ case CLIPBOARD_PRIMARY:
+ return primary_owner_p ();
+
+ case CLIPBOARD_SECONDARY:
+ return secondary_owner_p ();
+
+ case CLIPBOARD_CLIPBOARD:
+ return clipboard_owner_p ();
+ }
+
+ abort ();
+}
+
void
init_haiku_select (void)
{
@@ -443,12 +462,7 @@ be_lock_clipboard_message (enum haiku_clipboard clipboard,
{
BClipboard *board;
- if (clipboard == CLIPBOARD_PRIMARY)
- board = primary;
- else if (clipboard == CLIPBOARD_SECONDARY)
- board = secondary;
- else
- board = system_clipboard;
+ board = get_clipboard_object (clipboard);
if (!board->Lock ())
return 1;
@@ -465,12 +479,7 @@ be_unlock_clipboard (enum haiku_clipboard clipboard, bool discard)
{
BClipboard *board;
- if (clipboard == CLIPBOARD_PRIMARY)
- board = primary;
- else if (clipboard == CLIPBOARD_SECONDARY)
- board = secondary;
- else
- board = system_clipboard;
+ board = get_clipboard_object (clipboard);
if (discard)
board->Revert ();
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 5dfb25d6dd7..182f2128473 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -17,10 +17,12 @@ You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
+#include <attribute.h>
#include <app/Application.h>
#include <app/Cursor.h>
#include <app/Messenger.h>
+#include <app/Roster.h>
#include <interface/GraphicsDefs.h>
#include <interface/InterfaceDefs.h>
@@ -81,8 +83,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <csignal>
#include <cfloat>
-#include <pthread.h>
-
#ifdef USE_BE_CAIRO
#include <cairo.h>
#endif
@@ -107,6 +107,7 @@ enum
SET_FONT_INDICES = 3012,
SET_PREVIEW_DIALOG = 3013,
UPDATE_PREVIEW_DIALOG = 3014,
+ SEND_MOVE_FRAME_EVENT = 3015,
};
/* X11 keysyms that we use. */
@@ -142,7 +143,7 @@ struct font_selection_dialog_message
/* Whether or not font selection was cancelled. */
bool_bf cancel : 1;
- /* Whether or not a size was explictly specified. */
+ /* Whether or not a size was explicitly specified. */
bool_bf size_specified : 1;
/* The index of the selected font family. */
@@ -155,44 +156,45 @@ struct font_selection_dialog_message
int size;
};
+/* The color space of the main screen. B_NO_COLOR_SPACE means it has
+ not yet been computed. */
static color_space dpy_color_space = B_NO_COLOR_SPACE;
-static key_map *key_map = NULL;
-static char *key_chars = NULL;
+
+/* The keymap, or NULL if it has not been initialized. */
+static key_map *key_map;
+
+/* Indices of characters into the keymap. */
+static char *key_chars;
+
+/* Lock around keymap data, since it's touched from different
+ threads. */
static BLocker key_map_lock;
/* The locking semantics of BWindows running in multiple threads are
so complex that child frame state (which is the only state that is
shared between different BWindows at runtime) does best with a
single global lock. */
-
static BLocker child_frame_lock;
-/* A LeaveNotify event (well, the closest equivalent on Haiku, which
- is a B_MOUSE_MOVED event with `transit' set to B_EXITED_VIEW) might
- be sent out-of-order with regards to motion events from other
- windows, such as when the mouse pointer rapidly moves from an
- undecorated child frame to its parent. This can cause a failure to
- clear the mouse face on the former if an event for the latter is
- read by Emacs first and ends up showing the mouse face there.
-
- While this lock doesn't really ensure that the events will be
- delivered in the correct order, it makes them arrive in the correct
- order "most of the time" on my machine, which is good enough and
- preferable to adding a lot of extra complexity to the event
- handling code to sort motion events by their timestamps.
-
- Obviously this depends on the number of execution units that are
- available, and the scheduling priority of each thread involved in
- the input handling, but it will be good enough for most people. */
-
-static BLocker movement_locker;
-
+/* Variable where the popup menu thread returns the chosen menu
+ item. */
static BMessage volatile *popup_track_message;
+
+/* Variable in which alert dialog threads return the selected button
+ number. */
static int32 volatile alert_popup_value;
+
+/* The current window ID. This is increased every time a frame is
+ created. */
static int current_window_id;
-static void *grab_view = NULL;
+/* The view that has the passive grab. */
+static void *grab_view;
+
+/* The locker for that variable. */
static BLocker grab_view_locker;
+
+/* Whether or not a drag-and-drop operation is in progress. */
static bool drag_and_drop_in_progress;
/* Many places require us to lock the child frame data, and then lock
@@ -448,13 +450,143 @@ map_normal (uint32_t kc, uint32_t *ch)
key_map_lock.Unlock ();
}
+static BRect
+get_zoom_rect (BWindow *window)
+{
+ BScreen screen;
+ BDeskbar deskbar;
+ BRect screen_frame;
+ BRect frame;
+ BRect deskbar_frame;
+ BRect window_frame;
+ BRect decorator_frame;
+
+ if (!screen.IsValid ())
+ gui_abort ("Failed to calculate screen rect");
+
+ screen_frame = frame = screen.Frame ();
+ deskbar_frame = deskbar.Frame ();
+
+ if (!(modifiers () & B_SHIFT_KEY) && !deskbar.IsAutoHide ())
+ {
+ switch (deskbar.Location ())
+ {
+ case B_DESKBAR_TOP:
+ frame.top = deskbar_frame.bottom + 2;
+ break;
+
+ case B_DESKBAR_BOTTOM:
+ case B_DESKBAR_LEFT_BOTTOM:
+ case B_DESKBAR_RIGHT_BOTTOM:
+ frame.bottom = deskbar_frame.top - 2;
+ break;
+
+ case B_DESKBAR_LEFT_TOP:
+ if (!deskbar.IsExpanded ())
+ frame.top = deskbar_frame.bottom + 2;
+ else if (!deskbar.IsAlwaysOnTop ()
+ && !deskbar.IsAutoRaise ())
+ frame.left = deskbar_frame.right + 2;
+ break;
+
+ default:
+ if (deskbar.IsExpanded ()
+ && !deskbar.IsAlwaysOnTop ()
+ && !deskbar.IsAutoRaise ())
+ frame.right = deskbar_frame.left - 2;
+ }
+ }
+
+ if (window)
+ {
+ window_frame = window->Frame ();
+ decorator_frame = window->DecoratorFrame ();
+
+ frame.top += (window_frame.top
+ - decorator_frame.top);
+ frame.bottom -= (decorator_frame.bottom
+ - window_frame.bottom);
+ frame.left += (window_frame.left
+ - decorator_frame.left);
+ frame.right -= (decorator_frame.right
+ - window_frame.right);
+
+ if (frame.top > deskbar_frame.bottom
+ || frame.bottom < deskbar_frame.top)
+ {
+ frame.left = screen_frame.left + (window_frame.left
+ - decorator_frame.left);
+ frame.right = screen_frame.right - (decorator_frame.right
+ - window_frame.right);
+ }
+ }
+
+ return frame;
+}
+
+/* Invisible window used to get B_SCREEN_CHANGED events. */
+class EmacsScreenChangeMonitor : public BWindow
+{
+ BRect previous_screen_frame;
+
+public:
+ EmacsScreenChangeMonitor (void) : BWindow (BRect (-100, -100, 0, 0), "",
+ B_NO_BORDER_WINDOW_LOOK,
+ B_FLOATING_ALL_WINDOW_FEEL,
+ B_AVOID_FRONT | B_AVOID_FOCUS)
+ {
+ BScreen screen (this);
+
+ if (!screen.IsValid ())
+ return;
+
+ previous_screen_frame = screen.Frame ();
+
+ /* Immediately show this window upon creation. It will not steal
+ the focus or become visible. */
+ Show ();
+
+ if (!LockLooper ())
+ return;
+
+ Hide ();
+ UnlockLooper ();
+ }
+
+ void
+ DispatchMessage (BMessage *msg, BHandler *handler)
+ {
+ struct haiku_screen_changed_event rq;
+ BRect frame;
+
+ if (msg->what == B_SCREEN_CHANGED)
+ {
+ if (msg->FindInt64 ("when", &rq.when) != B_OK)
+ rq.when = 0;
+
+ if (msg->FindRect ("frame", &frame) != B_OK
+ || frame != previous_screen_frame)
+ {
+ haiku_write (SCREEN_CHANGED_EVENT, &rq);
+
+ if (frame.IsValid ())
+ previous_screen_frame = frame;
+ }
+ }
+
+ BWindow::DispatchMessage (msg, handler);
+ }
+};
+
class Emacs : public BApplication
{
public:
BMessage settings;
- bool settings_valid_p = false;
+ bool settings_valid_p;
+ EmacsScreenChangeMonitor *monitor;
- Emacs () : BApplication ("application/x-vnd.GNU-emacs")
+ Emacs (void) : BApplication ("application/x-vnd.GNU-emacs"),
+ settings_valid_p (false)
{
BPath settings_path;
@@ -470,6 +602,15 @@ public:
return;
settings_valid_p = true;
+ monitor = new EmacsScreenChangeMonitor;
+ }
+
+ ~Emacs (void)
+ {
+ if (monitor->LockLooper ())
+ monitor->Quit ();
+ else
+ delete monitor;
}
void
@@ -518,33 +659,42 @@ public:
struct child_frame *next;
int xoff, yoff;
EmacsWindow *window;
- } *subset_windows = NULL;
+ } *subset_windows;
- EmacsWindow *parent = NULL;
+ EmacsWindow *parent;
BRect pre_fullscreen_rect;
BRect pre_zoom_rect;
- int x_before_zoom = INT_MIN;
- int y_before_zoom = INT_MIN;
- bool fullscreen_p = false;
- bool zoomed_p = false;
- bool shown_flag = false;
- volatile int was_shown_p = 0;
- bool menu_bar_active_p = false;
- bool override_redirect_p = false;
+ int x_before_zoom;
+ int y_before_zoom;
+ bool shown_flag;
+ volatile bool was_shown_p;
+ bool menu_bar_active_p;
+ bool override_redirect_p;
window_look pre_override_redirect_look;
window_feel pre_override_redirect_feel;
uint32 pre_override_redirect_workspaces;
int window_id;
- bool *menus_begun = NULL;
+ bool *menus_begun;
enum haiku_z_group z_group;
- bool tooltip_p = false;
+ bool tooltip_p;
+ enum haiku_fullscreen_mode fullscreen_mode;
EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK,
- B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS)
+ B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS),
+ subset_windows (NULL),
+ parent (NULL),
+ x_before_zoom (INT_MIN),
+ y_before_zoom (INT_MIN),
+ shown_flag (false),
+ was_shown_p (false),
+ menu_bar_active_p (false),
+ override_redirect_p (false),
+ window_id (current_window_id),
+ menus_begun (NULL),
+ z_group (Z_GROUP_NONE),
+ tooltip_p (false),
+ fullscreen_mode (FULLSCREEN_MODE_NONE)
{
- window_id = current_window_id++;
- z_group = Z_GROUP_NONE;
-
/* This pulse rate is used by scroll bars for repeating a button
action while a button is held down. */
SetPulseRate (30000);
@@ -583,77 +733,6 @@ public:
SetFeel (B_NORMAL_WINDOW_FEEL);
}
- BRect
- CalculateZoomRect (void)
- {
- BScreen screen (this);
- BDeskbar deskbar;
- BRect screen_frame;
- BRect frame;
- BRect deskbar_frame;
- BRect window_frame;
- BRect decorator_frame;
-
- if (!screen.IsValid ())
- gui_abort ("Failed to calculate screen rect");
-
- screen_frame = frame = screen.Frame ();
- deskbar_frame = deskbar.Frame ();
-
- if (!(modifiers () & B_SHIFT_KEY) && !deskbar.IsAutoHide ())
- {
- switch (deskbar.Location ())
- {
- case B_DESKBAR_TOP:
- frame.top = deskbar_frame.bottom + 2;
- break;
-
- case B_DESKBAR_BOTTOM:
- case B_DESKBAR_LEFT_BOTTOM:
- case B_DESKBAR_RIGHT_BOTTOM:
- frame.bottom = deskbar_frame.top - 2;
- break;
-
- case B_DESKBAR_LEFT_TOP:
- if (!deskbar.IsExpanded ())
- frame.top = deskbar_frame.bottom + 2;
- else if (!deskbar.IsAlwaysOnTop ()
- && !deskbar.IsAutoRaise ())
- frame.left = deskbar_frame.right + 2;
- break;
-
- default:
- if (deskbar.IsExpanded ()
- && !deskbar.IsAlwaysOnTop ()
- && !deskbar.IsAutoRaise ())
- frame.right = deskbar_frame.left - 2;
- }
- }
-
- window_frame = Frame ();
- decorator_frame = DecoratorFrame ();
-
- frame.top += (window_frame.top
- - decorator_frame.top);
- frame.bottom -= (decorator_frame.bottom
- - window_frame.bottom);
- frame.left += (window_frame.left
- - decorator_frame.left);
- frame.right -= (decorator_frame.right
- - window_frame.right);
-
- if (frame.top > deskbar_frame.bottom
- || frame.bottom < deskbar_frame.top)
- {
- frame.left = screen_frame.left + (window_frame.left
- - decorator_frame.left);
- frame.right = screen_frame.right - (decorator_frame.right
- - window_frame.right);
- }
-
- return frame;
- }
-
void
UpwardsSubset (EmacsWindow *w)
{
@@ -711,12 +790,6 @@ public:
RecomputeFeel ();
UpwardsUnSubsetChildren (parent);
this->RemoveFromSubset (this);
-
- if (fullscreen_p)
- {
- fullscreen_p = 0;
- MakeFullscreen (1);
- }
child_frame_lock.Unlock ();
}
@@ -766,11 +839,6 @@ public:
this->AddToSubset (this);
if (!IsHidden () && this->parent)
UpwardsSubsetChildren (parent);
- if (fullscreen_p)
- {
- fullscreen_p = 0;
- MakeFullscreen (1);
- }
window->LinkChild (this);
child_frame_lock.Unlock ();
@@ -797,11 +865,23 @@ public:
}
void
+ MoveToIncludingFrame (int x, int y)
+ {
+ BRect decorator, frame;
+
+ decorator = DecoratorFrame ();
+ frame = Frame ();
+
+ MoveTo (x + frame.left - decorator.left,
+ y + frame.top - decorator.top);
+ }
+
+ void
DoMove (struct child_frame *f)
{
BRect frame = this->Frame ();
- f->window->MoveTo (frame.left + f->xoff,
- frame.top + f->yoff);
+ f->window->MoveToIncludingFrame (frame.left + f->xoff,
+ frame.top + f->yoff);
}
void
@@ -982,6 +1062,15 @@ public:
haiku_write (WHEEL_MOVE_EVENT, &rq);
};
}
+ else if (msg->what == SEND_MOVE_FRAME_EVENT)
+ FrameMoved (Frame ().LeftTop ());
+ else if (msg->what == B_SCREEN_CHANGED)
+ {
+ if (fullscreen_mode != FULLSCREEN_MODE_NONE)
+ SetFullscreen (fullscreen_mode);
+
+ BWindow::DispatchMessage (msg, handler);
+ }
else
BWindow::DispatchMessage (msg, handler);
}
@@ -1015,41 +1104,66 @@ public:
{
struct haiku_resize_event rq;
rq.window = this;
- rq.px_heightf = newHeight + 1.0f;
- rq.px_widthf = newWidth + 1.0f;
+ rq.width = newWidth + 1.0f;
+ rq.height = newHeight + 1.0f;
haiku_write (FRAME_RESIZED, &rq);
BWindow::FrameResized (newWidth, newHeight);
}
void
- FrameMoved (BPoint newPosition)
+ FrameMoved (BPoint new_position)
{
struct haiku_move_event rq;
+ BRect frame, decorator_frame;
+ struct child_frame *f;
+
+ if (fullscreen_mode == FULLSCREEN_MODE_WIDTH
+ && new_position.x != 0)
+ {
+ MoveTo (0, new_position.y);
+ return;
+ }
+
+ if (fullscreen_mode == FULLSCREEN_MODE_HEIGHT
+ && new_position.y != 0)
+ {
+ MoveTo (new_position.x, 0);
+ return;
+ }
+
rq.window = this;
- rq.x = std::lrint (newPosition.x);
- rq.y = std::lrint (newPosition.y);
+ rq.x = std::lrint (new_position.x);
+ rq.y = std::lrint (new_position.y);
+
+ frame = Frame ();
+ decorator_frame = DecoratorFrame ();
+
+ rq.decorator_width
+ = std::lrint (frame.left - decorator_frame.left);
+ rq.decorator_height
+ = std::lrint (frame.top - decorator_frame.top);
haiku_write (MOVE_EVENT, &rq);
CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK
{
- for (struct child_frame *f = subset_windows;
- f; f = f->next)
+ for (f = subset_windows; f; f = f->next)
DoMove (f);
child_frame_lock.Unlock ();
- BWindow::FrameMoved (newPosition);
+ BWindow::FrameMoved (new_position);
}
}
void
WorkspacesChanged (uint32_t old, uint32_t n)
{
+ struct child_frame *f;
+
CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK
{
- for (struct child_frame *f = subset_windows;
- f; f = f->next)
+ for (f = subset_windows; f; f = f->next)
DoUpdateWorkspace (f);
child_frame_lock.Unlock ();
@@ -1063,7 +1177,7 @@ public:
gui_abort ("Failed to lock child frame state lock");
if (!this->parent)
- this->MoveTo (x, y);
+ this->MoveToIncludingFrame (x, y);
else
this->parent->MoveChild (this, x, y, 0);
child_frame_lock.Unlock ();
@@ -1135,66 +1249,113 @@ public:
child_frame_lock.Unlock ();
}
- void
- Zoom (BPoint o, float w, float h)
+ BRect
+ ClearFullscreen (enum haiku_fullscreen_mode target_mode)
{
- struct haiku_zoom_event rq;
- BRect rect;
- rq.window = this;
-
- if (fullscreen_p)
- MakeFullscreen (0);
+ BRect original_frame;
- if (!zoomed_p)
- {
- pre_zoom_rect = Frame ();
- zoomed_p = true;
- rect = CalculateZoomRect ();
- }
- else
+ switch (fullscreen_mode)
{
- zoomed_p = false;
- rect = pre_zoom_rect;
- }
+ case FULLSCREEN_MODE_MAXIMIZED:
+ original_frame = pre_zoom_rect;
- rq.zoomed = zoomed_p;
- haiku_write (ZOOM_EVENT, &rq);
+ if (target_mode == FULLSCREEN_MODE_NONE)
+ BWindow::Zoom (pre_zoom_rect.LeftTop (),
+ BE_RECT_WIDTH (pre_zoom_rect) - 1,
+ BE_RECT_HEIGHT (pre_zoom_rect) - 1);
+ break;
+
+ case FULLSCREEN_MODE_BOTH:
+ case FULLSCREEN_MODE_HEIGHT:
+ case FULLSCREEN_MODE_WIDTH:
+ original_frame = pre_fullscreen_rect;
+ SetFlags (Flags () & ~(B_NOT_MOVABLE
+ | B_NOT_ZOOMABLE
+ | B_NOT_RESIZABLE));
+
+ if (target_mode != FULLSCREEN_MODE_NONE)
+ goto out;
+
+ MoveTo (pre_fullscreen_rect.LeftTop ());
+ ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1,
+ BE_RECT_HEIGHT (pre_fullscreen_rect) - 1);
+ break;
+
+ case FULLSCREEN_MODE_NONE:
+ original_frame = Frame ();
+ break;
+ }
- BWindow::Zoom (rect.LeftTop (), BE_RECT_WIDTH (rect) - 1,
- BE_RECT_HEIGHT (rect) - 1);
+ out:
+ fullscreen_mode = FULLSCREEN_MODE_NONE;
+ return original_frame;
}
- void
- UnZoom (void)
+ BRect
+ FullscreenRectForMode (enum haiku_fullscreen_mode mode)
{
- if (!zoomed_p)
- return;
+ BScreen screen (this);
+ BRect frame;
+
+ if (!screen.IsValid ())
+ return BRect (0, 0, 0, 0);
+
+ frame = screen.Frame ();
+
+ if (mode == FULLSCREEN_MODE_HEIGHT)
+ frame.right -= BE_RECT_WIDTH (frame) / 2;
+ else if (mode == FULLSCREEN_MODE_WIDTH)
+ frame.bottom -= BE_RECT_HEIGHT (frame) / 2;
- BWindow::Zoom ();
+ return frame;
}
void
- GetParentWidthHeight (int *width, int *height)
+ SetFullscreen (enum haiku_fullscreen_mode mode)
{
- if (!child_frame_lock.Lock ())
- gui_abort ("Failed to lock child frame state lock");
+ BRect zoom_rect, frame;
- if (parent)
- {
- BRect frame = parent->Frame ();
- *width = BE_RECT_WIDTH (frame);
- *height = BE_RECT_HEIGHT (frame);
- }
- else
+ frame = ClearFullscreen (mode);
+
+ switch (mode)
{
- BScreen s (this);
- BRect frame = s.Frame ();
+ case FULLSCREEN_MODE_MAXIMIZED:
+ pre_zoom_rect = frame;
+ zoom_rect = get_zoom_rect (this);
+ BWindow::Zoom (zoom_rect.LeftTop (),
+ BE_RECT_WIDTH (zoom_rect) - 1,
+ BE_RECT_HEIGHT (zoom_rect) - 1);
+ break;
+
+ case FULLSCREEN_MODE_BOTH:
+ SetFlags (Flags () | B_NOT_MOVABLE);
+ FALLTHROUGH;
+
+ case FULLSCREEN_MODE_HEIGHT:
+ case FULLSCREEN_MODE_WIDTH:
+ SetFlags (Flags () | B_NOT_ZOOMABLE | B_NOT_RESIZABLE);
+ pre_fullscreen_rect = frame;
+ zoom_rect = FullscreenRectForMode (mode);
+ ResizeTo (BE_RECT_WIDTH (zoom_rect) - 1,
+ BE_RECT_HEIGHT (zoom_rect) - 1);
+ MoveTo (zoom_rect.left, zoom_rect.top);
+ break;
- *width = BE_RECT_WIDTH (frame);
- *height = BE_RECT_HEIGHT (frame);
+ case FULLSCREEN_MODE_NONE:
+ break;
}
- child_frame_lock.Unlock ();
+ fullscreen_mode = mode;
+ }
+
+ void
+ Zoom (BPoint origin, float width, float height)
+ {
+ struct haiku_zoom_event rq;
+
+ rq.window = this;
+ rq.fullscreen_mode = fullscreen_mode;
+ haiku_write (ZOOM_EVENT, &rq);
}
void
@@ -1217,53 +1378,6 @@ public:
child_frame_lock.Lock ();
gui_abort ("Trying to calculate offsets for a child frame that doesn't exist");
}
-
- void
- MakeFullscreen (int make_fullscreen_p)
- {
- BScreen screen (this);
-
- if (!screen.IsValid ())
- gui_abort ("Trying to make a window fullscreen without a screen");
-
- UnZoom ();
-
- if (make_fullscreen_p == fullscreen_p)
- return;
-
- fullscreen_p = make_fullscreen_p;
- uint32 flags = Flags ();
- if (fullscreen_p)
- {
- if (zoomed_p)
- UnZoom ();
-
- flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE;
- pre_fullscreen_rect = Frame ();
-
- if (!child_frame_lock.Lock ())
- gui_abort ("Failed to lock child frame state lock");
-
- if (parent)
- parent->OffsetChildRect (&pre_fullscreen_rect, this);
-
- child_frame_lock.Unlock ();
-
- int w, h;
- EmacsMoveTo (0, 0);
- GetParentWidthHeight (&w, &h);
- ResizeTo (w - 1, h - 1);
- }
- else
- {
- flags &= ~(B_NOT_MOVABLE | B_NOT_ZOOMABLE);
- EmacsMoveTo (pre_fullscreen_rect.left,
- pre_fullscreen_rect.top);
- ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1,
- BE_RECT_HEIGHT (pre_fullscreen_rect) - 1);
- }
- SetFlags (flags);
- }
};
class EmacsMenuBar : public BMenuBar
@@ -1322,11 +1436,7 @@ public:
rq.y = std::lrint (point.y);
rq.window = this->Window ();
- if (movement_locker.Lock ())
- {
- haiku_write (MENU_BAR_LEFT, &rq);
- movement_locker.Unlock ();
- }
+ haiku_write (MENU_BAR_LEFT, &rq);
}
BMenuBar::MouseMoved (point, transit, msg);
@@ -1383,25 +1493,36 @@ public:
class EmacsView : public BView
{
public:
- uint32_t previous_buttons = 0;
- int looper_locked_count = 0;
+ uint32_t previous_buttons;
+ int looper_locked_count;
BRegion sb_region;
BRegion invalid_region;
- BView *offscreen_draw_view = NULL;
- BBitmap *offscreen_draw_bitmap_1 = NULL;
- BBitmap *copy_bitmap = NULL;
+ BView *offscreen_draw_view;
+ BBitmap *offscreen_draw_bitmap_1;
+ BBitmap *copy_bitmap;
#ifdef USE_BE_CAIRO
- cairo_surface_t *cr_surface = NULL;
- cairo_t *cr_context = NULL;
+ cairo_surface_t *cr_surface;
+ cairo_t *cr_context;
BLocker cr_surface_lock;
#endif
BPoint tt_absl_pos;
- BMessage *wait_for_release_message = NULL;
-
- EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs", B_FOLLOW_NONE, B_WILL_DRAW)
+ BMessage *wait_for_release_message;
+
+ EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs",
+ B_FOLLOW_NONE, B_WILL_DRAW),
+ previous_buttons (0),
+ looper_locked_count (0),
+ offscreen_draw_view (NULL),
+ offscreen_draw_bitmap_1 (NULL),
+ copy_bitmap (NULL),
+#ifdef USE_BE_CAIRO
+ cr_surface (NULL),
+ cr_context (NULL),
+#endif
+ wait_for_release_message (NULL)
{
}
@@ -1549,9 +1670,7 @@ public:
#endif
if (looper_locked_count)
- {
- offscreen_draw_bitmap_1->Lock ();
- }
+ offscreen_draw_bitmap_1->Lock ();
UnlockLooper ();
}
@@ -1618,16 +1737,17 @@ public:
copy_bitmap = NULL;
}
if (!copy_bitmap)
- copy_bitmap = new BBitmap (offscreen_draw_bitmap_1);
+ {
+ copy_bitmap = new BBitmap (offscreen_draw_bitmap_1);
+ SetViewBitmap (copy_bitmap, Frame (),
+ Frame (), B_FOLLOW_NONE, 0);
+ }
else
copy_bitmap->ImportBits (offscreen_draw_bitmap_1);
if (copy_bitmap->InitCheck () != B_OK)
gui_abort ("Failed to init copy bitmap during buffer flip");
- SetViewBitmap (copy_bitmap,
- Frame (), Frame (), B_FOLLOW_NONE, 0);
-
Invalidate (&invalid_region);
invalid_region.MakeEmpty ();
UnlockLooper ();
@@ -1668,8 +1788,11 @@ public:
struct haiku_mouse_motion_event rq;
int32 windowid;
EmacsWindow *window;
+ BToolTip *tooltip;
window = (EmacsWindow *) Window ();
+ tooltip = ToolTip ();
+
rq.just_exited_p = transit == B_EXITED_VIEW;
rq.x = point.x;
rq.y = point.y;
@@ -1684,9 +1807,9 @@ public:
else
rq.dnd_message = false;
- if (ToolTip ())
- ToolTip ()->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x),
- -(point.y - tt_absl_pos.y)));
+ if (tooltip)
+ tooltip->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x),
+ -(point.y - tt_absl_pos.y)));
if (!grab_view_locker.Lock ())
gui_abort ("Couldn't lock grab view locker");
@@ -1699,18 +1822,14 @@ public:
grab_view_locker.Unlock ();
- if (movement_locker.Lock ())
- {
- haiku_write (MOUSE_MOTION, &rq);
- movement_locker.Unlock ();
- }
+ haiku_write (MOUSE_MOTION, &rq);
}
void
- MouseDown (BPoint point)
+ BasicMouseDown (BPoint point, BView *scroll_bar)
{
struct haiku_button_event rq;
- uint32 buttons;
+ uint32 mods, buttons;
this->GetMouse (&point, &buttons, false);
@@ -1721,6 +1840,7 @@ public:
grab_view_locker.Unlock ();
rq.window = this->Window ();
+ rq.scroll_bar = scroll_bar;
if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON)
&& (buttons & B_PRIMARY_MOUSE_BUTTON))
@@ -1739,7 +1859,7 @@ public:
rq.x = point.x;
rq.y = point.y;
- uint32_t mods = modifiers ();
+ mods = modifiers ();
rq.modifiers = 0;
if (mods & B_SHIFT_KEY)
@@ -1754,18 +1874,25 @@ public:
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
- SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS
- | B_NO_POINTER_HISTORY));
+ if (!scroll_bar)
+ SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS
+ | B_NO_POINTER_HISTORY));
rq.time = system_time ();
haiku_write (BUTTON_DOWN, &rq);
}
void
- MouseUp (BPoint point)
+ MouseDown (BPoint point)
+ {
+ BasicMouseDown (point, NULL);
+ }
+
+ void
+ BasicMouseUp (BPoint point, BView *scroll_bar)
{
struct haiku_button_event rq;
- uint32 buttons;
+ uint32 buttons, mods;
this->GetMouse (&point, &buttons, false);
@@ -1786,6 +1913,7 @@ public:
}
rq.window = this->Window ();
+ rq.scroll_bar = scroll_bar;
if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON)
&& !(buttons & B_PRIMARY_MOUSE_BUTTON))
@@ -1804,7 +1932,7 @@ public:
rq.x = point.x;
rq.y = point.y;
- uint32_t mods = modifiers ();
+ mods = modifiers ();
rq.modifiers = 0;
if (mods & B_SHIFT_KEY)
@@ -1819,37 +1947,48 @@ public:
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
- if (!buttons)
- SetMouseEventMask (0, 0);
-
rq.time = system_time ();
haiku_write (BUTTON_UP, &rq);
}
+
+ void
+ MouseUp (BPoint point)
+ {
+ BasicMouseUp (point, NULL);
+ }
};
class EmacsScrollBar : public BScrollBar
{
public:
- int dragging = 0;
+ int dragging;
bool horizontal;
enum haiku_scroll_bar_part current_part;
float old_value;
scroll_bar_info info;
/* True if button events should be passed to the parent. */
- bool handle_button = false;
- bool in_overscroll = false;
- bool can_overscroll = false;
- bool maybe_overscroll = false;
+ bool handle_button;
+ bool in_overscroll;
+ bool can_overscroll;
+ bool maybe_overscroll;
BPoint last_overscroll;
int last_reported_overscroll_value;
int max_value, real_max_value;
int overscroll_start_value;
bigtime_t repeater_start;
-
- EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p) :
- BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ?
- B_HORIZONTAL : B_VERTICAL)
+ EmacsView *parent;
+
+ EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p,
+ EmacsView *parent)
+ : BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ?
+ B_HORIZONTAL : B_VERTICAL),
+ dragging (0),
+ handle_button (false),
+ in_overscroll (false),
+ can_overscroll (false),
+ maybe_overscroll (false),
+ parent (parent)
{
BView *vw = (BView *) this;
vw->SetResizingMode (B_FOLLOW_NONE);
@@ -2050,7 +2189,6 @@ public:
BLooper *looper;
BMessage *message;
int32 buttons, mods;
- BView *parent;
looper = Looper ();
message = NULL;
@@ -2071,8 +2209,9 @@ public:
{
/* Allow C-mouse-3 to split the window on a scroll bar. */
handle_button = true;
- parent = Parent ();
- parent->MouseDown (ConvertToParent (pt));
+ SetMouseEventMask (B_POINTER_EVENTS, (B_SUSPEND_VIEW_FOCUS
+ | B_LOCK_WINDOW_FOCUS));
+ parent->BasicMouseDown (ConvertToParent (pt), this);
return;
}
@@ -2135,7 +2274,6 @@ public:
MouseUp (BPoint pt)
{
struct haiku_scroll_bar_drag_event rq;
- BView *parent;
in_overscroll = false;
maybe_overscroll = false;
@@ -2143,8 +2281,7 @@ public:
if (handle_button)
{
handle_button = false;
- parent = Parent ();
- parent->MouseUp (ConvertToParent (pt));
+ parent->BasicMouseUp (ConvertToParent (pt), this);
return;
}
@@ -2179,11 +2316,7 @@ public:
rq.y = std::lrint (conv.y);
rq.window = this->Window ();
- if (movement_locker.Lock ())
- {
- haiku_write (MENU_BAR_LEFT, &rq);
- movement_locker.Unlock ();
- }
+ haiku_write (MENU_BAR_LEFT, &rq);
}
if (in_overscroll)
@@ -2280,30 +2413,26 @@ public:
class EmacsMenuItem : public BMenuItem
{
public:
- int menu_bar_id = -1;
- void *menu_ptr = NULL;
- void *wind_ptr = NULL;
- char *key = NULL;
- char *help = NULL;
-
- EmacsMenuItem (const char *ky,
- const char *str,
- const char *help,
- BMessage *message = NULL) : BMenuItem (str, message)
+ int menu_bar_id;
+ void *menu_ptr;
+ void *wind_ptr;
+ char *key;
+ char *help;
+
+ EmacsMenuItem (const char *key_label, const char *label,
+ const char *help, BMessage *message = NULL)
+ : BMenuItem (label, message),
+ menu_bar_id (-1),
+ menu_ptr (NULL),
+ wind_ptr (NULL),
+ key (NULL),
+ help (NULL)
{
- if (ky)
- {
- key = strdup (ky);
- if (!key)
- gui_abort ("strdup failed");
- }
+ if (key_label)
+ key = strdup (key_label);
if (help)
- {
- this->help = strdup (help);
- if (!this->help)
- gui_abort ("strdup failed");
- }
+ this->help = strdup (help);
}
~EmacsMenuItem ()
@@ -2383,22 +2512,6 @@ public:
}
};
-class EmacsPopUpMenu : public BPopUpMenu
-{
-public:
- EmacsPopUpMenu (const char *name) : BPopUpMenu (name, 0)
- {
-
- }
-
- void
- FrameResized (float w, float h)
- {
- Invalidate ();
- BPopUpMenu::FrameResized (w, h);
- }
-};
-
class EmacsFontPreviewDialog : public BWindow
{
BStringView text_view;
@@ -2618,13 +2731,22 @@ class EmacsFontSelectionDialog : public BWindow
void
UpdateStylesForIndex (int idx)
{
- int n, i;
+ int n, i, previous_selection;
uint32 flags;
font_family family;
font_style style;
BStringItem *item;
+ char *current_style;
n = all_styles.CountItems ();
+ current_style = NULL;
+ previous_selection = font_style_pane.CurrentSelection ();
+
+ if (previous_selection >= 0)
+ {
+ item = all_styles.ItemAt (previous_selection);
+ current_style = strdup (item->Text ());
+ }
font_style_pane.MakeEmpty ();
all_styles.MakeEmpty ();
@@ -2640,6 +2762,10 @@ class EmacsFontSelectionDialog : public BWindow
else
item = new BStringItem ("<error>");
+ if (current_style && pending_selection_idx < 0
+ && !strcmp (current_style, style))
+ pending_selection_idx = i;
+
font_style_pane.AddItem (item);
all_styles.AddItem (item);
}
@@ -2653,6 +2779,9 @@ class EmacsFontSelectionDialog : public BWindow
pending_selection_idx = -1;
UpdateForSelectedStyle ();
+
+ if (current_style)
+ free (current_style);
}
bool
@@ -3361,56 +3490,28 @@ BView_resize_to (void *view, int width, int height)
vw->UnlockLooper ();
}
-void *
-BCursor_create_default (void)
-{
- return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT);
-}
-
-void *
-BCursor_create_modeline (void)
-{
- return new BCursor (B_CURSOR_ID_CONTEXT_MENU);
-}
-
-void *
-BCursor_from_id (enum haiku_cursor cursor)
-{
- return new BCursor ((enum BCursorID) cursor);
-}
-
-void *
-BCursor_create_i_beam (void)
-{
- return new BCursor (B_CURSOR_ID_I_BEAM);
-}
-
-void *
-BCursor_create_progress_cursor (void)
+void
+be_delete_cursor (void *cursor)
{
- return new BCursor (B_CURSOR_ID_PROGRESS);
+ if (cursor)
+ delete (BCursor *) cursor;
}
void *
-BCursor_create_grab (void)
-{
- return new BCursor (B_CURSOR_ID_GRAB);
-}
-
-void
-BCursor_delete (void *cursor)
+be_create_cursor_from_id (int id)
{
- if (cursor)
- delete (BCursor *) cursor;
+ return new BCursor ((enum BCursorID) id);
}
void
BView_set_view_cursor (void *view, void *cursor)
{
- if (!((BView *) view)->LockLooper ())
+ BView *v = (BView *) view;
+
+ if (!v->LockLooper ())
gui_abort ("Failed to lock view setting cursor");
- ((BView *) view)->SetViewCursor ((BCursor *) cursor);
- ((BView *) view)->UnlockLooper ();
+ v->SetViewCursor ((BCursor *) cursor);
+ v->UnlockLooper ();
}
void
@@ -3421,20 +3522,22 @@ BWindow_Flush (void *window)
/* Make a scrollbar, attach it to VIEW's window, and return it. */
void *
-BScrollBar_make_for_view (void *view, int horizontal_p,
- int x, int y, int x1, int y1,
- void *scroll_bar_ptr)
+be_make_scroll_bar_for_view (void *view, int horizontal_p,
+ int x, int y, int x1, int y1)
{
- EmacsScrollBar *sb = new EmacsScrollBar (x, y, x1, y1, horizontal_p);
+ EmacsScrollBar *scroll_bar;
BView *vw = (BView *) view;
- BView *sv = (BView *) sb;
if (!vw->LockLooper ())
gui_abort ("Failed to lock scrollbar owner");
- vw->AddChild ((BView *) sb);
- sv->WindowActivated (vw->Window ()->IsActive ());
+
+ scroll_bar = new EmacsScrollBar (x, y, x1, y1, horizontal_p,
+ (EmacsView *) vw);
+
+ vw->AddChild (scroll_bar);
vw->UnlockLooper ();
- return sb;
+
+ return scroll_bar;
}
void
@@ -3599,17 +3702,6 @@ BBitmap_import_fringe_bitmap (void *bitmap, unsigned short *bits, int wd, int h)
}
}
-void
-BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h)
-{
- BBitmap *bmp = (BBitmap *) bitmap;
-
- if (wd % 8)
- wd += 8 - (wd % 8);
-
- bmp->ImportBits (bits, wd / 8 * h, wd / 8, 0, B_GRAY1);
-}
-
/* Make a scrollbar at X, Y known to the view VIEW. */
void
BView_publish_scroll_bar (void *view, int x, int y, int width, int height)
@@ -3768,7 +3860,8 @@ BView_emacs_delete (void *view)
void *
BPopUpMenu_new (const char *name)
{
- BPopUpMenu *menu = new EmacsPopUpMenu (name);
+ BPopUpMenu *menu = new BPopUpMenu (name);
+
menu->SetRadioMode (0);
return menu;
}
@@ -3778,9 +3871,11 @@ BPopUpMenu_new (const char *name)
void
BMenu_add_title (void *menu, const char *text)
{
- EmacsTitleMenuItem *it = new EmacsTitleMenuItem (text);
- BMenu *mn = (BMenu *) menu;
- mn->AddItem (it);
+ BMenu *be_menu = (BMenu *) menu;
+ EmacsTitleMenuItem *it;
+
+ it = new EmacsTitleMenuItem (text);
+ be_menu->AddItem (it);
}
/* Add an item to the menu MENU. */
@@ -4522,30 +4617,6 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p,
return file_name;
}
-/* Zoom WINDOW. */
-void
-BWindow_zoom (void *window)
-{
- BWindow *w = (BWindow *) window;
- w->Zoom ();
-}
-
-/* Make WINDOW fullscreen if FULLSCREEN_P. */
-void
-EmacsWindow_make_fullscreen (void *window, int fullscreen_p)
-{
- EmacsWindow *w = (EmacsWindow *) window;
- w->MakeFullscreen (fullscreen_p);
-}
-
-/* Unzoom (maximize) WINDOW. */
-void
-EmacsWindow_unzoom (void *window)
-{
- EmacsWindow *w = (EmacsWindow *) window;
- w->UnZoom ();
-}
-
/* Move the pointer into MBAR and start tracking. Return whether the
menu bar was opened correctly. */
bool
@@ -5082,3 +5153,172 @@ BWindow_set_sticky (void *window, bool sticky)
w->UnlockLooper ();
}
}
+
+status_t
+be_roster_launch (const char *type, const char *file, char **cargs,
+ ptrdiff_t nargs, void *message, team_id *team_id)
+{
+ BEntry entry;
+ entry_ref ref;
+
+ if (type)
+ {
+ if (message)
+ return be_roster->Launch (type, (BMessage *) message,
+ team_id);
+
+ return be_roster->Launch (type, (nargs > INT_MAX
+ ? INT_MAX : nargs),
+ cargs, team_id);
+ }
+
+ if (entry.SetTo (file) != B_OK)
+ return B_ERROR;
+
+ if (entry.GetRef (&ref) != B_OK)
+ return B_ERROR;
+
+ if (message)
+ return be_roster->Launch (&ref, (BMessage *) message,
+ team_id);
+
+ return be_roster->Launch (&ref, (nargs > INT_MAX
+ ? INT_MAX : nargs),
+ cargs, team_id);
+}
+
+void *
+be_create_pixmap_cursor (void *bitmap, int x, int y)
+{
+ BBitmap *bm;
+ BCursor *cursor;
+
+ bm = (BBitmap *) bitmap;
+ cursor = new BCursor (bm, BPoint (x, y));
+
+ if (cursor->InitCheck () != B_OK)
+ {
+ delete cursor;
+ return NULL;
+ }
+
+ return cursor;
+}
+
+void
+be_get_window_decorator_dimensions (void *window, int *left, int *top,
+ int *right, int *bottom)
+{
+ BWindow *wnd;
+ BRect frame, window_frame;
+
+ wnd = (BWindow *) window;
+
+ if (!wnd->LockLooper ())
+ gui_abort ("Failed to lock window looper frame");
+
+ frame = wnd->DecoratorFrame ();
+ window_frame = wnd->Frame ();
+
+ if (left)
+ *left = window_frame.left - frame.left;
+
+ if (top)
+ *top = window_frame.top - frame.top;
+
+ if (right)
+ *right = frame.right - window_frame.right;
+
+ if (bottom)
+ *bottom = frame.bottom - window_frame.bottom;
+
+ wnd->UnlockLooper ();
+}
+
+void
+be_get_window_decorator_frame (void *window, int *left, int *top,
+ int *width, int *height)
+{
+ BWindow *wnd;
+ BRect frame;
+
+ wnd = (BWindow *) window;
+
+ if (!wnd->LockLooper ())
+ gui_abort ("Failed to lock window looper frame");
+
+ frame = wnd->DecoratorFrame ();
+
+ *left = frame.left;
+ *top = frame.top;
+ *width = BE_RECT_WIDTH (frame);
+ *height = BE_RECT_HEIGHT (frame);
+
+ wnd->UnlockLooper ();
+}
+
+/* Request that a MOVE_EVENT be sent for WINDOW. This is so that
+ frame offsets can be updated after a frame parameter affecting
+ decorators changes. Sending an event instead of updating the
+ offsets directly avoids race conditions where events with older
+ information are received after the update happens. */
+void
+be_send_move_frame_event (void *window)
+{
+ BWindow *wnd = (BWindow *) window;
+ BMessenger msg (wnd);
+
+ msg.SendMessage (SEND_MOVE_FRAME_EVENT);
+}
+
+void
+be_lock_window (void *window)
+{
+ BWindow *wnd = (BWindow *) window;
+
+ if (!wnd->LockLooper ())
+ gui_abort ("Failed to lock window looper");
+}
+
+void
+be_unlock_window (void *window)
+{
+ BWindow *wnd = (BWindow *) window;
+
+ wnd->UnlockLooper ();
+}
+
+void
+be_set_window_fullscreen_mode (void *window, enum haiku_fullscreen_mode mode)
+{
+ EmacsWindow *w = (EmacsWindow *) window;
+
+ if (!w->LockLooper ())
+ gui_abort ("Failed to lock window to set fullscreen mode");
+
+ w->SetFullscreen (mode);
+ w->UnlockLooper ();
+}
+
+bool
+be_get_explicit_workarea (int *x, int *y, int *width, int *height)
+{
+ BDeskbar deskbar;
+ BRect zoom;
+ deskbar_location location;
+
+ location = deskbar.Location ();
+
+ if (location != B_DESKBAR_TOP
+ && location != B_DESKBAR_BOTTOM)
+ return false;
+
+ zoom = get_zoom_rect (NULL);
+
+ *x = zoom.left;
+ *y = zoom.top;
+ *width = BE_RECT_WIDTH (zoom);
+ *height = BE_RECT_HEIGHT (zoom);
+
+ return true;
+}
diff --git a/src/haiku_support.h b/src/haiku_support.h
index 5ded9300d8a..7f8d471b650 100644
--- a/src/haiku_support.h
+++ b/src/haiku_support.h
@@ -38,7 +38,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
enum haiku_cursor
{
+ CURSOR_ID_SYSTEM_DEFAULT = 1,
+ CURSOR_ID_CONTEXT_MENU = 3,
+ CURSOR_ID_COPY = 4,
+ CURSOR_ID_CREATE_LINK = 29,
+ CURSOR_ID_CROSS_HAIR = 5,
+ CURSOR_ID_FOLLOW_LINK = 6,
+ CURSOR_ID_GRAB = 7,
+ CURSOR_ID_GRABBING = 8,
+ CURSOR_ID_HELP = 9,
+ CURSOR_ID_I_BEAM = 2,
+ CURSOR_ID_I_BEAM_HORIZONTAL = 10,
+ CURSOR_ID_MOVE = 11,
CURSOR_ID_NO_CURSOR = 12,
+ CURSOR_ID_NOT_ALLOWED = 13,
+ CURSOR_ID_PROGRESS = 14,
CURSOR_ID_RESIZE_NORTH = 15,
CURSOR_ID_RESIZE_EAST = 16,
CURSOR_ID_RESIZE_SOUTH = 17,
@@ -50,7 +64,9 @@ enum haiku_cursor
CURSOR_ID_RESIZE_NORTH_SOUTH = 23,
CURSOR_ID_RESIZE_EAST_WEST = 24,
CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST = 25,
- CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26
+ CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26,
+ CURSOR_ID_ZOOM_IN = 27,
+ CURSOR_ID_ZOOM_OUT = 28
};
enum haiku_z_group
@@ -96,9 +112,15 @@ enum haiku_event_type
DRAG_AND_DROP_EVENT,
APP_QUIT_REQUESTED_EVENT,
DUMMY_EVENT,
- MENU_BAR_LEFT
+ SCREEN_CHANGED_EVENT,
+ MENU_BAR_LEFT,
};
+struct haiku_screen_changed_event
+{
+ bigtime_t when;
+};
+
struct haiku_quit_requested_event
{
void *window;
@@ -107,8 +129,8 @@ struct haiku_quit_requested_event
struct haiku_resize_event
{
void *window;
- float px_heightf;
- float px_widthf;
+ float width;
+ float height;
};
struct haiku_expose_event
@@ -187,6 +209,7 @@ struct haiku_menu_bar_click_event
struct haiku_button_event
{
void *window;
+ void *scroll_bar;
int btn_no;
int modifiers;
int x;
@@ -203,8 +226,9 @@ struct haiku_iconification_event
struct haiku_move_event
{
void *window;
- int x;
- int y;
+ int x, y;
+ int decorator_width;
+ int decorator_height;
};
struct haiku_wheel_move_event
@@ -232,7 +256,7 @@ struct haiku_menu_bar_help_event
struct haiku_zoom_event
{
void *window;
- bool zoomed;
+ int fullscreen_mode;
};
enum haiku_font_specification
@@ -299,6 +323,15 @@ enum haiku_font_weight
HAIKU_MEDIUM = 2000,
};
+enum haiku_fullscreen_mode
+ {
+ FULLSCREEN_MODE_NONE,
+ FULLSCREEN_MODE_WIDTH,
+ FULLSCREEN_MODE_HEIGHT,
+ FULLSCREEN_MODE_BOTH,
+ FULLSCREEN_MODE_MAXIMIZED,
+ };
+
struct haiku_font_pattern
{
/* Bitmask indicating which fields are set. */
@@ -421,32 +454,14 @@ struct haiku_session_manager_reply
dimensions of a BRect, instead of relying on the broken Width and
Height functions. */
-#define BE_RECT_HEIGHT(rect) (ceil (((rect).bottom - (rect).top) + 1))
-#define BE_RECT_WIDTH(rect) (ceil (((rect).right - (rect).left) + 1))
+#define BE_RECT_HEIGHT(rect) (ceil (((rect).bottom - (rect).top) + 1))
+#define BE_RECT_WIDTH(rect) (ceil (((rect).right - (rect).left) + 1))
#endif /* __cplusplus */
-/* C++ code cannot include lisp.h, but file dialogs need to be able
- to bind to the specpdl and handle quitting correctly. */
-
-#ifdef __cplusplus
-#if SIZE_MAX > 0xffffffff
-#define WRAP_SPECPDL_REF 1
-#endif
-#ifdef WRAP_SPECPDL_REF
-typedef struct { ptrdiff_t bytes; } specpdl_ref;
-#else
-typedef ptrdiff_t specpdl_ref;
-#endif
-
-#else
-#include "lisp.h"
-#endif
-
#ifdef __cplusplus
extern "C"
{
#endif
-#include <pthread.h>
#include <OS.h>
#ifdef __cplusplus
@@ -477,6 +492,8 @@ extern void hsl_color_rgb (double, double, double, uint32_t *);
extern void *BBitmap_new (int, int, int);
extern void *BBitmap_data (void *);
extern int BBitmap_convert (void *, void **);
+extern void be_draw_cross_on_pixmap (void *, int, int, int, int,
+ uint32_t);
extern void BBitmap_free (void *);
@@ -496,7 +513,6 @@ extern void BWindow_center_on_screen (void *);
extern void BWindow_change_decoration (void *, int);
extern void BWindow_set_tooltip_decoration (void *);
extern void BWindow_set_avoid_focus (void *, int);
-extern void BWindow_zoom (void *);
extern void BWindow_set_size_alignment (void *, int, int);
extern void BWindow_sync (void *);
extern void BWindow_send_behind (void *, void *);
@@ -541,6 +557,8 @@ extern void BView_DrawBitmap (void *, void *, int, int, int, int, int, int,
extern void BView_DrawBitmapWithEraseOp (void *, void *, int, int, int, int);
extern void BView_DrawMask (void *, void *, int, int, int, int, int, int,
int, int, uint32_t);
+extern void BView_DrawBitmapTiled (void *, void *, int, int,
+ int, int, int, int, int, int);
extern void BView_resize_to (void *, int, int);
extern void BView_set_view_cursor (void *, void *);
@@ -554,15 +572,11 @@ extern void be_get_display_resolution (double *, double *);
extern void be_get_screen_dimensions (int *, int *);
/* Functions for creating and freeing cursors. */
-extern void *BCursor_create_default (void);
-extern void *BCursor_from_id (enum haiku_cursor);
-extern void *BCursor_create_modeline (void);
-extern void *BCursor_create_i_beam (void);
-extern void *BCursor_create_progress_cursor (void);
-extern void *BCursor_create_grab (void);
-extern void BCursor_delete (void *);
-
-extern void *BScrollBar_make_for_view (void *, int, int, int, int, int, void *);
+extern void *be_create_cursor_from_id (int);
+extern void *be_create_pixmap_cursor (void *, int, int);
+extern void be_delete_cursor (void *);
+
+extern void *be_make_scroll_bar_for_view (void *, int, int, int, int, int);
extern void BScrollBar_delete (void *);
extern int BScrollBar_default_size (int);
@@ -570,9 +584,7 @@ extern void BView_invalidate (void *);
extern void BView_draw_lock (void *, bool, int, int, int, int);
extern void BView_invalidate_region (void *, int, int, int, int);
extern void BView_draw_unlock (void *);
-
extern void BBitmap_import_fringe_bitmap (void *, unsigned short *, int, int);
-extern void BBitmap_import_mono_bits (void *, void *, int, int);
extern void haiku_font_pattern_free (struct haiku_font_pattern *);
@@ -628,8 +640,6 @@ extern void BAlert_delete (void *);
extern void EmacsWindow_parent_to (void *, void *);
extern void EmacsWindow_unparent (void *);
extern void EmacsWindow_move_weak_child (void *, void *, int, int);
-extern void EmacsWindow_make_fullscreen (void *, int);
-extern void EmacsWindow_unzoom (void *);
extern void be_get_version_string (char *, int);
extern int be_get_display_planes (void);
@@ -690,6 +700,16 @@ extern bool be_select_font (void (*) (void), bool (*) (void),
int *, bool, int, int, int);
extern int be_find_font_indices (struct haiku_font_pattern *, int *, int *);
+extern status_t be_roster_launch (const char *, const char *, char **,
+ ptrdiff_t, void *, team_id *);
+extern void be_get_window_decorator_dimensions (void *, int *, int *, int *, int *);
+extern void be_get_window_decorator_frame (void *, int *, int *, int *, int *);
+extern void be_send_move_frame_event (void *);
+extern void be_set_window_fullscreen_mode (void *, enum haiku_fullscreen_mode);
+
+extern void be_lock_window (void *);
+extern void be_unlock_window (void *);
+extern bool be_get_explicit_workarea (int *, int *, int *, int *);
#ifdef __cplusplus
}
diff --git a/src/haikufns.c b/src/haikufns.c
index 8596317de25..b79443203ff 100644
--- a/src/haikufns.c
+++ b/src/haikufns.c
@@ -34,6 +34,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "haiku_support.h"
#include "termhooks.h"
+#include "bitmaps/leftptr.xbm"
+#include "bitmaps/leftpmsk.xbm"
+
#include <stdlib.h>
#include <kernel/OS.h>
@@ -47,6 +50,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* The frame of the currently visible tooltip. */
Lisp_Object tip_frame;
+/* The X and Y deltas of the last call to `x-show-tip'. */
+Lisp_Object tip_dx, tip_dy;
+
/* The window-system window corresponding to the frame of the
currently visible tooltip. */
static Window tip_window;
@@ -93,7 +99,7 @@ get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
Lisp_Object value
= gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (r[i].tem, value), parms);
}
}
@@ -101,6 +107,22 @@ get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
return parms;
}
+/* Update the left and top offsets of F after its decorators
+ change. */
+static void
+haiku_update_after_decoration_change (struct frame *f)
+{
+ /* Don't reset offsets during initial frame creation, since the
+ contents of f->left_pos and f->top_pos won't be applied to the
+ window until `x-create-frame' finishes, so setting them here will
+ overwrite the offsets that the window should be moved to. */
+
+ if (!FRAME_OUTPUT_DATA (f)->configury_done)
+ return;
+
+ be_send_move_frame_event (FRAME_HAIKU_WINDOW (f));
+}
+
void
haiku_change_tool_bar_height (struct frame *f, int height)
{
@@ -249,6 +271,22 @@ haiku_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
haiku_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
}
+void
+gamma_correct (struct frame *f, Emacs_Color *color)
+{
+ if (f->gamma)
+ {
+ color->red = (pow (color->red / 65535.0, f->gamma)
+ * 65535.0 + 0.5);
+ color->green = (pow (color->green / 65535.0, f->gamma)
+ * 65535.0 + 0.5);
+ color->blue = (pow (color->blue / 65535.0, f->gamma)
+ * 65535.0 + 0.5);
+ color->pixel = RGB_TO_ULONG (color->red / 256,
+ color->green / 256,
+ color->blue / 256);
+ }
+}
int
haiku_get_color (const char *name, Emacs_Color *color)
@@ -323,12 +361,12 @@ haiku_display_info_for_name (Lisp_Object name)
{
CHECK_STRING (name);
- if (!NILP (Fstring_equal (name, build_string ("be"))))
+ if (!strcmp (SSDATA (name), "be"))
{
- if (!x_display_list)
+ if (x_display_list)
return x_display_list;
- error ("Haiku windowing not initialized");
+ return haiku_term_init ();
}
error ("Haiku displays can only be named \"be\"");
@@ -498,8 +536,12 @@ haiku_set_z_group (struct frame *f, Lisp_Object new_value,
rc = 0;
unblock_input ();
+
if (!rc)
error ("Invalid z-group specification");
+
+ /* Setting the Z-group can change the frame's decorator. */
+ haiku_update_after_decoration_change (f);
}
static void
@@ -578,37 +620,34 @@ unwind_create_tip_frame (Lisp_Object frame)
tip_frame = Qnil;
}
-static void
-haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+static unsigned long
+haiku_decode_color (struct frame *f, Lisp_Object color_name)
{
- struct haiku_output *output = FRAME_OUTPUT_DATA (f);
- unsigned long old_fg;
+ Emacs_Color cdef;
- Emacs_Color color;
+ CHECK_STRING (color_name);
- if (haiku_get_color (SSDATA (arg), &color))
- {
- store_frame_param (f, Qforeground_color, oldval);
- unblock_input ();
- error ("Bad color");
- }
+ if (!haiku_get_color (SSDATA (color_name), &cdef))
+ return cdef.pixel;
+
+ signal_error ("Undefined color", color_name);
+}
+static void
+haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ struct haiku_output *output;
+ unsigned long fg, old_fg;
+
+ fg = haiku_decode_color (f, arg);
old_fg = FRAME_FOREGROUND_PIXEL (f);
- FRAME_FOREGROUND_PIXEL (f) = color.pixel;
+ FRAME_FOREGROUND_PIXEL (f) = fg;
+ output = FRAME_OUTPUT_DATA (f);
if (FRAME_HAIKU_WINDOW (f))
{
-
- block_input ();
if (output->cursor_color.pixel == old_fg)
- {
- output->cursor_color.pixel = old_fg;
- output->cursor_color.red = RED_FROM_ULONG (old_fg);
- output->cursor_color.green = GREEN_FROM_ULONG (old_fg);
- output->cursor_color.blue = BLUE_FROM_ULONG (old_fg);
- }
-
- unblock_input ();
+ haiku_query_color (fg, &output->cursor_color);
update_face_from_frame_parameter (f, Qforeground_color, arg);
@@ -648,7 +687,7 @@ haiku_create_frame (Lisp_Object parms)
display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
RES_TYPE_STRING);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display = Qnil;
dpyinfo = check_haiku_display_info (display);
kb = dpyinfo->terminal->kboard;
@@ -659,7 +698,7 @@ haiku_create_frame (Lisp_Object parms)
name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0,
RES_TYPE_STRING);
if (!STRINGP (name)
- && ! EQ (name, Qunbound)
+ && ! BASE_EQ (name, Qunbound)
&& ! NILP (name))
error ("Invalid frame name--not a string or nil");
@@ -707,7 +746,7 @@ haiku_create_frame (Lisp_Object parms)
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
{
fset_name (f, Vinvocation_name);
f->explicit_name = 0;
@@ -763,6 +802,8 @@ haiku_create_frame (Lisp_Object parms)
"foreground", "Foreground", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
"background", "Background", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qmouse_color, build_string ("font-color"),
+ "pointerColor", "Foreground", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qline_spacing, Qnil,
"lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qleft_fringe, Qnil,
@@ -818,36 +859,11 @@ haiku_create_frame (Lisp_Object parms)
tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
RES_TYPE_BOOLEAN);
- f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem));
-
- block_input ();
-#define ASSIGN_CURSOR(cursor) \
- (FRAME_OUTPUT_DATA (f)->cursor = dpyinfo->cursor)
-
- ASSIGN_CURSOR (text_cursor);
- ASSIGN_CURSOR (nontext_cursor);
- ASSIGN_CURSOR (modeline_cursor);
- ASSIGN_CURSOR (hand_cursor);
- ASSIGN_CURSOR (hourglass_cursor);
- ASSIGN_CURSOR (horizontal_drag_cursor);
- ASSIGN_CURSOR (vertical_drag_cursor);
- ASSIGN_CURSOR (left_edge_cursor);
- ASSIGN_CURSOR (top_left_corner_cursor);
- ASSIGN_CURSOR (top_edge_cursor);
- ASSIGN_CURSOR (top_right_corner_cursor);
- ASSIGN_CURSOR (right_edge_cursor);
- ASSIGN_CURSOR (bottom_right_corner_cursor);
- ASSIGN_CURSOR (bottom_edge_cursor);
- ASSIGN_CURSOR (bottom_left_corner_cursor);
- ASSIGN_CURSOR (no_cursor);
-
- FRAME_OUTPUT_DATA (f)->current_cursor = dpyinfo->text_cursor;
-#undef ASSIGN_CURSOR
+ f->no_split = minibuffer_only || (!BASE_EQ (tem, Qunbound) && !NILP (tem));
f->terminal->reference_count++;
FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view);
- unblock_input ();
if (!FRAME_OUTPUT_DATA (f)->window)
xsignal1 (Qerror, build_unibyte_string ("Could not create window"));
@@ -859,10 +875,11 @@ haiku_create_frame (Lisp_Object parms)
Vframe_list = Fcons (frame, Vframe_list);
- Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
+ Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms,
+ Qparent_frame, NULL, NULL,
RES_TYPE_SYMBOL);
- if (EQ (parent_frame, Qunbound)
+ if (BASE_EQ (parent_frame, Qunbound)
|| NILP (parent_frame)
|| !FRAMEP (parent_frame)
|| !FRAME_LIVE_P (XFRAME (parent_frame)))
@@ -916,7 +933,7 @@ haiku_create_frame (Lisp_Object parms)
visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
RES_TYPE_SYMBOL);
- if (EQ (visibility, Qunbound))
+ if (BASE_EQ (visibility, Qunbound))
visibility = Qt;
if (EQ (visibility, Qicon))
haiku_iconify_frame (f);
@@ -989,7 +1006,7 @@ haiku_create_tip_frame (Lisp_Object parms)
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
- && !EQ (name, Qunbound)
+ && !BASE_EQ (name, Qunbound)
&& !NILP (name))
error ("Invalid frame name--not a string or nil");
@@ -1018,7 +1035,7 @@ haiku_create_tip_frame (Lisp_Object parms)
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
f->explicit_name = false;
else
{
@@ -1056,7 +1073,7 @@ haiku_create_tip_frame (Lisp_Object parms)
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
@@ -1076,7 +1093,10 @@ haiku_create_tip_frame (Lisp_Object parms)
gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
"background", "Background", RES_TYPE_STRING);
- gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
+
+ /* FIXME: is there a better method to tell Emacs to not recolor the
+ cursors other than setting the color to a special value? */
+ gui_default_parameter (f, parms, Qmouse_color, build_string ("font-color"),
"pointerColor", "Foreground", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
"cursorColor", "Foreground", RES_TYPE_STRING);
@@ -1133,6 +1153,23 @@ haiku_create_tip_frame (Lisp_Object parms)
/* FIXME - can this be done in a similar way to normal frames?
https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
+ {
+ Lisp_Object disptype;
+
+ if (be_get_display_planes () == 1)
+ disptype = Qmono;
+ else if (be_is_display_grayscale ())
+ disptype = Qgrayscale;
+ else
+ disptype = Qcolor;
+
+ if (NILP (Fframe_parameter (frame, Qdisplay_type)))
+ {
+ AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
+ Fmodify_frame_parameters (frame, arg);
+ }
+ }
+
/* Set up faces after all frame parameters are known. This call
also merges in face attributes specified for new frames.
@@ -1312,6 +1349,8 @@ haiku_set_undecorated (struct frame *f, Lisp_Object new_value,
FRAME_UNDECORATED (f) = !NILP (new_value);
BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value));
unblock_input ();
+
+ haiku_update_after_decoration_change (f);
}
static void
@@ -1326,6 +1365,8 @@ haiku_set_override_redirect (struct frame *f, Lisp_Object new_value,
!NILP (new_value));
FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value);
unblock_input ();
+
+ haiku_update_after_decoration_change (f);
}
static void
@@ -1372,122 +1413,129 @@ haiku_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval
static Lisp_Object
frame_geometry (Lisp_Object frame, Lisp_Object attribute)
{
- struct frame *f = decode_live_frame (frame);
- check_window_system (f);
+ struct frame *f, *parent;
+ void *window;
+ int outer_x, outer_y, outer_width, outer_height;
+ int right_off, bottom_off, top_off;
+ int native_x, native_y;
+
+ f = decode_window_system_frame (frame);
+ parent = FRAME_PARENT_FRAME (f);
+ window = FRAME_HAIKU_WINDOW (f);
+
+ be_lock_window (window);
+ be_get_window_decorator_frame (window, &outer_x, &outer_y,
+ &outer_width, &outer_height);
+ be_get_window_decorator_dimensions (window, NULL, &top_off,
+ &right_off, &bottom_off);
+ be_unlock_window (window);
+
+ native_x = FRAME_OUTPUT_DATA (f)->frame_x;
+ native_y = FRAME_OUTPUT_DATA (f)->frame_y;
+
+ if (parent)
+ {
+ /* Adjust all the coordinates by the coordinates of the parent
+ frame. */
+ outer_x -= FRAME_OUTPUT_DATA (parent)->frame_x;
+ outer_y -= FRAME_OUTPUT_DATA (parent)->frame_y;
+ native_x -= FRAME_OUTPUT_DATA (parent)->frame_x;
+ native_y -= FRAME_OUTPUT_DATA (parent)->frame_y;
+ }
if (EQ (attribute, Qouter_edges))
- return list4i (f->left_pos, f->top_pos,
- f->left_pos, f->top_pos);
+ return list4i (outer_x, outer_y,
+ outer_x + outer_width,
+ outer_y + outer_height);
else if (EQ (attribute, Qnative_edges))
- return list4i (f->left_pos, f->top_pos,
- f->left_pos + FRAME_PIXEL_WIDTH (f),
- f->top_pos + FRAME_PIXEL_HEIGHT (f));
+ return list4i (native_x, native_y,
+ native_x + FRAME_PIXEL_WIDTH (f),
+ native_y + FRAME_PIXEL_HEIGHT (f));
else if (EQ (attribute, Qinner_edges))
- return list4i (f->left_pos + FRAME_INTERNAL_BORDER_WIDTH (f),
- f->top_pos + FRAME_INTERNAL_BORDER_WIDTH (f) +
- FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
- f->left_pos - FRAME_INTERNAL_BORDER_WIDTH (f) +
- FRAME_PIXEL_WIDTH (f),
- f->top_pos + FRAME_PIXEL_HEIGHT (f) -
- FRAME_INTERNAL_BORDER_WIDTH (f));
+ return list4i (native_x + FRAME_INTERNAL_BORDER_WIDTH (f),
+ native_y + FRAME_INTERNAL_BORDER_WIDTH (f)
+ + FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
+ native_x - FRAME_INTERNAL_BORDER_WIDTH (f)
+ + FRAME_PIXEL_WIDTH (f),
+ native_y + FRAME_PIXEL_HEIGHT (f)
+ - FRAME_INTERNAL_BORDER_WIDTH (f));
else
- return
- list (Fcons (Qouter_position,
- Fcons (make_fixnum (f->left_pos),
- make_fixnum (f->top_pos))),
- Fcons (Qouter_size,
- Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
- make_fixnum (FRAME_PIXEL_HEIGHT (f)))),
- Fcons (Qexternal_border_size,
- Fcons (make_fixnum (0), make_fixnum (0))),
- Fcons (Qtitle_bar_size,
- Fcons (make_fixnum (0), make_fixnum (0))),
- Fcons (Qmenu_bar_external, Qnil),
- Fcons (Qmenu_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
- (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
- make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
- Fcons (Qtool_bar_external, Qnil),
- Fcons (Qtool_bar_position, Qtop),
- Fcons (Qtool_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
- (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
- make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
- Fcons (Qinternal_border_width, make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
+ return list (Fcons (Qouter_position,
+ Fcons (make_fixnum (outer_x),
+ make_fixnum (outer_y))),
+ Fcons (Qouter_size,
+ Fcons (make_fixnum (outer_width),
+ make_fixnum (outer_height))),
+ Fcons (Qexternal_border_size,
+ Fcons (make_fixnum (right_off),
+ make_fixnum (bottom_off))),
+ Fcons (Qtitle_bar_size,
+ Fcons (make_fixnum (outer_width),
+ make_fixnum (top_off))),
+ Fcons (Qmenu_bar_external, Qnil),
+ Fcons (Qmenu_bar_size,
+ Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)
+ - (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
+ make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
+ Fcons (Qtool_bar_external, Qnil),
+ Fcons (Qtool_bar_position, Qtop),
+ Fcons (Qtool_bar_size,
+ Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)
+ - (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
+ make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
+ Fcons (Qinternal_border_width,
+ make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
}
void
haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
- Emacs_Color color;
- struct face *defface;
+ unsigned long background;
- CHECK_STRING (arg);
+ background = haiku_decode_color (f, arg);
- block_input ();
- if (haiku_get_color (SSDATA (arg), &color))
- {
- store_frame_param (f, Qbackground_color, oldval);
- unblock_input ();
- error ("Bad color");
- }
-
- FRAME_OUTPUT_DATA (f)->cursor_fg = color.pixel;
- FRAME_BACKGROUND_PIXEL (f) = color.pixel;
+ FRAME_OUTPUT_DATA (f)->cursor_fg = background;
+ FRAME_BACKGROUND_PIXEL (f) = background;
if (FRAME_HAIKU_VIEW (f))
{
BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0);
- BView_SetViewColor (FRAME_HAIKU_VIEW (f), color.pixel);
+ BView_SetViewColor (FRAME_HAIKU_VIEW (f), background);
BView_draw_unlock (FRAME_HAIKU_VIEW (f));
- defface = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
- if (defface)
- {
- defface->background = color.pixel;
- update_face_from_frame_parameter (f, Qbackground_color, arg);
- clear_frame (f);
- }
- }
+ FRAME_OUTPUT_DATA (f)->cursor_fg = background;
+ update_face_from_frame_parameter (f, Qbackground_color, arg);
- if (FRAME_VISIBLE_P (f))
- SET_FRAME_GARBAGED (f);
- unblock_input ();
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+ }
}
void
haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
- Emacs_Color color, fore_pixel;
-
- CHECK_STRING (arg);
- block_input ();
-
- if (haiku_get_color (SSDATA (arg), &color))
- {
- store_frame_param (f, Qcursor_color, oldval);
- unblock_input ();
- error ("Bad color");
- }
+ unsigned long fore_pixel, pixel;
- FRAME_CURSOR_COLOR (f) = color;
+ pixel = haiku_decode_color (f, arg);
- if (STRINGP (Vx_cursor_fore_pixel))
+ if (!NILP (Vx_cursor_fore_pixel))
{
- if (haiku_get_color (SSDATA (Vx_cursor_fore_pixel),
- &fore_pixel))
- error ("Bad color %s", SSDATA (Vx_cursor_fore_pixel));
- FRAME_OUTPUT_DATA (f)->cursor_fg = fore_pixel.pixel;
+ fore_pixel = haiku_decode_color (f, Vx_cursor_fore_pixel);
+ FRAME_OUTPUT_DATA (f)->cursor_fg = fore_pixel;
}
else
FRAME_OUTPUT_DATA (f)->cursor_fg = FRAME_BACKGROUND_PIXEL (f);
+ haiku_query_color (pixel, &FRAME_CURSOR_COLOR (f));
+
if (FRAME_VISIBLE_P (f))
{
- gui_update_cursor (f, 0);
- gui_update_cursor (f, 1);
+ gui_update_cursor (f, false);
+ gui_update_cursor (f, true);
}
+
update_face_from_frame_parameter (f, Qcursor_color, arg);
- unblock_input ();
}
void
@@ -1567,6 +1615,7 @@ haiku_free_frame_resources (struct frame *f)
dpyinfo = FRAME_DISPLAY_INFO (f);
free_frame_faces (f);
+ haiku_free_custom_cursors (f);
/* Free scroll bars */
for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
@@ -1792,6 +1841,279 @@ haiku_set_sticky (struct frame *f, Lisp_Object new_value,
unblock_input ();
}
+struct user_cursor_info
+{
+ /* A pointer to the Lisp_Object describing the cursor. */
+ Lisp_Object *lisp_cursor;
+
+ /* The offset of the cursor in the `struct haiku_output' of each
+ frame. */
+ ptrdiff_t output_offset;
+
+ /* The offset of the default value of the cursor in the display
+ info structure. */
+ ptrdiff_t default_offset;
+};
+
+struct user_cursor_bitmap_info
+{
+ /* A bitmap to use instead of the font cursor to create cursors in a
+ certain color. */
+ const void *bits;
+
+ /* The mask for that bitmap. */
+ const void *mask;
+
+ /* The dimensions of the cursor bitmap. */
+ int width, height;
+
+ /* The position inside the cursor bitmap corresponding to the
+ position of the mouse pointer. */
+ int x, y;
+};
+
+#define INIT_USER_CURSOR(lisp, cursor) \
+ { (lisp), offsetof (struct haiku_output, cursor), \
+ offsetof (struct haiku_display_info, cursor) }
+
+struct user_cursor_info custom_cursors[] =
+ {
+ INIT_USER_CURSOR (&Vx_pointer_shape, text_cursor),
+ INIT_USER_CURSOR (NULL, nontext_cursor),
+ INIT_USER_CURSOR (NULL, modeline_cursor),
+ INIT_USER_CURSOR (&Vx_sensitive_text_pointer_shape, hand_cursor),
+ INIT_USER_CURSOR (&Vx_hourglass_pointer_shape, hourglass_cursor),
+ INIT_USER_CURSOR (NULL, horizontal_drag_cursor),
+ INIT_USER_CURSOR (NULL, vertical_drag_cursor),
+ INIT_USER_CURSOR (NULL, left_edge_cursor),
+ INIT_USER_CURSOR (NULL, top_left_corner_cursor),
+ INIT_USER_CURSOR (NULL, top_edge_cursor),
+ INIT_USER_CURSOR (NULL, top_right_corner_cursor),
+ INIT_USER_CURSOR (NULL, right_edge_cursor),
+ INIT_USER_CURSOR (NULL, bottom_right_corner_cursor),
+ INIT_USER_CURSOR (NULL, bottom_edge_cursor),
+ INIT_USER_CURSOR (NULL, bottom_left_corner_cursor),
+ INIT_USER_CURSOR (NULL, no_cursor),
+ };
+
+struct user_cursor_bitmap_info cursor_bitmaps[] =
+ {
+ { ibeam_ptr_bits, ibeam_ptrmask_bits, 15, 15, 7, 7 }, /* text_cursor */
+ { left_ptr_bits, left_ptrmsk_bits, 16, 16, 3, 1 }, /* nontext_cursor */
+ { left_ptr_bits, left_ptrmsk_bits, 16, 16, 3, 1 }, /* modeline_cursor */
+ { hand_ptr_bits, hand_ptrmask_bits, 15, 15, 4, 3 }, /* hand_cursor */
+ { hourglass_bits, hourglass_mask_bits, 15, 15, 7, 7 }, /* hourglass_cursor */
+ { horizd_ptr_bits, horizd_ptrmask_bits, 15, 15, 7, 7 }, /* horizontal_drag_cursor */
+ { vertd_ptr_bits, vertd_ptrmask_bits, 15, 15, 7, 7 }, /* vertical_drag_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* left_edge_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* top_left_corner_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* top_edge_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* top_right_corner_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* right_edge_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* bottom_right_corner_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* bottom_edge_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* bottom_left_corner_cursor */
+ { NULL, NULL, 0, 0, 0, 0 }, /* no_cursor */
+ };
+
+/* Array of cursor bitmaps for each system cursor ID. This is used to
+ color in user-specified cursors. */
+struct user_cursor_bitmap_info cursor_bitmaps_for_id[28] =
+ {
+ { NULL, NULL, 0, 0, 0, 0 },
+ { left_ptr_bits, left_ptrmsk_bits, 16, 16, 3, 1 },
+ { ibeam_ptr_bits, ibeam_ptrmask_bits, 15, 15, 7, 7 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { cross_ptr_bits, cross_ptrmask_bits, 30, 30, 15, 15 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { hand_ptr_bits, hand_ptrmask_bits, 15, 15, 4, 3 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { hourglass_bits, hourglass_mask_bits, 15, 15, 7, 7 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { horizd_ptr_bits, horizd_ptrmask_bits, 15, 15, 7, 7 },
+ { vertd_ptr_bits, vertd_ptrmask_bits, 15, 15, 7, 7 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ { NULL, NULL, 0, 0, 0, 0 },
+ };
+
+static void *
+haiku_create_colored_cursor (struct user_cursor_bitmap_info *info,
+ uint32_t foreground, uint32_t background)
+{
+ const char *bits, *mask;
+ void *bitmap, *cursor;
+ int width, height, bytes_per_line, x, y;
+
+ bits = info->bits;
+ mask = info->mask;
+ width = info->width;
+ height = info->height;
+ bytes_per_line = (width + 7) / 8;
+
+ bitmap = BBitmap_new (width, height, false);
+
+ if (!bitmap)
+ memory_full (SIZE_MAX);
+
+ for (y = 0; y < height; ++y)
+ {
+ for (x = 0; x < width; ++x)
+ {
+ if (mask[x / 8] >> (x % 8) & 1)
+ haiku_put_pixel (bitmap, x, y,
+ (bits[x / 8] >> (x % 8) & 1
+ ? (foreground | 255u << 24)
+ : (background | 255u << 24)));
+ else
+ haiku_put_pixel (bitmap, x, y, 0);
+ }
+
+ mask += bytes_per_line;
+ bits += bytes_per_line;
+ }
+
+ cursor = be_create_pixmap_cursor (bitmap, info->x, info->y);
+ BBitmap_free (bitmap);
+
+ return cursor;
+}
+
+/* Free all cursors on F that were allocated specifically for the
+ frame. */
+void
+haiku_free_custom_cursors (struct frame *f)
+{
+ struct user_cursor_info *cursor;
+ struct haiku_output *output;
+ struct haiku_display_info *dpyinfo;
+ Emacs_Cursor *frame_cursor;
+ Emacs_Cursor *display_cursor;
+ int i;
+
+ output = FRAME_OUTPUT_DATA (f);
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ for (i = 0; i < ARRAYELTS (custom_cursors); ++i)
+ {
+ cursor = &custom_cursors[i];
+ frame_cursor = (Emacs_Cursor *) ((char *) output
+ + cursor->output_offset);
+ display_cursor = (Emacs_Cursor *) ((char *) dpyinfo
+ + cursor->default_offset);
+
+ if (*frame_cursor != *display_cursor && *frame_cursor)
+ {
+ if (output->current_cursor == *frame_cursor)
+ output->current_cursor = *display_cursor;
+
+ be_delete_cursor (*frame_cursor);
+ }
+
+ *frame_cursor = *display_cursor;
+ }
+}
+
+static void
+haiku_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ struct haiku_output *output;
+ Emacs_Cursor *frame_cursor, old, *recolored;
+ int i, n, rc;
+ bool color_specified_p;
+ Emacs_Color color;
+
+ CHECK_STRING (arg);
+ color_specified_p = true;
+
+ if (!strcmp (SSDATA (arg), "font-color"))
+ color_specified_p = false;
+ else
+ rc = haiku_get_color (SSDATA (arg), &color);
+
+ if (color_specified_p && rc)
+ signal_error ("Undefined color", arg);
+
+ output = FRAME_OUTPUT_DATA (f);
+
+ /* This will also reset all the cursors back to their default
+ values. */
+ haiku_free_custom_cursors (f);
+
+ for (i = 0; i < ARRAYELTS (custom_cursors); ++i)
+ {
+ frame_cursor = (Emacs_Cursor *) ((char *) output
+ + custom_cursors[i].output_offset);
+ old = *frame_cursor;
+
+ if (custom_cursors[i].lisp_cursor
+ && FIXNUMP (*custom_cursors[i].lisp_cursor))
+ {
+ if (!RANGED_FIXNUMP (0, *custom_cursors[i].lisp_cursor,
+ 28)) /* 28 is the largest Haiku cursor ID. */
+ signal_error ("Invalid cursor",
+ *custom_cursors[i].lisp_cursor);
+
+ n = XFIXNUM (*custom_cursors[i].lisp_cursor);
+
+ if (color_specified_p && cursor_bitmaps_for_id[n].bits)
+ {
+ recolored
+ = haiku_create_colored_cursor (&cursor_bitmaps_for_id[n],
+ color.pixel,
+ FRAME_BACKGROUND_PIXEL (f));
+
+ if (recolored)
+ {
+ *frame_cursor = recolored;
+ continue;
+ }
+ }
+
+ /* Create and set the custom cursor. */
+ *frame_cursor = be_create_cursor_from_id (n);
+ }
+ else if (color_specified_p && cursor_bitmaps[i].bits)
+ {
+ recolored
+ = haiku_create_colored_cursor (&cursor_bitmaps[i], color.pixel,
+ FRAME_BACKGROUND_PIXEL (f));
+
+ if (recolored)
+ *frame_cursor = recolored;
+ }
+ }
+
+ /* This function can be called before the frame's window is
+ created. */
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ if (output->current_cursor == old
+ && old != *frame_cursor)
+ {
+ output->current_cursor = *frame_cursor;
+
+ BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
+ *frame_cursor);
+ }
+ }
+
+ update_face_from_frame_parameter (f, Qmouse_color, arg);
+}
+
DEFUN ("haiku-set-mouse-absolute-pixel-position",
@@ -1890,34 +2212,28 @@ DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
}
DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
- 1, 3, 0,
- doc: /* SKIP: real doc in xfns.c. */)
+ 1, 3, 0, doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
{
- struct haiku_display_info *dpyinfo;
CHECK_STRING (display);
if (NILP (Fstring_equal (display, build_string ("be"))))
{
if (!NILP (must_succeed))
- fatal ("Bad display");
+ fatal ("Invalid display %s", SDATA (display));
else
- error ("Bad display");
+ signal_error ("Invalid display", display);
}
if (x_display_list)
- return Qnil;
-
- dpyinfo = haiku_term_init ();
-
- if (!dpyinfo)
{
if (!NILP (must_succeed))
- fatal ("Display not responding");
+ fatal ("A display is already open");
else
- error ("Display not responding");
+ error ("A display is already open");
}
+ haiku_term_init ();
return Qnil;
}
@@ -1944,7 +2260,7 @@ DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_heigh
check_haiku_display_info (terminal);
be_get_screen_dimensions (&width, &height);
- return make_fixnum (width);
+ return make_fixnum (height);
}
DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
@@ -2039,6 +2355,9 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
else
CHECK_FIXNUM (dy);
+ tip_dx = dx;
+ tip_dy = dy;
+
if (use_system_tooltips)
{
int root_x, root_y;
@@ -2579,6 +2898,7 @@ Frames are listed from topmost (first) to bottommost (last). */)
if (NILP (sel))
return frames;
+
return Fcons (sel, frames);
}
@@ -2683,6 +3003,57 @@ call this function yourself. */)
return Qnil;
}
+DEFUN ("haiku-display-monitor-attributes-list",
+ Fhaiku_display_monitor_attributes_list,
+ Shaiku_display_monitor_attributes_list,
+ 0, 1, 0,
+ doc: /* Return a list of physical monitor attributes on the display TERMINAL.
+
+The optional argument TERMINAL specifies which display to ask about.
+TERMINAL should be a terminal object, a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display.
+
+Internal use only, use `display-monitor-attributes-list' instead. */)
+ (Lisp_Object terminal)
+{
+ struct MonitorInfo monitor;
+ struct haiku_display_info *dpyinfo;
+ Lisp_Object frames, tail, tem;
+
+ dpyinfo = check_haiku_display_info (terminal);
+ frames = Qnil;
+
+ FOR_EACH_FRAME (tail, tem)
+ {
+ maybe_quit ();
+
+ if (FRAME_HAIKU_P (XFRAME (tem))
+ && !FRAME_TOOLTIP_P (XFRAME (tem)))
+ frames = Fcons (tem, frames);
+ }
+
+ monitor.geom.x = 0;
+ monitor.geom.y = 0;
+ be_get_screen_dimensions ((int *) &monitor.geom.width,
+ (int *) &monitor.geom.height);
+
+ monitor.mm_width = (monitor.geom.width
+ / (dpyinfo->resx / 25.4));
+ monitor.mm_height = (monitor.geom.height
+ / (dpyinfo->resy / 25.4));
+ monitor.name = (char *) "BeOS monitor";
+
+ if (!be_get_explicit_workarea ((int *) &monitor.work.x,
+ (int *) &monitor.work.y,
+ (int *) &monitor.work.width,
+ (int *) &monitor.work.height))
+ monitor.work = monitor.geom;
+
+ return make_monitor_attribute_list (&monitor, 1, 0,
+ make_vector (1, frames),
+ "fallback");
+}
+
frame_parm_handler haiku_frame_parm_handlers[] =
{
gui_set_autoraise,
@@ -2701,7 +3072,7 @@ frame_parm_handler haiku_frame_parm_handlers[] =
gui_set_right_divider_width,
gui_set_bottom_divider_width,
haiku_set_menu_bar_lines,
- NULL, /* set mouse color */
+ haiku_set_mouse_color,
haiku_explicitly_set_name,
gui_set_scroll_bar_width,
gui_set_scroll_bar_height,
@@ -2751,6 +3122,9 @@ syms_of_haikufns (void)
DEFSYM (Qstatic_color, "static-color");
DEFSYM (Qstatic_gray, "static-gray");
DEFSYM (Qtrue_color, "true-color");
+ DEFSYM (Qmono, "mono");
+ DEFSYM (Qgrayscale, "grayscale");
+ DEFSYM (Qcolor, "color");
defsubr (&Sx_hide_tip);
defsubr (&Sxw_display_color_p);
@@ -2785,6 +3159,7 @@ syms_of_haikufns (void)
defsubr (&Sx_display_save_under);
defsubr (&Shaiku_frame_restack);
defsubr (&Shaiku_save_session_reply);
+ defsubr (&Shaiku_display_monitor_attributes_list);
tip_timer = Qnil;
staticpro (&tip_timer);
@@ -2796,6 +3171,10 @@ syms_of_haikufns (void)
staticpro (&tip_last_string);
tip_last_parms = Qnil;
staticpro (&tip_last_parms);
+ tip_dx = Qnil;
+ staticpro (&tip_dx);
+ tip_dy = Qnil;
+ staticpro (&tip_dy);
DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
doc: /* SKIP: real doc in xfns.c. */);
@@ -2805,6 +3184,19 @@ syms_of_haikufns (void)
doc: /* SKIP: real doc in xfns.c. */);
Vx_cursor_fore_pixel = Qnil;
+ DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
+ doc: /* SKIP: real doc in xfns.c. */);
+ Vx_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-hourglass-pointer-shape", Vx_hourglass_pointer_shape,
+ doc: /* SKIP: real doc in xfns.c. */);
+ Vx_hourglass_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-sensitive-text-pointer-shape",
+ Vx_sensitive_text_pointer_shape,
+ doc: /* SKIP: real doc in xfns.c. */);
+ Vx_sensitive_text_pointer_shape = Qnil;
+
DEFVAR_LISP ("haiku-allowed-ui-colors", Vhaiku_allowed_ui_colors,
doc: /* Vector of UI colors that Emacs can look up from the system.
If this is set up incorrectly, Emacs can crash when encoutering an
diff --git a/src/haikufont.c b/src/haikufont.c
index e0db086aa00..54f11c6e413 100644
--- a/src/haikufont.c
+++ b/src/haikufont.c
@@ -1084,8 +1084,8 @@ haikufont_draw (struct glyph_string *s, int from, int to,
s->first_glyph->slice.glyphless.lower_yoff
- s->first_glyph->slice.glyphless.upper_yoff;
- BView_SetHighColor (view, background);
- BView_FillRectangle (view, x, y - ascent, s->width, height);
+ haiku_draw_background_rect (s, s->face, x, y - ascent,
+ s->width, height);
s->background_filled_p = 1;
}
diff --git a/src/haikugui.h b/src/haikugui.h
index a6cf3a4e6ce..0dc127e6b63 100644
--- a/src/haikugui.h
+++ b/src/haikugui.h
@@ -95,4 +95,109 @@ typedef haiku Drawable;
typedef haiku Window;
typedef int Display;
+/* Cursor bitmaps. These are only used to create colored cursors when
+ the user specifies a mouse color. */
+
+MAYBE_UNUSED static unsigned char cross_ptr_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xf0, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char cross_ptrmask_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01,
+ 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0,
+ 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x07, 0xf0, 0x1f, 0xfe, 0x0f, 0xf8, 0x3f, 0xfc, 0x07,
+ 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01,
+ 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0,
+ 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char ibeam_ptr_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
+ 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
+ 0xc0, 0x01, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char ibeam_ptrmask_bits[] =
+ {
+ 0x00, 0x00, 0xfc, 0x1f, 0xfe, 0x3f, 0xfc, 0x1f, 0xe0, 0x03, 0xe0,
+ 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03,
+ 0xfc, 0x1f, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char hand_ptr_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xa0, 0x02, 0xa0,
+ 0x02, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char hand_ptrmask_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xf0, 0x07, 0xf0, 0x07, 0xf8,
+ 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char horizd_ptr_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x28,
+ 0x0a, 0xf4, 0x17, 0x02, 0x20, 0xf4, 0x17, 0x28, 0x0a, 0x10, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char horizd_ptrmask_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x38,
+ 0x0e, 0xfc, 0x1f, 0xfe, 0x3f, 0xfc, 0x1f, 0x38, 0x0e, 0x10, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char vertd_ptr_bits[] =
+ {
+ 0x00, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, 0x50, 0x05, 0x60,
+ 0x03, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x60, 0x03, 0x50, 0x05,
+ 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char vertd_ptrmask_bits[] =
+ {
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0,
+ 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07,
+ 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char hourglass_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x10, 0x04, 0x08, 0x08, 0x24,
+ 0x10, 0x44, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x88, 0x08,
+ 0x10, 0x04, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00
+ };
+
+MAYBE_UNUSED static unsigned char hourglass_mask_bits[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00
+ };
+
#endif /* _HAIKU_GUI_H_ */
diff --git a/src/haikumenu.c b/src/haikumenu.c
index 9779c34a998..5729bed4a9b 100644
--- a/src/haikumenu.c
+++ b/src/haikumenu.c
@@ -35,26 +35,35 @@ int popup_activated_p = 0;
static void
digest_menu_items (void *first_menu, int start, int menu_items_used,
- int mbar_p)
+ bool is_menu_bar)
{
void **menus, **panes;
- ssize_t menu_len = (menu_items_used + 1 - start) * sizeof *menus;
- ssize_t pane_len = (menu_items_used + 1 - start) * sizeof *panes;
+ ssize_t menu_len;
+ ssize_t pane_len;
+ int i, menu_depth;
+ void *menu, *window, *view;
+ Lisp_Object pane_name, prefix;
+ const char *pane_string;
+ Lisp_Object item_name, enable, descrip, def, selected, help;
- menus = alloca (menu_len);
- panes = alloca (pane_len);
+ USE_SAFE_ALLOCA;
- int i = start, menu_depth = 0;
+ menu_len = (menu_items_used + 1 - start) * sizeof *menus;
+ pane_len = (menu_items_used + 1 - start) * sizeof *panes;
+ menu = first_menu;
+ i = start;
+ menu_depth = 0;
+
+ menus = SAFE_ALLOCA (menu_len);
+ panes = SAFE_ALLOCA (pane_len);
memset (menus, 0, menu_len);
memset (panes, 0, pane_len);
-
- void *menu = first_menu;
-
menus[0] = first_menu;
- void *window = NULL;
- void *view = NULL;
+ window = NULL;
+ view = NULL;
+
if (FRAMEP (Vmenu_updating_frame) &&
FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) &&
FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame)))
@@ -83,9 +92,6 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
i += 1;
else if (EQ (AREF (menu_items, i), Qt))
{
- Lisp_Object pane_name, prefix;
- const char *pane_string;
-
if (menu_items_n_panes == 1)
{
i += MENU_ITEMS_PANE_LENGTH;
@@ -116,7 +122,6 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
}
else
{
- Lisp_Object item_name, enable, descrip, def, selected, help;
item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
@@ -144,7 +149,7 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable));
else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
BMenu_add_separator (menu);
- else if (!mbar_p)
+ else if (!is_menu_bar)
{
if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode)))
BMenu_add_item (menu, SSDATA (item_name),
@@ -178,6 +183,8 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
if (view)
BView_draw_unlock (view);
+
+ SAFE_FREE ();
}
static Lisp_Object
@@ -376,12 +383,18 @@ Lisp_Object
haiku_menu_show (struct frame *f, int x, int y, int menuflags,
Lisp_Object title, const char **error_name)
{
- int i = 0, submenu_depth = 0;
- void *view = FRAME_HAIKU_VIEW (f);
- void *menu;
+ int i, submenu_depth, j;
+ void *view, *menu;
+ Lisp_Object *subprefix_stack;
+ Lisp_Object prefix, entry;
- Lisp_Object *subprefix_stack =
- alloca (menu_items_used * sizeof (Lisp_Object));
+ USE_SAFE_ALLOCA;
+
+ view = FRAME_HAIKU_VIEW (f);
+ i = 0;
+ submenu_depth = 0;
+ subprefix_stack
+ = SAFE_ALLOCA (menu_items_used * sizeof (Lisp_Object));
eassert (FRAME_HAIKU_P (f));
@@ -390,6 +403,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
{
*error_name = "Empty menu";
+
+ SAFE_FREE ();
return Qnil;
}
@@ -417,8 +432,6 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
if (menu_item_selection)
{
- Lisp_Object prefix, entry;
-
prefix = entry = Qnil;
i = 0;
while (i < menu_items_used)
@@ -452,8 +465,6 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
{
if (menuflags & MENU_KEYMAPS)
{
- int j;
-
entry = list1 (entry);
if (!NILP (prefix))
entry = Fcons (prefix, entry);
@@ -464,6 +475,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
block_input ();
BPopUpMenu_delete (menu);
unblock_input ();
+
+ SAFE_FREE ();
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
@@ -480,6 +493,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
block_input ();
BPopUpMenu_delete (menu);
unblock_input ();
+
+ SAFE_FREE ();
return Qnil;
}
@@ -728,7 +743,7 @@ run_menu_bar_help_event (struct frame *f, int mb_idx)
vec = f->menu_bar_vector;
if ((mb_idx + MENU_ITEMS_ITEM_HELP) >= ASIZE (vec))
- emacs_abort ();
+ return;
help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP);
if (STRINGP (help) || NILP (help))
diff --git a/src/haikuselect.c b/src/haikuselect.c
index a186acc66ff..8a7b6f2e0b1 100644
--- a/src/haikuselect.c
+++ b/src/haikuselect.c
@@ -33,8 +33,26 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
the nested event loop inside be_drag_message. */
struct frame *haiku_dnd_frame;
+/* Whether or not to move the tip frame during drag-and-drop. */
+bool haiku_dnd_follow_tooltip;
+
static void haiku_lisp_to_message (Lisp_Object, void *);
+static enum haiku_clipboard
+haiku_get_clipboard_name (Lisp_Object clipboard)
+{
+ if (EQ (clipboard, QPRIMARY))
+ return CLIPBOARD_PRIMARY;
+
+ if (EQ (clipboard, QSECONDARY))
+ return CLIPBOARD_SECONDARY;
+
+ if (EQ (clipboard, QCLIPBOARD))
+ return CLIPBOARD_CLIPBOARD;
+
+ signal_error ("Invalid clipboard", clipboard);
+}
+
DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data,
2, 2, 0,
doc: /* Retrieve content typed as NAME from the clipboard
@@ -53,22 +71,15 @@ message in the format accepted by `haiku-drag-message', which see. */)
int rc;
CHECK_SYMBOL (clipboard);
-
- if (!EQ (clipboard, QPRIMARY) && !EQ (clipboard, QSECONDARY)
- && !EQ (clipboard, QCLIPBOARD))
- signal_error ("Invalid clipboard", clipboard);
+ clipboard_name = haiku_get_clipboard_name (clipboard);
if (!NILP (name))
{
CHECK_STRING (name);
block_input ();
- if (EQ (clipboard, QPRIMARY))
- dat = BClipboard_find_primary_selection_data (SSDATA (name), &len);
- else if (EQ (clipboard, QSECONDARY))
- dat = BClipboard_find_secondary_selection_data (SSDATA (name), &len);
- else
- dat = BClipboard_find_system_data (SSDATA (name), &len);
+ dat = be_find_clipboard_data (clipboard_name,
+ SSDATA (name), &len);
unblock_input ();
if (!dat)
@@ -83,18 +94,11 @@ message in the format accepted by `haiku-drag-message', which see. */)
Qforeign_selection, Qt, str);
block_input ();
- BClipboard_free_data (dat);
+ free (dat);
unblock_input ();
}
else
{
- if (EQ (clipboard, QPRIMARY))
- clipboard_name = CLIPBOARD_PRIMARY;
- else if (EQ (clipboard, QSECONDARY))
- clipboard_name = CLIPBOARD_SECONDARY;
- else
- clipboard_name = CLIPBOARD_CLIPBOARD;
-
block_input ();
rc = be_lock_clipboard_message (clipboard_name, &message, false);
unblock_input ();
@@ -139,16 +143,12 @@ In that case, the arguments after NAME are ignored. */)
int rc;
void *message;
+ CHECK_SYMBOL (clipboard);
+ clipboard_name = haiku_get_clipboard_name (clipboard);
+
if (CONSP (name) || NILP (name))
{
- if (EQ (clipboard, QPRIMARY))
- clipboard_name = CLIPBOARD_PRIMARY;
- else if (EQ (clipboard, QSECONDARY))
- clipboard_name = CLIPBOARD_SECONDARY;
- else if (EQ (clipboard, QCLIPBOARD))
- clipboard_name = CLIPBOARD_CLIPBOARD;
- else
- signal_error ("Invalid clipboard", clipboard);
+ be_update_clipboard_count (clipboard_name);
rc = be_lock_clipboard_message (clipboard_name,
&message, true);
@@ -164,7 +164,6 @@ In that case, the arguments after NAME are ignored. */)
return unbind_to (ref, Qnil);
}
- CHECK_SYMBOL (clipboard);
CHECK_STRING (name);
if (!NILP (data))
CHECK_STRING (data);
@@ -172,20 +171,8 @@ In that case, the arguments after NAME are ignored. */)
dat = !NILP (data) ? SSDATA (data) : NULL;
len = !NILP (data) ? SBYTES (data) : 0;
- if (EQ (clipboard, QPRIMARY))
- BClipboard_set_primary_selection_data (SSDATA (name), dat, len,
- !NILP (clear));
- else if (EQ (clipboard, QSECONDARY))
- BClipboard_set_secondary_selection_data (SSDATA (name), dat, len,
- !NILP (clear));
- else if (EQ (clipboard, QCLIPBOARD))
- BClipboard_set_system_data (SSDATA (name), dat, len, !NILP (clear));
- else
- {
- unblock_input ();
- signal_error ("Bad clipboard", clipboard);
- }
-
+ be_set_clipboard_data (clipboard_name, SSDATA (name), dat, len,
+ !NILP (clear));
return Qnil;
}
@@ -193,27 +180,15 @@ DEFUN ("haiku-selection-owner-p", Fhaiku_selection_owner_p, Shaiku_selection_own
0, 1, 0,
doc: /* Whether the current Emacs process owns the given SELECTION.
The arg should be the name of the selection in question, typically one
-of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. For
-convenience, the symbol nil is the same as `PRIMARY', and t is the
-same as `SECONDARY'. */)
+of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. */)
(Lisp_Object selection)
{
bool value;
-
- if (NILP (selection))
- selection = QPRIMARY;
- else if (EQ (selection, Qt))
- selection = QSECONDARY;
+ enum haiku_clipboard name;
block_input ();
- if (EQ (selection, QPRIMARY))
- value = BClipboard_owns_primary ();
- else if (EQ (selection, QSECONDARY))
- value = BClipboard_owns_secondary ();
- else if (EQ (selection, QCLIPBOARD))
- value = BClipboard_owns_clipboard ();
- else
- value = false;
+ name = haiku_get_clipboard_name (selection);
+ value = be_clipboard_owner_p (name);
unblock_input ();
return value ? Qt : Qnil;
@@ -275,7 +250,7 @@ haiku_message_to_lisp (void *message)
if (!pbuf)
memory_full (SIZE_MAX);
- t1 = build_string (pbuf);
+ t1 = DECODE_FILE (build_string (pbuf));
free (pbuf);
break;
@@ -320,6 +295,14 @@ haiku_message_to_lisp (void *message)
t1 = make_int ((intmax_t) *(ssize_t *) buf);
break;
+ case 'DBLE':
+ t1 = make_float (*(double *) buf);
+ break;
+
+ case 'FLOT':
+ t1 = make_float (*(float *) buf);
+ break;
+
default:
t1 = make_uninit_string (buf_size);
memcpy (SDATA (t1), buf, buf_size);
@@ -378,6 +361,14 @@ haiku_message_to_lisp (void *message)
t2 = Qpoint;
break;
+ case 'DBLE':
+ t2 = Qdouble;
+ break;
+
+ case 'FLOT':
+ t2 = Qfloat;
+ break;
+
default:
t2 = make_int (type_code);
}
@@ -423,6 +414,10 @@ lisp_to_type_code (Lisp_Object obj)
return 'SSZT';
else if (EQ (obj, Qpoint))
return 'BPNT';
+ else if (EQ (obj, Qfloat))
+ return 'FLOT';
+ else if (EQ (obj, Qdouble))
+ return 'DBLE';
else
return -1;
}
@@ -441,7 +436,8 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
ssize_t ssizet_data;
intmax_t t4;
uintmax_t t5;
- float t6, t7;
+ float t6, t7, float_data;
+ double double_data;
int rc;
specpdl_ref ref;
@@ -526,7 +522,8 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
case 'RREF':
CHECK_STRING (data);
- if (be_add_refs_data (message, SSDATA (name), SSDATA (data))
+ if (be_add_refs_data (message, SSDATA (name),
+ SSDATA (ENCODE_FILE (data)))
&& haiku_signal_invalid_refs)
signal_error ("Invalid file name", data);
break;
@@ -544,6 +541,30 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
signal_error ("Invalid point", data);
break;
+ case 'FLOT':
+ CHECK_NUMBER (data);
+ float_data = XFLOATINT (data);
+
+ rc = be_add_message_data (message, SSDATA (name),
+ type_code, &float_data,
+ sizeof float_data);
+
+ if (rc)
+ signal_error ("Failed to add float", data);
+ break;
+
+ case 'DBLE':
+ CHECK_NUMBER (data);
+ double_data = XFLOATINT (data);
+
+ rc = be_add_message_data (message, SSDATA (name),
+ type_code, &double_data,
+ sizeof double_data);
+
+ if (rc)
+ signal_error ("Failed to add double", data);
+ break;
+
case 'SHRT':
if (!TYPE_RANGED_FIXNUMP (int16, data))
signal_error ("Invalid value", data);
@@ -737,7 +758,7 @@ haiku_unwind_drag_message (void *message)
}
DEFUN ("haiku-drag-message", Fhaiku_drag_message, Shaiku_drag_message,
- 2, 3, 0,
+ 2, 4, 0,
doc: /* Begin dragging MESSAGE from FRAME.
MESSAGE an alist of strings, denoting message field names, to a list
@@ -758,6 +779,10 @@ system. If TYPE is `ssize_t', then DATA is an integer that can hold
values from -1 to the maximum value of the C data type `ssize_t' on
the current system. If TYPE is `point', then DATA is a cons of float
values describing the X and Y coordinates of an on-screen location.
+If TYPE is `float', then DATA is a low-precision floating point
+number, whose exact precision is not guaranteed. If TYPE is `double',
+then DATA is a floating point number that can represent any value a
+Lisp float can represent.
If the field name is not a string but the symbol `type', then it
associates to a 32-bit unsigned integer describing the type of the
@@ -767,8 +792,12 @@ FRAME is a window system frame that must be visible, from which the
drag will originate.
ALLOW-SAME-FRAME, if nil or not specified, means that MESSAGE will be
-ignored if it is dropped on top of FRAME. */)
- (Lisp_Object frame, Lisp_Object message, Lisp_Object allow_same_frame)
+ignored if it is dropped on top of FRAME.
+
+FOLLOW-TOOLTIP, if non-nil, will cause any non-system tooltip
+currently being displayed to move along with the mouse pointer. */)
+ (Lisp_Object frame, Lisp_Object message, Lisp_Object allow_same_frame,
+ Lisp_Object follow_tooltip)
{
specpdl_ref idx;
void *be_message;
@@ -782,23 +811,167 @@ ignored if it is dropped on top of FRAME. */)
error ("Frame is invisible");
haiku_dnd_frame = f;
+ haiku_dnd_follow_tooltip = !NILP (follow_tooltip);
be_message = be_create_simple_message ();
record_unwind_protect_ptr (haiku_unwind_drag_message, be_message);
haiku_lisp_to_message (message, be_message);
+
rc = be_drag_message (FRAME_HAIKU_VIEW (f), be_message,
!NILP (allow_same_frame),
block_input, unblock_input,
process_pending_signals,
haiku_should_quit_drag);
- FRAME_DISPLAY_INFO (f)->grabbed = 0;
+ /* Don't clear the mouse grab if the user decided to quit instead
+ of the drop finishing. */
if (rc)
quit ();
+ /* Now dismiss the tooltip, since the drop presumably succeeded. */
+ if (!NILP (follow_tooltip))
+ Fx_hide_tip ();
+
+ FRAME_DISPLAY_INFO (f)->grabbed = 0;
+
return unbind_to (idx, Qnil);
}
+DEFUN ("haiku-roster-launch", Fhaiku_roster_launch, Shaiku_roster_launch,
+ 2, 2, 0,
+ doc: /* Launch an application associated with FILE-OR-TYPE.
+Return the process ID of any process created, the symbol
+`already-running' if ARGS was sent to a program that's already
+running, or nil if launching the application failed because no
+application was found for FILE-OR-TYPE.
+
+Signal an error if FILE-OR-TYPE is invalid, or if ARGS is a message
+but the application doesn't accept messages.
+
+FILE-OR-TYPE can either be a string denoting a MIME type, or a list
+with one argument FILE, denoting a file whose associated application
+will be launched.
+
+ARGS can either be a vector of strings containing the arguments that
+will be passed to the application, or a system message in the form
+accepted by `haiku-drag-message' that will be sent to the application
+after it starts. */)
+ (Lisp_Object file_or_type, Lisp_Object args)
+{
+ char **cargs;
+ char *type, *file;
+ team_id team_id;
+ status_t rc;
+ ptrdiff_t i, nargs;
+ Lisp_Object tem, canonical;
+ void *message;
+ specpdl_ref depth;
+
+ type = NULL;
+ file = NULL;
+ cargs = NULL;
+ message = NULL;
+ nargs = 0;
+ depth = SPECPDL_INDEX ();
+
+ USE_SAFE_ALLOCA;
+
+ if (STRINGP (file_or_type))
+ SAFE_ALLOCA_STRING (type, file_or_type);
+ else
+ {
+ CHECK_LIST (file_or_type);
+ tem = XCAR (file_or_type);
+ canonical = Fexpand_file_name (tem, Qnil);
+
+ CHECK_STRING (tem);
+ SAFE_ALLOCA_STRING (file, ENCODE_FILE (canonical));
+ CHECK_LIST_END (XCDR (file_or_type), file_or_type);
+ }
+
+ if (VECTORP (args))
+ {
+ nargs = ASIZE (args);
+ cargs = SAFE_ALLOCA (nargs * sizeof *cargs);
+
+ for (i = 0; i < nargs; ++i)
+ {
+ tem = AREF (args, i);
+ CHECK_STRING (tem);
+ maybe_quit ();
+
+ cargs[i] = SAFE_ALLOCA (SBYTES (tem) + 1);
+ memcpy (cargs[i], SDATA (tem), SBYTES (tem) + 1);
+ }
+ }
+ else
+ {
+ message = be_create_simple_message ();
+
+ record_unwind_protect_ptr (BMessage_delete, message);
+ haiku_lisp_to_message (args, message);
+ }
+
+ block_input ();
+ rc = be_roster_launch (type, file, cargs, nargs, message,
+ &team_id);
+ unblock_input ();
+
+ /* `be_roster_launch' can potentially take a while in IO, but
+ signals from async input will interrupt that operation. If the
+ user wanted to quit, act like it. */
+ maybe_quit ();
+
+ if (rc == B_OK)
+ return SAFE_FREE_UNBIND_TO (depth,
+ make_uint (team_id));
+ else if (rc == B_ALREADY_RUNNING)
+ return Qalready_running;
+ else if (rc == B_BAD_VALUE)
+ signal_error ("Invalid type or bad arguments",
+ list2 (file_or_type, args));
+
+ return SAFE_FREE_UNBIND_TO (depth, Qnil);
+}
+
+static void
+haiku_dnd_compute_tip_xy (int *root_x, int *root_y)
+{
+ int min_x, min_y, max_x, max_y;
+ int width, height;
+
+ width = FRAME_PIXEL_WIDTH (XFRAME (tip_frame));
+ height = FRAME_PIXEL_HEIGHT (XFRAME (tip_frame));
+
+ min_x = 0;
+ min_y = 0;
+ be_get_screen_dimensions (&max_x, &max_y);
+
+ if (*root_y + XFIXNUM (tip_dy) <= min_y)
+ *root_y = min_y; /* Can happen for negative dy */
+ else if (*root_y + XFIXNUM (tip_dy) + height <= max_y)
+ /* It fits below the pointer */
+ *root_y += XFIXNUM (tip_dy);
+ else if (height + XFIXNUM (tip_dy) + min_y <= *root_y)
+ /* It fits above the pointer. */
+ *root_y -= height + XFIXNUM (tip_dy);
+ else
+ /* Put it on the top. */
+ *root_y = min_y;
+
+ if (*root_x + XFIXNUM (tip_dx) <= min_x)
+ *root_x = 0; /* Can happen for negative dx */
+ else if (*root_x + XFIXNUM (tip_dx) + width <= max_x)
+ /* It fits to the right of the pointer. */
+ *root_x += XFIXNUM (tip_dx);
+ else if (width + XFIXNUM (tip_dx) + min_x <= *root_x)
+ /* It fits to the left of the pointer. */
+ *root_x -= width + XFIXNUM (tip_dx);
+ else
+ /* Put it left justified on the screen -- it ought to fit that way. */
+ *root_x = min_x;
+}
+
static Lisp_Object
haiku_note_drag_motion_1 (void *data)
{
@@ -817,6 +990,26 @@ haiku_note_drag_motion_2 (enum nonlocal_exit exit, Lisp_Object error)
void
haiku_note_drag_motion (void)
{
+ struct frame *tip_f;
+ int x, y;
+
+ if (FRAMEP (tip_frame) && haiku_dnd_follow_tooltip
+ && FIXNUMP (tip_dx) && FIXNUMP (tip_dy))
+ {
+ tip_f = XFRAME (tip_frame);
+
+ if (FRAME_LIVE_P (tip_f) && FRAME_VISIBLE_P (tip_f))
+ {
+ BView_get_mouse (FRAME_HAIKU_VIEW (haiku_dnd_frame),
+ &x, &y);
+ BView_convert_to_screen (FRAME_HAIKU_VIEW (haiku_dnd_frame),
+ &x, &y);
+
+ haiku_dnd_compute_tip_xy (&x, &y);
+ BWindow_set_offset (FRAME_HAIKU_WINDOW (tip_f), x, y);
+ }
+ }
+
internal_catch_all (haiku_note_drag_motion_1, NULL,
haiku_note_drag_motion_2);
}
@@ -855,11 +1048,15 @@ used to retrieve the current position of the mouse. */);
DEFSYM (Qsize_t, "size_t");
DEFSYM (Qssize_t, "ssize_t");
DEFSYM (Qpoint, "point");
+ DEFSYM (Qfloat, "float");
+ DEFSYM (Qdouble, "double");
+ DEFSYM (Qalready_running, "already-running");
defsubr (&Shaiku_selection_data);
defsubr (&Shaiku_selection_put);
defsubr (&Shaiku_selection_owner_p);
defsubr (&Shaiku_drag_message);
+ defsubr (&Shaiku_roster_launch);
haiku_dnd_frame = NULL;
}
diff --git a/src/haikuselect.h b/src/haikuselect.h
index d4f331a9ccb..e9a2f2dd77d 100644
--- a/src/haikuselect.h
+++ b/src/haikuselect.h
@@ -37,31 +37,17 @@ enum haiku_clipboard
#ifdef __cplusplus
extern "C"
{
+/* Also declared in haikuterm.h for use in emacs.c. */
extern void init_haiku_select (void);
#endif
/* Whether or not the selection was recently changed. */
-/* Find a string with the MIME type TYPE in the system clipboard. */
-extern char *BClipboard_find_system_data (const char *, ssize_t *);
-extern char *BClipboard_find_primary_selection_data (const char *, ssize_t *);
-extern char *BClipboard_find_secondary_selection_data (const char *, ssize_t *);
-
-extern void BClipboard_set_system_data (const char *, const char *, ssize_t, bool);
-extern void BClipboard_set_primary_selection_data (const char *, const char *,
- ssize_t, bool);
-extern void BClipboard_set_secondary_selection_data (const char *, const char *,
- ssize_t, bool);
-
-extern void BClipboard_system_targets (char **, int);
-extern void BClipboard_primary_targets (char **, int);
-extern void BClipboard_secondary_targets (char **, int);
-
-extern bool BClipboard_owns_clipboard (void);
-extern bool BClipboard_owns_primary (void);
-extern bool BClipboard_owns_secondary (void);
-
-/* Free the returned data. */
-extern void BClipboard_free_data (void *);
+extern char *be_find_clipboard_data (enum haiku_clipboard, const char *, ssize_t *);
+extern void be_set_clipboard_data (enum haiku_clipboard, const char *, const char *,
+ ssize_t, bool);
+extern void be_get_clipboard_targets (enum haiku_clipboard, char **, int);
+extern bool be_clipboard_owner_p (enum haiku_clipboard);
+extern void be_update_clipboard_count (enum haiku_clipboard);
extern int be_enum_message (void *, int32 *, int32, int32 *, const char **);
extern int be_get_message_data (void *, const char *, int32, int32,
diff --git a/src/haikuterm.c b/src/haikuterm.c
index ced16d9f09b..365b23cd92c 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -43,17 +43,24 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* Minimum and maximum values used for Haiku scroll bars. */
#define BE_SB_MAX 12000000
-struct haiku_display_info *x_display_list = NULL;
-extern frame_parm_handler haiku_frame_parm_handlers[];
+/* The single Haiku display (if any). */
+struct haiku_display_info *x_display_list;
/* This is used to determine when to evict the font lookup cache,
which we do every 50 updates. */
static int up_to_date_count;
+/* List of defined fringe bitmaps. */
static void **fringe_bmps;
-static int max_fringe_bmp = 0;
+/* The amount of fringe bitmaps in that list. */
+static int max_fringe_bmp;
+
+/* Alist of resources to their values. */
static Lisp_Object rdb;
+
+/* Non-zero means that a HELP_EVENT has been generated since Emacs
+ start. */
static bool any_help_event_p;
char *
@@ -89,14 +96,9 @@ static void
haiku_coords_from_parent (struct frame *f, int *x, int *y)
{
struct frame *p = FRAME_PARENT_FRAME (f);
- eassert (p);
- for (struct frame *parent = p; parent;
- parent = FRAME_PARENT_FRAME (parent))
- {
- *x -= parent->left_pos;
- *y -= parent->top_pos;
- }
+ *x -= FRAME_OUTPUT_DATA (p)->frame_x;
+ *y -= FRAME_OUTPUT_DATA (p)->frame_y;
}
static void
@@ -115,7 +117,8 @@ haiku_delete_terminal (struct terminal *terminal)
}
static const char *
-get_string_resource (void *ignored, const char *name, const char *class)
+haiku_get_string_resource (void *ignored, const char *name,
+ const char *class)
{
const char *native;
@@ -196,6 +199,8 @@ haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst)
{
BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y,
s->width, s->height);
+ BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), s->x,
+ s->y, s->width, s->height);
}
static void
@@ -511,6 +516,9 @@ haiku_scroll_bar_from_widget (void *scroll_bar, void *window)
if (!frame)
return NULL;
+ if (!scroll_bar)
+ return NULL;
+
if (!NILP (FRAME_SCROLL_BARS (frame)))
{
for (tem = FRAME_SCROLL_BARS (frame); !NILP (tem);
@@ -567,20 +575,24 @@ haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor)
}
static bool
-haiku_defined_color (struct frame *f,
- const char *name,
- Emacs_Color *color,
- bool alloc,
- bool make_index)
+haiku_defined_color (struct frame *f, const char *name,
+ Emacs_Color *color, bool alloc, bool make_index)
{
- return !haiku_get_color (name, color);
+ int rc;
+
+ rc = !haiku_get_color (name, color);
+
+ if (rc && f->gamma && alloc)
+ gamma_correct (f, color);
+
+ return rc;
}
/* Adapted from xterm `x_draw_box_rect'. */
static void
-haiku_draw_box_rect (struct glyph_string *s,
- int left_x, int top_y, int right_x, int bottom_y, int hwidth,
- int vwidth, bool left_p, bool right_p, struct haiku_rect *clip_rect)
+haiku_draw_box_rect (struct glyph_string *s, int left_x, int top_y,
+ int right_x, int bottom_y, int hwidth, int vwidth,
+ bool left_p, bool right_p, struct haiku_rect *clip_rect)
{
void *view = FRAME_HAIKU_VIEW (s->f);
struct face *face = s->face;
@@ -604,13 +616,19 @@ static void
haiku_calculate_relief_colors (struct glyph_string *s, uint32_t *rgbout_w,
uint32_t *rgbout_b)
{
- struct face *face = s->face;
double h, cs, l;
uint32_t rgbin;
struct haiku_output *di;
- rgbin = (face->use_box_color_for_shadows_p
- ? face->box_color : face->background);
+ if (s->face->use_box_color_for_shadows_p)
+ rgbin = s->face->box_color;
+ else if (s->first_glyph->type == IMAGE_GLYPH
+ && s->img->pixmap
+ && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
+ rgbin = IMAGE_BACKGROUND (s->img, s->f, 0);
+ else
+ rgbin = s->face->background;
+
di = FRAME_OUTPUT_DATA (s->f);
if (s->hl == DRAW_CURSOR)
@@ -632,30 +650,35 @@ haiku_calculate_relief_colors (struct glyph_string *s, uint32_t *rgbout_w,
}
static void
-haiku_draw_relief_rect (struct glyph_string *s,
- int left_x, int top_y, int right_x, int bottom_y,
- int hwidth, int vwidth, bool raised_p, bool top_p,
- bool bot_p, bool left_p, bool right_p,
- struct haiku_rect *clip_rect, bool fancy_p)
+haiku_draw_relief_rect (struct glyph_string *s, int left_x, int top_y,
+ int right_x, int bottom_y, int hwidth, int vwidth,
+ bool raised_p, bool top_p, bool bot_p, bool left_p,
+ bool right_p, struct haiku_rect *clip_rect)
{
uint32_t color_white, color_black;
void *view;
+ view = FRAME_HAIKU_VIEW (s->f);
haiku_calculate_relief_colors (s, &color_white, &color_black);
- view = FRAME_HAIKU_VIEW (s->f);
BView_SetHighColor (view, raised_p ? color_white : color_black);
+
if (clip_rect)
{
BView_StartClip (view);
haiku_clip_to_string (s);
- BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
- clip_rect->height);
+ BView_ClipToRect (view, clip_rect->x, clip_rect->y,
+ clip_rect->width, clip_rect->height);
}
+
if (top_p)
- BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
+ BView_FillRectangle (view, left_x, top_y,
+ right_x - left_x + 1, hwidth);
+
if (left_p)
- BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
+ BView_FillRectangle (view, left_x, top_y,
+ vwidth, bottom_y - top_y + 1);
+
BView_SetHighColor (view, !raised_p ? color_white : color_black);
if (bot_p)
@@ -696,10 +719,10 @@ haiku_draw_relief_rect (struct glyph_string *s,
if (vwidth > 1 && right_p)
BView_StrokeLine (view, right_x, top_y, right_x, bottom_y);
- BView_SetHighColor (view, s->face->background);
+ BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (s->f));
/* Omit corner pixels. */
- if (hwidth > 1 || vwidth > 1)
+ if (hwidth > 1 && vwidth > 1)
{
if (left_p && top_p)
BView_FillRectangle (view, left_x, top_y, 1, 1);
@@ -716,21 +739,40 @@ haiku_draw_relief_rect (struct glyph_string *s,
}
static void
+haiku_get_scale_factor (int *scale_x, int *scale_y)
+{
+ struct haiku_display_info *dpyinfo = x_display_list;
+
+ if (dpyinfo->resx > 96)
+ *scale_x = floor (dpyinfo->resx / 96);
+ if (dpyinfo->resy > 96)
+ *scale_y = floor (dpyinfo->resy / 96);
+}
+
+static void
haiku_draw_underwave (struct glyph_string *s, int width, int x)
{
- int wave_height = 3, wave_length = 2;
- int y, dx, dy, odd, xmax;
+ int wave_height, wave_length;
+ int y, dx, dy, odd, xmax, scale_x, scale_y;
float ax, ay, bx, by;
- void *view = FRAME_HAIKU_VIEW (s->f);
+ void *view;
+
+ scale_x = 1;
+ scale_y = 1;
+ haiku_get_scale_factor (&scale_x, &scale_y);
+ wave_height = 3 * scale_y;
+ wave_length = 2 * scale_x;
dx = wave_length;
dy = wave_height - 1;
y = s->ybase - wave_height + 3;
xmax = x + width;
+ view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
haiku_clip_to_string (s);
BView_ClipToRect (view, x, y, width, wave_height);
+
ax = x - ((int) (x) % dx) + (float) 0.5;
bx = ax + dx;
odd = (int) (ax / dx) % 2;
@@ -741,6 +783,8 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x)
else
by += dy;
+ BView_SetPenSize (view, scale_y);
+
while (ax <= xmax)
{
BView_StrokeLine (view, ax, ay, bx, by);
@@ -748,6 +792,8 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x)
bx += dx, by = y + 0.5 + odd * dy;
odd = !odd;
}
+
+ BView_SetPenSize (view, 1);
BView_EndClip (view);
}
@@ -809,13 +855,13 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
- = (!(NILP (val) || EQ (val, Qunbound))
+ = (!(NILP (val) || BASE_EQ (val, Qunbound))
|| s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
use_underline_position_properties
- = !(NILP (val) || EQ (val, Qunbound));
+ = !(NILP (val) || BASE_EQ (val, Qunbound));
/* Get the underline thickness. Default is 1 pixel. */
if (font && font->underline_thickness > 0)
@@ -958,15 +1004,16 @@ haiku_draw_string_box (struct glyph_string *s)
else
haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
vwidth, raised_p, true, true, left_p, right_p,
- NULL, 1);
+ NULL);
}
static void
haiku_draw_plain_background (struct glyph_string *s, struct face *face,
- int box_line_hwidth, int box_line_vwidth)
+ int x, int y, int width, int height)
{
void *view = FRAME_HAIKU_VIEW (s->f);
unsigned long cursor_color;
+
if (s->hl == DRAW_CURSOR)
{
haiku_merge_cursor_foreground (s, NULL, &cursor_color);
@@ -975,18 +1022,92 @@ haiku_draw_plain_background (struct glyph_string *s, struct face *face,
else
BView_SetHighColor (view, face->background_defaulted_p ?
FRAME_BACKGROUND_PIXEL (s->f) :
- face->background);
+ face->background);
+
+ BView_FillRectangle (view, x, y, width, height);
+}
+
+static struct haiku_bitmap_record *
+haiku_get_bitmap_rec (struct frame *f, ptrdiff_t id)
+{
+ return &FRAME_DISPLAY_INFO (f)->bitmaps[id - 1];
+}
+
+static void
+haiku_update_bitmap_rec (struct haiku_bitmap_record *rec,
+ uint32_t new_foreground,
+ uint32_t new_background)
+{
+ char *bits;
+ int x, y, bytes_per_line;
+
+ if (new_foreground == rec->stipple_foreground
+ && new_background == rec->stipple_background)
+ return;
+
+ bits = rec->stipple_bits;
+ bytes_per_line = (rec->width + 7) / 8;
+
+ for (y = 0; y < rec->height; y++)
+ {
+ for (x = 0; x < rec->width; x++)
+ haiku_put_pixel (rec->img, x, y,
+ ((bits[x / 8] >> (x % 8)) & 1
+ ? new_foreground : new_background));
+
+ bits += bytes_per_line;
+ }
- BView_FillRectangle (view, s->x,
- s->y + box_line_hwidth,
- s->background_width,
- s->height - 2 * box_line_hwidth);
+ rec->stipple_foreground = new_foreground;
+ rec->stipple_background = new_background;
}
static void
haiku_draw_stipple_background (struct glyph_string *s, struct face *face,
- int box_line_hwidth, int box_line_vwidth)
+ int x, int y, int width, int height,
+ bool explicit_colors_p,
+ uint32 explicit_background,
+ uint32 explicit_foreground)
{
+ struct haiku_bitmap_record *rec;
+ unsigned long foreground, background;
+ void *view;
+
+ view = FRAME_HAIKU_VIEW (s->f);
+ rec = haiku_get_bitmap_rec (s->f, s->face->stipple);
+
+ if (explicit_colors_p)
+ {
+ background = explicit_background;
+ foreground = explicit_foreground;
+ }
+ else if (s->hl == DRAW_CURSOR)
+ haiku_merge_cursor_foreground (s, &foreground, &background);
+ else
+ {
+ foreground = s->face->foreground;
+ background = s->face->background;
+ }
+
+ haiku_update_bitmap_rec (rec, foreground, background);
+
+ BView_StartClip (view);
+ haiku_clip_to_string (s);
+ BView_ClipToRect (view, x, y, width, height);
+ BView_DrawBitmapTiled (view, rec->img, 0, 0, -1, -1,
+ 0, 0, x + width, y + height);
+ BView_EndClip (view);
+}
+
+void
+haiku_draw_background_rect (struct glyph_string *s, struct face *face,
+ int x, int y, int width, int height)
+{
+ if (!s->stippled_p)
+ haiku_draw_plain_background (s, face, x, y, width, height);
+ else
+ haiku_draw_stipple_background (s, face, x, y, width, height,
+ false, 0, 0);
}
static void
@@ -1002,12 +1123,10 @@ haiku_maybe_draw_background (struct glyph_string *s, int force_p)
|| FONT_TOO_HIGH (s->font)
|| s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
{
- if (!face->stipple)
- haiku_draw_plain_background (s, face, box_line_width,
- box_vline_width);
- else
- haiku_draw_stipple_background (s, face, box_line_width,
- box_vline_width);
+ haiku_draw_background_rect (s, s->face, s->x, s->y + box_line_width,
+ s->background_width,
+ s->height - 2 * box_line_width);
+
s->background_filled_p = 1;
}
}
@@ -1182,9 +1301,8 @@ haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
static void
haiku_draw_stretch_glyph_string (struct glyph_string *s)
{
- eassert (s->first_glyph->type == STRETCH_GLYPH);
-
struct face *face = s->face;
+ uint32_t bkg;
if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
{
@@ -1232,9 +1350,11 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
int y = s->y;
int w = background_width - width, h = s->height;
+ /* Draw stipples manually because we want the background
+ part of a stretch glyph to have a stipple even if the
+ cursor is visible on top. */
if (!face->stipple)
{
- uint32_t bkg;
if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
haiku_mouse_face_colors (s, NULL, &bkg);
else
@@ -1243,6 +1363,16 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
BView_SetHighColor (view, bkg);
BView_FillRectangle (view, x, y, w, h);
}
+ else
+ {
+ if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
+ haiku_mouse_face_colors (s, NULL, &bkg);
+ else
+ bkg = face->background;
+
+ haiku_draw_stipple_background (s, s->face, x, y, w, h,
+ true, bkg, face->foreground);
+ }
}
}
else if (!s->background_filled_p)
@@ -1260,17 +1390,8 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
}
if (background_width > 0)
- {
- void *view = FRAME_HAIKU_VIEW (s->f);
- unsigned long bkg;
- if (s->hl == DRAW_CURSOR)
- haiku_merge_cursor_foreground (s, NULL, &bkg);
- else
- bkg = s->face->background;
-
- BView_SetHighColor (view, bkg);
- BView_FillRectangle (view, x, s->y, background_width, s->height);
- }
+ haiku_draw_background_rect (s, s->face, s->x, s->y,
+ background_width, s->height);
}
s->background_filled_p = 1;
}
@@ -1504,19 +1625,20 @@ haiku_draw_image_relief (struct glyph_string *s)
get_glyph_string_clip_rect (s, &r);
haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p,
- top_p, bot_p, left_p, right_p, &r, 0);
+ top_p, bot_p, left_p, right_p, &r);
}
static void
haiku_draw_image_glyph_string (struct glyph_string *s)
{
struct face *face = s->face;
-
+ void *view, *bitmap, *mask;
int box_line_hwidth = max (face->box_vertical_line_width, 0);
int box_line_vwidth = max (face->box_horizontal_line_width, 0);
-
- int x, y;
- int height, width;
+ int x, y, height, width, relief;
+ struct haiku_rect nr;
+ Emacs_Rectangle cr, ir, r;
+ unsigned long background;
height = s->height;
if (s->slice.y == 0)
@@ -1537,19 +1659,22 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
if (s->slice.y == 0)
y += box_line_vwidth;
- void *view = FRAME_HAIKU_VIEW (s->f);
- void *bitmap = s->img->pixmap;
+ view = FRAME_HAIKU_VIEW (s->f);
+ bitmap = s->img->pixmap;
+ /* TODO: implement stipples for images with masks. */
s->stippled_p = face->stipple != 0;
- BView_SetHighColor (view, face->background);
+ if (s->hl == DRAW_CURSOR)
+ haiku_merge_cursor_foreground (s, NULL, &background);
+ else
+ background = face->background;
+
+ BView_SetHighColor (view, background);
BView_FillRectangle (view, x, y, width, height);
if (bitmap)
{
- struct haiku_rect nr;
- Emacs_Rectangle cr, ir, r;
-
get_glyph_string_clip_rect (s, &nr);
CONVERT_TO_EMACS_RECT (cr, nr);
x = s->x;
@@ -1571,7 +1696,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
ir.height = s->slice.height;
r = ir;
- void *mask = s->img->mask;
+ mask = s->img->mask;
if (gui_intersect_rectangles (&cr, &ir, &r))
{
@@ -1605,11 +1730,25 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
BBitmap_free (bitmap);
}
- if (s->hl == DRAW_CURSOR)
+ if (!s->img->mask)
{
- BView_SetPenSize (view, 1);
- BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
- BView_StrokeRectangle (view, r.x, r.y, r.width, r.height);
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+
+ if (s->hl == DRAW_CURSOR)
+ {
+ relief = eabs (s->img->relief);
+
+ BView_SetPenSize (view, 1);
+ BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
+ BView_StrokeRectangle (view, x - relief, y - relief,
+ s->slice.width + relief * 2,
+ s->slice.height + relief * 2);
+ }
}
}
@@ -1622,16 +1761,14 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
static void
haiku_draw_glyph_string (struct glyph_string *s)
{
- void *view;
+ void *view = FRAME_HAIKU_VIEW (s->f);;
+ struct face *face = s->face;
block_input ();
- view = FRAME_HAIKU_VIEW (s->f);
BView_draw_lock (view, false, 0, 0, 0, 0);
prepare_face_for_display (s->f, s->face);
- struct face *face = s->face;
- if (face != s->face)
- prepare_face_for_display (s->f, face);
+ s->stippled_p = s->hl != DRAW_CURSOR && face->stipple;
if (s->next && s->right_overhang && !s->for_overlaps)
{
@@ -1643,13 +1780,16 @@ haiku_draw_glyph_string (struct glyph_string *s)
width += next->width, next = next->next)
if (next->first_glyph->type != IMAGE_GLYPH)
{
- prepare_face_for_display (s->f, s->next->face);
- haiku_start_clip (s->next);
- haiku_clip_to_string (s->next);
+ prepare_face_for_display (s->f, next->face);
+ next->stippled_p
+ = next->hl != DRAW_CURSOR && next->face->stipple;
+
+ haiku_start_clip (next);
+ haiku_clip_to_string (next);
if (next->first_glyph->type != STRETCH_GLYPH)
- haiku_maybe_draw_background (s->next, 1);
+ haiku_maybe_draw_background (next, true);
else
- haiku_draw_stretch_glyph_string (s->next);
+ haiku_draw_stretch_glyph_string (next);
haiku_end_clip (s);
}
}
@@ -1774,8 +1914,21 @@ haiku_draw_glyph_string (struct glyph_string *s)
}
}
}
+
haiku_end_clip (s);
BView_draw_unlock (view);
+
+ /* Set the stipple_p flag indicating whether or not a stipple was
+ drawn in s->row. That is the case either when s is a stretch
+ glyph string and s->face->stipple is not NULL, or when
+ s->face->stipple exists and s->hl is not DRAW_CURSOR, and s is
+ not an image. This is different from X. */
+ if (s->first_glyph->type != IMAGE_GLYPH
+ && s->face->stipple
+ && (s->first_glyph->type == STRETCH_GLYPH
+ || s->hl != DRAW_CURSOR))
+ s->row->stipple_p = true;
+
unblock_input ();
}
@@ -1811,8 +1964,9 @@ haiku_after_update_window_line (struct window *w,
void *view = FRAME_HAIKU_VIEW (f);
BView_draw_lock (view, false, 0, 0, 0, 0);
BView_StartClip (view);
- BView_SetHighColor (view, face->background_defaulted_p ?
- FRAME_BACKGROUND_PIXEL (f) : face->background);
+ BView_SetHighColor (view, (face->background_defaulted_p
+ ? FRAME_BACKGROUND_PIXEL (f)
+ : face->background));
BView_FillRectangle (view, 0, y, width, height);
BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
y, width, height);
@@ -1847,7 +2001,7 @@ haiku_set_window_size (struct frame *f, bool change_gravity,
/* Only do this if the fullscreen status has actually been
applied. */
&& f->want_fullscreen == FULLSCREEN_NONE
- /* And if the configury during frame completion has been
+ /* And if the configury during frame creation has been
completed. Otherwise, there will be no valid "old size" to
go back to. */
&& FRAME_OUTPUT_DATA (f)->configury_done)
@@ -1858,134 +2012,215 @@ haiku_set_window_size (struct frame *f, bool change_gravity,
if (FRAME_HAIKU_WINDOW (f))
{
block_input ();
- BWindow_resize (FRAME_HAIKU_WINDOW (f), width, height);
+ BWindow_resize (FRAME_HAIKU_WINDOW (f),
+ width, height);
+
+ if (FRAME_VISIBLE_P (f)
+ && (width != FRAME_PIXEL_WIDTH (f)
+ || height != FRAME_PIXEL_HEIGHT (f)))
+ haiku_wait_for_event (f, FRAME_RESIZED);
unblock_input ();
}
+
+ do_pending_window_change (false);
}
static void
-haiku_draw_window_cursor (struct window *w,
- struct glyph_row *glyph_row,
- int x, int y,
- enum text_cursor_kinds cursor_type,
- int cursor_width, bool on_p, bool active_p)
+haiku_draw_hollow_cursor (struct window *w, struct glyph_row *row)
{
- struct frame *f = XFRAME (WINDOW_FRAME (w));
- struct face *face;
- struct glyph *phys_cursor_glyph;
+ struct frame *f;
+ int x, y, wd, h;
struct glyph *cursor_glyph;
+ uint32_t foreground;
+ void *view;
- void *view = FRAME_HAIKU_VIEW (f);
-
- int fx, fy, h, cursor_height;
+ f = XFRAME (WINDOW_FRAME (w));
+ view = FRAME_HAIKU_VIEW (f);
- if (!on_p)
+ /* Get the glyph the cursor is on. If we can't tell because
+ the current matrix is invalid or such, give up. */
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
return;
- if (cursor_type == NO_CURSOR)
- {
- w->phys_cursor_width = 0;
- return;
- }
+ /* Compute frame-relative coordinates for phys cursor. */
+ get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
+ wd = w->phys_cursor_width;
- w->phys_cursor_on_p = true;
- w->phys_cursor_type = cursor_type;
+ /* The foreground of cursor_gc is typically the same as the normal
+ background color, which can cause the cursor box to be invisible. */
+ foreground = FRAME_CURSOR_COLOR (f).pixel;
- phys_cursor_glyph = get_phys_cursor_glyph (w);
+ /* When on R2L character, show cursor at the right edge of the
+ glyph, unless the cursor box is as wide as the glyph or wider
+ (the latter happens when x-stretch-cursor is non-nil). */
+ if ((cursor_glyph->resolved_level & 1) != 0
+ && cursor_glyph->pixel_width > wd)
+ x += cursor_glyph->pixel_width - wd;
- if (!phys_cursor_glyph)
- {
- if (glyph_row->exact_window_width_line_p
- && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
- {
- glyph_row->cursor_in_fringe_p = 1;
- draw_fringe_bitmap (w, glyph_row, 0);
- }
- return;
- }
+ /* Set clipping, draw the rectangle, and reset clipping again.
+ This also marks the region as invalidated. */
+
+ BView_draw_lock (view, true, x, y, wd, h);
+ BView_StartClip (view);
+ haiku_clip_to_row (w, row, TEXT_AREA);
- get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
+ /* Now set the foreground color and pen size. */
+ BView_SetHighColor (view, foreground);
+ BView_SetPenSize (view, 1);
- if (cursor_type == BAR_CURSOR)
+ /* Actually draw the rectangle. */
+ BView_StrokeRectangle (view, x, y, wd, h);
+
+ /* Reset clipping. */
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_draw_bar_cursor (struct window *w, struct glyph_row *row,
+ int width, enum text_cursor_kinds kind)
+{
+ struct frame *f;
+ struct glyph *cursor_glyph;
+ struct glyph_row *r;
+ struct face *face;
+ uint32_t foreground;
+ void *view;
+ int x, y, dummy_x, dummy_y, dummy_h;
+
+ f = XFRAME (w->frame);
+
+ /* If cursor is out of bounds, don't draw garbage. This can happen
+ in mini-buffer windows when switching between echo area glyphs
+ and mini-buffer. */
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ return;
+
+ /* If on an image, draw like a normal cursor. That's usually better
+ visible than drawing a bar, esp. if the image is large so that
+ the bar might not be in the window. */
+ if (cursor_glyph->type == IMAGE_GLYPH)
{
- if (cursor_width < 1)
- cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
- if (cursor_width < w->phys_cursor_width)
- w->phys_cursor_width = cursor_width;
+ r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
+ draw_phys_cursor_glyph (w, r, DRAW_CURSOR);
}
- else if (cursor_type == HBAR_CURSOR)
+ else
{
- cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
- if (cursor_height > glyph_row->height)
- cursor_height = glyph_row->height;
- if (h > cursor_height)
- fy += h - cursor_height;
- h = cursor_height;
- }
+ view = FRAME_HAIKU_VIEW (f);
+ face = FACE_FROM_ID (f, cursor_glyph->face_id);
- BView_draw_lock (view, false, 0, 0, 0, 0);
- BView_StartClip (view);
+ /* If the glyph's background equals the color we normally draw
+ the bars cursor in, the bar cursor in its normal color is
+ invisible. Use the glyph's foreground color instead in this
+ case, on the assumption that the glyph's colors are chosen so
+ that the glyph is legible. */
+ if (face->background == FRAME_CURSOR_COLOR (f).pixel)
+ foreground = face->foreground;
+ else
+ foreground = FRAME_CURSOR_COLOR (f).pixel;
- if (cursor_type == BAR_CURSOR)
- {
- cursor_glyph = get_phys_cursor_glyph (w);
- face = FACE_FROM_ID (f, cursor_glyph->face_id);
- }
+ BView_draw_lock (view, false, 0, 0, 0, 0);
+ BView_StartClip (view);
+ BView_SetHighColor (view, foreground);
+ haiku_clip_to_row (w, row, TEXT_AREA);
- /* If the glyph's background equals the color we normally draw the
- bar cursor in, our cursor in its normal color is invisible. Use
- the glyph's foreground color instead in this case, on the
- assumption that the glyph's colors are chosen so that the glyph
- is legible. */
+ if (kind == BAR_CURSOR)
+ {
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y);
- /* xterm.c only does this for bar cursors, and nobody has
- complained, so it would be best to do that here as well. */
- if (cursor_type == BAR_CURSOR
- && face->background == FRAME_CURSOR_COLOR (f).pixel)
- BView_SetHighColor (view, face->foreground);
- else
- BView_SetHighColor (view, FRAME_CURSOR_COLOR (f).pixel);
- haiku_clip_to_row (w, glyph_row, TEXT_AREA);
+ if (width < 0)
+ width = FRAME_CURSOR_WIDTH (f);
+ width = min (cursor_glyph->pixel_width, width);
- switch (cursor_type)
- {
- default:
- case DEFAULT_CURSOR:
- case NO_CURSOR:
- break;
- case HBAR_CURSOR:
- BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
- BView_invalidate_region (view, fx, fy, w->phys_cursor_width, h);
- break;
- case BAR_CURSOR:
- if (cursor_glyph->resolved_level & 1)
+ w->phys_cursor_width = width;
+
+ /* If the character under cursor is R2L, draw the bar cursor
+ on the right of its glyph, rather than on the left. */
+ if ((cursor_glyph->resolved_level & 1) != 0)
+ x += cursor_glyph->pixel_width - width;
+
+ BView_FillRectangle (view, x, y, width, row->height);
+ BView_invalidate_region (view, x, y, width, row->height);
+ }
+ else /* HBAR_CURSOR */
{
- BView_FillRectangle (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width,
- fy, w->phys_cursor_width, h);
- BView_invalidate_region (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width,
- fy, w->phys_cursor_width, h);
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
+ row->height - width);
+
+ if (width < 0)
+ width = row->height;
+
+ width = min (row->height, width);
+
+ get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
+ &dummy_y, &dummy_h);
+
+ if ((cursor_glyph->resolved_level & 1) != 0
+ && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
+ x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
+
+ BView_FillRectangle (view, x, y, w->phys_cursor_width - 1,
+ width);
+ BView_invalidate_region (view, x, y, w->phys_cursor_width - 1,
+ width);
}
- else
- BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
- BView_invalidate_region (view, fx, fy, w->phys_cursor_width, h);
- break;
- case HOLLOW_BOX_CURSOR:
- if (phys_cursor_glyph->type != IMAGE_GLYPH)
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ }
+}
+
+static void
+haiku_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
+ int x, int y, enum text_cursor_kinds cursor_type,
+ int cursor_width, bool on_p, bool active_p)
+{
+ if (on_p)
+ {
+ w->phys_cursor_type = cursor_type;
+ w->phys_cursor_on_p = true;
+
+ if (glyph_row->exact_window_width_line_p
+ && (glyph_row->reversed_p
+ ? (w->phys_cursor.hpos < 0)
+ : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
{
- BView_SetPenSize (view, 1);
- BView_StrokeRectangle (view, fx, fy, w->phys_cursor_width, h);
+ glyph_row->cursor_in_fringe_p = true;
+ draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
}
else
- draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ {
+ switch (cursor_type)
+ {
+ case HOLLOW_BOX_CURSOR:
+ haiku_draw_hollow_cursor (w, glyph_row);
+ break;
- BView_invalidate_region (view, fx, fy, w->phys_cursor_width, h);
- break;
- case FILLED_BOX_CURSOR:
- draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ case FILLED_BOX_CURSOR:
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ break;
+
+ case BAR_CURSOR:
+ haiku_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
+ break;
+
+ case HBAR_CURSOR:
+ haiku_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
+ break;
+
+ case NO_CURSOR:
+ w->phys_cursor_width = 0;
+ break;
+
+ default:
+ emacs_abort ();
+ }
+ }
}
- BView_EndClip (view);
- BView_draw_unlock (view);
}
static void
@@ -2072,19 +2307,25 @@ haiku_draw_vertical_window_border (struct window *w,
static void
haiku_set_scroll_bar_default_width (struct frame *f)
{
- int unit = FRAME_COLUMN_WIDTH (f);
- FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1;
- FRAME_CONFIG_SCROLL_BAR_COLS (f) =
- (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
+ int unit, size;
+
+ unit = FRAME_COLUMN_WIDTH (f);
+ size = BScrollBar_default_size (0) + 1;
+
+ FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = size;
+ FRAME_CONFIG_SCROLL_BAR_COLS (f) = (size + unit - 1) / unit;
}
static void
haiku_set_scroll_bar_default_height (struct frame *f)
{
- int height = FRAME_LINE_HEIGHT (f);
- FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1;
- FRAME_CONFIG_SCROLL_BAR_LINES (f) =
- (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
+ int height, size;
+
+ height = FRAME_LINE_HEIGHT (f);
+ size = BScrollBar_default_size (true) + 1;
+
+ FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = size;
+ FRAME_CONFIG_SCROLL_BAR_LINES (f) = (size + height - 1) / height;
}
static void
@@ -2266,15 +2507,17 @@ static struct scroll_bar *
haiku_scroll_bar_create (struct window *w, int left, int top,
int width, int height, bool horizontal_p)
{
- struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct frame *f;
Lisp_Object barobj;
+ struct scroll_bar *bar;
+ void *scroll_bar;
+ void *view;
- void *sb = NULL;
- void *vw = FRAME_HAIKU_VIEW (f);
+ f = XFRAME (WINDOW_FRAME (w));
+ view = FRAME_HAIKU_VIEW (f);
block_input ();
- struct scroll_bar *bar
- = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
+ bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
XSETWINDOW (bar->window, w);
bar->top = top;
@@ -2287,15 +2530,14 @@ haiku_scroll_bar_create (struct window *w, int left, int top,
bar->update = -1;
bar->horizontal = horizontal_p;
- sb = BScrollBar_make_for_view (vw, horizontal_p,
- left, top, left + width - 1,
- top + height - 1, bar);
-
- BView_publish_scroll_bar (vw, left, top, width, height);
+ scroll_bar = be_make_scroll_bar_for_view (view, horizontal_p,
+ left, top, left + width - 1,
+ top + height - 1);
+ BView_publish_scroll_bar (view, left, top, width, height);
bar->next = FRAME_SCROLL_BARS (f);
bar->prev = Qnil;
- bar->scroll_bar = sb;
+ bar->scroll_bar = scroll_bar;
XSETVECTOR (barobj, bar);
fset_scroll_bars (f, barobj);
@@ -2309,18 +2551,20 @@ haiku_scroll_bar_create (struct window *w, int left, int top,
static void
haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
{
- eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
Lisp_Object barobj;
struct scroll_bar *bar;
int top, height, left, width;
int window_x, window_width;
+ void *view;
+ eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
/* Get window dimensions. */
window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
left = window_x;
width = window_width;
top = WINDOW_SCROLL_BAR_AREA_Y (w);
height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
+ view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
block_input ();
@@ -2335,15 +2579,15 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p
{
bar = XSCROLL_BAR (w->horizontal_scroll_bar);
- if (bar->left != left || bar->top != top ||
- bar->width != width || bar->height != height)
+ if (bar->left != left || bar->top != top
+ || bar->width != width || bar->height != height)
{
- void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
BView_forget_scroll_bar (view, bar->left, bar->top,
bar->width, bar->height);
BView_move_frame (bar->scroll_bar, left, top,
left + width - 1, top + height - 1);
BView_publish_scroll_bar (view, left, top, width, height);
+
bar->left = left;
bar->top = top;
bar->width = width;
@@ -2360,14 +2604,15 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p
}
static void
-haiku_set_vertical_scroll_bar (struct window *w,
- int portion, int whole, int position)
+haiku_set_vertical_scroll_bar (struct window *w, int portion, int whole, int position)
{
- eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
Lisp_Object barobj;
struct scroll_bar *bar;
int top, height, left, width;
int window_y, window_height;
+ void *view;
+
+ eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
/* Get window dimensions. */
window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
@@ -2377,8 +2622,10 @@ haiku_set_vertical_scroll_bar (struct window *w,
/* Compute the left edge and the width of the scroll bar area. */
left = WINDOW_SCROLL_BAR_AREA_X (w);
width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
- block_input ();
+ view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
+
+ block_input ();
if (NILP (w->vertical_scroll_bar))
{
bar = haiku_scroll_bar_create (w, left, top, width, height, false);
@@ -2389,15 +2636,15 @@ haiku_set_vertical_scroll_bar (struct window *w,
{
bar = XSCROLL_BAR (w->vertical_scroll_bar);
- if (bar->left != left || bar->top != top ||
- bar->width != width || bar->height != height)
+ if (bar->left != left || bar->top != top
+ || bar->width != width || bar->height != height)
{
- void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
BView_forget_scroll_bar (view, bar->left, bar->top,
bar->width, bar->height);
BView_move_frame (bar->scroll_bar, left, top,
left + width - 1, top + height - 1);
BView_publish_scroll_bar (view, left, top, width, height);
+
bar->left = left;
bar->top = top;
bar->width = width;
@@ -2418,25 +2665,57 @@ static void
haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
struct draw_fringe_bitmap_params *p)
{
- void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w)));
- struct face *face = p->face;
+ struct face *face;
+ struct frame *f;
+ struct haiku_bitmap_record *rec;
+ void *view, *bitmap;
+ uint32 col;
+
+ f = XFRAME (WINDOW_FRAME (w));
+ view = FRAME_HAIKU_VIEW (f);
+ face = p->face;
block_input ();
- BView_draw_lock (view, true, p->x, p->y, p->wd, p->h);
+ BView_draw_lock (view, true, 0, 0, 0, 0);
BView_StartClip (view);
+ if (p->wd && p->h)
+ BView_invalidate_region (view, p->x, p->y, p->wd, p->h);
+
haiku_clip_to_row (w, row, ANY_AREA);
+
if (p->bx >= 0 && !p->overlay_p)
{
- BView_SetHighColor (view, face->background);
- BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
+ BView_invalidate_region (view, p->bx, p->by, p->nx, p->ny);
+
+ if (!face->stipple)
+ {
+ BView_SetHighColor (view, face->background);
+ BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
+ }
+ else
+ {
+ rec = haiku_get_bitmap_rec (f, face->stipple);
+ haiku_update_bitmap_rec (rec, face->foreground,
+ face->background);
+
+ BView_StartClip (view);
+ haiku_clip_to_row (w, row, ANY_AREA);
+ BView_ClipToRect (view, p->bx, p->by, p->nx, p->ny);
+ BView_DrawBitmapTiled (view, rec->img, 0, 0, -1, -1,
+ 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+ BView_EndClip (view);
+
+ row->stipple_p = true;
+ }
}
if (p->which
&& p->which < max_fringe_bmp
&& p->which < max_used_fringe_bitmap)
{
- void *bitmap = fringe_bmps[p->which];
+ bitmap = fringe_bmps[p->which];
if (!bitmap)
{
@@ -2450,8 +2729,6 @@ haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
bitmap = fringe_bmps[p->which];
}
- uint32_t col;
-
if (!p->cursor_p)
col = face->foreground;
else if (p->overlay_p)
@@ -2610,7 +2887,7 @@ haiku_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
x_display_list->last_mouse_glyph_frame = f1;
*bar_window = Qnil;
- *part = scroll_bar_above_handle;
+ *part = scroll_bar_nowhere;
/* If track-mouse is `drag-source' and the mouse pointer is
certain to not be actually under the chosen frame, return
@@ -2659,20 +2936,13 @@ haiku_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
}
static void
-haiku_update_window_end (struct window *w, bool cursor_on_p,
- bool mouse_face_overwritten_p)
-{
-
-}
-
-static void
haiku_default_font_parameter (struct frame *f, Lisp_Object parms)
{
struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
RES_TYPE_STRING);
Lisp_Object font = Qnil;
- if (EQ (font_param, Qunbound))
+ if (BASE_EQ (font_param, Qunbound))
font_param = Qnil;
if (NILP (font_param))
@@ -2733,8 +3003,8 @@ static struct redisplay_interface haiku_redisplay_interface =
gui_clear_end_of_line,
haiku_scroll_run,
haiku_after_update_window_line,
- NULL,
- haiku_update_window_end,
+ NULL, /* update_window_begin */
+ NULL, /* update_window_end */
haiku_flush,
gui_clear_window_mouse_face,
gui_get_glyph_overhangs,
@@ -2750,7 +3020,7 @@ static struct redisplay_interface haiku_redisplay_interface =
haiku_draw_window_cursor,
haiku_draw_vertical_window_border,
haiku_draw_window_divider,
- 0, /* shift glyphs for insert */
+ NULL, /* shift glyphs for insert */
haiku_show_hourglass,
haiku_hide_hourglass,
haiku_default_font_parameter,
@@ -2759,11 +3029,20 @@ static struct redisplay_interface haiku_redisplay_interface =
static void
haiku_make_fullscreen_consistent (struct frame *f)
{
- Lisp_Object lval = get_frame_param (f, Qfullscreen);
-
- if (!EQ (lval, Qmaximized) && FRAME_OUTPUT_DATA (f)->zoomed_p)
+ Lisp_Object lval;
+ struct haiku_output *output;
+
+ output = FRAME_OUTPUT_DATA (f);
+
+ if (output->fullscreen_mode == FULLSCREEN_MODE_BOTH)
+ lval = Qfullboth;
+ else if (output->fullscreen_mode == FULLSCREEN_MODE_WIDTH)
+ lval = Qfullwidth;
+ else if (output->fullscreen_mode == FULLSCREEN_MODE_HEIGHT)
+ lval = Qfullheight;
+ else if (output->fullscreen_mode == FULLSCREEN_MODE_MAXIMIZED)
lval = Qmaximized;
- else if (EQ (lval, Qmaximized) && !FRAME_OUTPUT_DATA (f)->zoomed_p)
+ else
lval = Qnil;
store_frame_param (f, Qfullscreen, lval);
@@ -2778,7 +3057,7 @@ haiku_flush_dirty_back_buffer_on (struct frame *f)
haiku_flip_buffers (f);
}
-/* N.B. that support for TYPE must be explictly added to
+/* N.B. that support for TYPE must be explicitly added to
haiku_read_socket. */
void
haiku_wait_for_event (struct frame *f, int type)
@@ -2816,7 +3095,7 @@ static int
haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
{
int message_count;
- static void *buf;
+ void *buf;
ssize_t b_size;
int button_or_motion_p, do_help;
enum haiku_event_type type;
@@ -2825,11 +3104,10 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
message_count = 0;
button_or_motion_p = 0;
do_help = 0;
- buf = NULL;
+
+ buf = alloca (200);
block_input ();
- if (!buf)
- buf = xmalloc (200);
haiku_read_size (&b_size, false);
while (b_size >= 0)
{
@@ -2868,8 +3146,12 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
if (!f)
continue;
- int width = lrint (b->px_widthf);
- int height = lrint (b->px_heightf);
+ int width = lrint (b->width);
+ int height = lrint (b->height);
+
+ if (FRAME_OUTPUT_DATA (f)->wait_for_event_type
+ == FRAME_RESIZED)
+ FRAME_OUTPUT_DATA (f)->wait_for_event_type = -1;
if (FRAME_TOOLTIP_P (f))
{
@@ -2899,6 +3181,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
cancel_mouse_face (f);
haiku_clear_under_internal_border (f);
}
+
break;
}
case FRAME_EXPOSED:
@@ -3006,10 +3289,18 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
if (FRAME_TOOLTIP_P (f))
{
/* Dismiss the tooltip if the mouse moves onto a
- tooltip frame. FIXME: for some reason we don't get
- leave notification events for this. */
-
- if (any_help_event_p)
+ tooltip frame (except when drag-and-drop is in
+ progress and we are trying to move the tooltip
+ along with the mouse pointer). FIXME: for some
+ reason we don't get leave notification events for
+ this. */
+
+ if (any_help_event_p
+ && !(be_drag_and_drop_in_progress ()
+ && haiku_dnd_follow_tooltip)
+ && !((EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping))
+ && gui_mouse_grabbed (x_display_list)))
do_help = -1;
break;
}
@@ -3056,7 +3347,10 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
haiku_new_focus_frame (x_display_list->focused_frame);
- if (any_help_event_p)
+ if (any_help_event_p
+ && !((EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping))
+ && gui_mouse_grabbed (x_display_list)))
do_help = -1;
}
else
@@ -3081,18 +3375,17 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
previous_help_echo_string = help_echo_string;
help_echo_string = Qnil;
- /* A LeaveNotify event (well, the closest equivalent on Haiku, which
- is a B_MOUSE_MOVED event with `transit' set to B_EXITED_VIEW) might
- be sent out-of-order with regards to motion events from other
- windows, such as when the mouse pointer rapidly moves from an
- undecorated child frame to its parent. This can cause a failure to
- clear the mouse face on the former if an event for the latter is
- read by Emacs first and ends up showing the mouse face there.
+ /* A crossing event might be sent out-of-order with
+ regard to motion events from other windows, such as
+ when the mouse pointer rapidly moves from an
+ undecorated child frame to its parent. This can
+ cause a failure to clear the mouse face on the
+ former if an event for the latter is read by Emacs
+ first and ends up showing the mouse face there.
- In case the `movement_locker' (also see the comment
- there) doesn't take care of the problem, work
- around it by clearing the mouse face now, if it is
- currently shown on a different frame. */
+ Work around the problem by clearing the mouse face
+ now if it is currently shown on a different
+ frame. */
if (hlinfo->mouse_face_hidden
|| (f != hlinfo->mouse_face_mouse_frame
@@ -3181,13 +3474,13 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
Lisp_Object tab_bar_arg = Qnil;
int tab_bar_p = 0, tool_bar_p = 0;
bool up_okay_p = false;
+ struct scroll_bar *bar;
if (popup_activated_p || !f)
continue;
- struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
-
inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
+ bar = haiku_scroll_bar_from_widget (b->scroll_bar, b->window);
x_display_list->last_mouse_glyph_frame = 0;
x_display_list->last_mouse_movement_time = b->time / 1000;
@@ -3235,34 +3528,64 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
if (type == BUTTON_UP)
{
inev.modifiers |= up_modifier;
- up_okay_p = (dpyinfo->grabbed & (1 << b->btn_no));
- dpyinfo->grabbed &= ~(1 << b->btn_no);
+ up_okay_p = (x_display_list->grabbed & (1 << b->btn_no));
+ x_display_list->grabbed &= ~(1 << b->btn_no);
}
else
{
up_okay_p = true;
inev.modifiers |= down_modifier;
- dpyinfo->last_mouse_frame = f;
- dpyinfo->grabbed |= (1 << b->btn_no);
+ x_display_list->last_mouse_frame = f;
+ x_display_list->grabbed |= (1 << b->btn_no);
if (f && !tab_bar_p)
f->last_tab_bar_item = -1;
if (f && !tool_bar_p)
f->last_tool_bar_item = -1;
}
- if (up_okay_p
- && !(tab_bar_p && NILP (tab_bar_arg))
- && !tool_bar_p)
+ if (bar)
+ {
+ inev.kind = (bar->horizontal
+ ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
+ : SCROLL_BAR_CLICK_EVENT);
+ inev.part = (bar->horizontal
+ ? scroll_bar_horizontal_handle
+ : scroll_bar_handle);
+ }
+ else if (up_okay_p
+ && !(tab_bar_p && NILP (tab_bar_arg))
+ && !tool_bar_p)
inev.kind = MOUSE_CLICK_EVENT;
+
inev.arg = tab_bar_arg;
inev.code = b->btn_no;
f->mouse_moved = false;
- XSETINT (inev.x, b->x);
- XSETINT (inev.y, b->y);
+ if (bar)
+ {
+ if (bar->horizontal)
+ {
+ XSETINT (inev.x, min (max (0, b->x - bar->left),
+ bar->width));
+ XSETINT (inev.y, bar->width);
+ }
+ else
+ {
+ XSETINT (inev.x, min (max (0, b->y - bar->top),
+ bar->height));
+ XSETINT (inev.y, bar->height);
+ }
+
+ inev.frame_or_window = bar->window;
+ }
+ else
+ {
+ XSETINT (inev.x, b->x);
+ XSETINT (inev.y, b->y);
+ XSETFRAME (inev.frame_or_window, f);
+ }
- XSETFRAME (inev.frame_or_window, f);
break;
}
case ICONIFICATION:
@@ -3279,7 +3602,6 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
SET_FRAME_ICONIFIED (f, 0);
inev.kind = DEICONIFY_EVENT;
-
/* Haiku doesn't expose frames on deiconification, but
if we are double-buffered, the previous screen
contents should have been preserved. */
@@ -3303,30 +3625,36 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
{
struct haiku_move_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
+ int top, left;
+ struct frame *p;
if (!f)
continue;
+ FRAME_OUTPUT_DATA (f)->frame_x = b->x;
+ FRAME_OUTPUT_DATA (f)->frame_y = b->y;
+
if (FRAME_PARENT_FRAME (f))
haiku_coords_from_parent (f, &b->x, &b->y);
- if (b->x != f->left_pos || b->y != f->top_pos)
+ left = b->x - b->decorator_width;
+ top = b->y - b->decorator_height;
+
+ if (left != f->left_pos || top != f->top_pos)
{
inev.kind = MOVE_FRAME_EVENT;
- XSETINT (inev.x, b->x);
- XSETINT (inev.y, b->y);
+ XSETINT (inev.x, left);
+ XSETINT (inev.y, top);
- f->left_pos = b->x;
- f->top_pos = b->y;
+ f->left_pos = left;
+ f->top_pos = top;
- struct frame *p;
+ p = FRAME_PARENT_FRAME (f);
- if ((p = FRAME_PARENT_FRAME (f)))
- {
- void *window = FRAME_HAIKU_WINDOW (p);
- EmacsWindow_move_weak_child (window, b->window, b->x, b->y);
- }
+ if (p)
+ EmacsWindow_move_weak_child (FRAME_HAIKU_WINDOW (p),
+ b->window, left, top);
XSETFRAME (inev.frame_or_window, f);
}
@@ -3357,8 +3685,9 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
inev.kind = (bar->horizontal
? HORIZONTAL_SCROLL_BAR_CLICK_EVENT :
SCROLL_BAR_CLICK_EVENT);
- inev.part = bar->horizontal ?
- scroll_bar_horizontal_handle : scroll_bar_handle;
+ inev.part = (bar->horizontal
+ ? scroll_bar_horizontal_handle
+ : scroll_bar_handle);
if (bar->horizontal)
{
@@ -3594,14 +3923,17 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
case ZOOM_EVENT:
{
struct haiku_zoom_event *b = buf;
-
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
continue;
- FRAME_OUTPUT_DATA (f)->zoomed_p = b->zoomed;
- haiku_make_fullscreen_consistent (f);
+ if (b->fullscreen_mode == FULLSCREEN_MODE_MAXIMIZED)
+ f->want_fullscreen = FULLSCREEN_NONE;
+ else
+ f->want_fullscreen = FULLSCREEN_MAXIMIZED;
+
+ FRAME_TERMINAL (f)->fullscreen_hook (f);
break;
}
case DRAG_AND_DROP_EVENT:
@@ -3625,6 +3957,15 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
BMessage_delete (b->message);
break;
}
+ case SCREEN_CHANGED_EVENT:
+ {
+ struct haiku_screen_changed_event *b = buf;
+
+ inev.kind = MONITORS_CHANGED_EVENT;
+ XSETTERMINAL (inev.arg, x_display_list->terminal);
+ inev.timestamp = b->when / 1000;
+ break;
+ }
case APP_QUIT_REQUESTED_EVENT:
inev.kind = SAVE_SESSION_EVENT;
inev.arg = Qt;
@@ -3685,6 +4026,21 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
return message_count;
}
+static Lisp_Object
+haiku_get_focus_frame (struct frame *f)
+{
+ Lisp_Object lisp_focus;
+ struct frame *focus;
+
+ focus = FRAME_DISPLAY_INFO (f)->focused_frame;
+
+ if (!focus)
+ return Qnil;
+
+ XSETFRAME (lisp_focus, focus);
+ return lisp_focus;
+}
+
static void
haiku_frame_rehighlight (struct frame *frame)
{
@@ -3833,6 +4189,8 @@ haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p)
static void
haiku_fullscreen (struct frame *f)
{
+ enum haiku_fullscreen_mode mode;
+
/* When FRAME_OUTPUT_DATA (f)->configury_done is false, the frame is
being created, and its regular width and height have not yet been
set. This function will be called again by haiku_create_frame,
@@ -3841,18 +4199,22 @@ haiku_fullscreen (struct frame *f)
return;
if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
- BWindow_zoom (FRAME_HAIKU_WINDOW (f));
+ mode = FULLSCREEN_MODE_MAXIMIZED;
else if (f->want_fullscreen == FULLSCREEN_BOTH)
- EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 1);
+ mode = FULLSCREEN_MODE_BOTH;
+ else if (f->want_fullscreen == FULLSCREEN_WIDTH)
+ mode = FULLSCREEN_MODE_WIDTH;
+ else if (f->want_fullscreen == FULLSCREEN_HEIGHT)
+ mode = FULLSCREEN_MODE_HEIGHT;
else
- {
- EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
- EmacsWindow_unzoom (FRAME_HAIKU_WINDOW (f));
- }
+ mode = FULLSCREEN_MODE_NONE;
f->want_fullscreen = FULLSCREEN_NONE;
+ be_set_window_fullscreen_mode (FRAME_HAIKU_WINDOW (f), mode);
+ FRAME_OUTPUT_DATA (f)->fullscreen_mode = mode;
haiku_update_size_hints (f);
+ haiku_make_fullscreen_consistent (f);
}
static struct terminal *
@@ -3873,7 +4235,7 @@ haiku_create_terminal (struct haiku_display_info *dpyinfo)
terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible;
terminal->set_frame_offset_hook = haiku_set_offset;
terminal->delete_terminal_hook = haiku_delete_terminal;
- terminal->get_string_resource_hook = get_string_resource;
+ terminal->get_string_resource_hook = haiku_get_string_resource;
terminal->set_new_font_hook = haiku_new_font;
terminal->defined_color_hook = haiku_defined_color;
terminal->set_window_size_hook = haiku_set_window_size;
@@ -3904,6 +4266,7 @@ haiku_create_terminal (struct haiku_display_info *dpyinfo)
terminal->fullscreen_hook = haiku_fullscreen;
terminal->toolkit_position_hook = haiku_toolkit_position;
terminal->activate_menubar_hook = haiku_activate_menubar;
+ terminal->get_focus_frame = haiku_get_focus_frame;
return terminal;
}
@@ -3959,34 +4322,24 @@ haiku_term_init (void)
gui_init_fringe (terminal->rif);
-#define ASSIGN_CURSOR(cursor, be_cursor) (dpyinfo->cursor = be_cursor)
- ASSIGN_CURSOR (text_cursor, BCursor_create_i_beam ());
- ASSIGN_CURSOR (nontext_cursor, BCursor_create_default ());
- ASSIGN_CURSOR (modeline_cursor, BCursor_create_modeline ());
- ASSIGN_CURSOR (hand_cursor, BCursor_create_grab ());
- ASSIGN_CURSOR (hourglass_cursor, BCursor_create_progress_cursor ());
- ASSIGN_CURSOR (horizontal_drag_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_EAST_WEST));
- ASSIGN_CURSOR (vertical_drag_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_NORTH_SOUTH));
- ASSIGN_CURSOR (left_edge_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_WEST));
- ASSIGN_CURSOR (top_left_corner_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_NORTH_WEST));
- ASSIGN_CURSOR (top_edge_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_NORTH));
- ASSIGN_CURSOR (top_right_corner_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_NORTH_EAST));
- ASSIGN_CURSOR (right_edge_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_EAST));
- ASSIGN_CURSOR (bottom_right_corner_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_EAST));
- ASSIGN_CURSOR (bottom_edge_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_SOUTH));
- ASSIGN_CURSOR (bottom_left_corner_cursor,
- BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_WEST));
- ASSIGN_CURSOR (no_cursor,
- BCursor_from_id (CURSOR_ID_NO_CURSOR));
+#define ASSIGN_CURSOR(cursor, cursor_id) \
+ (dpyinfo->cursor = be_create_cursor_from_id (cursor_id))
+ ASSIGN_CURSOR (text_cursor, CURSOR_ID_I_BEAM);
+ ASSIGN_CURSOR (nontext_cursor, CURSOR_ID_SYSTEM_DEFAULT);
+ ASSIGN_CURSOR (modeline_cursor, CURSOR_ID_CONTEXT_MENU);
+ ASSIGN_CURSOR (hand_cursor, CURSOR_ID_GRAB);
+ ASSIGN_CURSOR (hourglass_cursor, CURSOR_ID_PROGRESS);
+ ASSIGN_CURSOR (horizontal_drag_cursor, CURSOR_ID_RESIZE_EAST_WEST);
+ ASSIGN_CURSOR (vertical_drag_cursor, CURSOR_ID_RESIZE_NORTH_SOUTH);
+ ASSIGN_CURSOR (left_edge_cursor, CURSOR_ID_RESIZE_WEST);
+ ASSIGN_CURSOR (top_left_corner_cursor, CURSOR_ID_RESIZE_NORTH_WEST);
+ ASSIGN_CURSOR (top_edge_cursor, CURSOR_ID_RESIZE_NORTH);
+ ASSIGN_CURSOR (top_right_corner_cursor, CURSOR_ID_RESIZE_NORTH_EAST);
+ ASSIGN_CURSOR (right_edge_cursor, CURSOR_ID_RESIZE_EAST);
+ ASSIGN_CURSOR (bottom_right_corner_cursor, CURSOR_ID_RESIZE_SOUTH_EAST);
+ ASSIGN_CURSOR (bottom_edge_cursor, CURSOR_ID_RESIZE_SOUTH);
+ ASSIGN_CURSOR (bottom_left_corner_cursor, CURSOR_ID_RESIZE_SOUTH_WEST);
+ ASSIGN_CURSOR (no_cursor, CURSOR_ID_NO_CURSOR);
#undef ASSIGN_CURSOR
system_name = Fsystem_name ();
@@ -4082,9 +4435,15 @@ mark_haiku_display (void)
void
haiku_scroll_bar_remove (struct scroll_bar *bar)
{
+ void *view;
+ struct frame *f;
+
+ f = WINDOW_XFRAME (XWINDOW (bar->window));
+ view = FRAME_HAIKU_VIEW (f);
+
block_input ();
- void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window)));
- BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height);
+ BView_forget_scroll_bar (view, bar->left, bar->top,
+ bar->width, bar->height);
BScrollBar_delete (bar->scroll_bar);
expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)),
bar->left, bar->top, bar->width, bar->height);
@@ -4093,7 +4452,6 @@ haiku_scroll_bar_remove (struct scroll_bar *bar)
wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
else
wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
-
unblock_input ();
};
@@ -4101,6 +4459,22 @@ void
haiku_set_offset (struct frame *frame, int x, int y,
int change_gravity)
{
+ Lisp_Object lframe;
+
+ /* Don't allow moving a fullscreen frame: the semantics of that are
+ unclear. */
+
+ XSETFRAME (lframe, frame);
+ if (EQ (Fframe_parameter (lframe, Qfullscreen), Qfullboth)
+ /* Only do this if the fullscreen status has actually been
+ applied. */
+ && frame->want_fullscreen == FULLSCREEN_NONE
+ /* And if the configury during frame creation has been
+ completed. Otherwise, there will be no valid "old position"
+ to go back to. */
+ && FRAME_OUTPUT_DATA (frame)->configury_done)
+ return;
+
if (change_gravity > 0)
{
frame->top_pos = y;
@@ -4160,7 +4534,7 @@ haiku_merge_cursor_foreground (struct glyph_string *s,
foreground = s->face->foreground;
if (background == s->face->background
- || foreground == s->face->foreground)
+ && foreground == s->face->foreground)
{
background = s->face->foreground;
foreground = s->face->background;
diff --git a/src/haikuterm.h b/src/haikuterm.h
index 30b474b1e1d..ea20289b5d1 100644
--- a/src/haikuterm.h
+++ b/src/haikuterm.h
@@ -52,6 +52,10 @@ struct haiku_bitmap_record
char *file;
int refcount;
int height, width, depth;
+
+ uint32_t stipple_foreground;
+ uint32_t stipple_background;
+ void *stipple_bits;
};
struct haiku_display_info
@@ -156,13 +160,16 @@ struct haiku_output
int fontset;
int baseline_offset;
- bool_bf zoomed_p : 1;
+ /* Whether or not the hourglass cursor is currently being
+ displayed. */
bool_bf hourglass_p : 1;
+
+ /* Whether or not the menu bar is open. */
bool_bf menu_bar_open_p : 1;
/* Whether or not there is data in a back buffer that hasn't been
displayed yet. */
- bool dirty_p;
+ bool_bf dirty_p : 1;
struct font *font;
@@ -192,6 +199,15 @@ struct haiku_output
They are changed only when a different background is involved.
-1 means no color has been computed. */
long relief_background;
+
+ /* The absolute position of this frame. This differs from left_pos
+ and top_pos in that the decorator and parent frames are not taken
+ into account. */
+ int frame_x, frame_y;
+
+ /* The current fullscreen mode of this frame. This should be `enum
+ haiku_fullscreen_mode', but that isn't available here. */
+ int fullscreen_mode;
};
struct x_output
@@ -203,7 +219,13 @@ extern struct haiku_display_info *x_display_list;
extern struct font_driver const haikufont_driver;
extern Lisp_Object tip_frame;
+extern Lisp_Object tip_dx;
+extern Lisp_Object tip_dy;
+
extern struct frame *haiku_dnd_frame;
+extern bool haiku_dnd_follow_tooltip;
+
+extern frame_parm_handler haiku_frame_parm_handlers[];
struct scroll_bar
{
@@ -298,6 +320,7 @@ extern void haiku_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
extern void haiku_set_internal_border_width (struct frame *, Lisp_Object, Lisp_Object);
extern void haiku_change_tab_bar_height (struct frame *, int);
extern void haiku_change_tool_bar_height (struct frame *, int);
+extern void haiku_free_custom_cursors (struct frame *);
extern void haiku_query_color (uint32_t, Emacs_Color *);
@@ -323,6 +346,9 @@ extern int haiku_load_image (struct frame *, struct image *,
extern void syms_of_haikuimage (void);
#endif
+extern void haiku_draw_background_rect (struct glyph_string *, struct face *,
+ int, int, int, int);
+
#ifdef USE_BE_CAIRO
extern cairo_t *haiku_begin_cr_clip (struct frame *, struct glyph_string *);
diff --git a/src/image.c b/src/image.c
index e4b56e29cff..058c1755704 100644
--- a/src/image.c
+++ b/src/image.c
@@ -542,12 +542,26 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
#endif /* HAVE_PGTK */
#ifdef HAVE_HAIKU
- void *bitmap = BBitmap_new (width, height, 1);
+ void *bitmap, *stipple;
+ int bytes_per_line, x, y;
+
+ bitmap = BBitmap_new (width, height, false);
if (!bitmap)
return -1;
- BBitmap_import_mono_bits (bitmap, bits, width, height);
+ bytes_per_line = (width + 7) / 8;
+ stipple = xmalloc (height * bytes_per_line);
+ memcpy (stipple, bits, height * bytes_per_line);
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ PUT_PIXEL (bitmap, x, y, ((bits[8] >> (x % 8)) & 1
+ ? f->foreground_pixel
+ : f->background_pixel));
+ bits += bytes_per_line;
+ }
#endif
id = image_allocate_bitmap_record (f);
@@ -567,6 +581,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
#ifdef HAVE_HAIKU
dpyinfo->bitmaps[id - 1].img = bitmap;
dpyinfo->bitmaps[id - 1].depth = 1;
+ dpyinfo->bitmaps[id - 1].stipple_bits = stipple;
+ dpyinfo->bitmaps[id - 1].stipple_foreground
+ = f->foreground_pixel & 0xffffffff;
+ dpyinfo->bitmaps[id - 1].stipple_background
+ = f->background_pixel & 0xffffffff;
#endif
dpyinfo->bitmaps[id - 1].file = NULL;
@@ -592,24 +611,55 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
return id;
}
+#if defined HAVE_HAIKU || defined HAVE_NS
+static char *slurp_file (int, ptrdiff_t *);
+static Lisp_Object image_find_image_fd (Lisp_Object, int *);
+static bool xbm_read_bitmap_data (struct frame *, char *, char *,
+ int *, int *, char **, bool);
+#endif
+
/* Create bitmap from file FILE for frame F. */
ptrdiff_t
image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
{
-#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
+#if defined (HAVE_NTGUI)
return -1; /* W32_TODO : bitmap support */
#else
Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
#endif
#ifdef HAVE_NS
- ptrdiff_t id;
- void *bitmap = ns_image_from_file (file);
+ ptrdiff_t id, size;
+ int fd, width, height, rc;
+ char *contents, *data;
+ void *bitmap;
- if (!bitmap)
+ if (!STRINGP (image_find_image_fd (file, &fd)))
+ return -1;
+
+ contents = slurp_file (fd, &size);
+
+ if (!contents)
+ return -1;
+
+ rc = xbm_read_bitmap_data (f, contents, contents + size,
+ &width, &height, &data, 0);
+
+ if (!rc)
+ {
+ xfree (contents);
return -1;
+ }
+ bitmap = ns_image_from_XBM (data, width, height, 0, 0);
+
+ if (!bitmap)
+ {
+ xfree (contents);
+ xfree (data);
+ return -1;
+ }
id = image_allocate_bitmap_record (f);
dpyinfo->bitmaps[id - 1].img = bitmap;
@@ -618,6 +668,9 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
+
+ xfree (contents);
+ xfree (data);
return id;
#endif
@@ -637,7 +690,6 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
dpyinfo->bitmaps[id - 1].img = bitmap;
dpyinfo->bitmaps[id - 1].refcount = 1;
dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
- //dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = gdk_pixbuf_get_width (bitmap);
dpyinfo->bitmaps[id - 1].width = gdk_pixbuf_get_height (bitmap);
dpyinfo->bitmaps[id - 1].pattern
@@ -692,6 +744,89 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
return id;
#endif /* HAVE_X_WINDOWS */
+
+#ifdef HAVE_HAIKU
+ ptrdiff_t id, size;
+ int fd, width, height, rc, bytes_per_line, x, y;
+ char *contents, *data, *tmp;
+ void *bitmap;
+ Lisp_Object found;
+
+ /* Look for an existing bitmap with the same name. */
+ for (id = 0; id < dpyinfo->bitmaps_last; ++id)
+ {
+ if (dpyinfo->bitmaps[id].refcount
+ && dpyinfo->bitmaps[id].file
+ && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
+ {
+ ++dpyinfo->bitmaps[id].refcount;
+ return id + 1;
+ }
+ }
+
+ /* Search bitmap-file-path for the file, if appropriate. */
+ if (openp (Vx_bitmap_file_path, file, Qnil, &found,
+ make_fixnum (R_OK), false, false)
+ < 0)
+ return -1;
+
+ if (!STRINGP (image_find_image_fd (file, &fd))
+ && !STRINGP (image_find_image_fd (found, &fd)))
+ return -1;
+
+ contents = slurp_file (fd, &size);
+
+ if (!contents)
+ return -1;
+
+ rc = xbm_read_bitmap_data (f, contents, contents + size,
+ &width, &height, &data, 0);
+
+ if (!rc)
+ {
+ xfree (contents);
+ return -1;
+ }
+
+ bitmap = BBitmap_new (width, height, false);
+
+ if (!bitmap)
+ {
+ xfree (contents);
+ xfree (data);
+ return -1;
+ }
+
+ id = image_allocate_bitmap_record (f);
+
+ dpyinfo->bitmaps[id - 1].img = bitmap;
+ dpyinfo->bitmaps[id - 1].depth = 1;
+ dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
+ dpyinfo->bitmaps[id - 1].height = height;
+ dpyinfo->bitmaps[id - 1].width = width;
+ dpyinfo->bitmaps[id - 1].refcount = 1;
+ dpyinfo->bitmaps[id - 1].stipple_foreground
+ = f->foreground_pixel & 0xffffffff;
+ dpyinfo->bitmaps[id - 1].stipple_background
+ = f->background_pixel & 0xffffffff;
+ dpyinfo->bitmaps[id - 1].stipple_bits = data;
+
+ bytes_per_line = (width + 7) / 8;
+ tmp = data;
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ PUT_PIXEL (bitmap, x, y, ((tmp[x / 8] >> (x % 8)) & 1
+ ? f->foreground_pixel
+ : f->background_pixel));
+
+ tmp += bytes_per_line;
+ }
+
+ xfree (contents);
+ return id;
+#endif
}
/* Free bitmap B. */
@@ -724,6 +859,9 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
#ifdef HAVE_HAIKU
BBitmap_free (bm->img);
+
+ if (bm->stipple_bits)
+ xfree (bm->stipple_bits);
#endif
if (bm->file)
@@ -6169,7 +6307,7 @@ image_edge_detection (struct frame *f, struct image *img,
}
-#if defined HAVE_X_WINDOWS || defined USE_CAIRO
+#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU
static void
image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap,
int x, int y, unsigned int width, unsigned int height,
@@ -6203,9 +6341,11 @@ image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap,
XDrawLine (dpy, pixmap, gc, x, y, x + width - 1, y + height - 1);
XDrawLine (dpy, pixmap, gc, x, y + height - 1, x + width - 1, y);
XFreeGC (dpy, gc);
-#endif /* HAVE_X_WINDOWS */
+#elif HAVE_HAIKU
+ be_draw_cross_on_pixmap (pixmap, x, y, width, height, color);
+#endif
}
-#endif /* HAVE_X_WINDOWS || USE_CAIRO */
+#endif /* HAVE_X_WINDOWS || USE_CAIRO || HAVE_HAIKU */
/* Transform image IMG on frame F so that it looks disabled. */
@@ -6247,25 +6387,23 @@ image_disable_image (struct frame *f, struct image *img)
{
#ifndef HAVE_NTGUI
#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */
-#ifndef HAVE_HAIKU
-#ifndef USE_CAIRO
+#if !defined USE_CAIRO && !defined HAVE_HAIKU
#define CrossForeground(f) BLACK_PIX_DEFAULT (f)
#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
-#else /* USE_CAIRO */
+#else /* USE_CAIRO || HAVE_HAIKU */
#define CrossForeground(f) 0
#define MaskForeground(f) PIX_MASK_DRAW
-#endif /* USE_CAIRO */
+#endif /* USE_CAIRO || HAVE_HAIKU */
-#ifndef USE_CAIRO
+#if !defined USE_CAIRO && !defined HAVE_HAIKU
image_sync_to_pixmaps (f, img);
-#endif /* !USE_CAIRO */
+#endif /* !USE_CAIRO && !HAVE_HAIKU */
image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height,
CrossForeground (f));
if (img->mask)
image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height,
MaskForeground (f));
-#endif /* !HAVE_HAIKU */
#endif /* !HAVE_NS */
#else
HDC hdc, bmpdc;
@@ -8970,7 +9108,7 @@ gif_load (struct frame *f, struct image *img)
goto gif_error;
}
- /* It's an animated image, so initalize the cache. */
+ /* It's an animated image, so initialize the cache. */
if (cache && !cache->handle)
{
cache->handle = gif;
diff --git a/src/indent.c b/src/indent.c
index acbb9dc9723..51f6f414de3 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -1204,7 +1204,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
/* Negative width means use all available text columns. */
if (width < 0)
{
- width = window_body_width (win, 0);
+ width = window_body_width (win, WINDOW_BODY_IN_CANONICAL_CHARS);
/* We must make room for continuation marks if we don't have fringes. */
#ifdef HAVE_WINDOW_SYSTEM
if (!FRAME_WINDOW_P (XFRAME (win->frame)))
@@ -1814,7 +1814,7 @@ visible section of the buffer, and pass LINE and COL as TOPOS. */)
? window_internal_height (w)
: XFIXNUM (XCDR (topos))),
(NILP (topos)
- ? (window_body_width (w, 0)
+ ? (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS)
- (
#ifdef HAVE_WINDOW_SYSTEM
FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
diff --git a/src/intervals.c b/src/intervals.c
index 687b237b9ea..9e28637d6bc 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -121,7 +121,6 @@ copy_properties (INTERVAL source, INTERVAL target)
{
if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
return;
- eassume (source && target);
COPY_INTERVAL_CACHE (source, target);
set_interval_plist (target, Fcopy_sequence (source->plist));
diff --git a/src/intervals.h b/src/intervals.h
index 484fca2e756..0ce581208e3 100644
--- a/src/intervals.h
+++ b/src/intervals.h
@@ -251,7 +251,7 @@ extern void traverse_intervals_noorder (INTERVAL,
void (*) (INTERVAL, void *), void *);
extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t)
ATTRIBUTE_RETURNS_NONNULL;
-extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t);
+extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t) ATTRIBUTE_RETURNS_NONNULL;
extern INTERVAL find_interval (INTERVAL, ptrdiff_t);
extern INTERVAL next_interval (INTERVAL);
extern INTERVAL previous_interval (INTERVAL);
diff --git a/src/json.c b/src/json.c
index 957f91b46bb..4b3fabb3eb3 100644
--- a/src/json.c
+++ b/src/json.c
@@ -364,7 +364,7 @@ lisp_to_json_nonscalar_1 (Lisp_Object lisp,
for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
{
Lisp_Object key = HASH_KEY (h, i);
- if (!EQ (key, Qunbound))
+ if (!BASE_EQ (key, Qunbound))
{
CHECK_STRING (key);
Lisp_Object ekey = json_encode (key);
diff --git a/src/keyboard.c b/src/keyboard.c
index 70908120cb0..55d710ed627 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -95,8 +95,6 @@ volatile int interrupt_input_blocked;
The maybe_quit function checks this. */
volatile bool pending_signals;
-enum { KBD_BUFFER_SIZE = 4096 };
-
KBOARD *initial_kboard;
KBOARD *current_kboard;
static KBOARD *all_kboards;
@@ -290,14 +288,14 @@ bool input_was_pending;
/* Circular buffer for pre-read keyboard input. */
-static union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
+union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
/* Pointer to next available character in kbd_buffer.
If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. */
-static union buffered_input_event *kbd_fetch_ptr;
+union buffered_input_event *kbd_fetch_ptr;
/* Pointer to next place to store character in kbd_buffer. */
-static union buffered_input_event *kbd_store_ptr;
+union buffered_input_event *kbd_store_ptr;
/* The above pair of variables forms a "queue empty" flag. When we
enqueue a non-hook event, we increment kbd_store_ptr. When we
@@ -391,14 +389,6 @@ next_kbd_event (union buffered_input_event *ptr)
return ptr == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : ptr + 1;
}
-#ifdef HAVE_X11
-static union buffered_input_event *
-prev_kbd_event (union buffered_input_event *ptr)
-{
- return ptr == kbd_buffer ? kbd_buffer + KBD_BUFFER_SIZE - 1 : ptr - 1;
-}
-#endif
-
/* Like EVENT_START, but assume EVENT is an event.
This pacifies gcc -Wnull-dereference, which might otherwise
complain about earlier checks that EVENT is indeed an event. */
@@ -3530,6 +3520,11 @@ readable_events (int flags)
return 1;
}
+#ifdef HAVE_X_WINDOWS
+ if (x_detect_pending_selection_requests ())
+ return 1;
+#endif
+
if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ())
return 1;
if (single_kboard)
@@ -3701,25 +3696,6 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event,
Vquit_flag = Vthrow_on_input;
}
-
-#ifdef HAVE_X11
-
-/* Put a selection input event back in the head of the event queue. */
-
-void
-kbd_buffer_unget_event (struct selection_input_event *event)
-{
- /* Don't let the very last slot in the buffer become full, */
- union buffered_input_event *kp = prev_kbd_event (kbd_fetch_ptr);
- if (kp != kbd_store_ptr)
- {
- kp->sie = *event;
- kbd_fetch_ptr = kp;
- }
-}
-
-#endif
-
/* Limit help event positions to this range, to avoid overflow problems. */
#define INPUT_EVENT_POS_MAX \
((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \
@@ -3876,6 +3852,11 @@ kbd_buffer_get_event (KBOARD **kbp,
struct timespec *end_time)
{
Lisp_Object obj, str;
+#ifdef HAVE_X_WINDOWS
+ bool had_pending_selection_requests;
+
+ had_pending_selection_requests = false;
+#endif
#ifdef subprocesses
if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4)
@@ -3928,10 +3909,18 @@ kbd_buffer_get_event (KBOARD **kbp,
#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
gobble_input ();
#endif
+
if (kbd_fetch_ptr != kbd_store_ptr)
break;
if (some_mouse_moved ())
break;
+#ifdef HAVE_X_WINDOWS
+ if (x_detect_pending_selection_requests ())
+ {
+ had_pending_selection_requests = true;
+ break;
+ }
+#endif
if (end_time)
{
struct timespec now = current_timespec ();
@@ -3968,6 +3957,16 @@ kbd_buffer_get_event (KBOARD **kbp,
gobble_input ();
}
+#ifdef HAVE_X_WINDOWS
+ /* Handle pending selection requests. This can happen if Emacs
+ enters a recursive edit inside a nested event loop (probably
+ because the debugger opened) or someone called
+ `read-char'. */
+
+ if (had_pending_selection_requests)
+ x_handle_pending_selection_requests ();
+#endif
+
if (CONSP (Vunread_command_events))
{
Lisp_Object first;
@@ -4022,6 +4021,11 @@ kbd_buffer_get_event (KBOARD **kbp,
kbd_fetch_ptr = next_kbd_event (event);
input_pending = readable_events (0);
+ /* This means this event was already handled in
+ `x_dnd_begin_drag_and_drop'. */
+ if (event->ie.modifiers < x_dnd_unsupported_event_level)
+ break;
+
f = XFRAME (event->ie.frame_or_window);
if (!FRAME_LIVE_P (f))
@@ -4029,14 +4033,20 @@ kbd_buffer_get_event (KBOARD **kbp,
if (!NILP (Vx_dnd_unsupported_drop_function))
{
- if (!NILP (call6 (Vx_dnd_unsupported_drop_function,
+ if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
XCAR (XCDR (event->ie.arg)), event->ie.x,
event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
make_uint (event->ie.code),
- event->ie.frame_or_window)))
+ event->ie.frame_or_window,
+ make_int (event->ie.timestamp))))
break;
}
+ /* `x-dnd-unsupported-drop-function' could have deleted the
+ event frame. */
+ if (!FRAME_LIVE_P (f))
+ break;
+
x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f),
event->ie.frame_or_window,
XCAR (event->ie.arg),
@@ -4049,6 +4059,18 @@ kbd_buffer_get_event (KBOARD **kbp,
}
#endif
+ case MONITORS_CHANGED_EVENT:
+ {
+ kbd_fetch_ptr = next_kbd_event (event);
+ input_pending = readable_events (0);
+
+ CALLN (Frun_hook_with_args,
+ Qdisplay_monitors_changed_functions,
+ event->ie.arg);
+
+ break;
+ }
+
#ifdef HAVE_EXT_MENU_BAR
case MENU_BAR_ACTIVATE_EVENT:
{
@@ -4324,6 +4346,10 @@ kbd_buffer_get_event (KBOARD **kbp,
? movement_frame->last_mouse_device
: virtual_core_pointer_name);
}
+#ifdef HAVE_X_WINDOWS
+ else if (had_pending_selection_requests)
+ obj = Qnil;
+#endif
else
/* We were promised by the above while loop that there was
something for us to read! */
@@ -7220,7 +7246,10 @@ lucid_event_type_list_p (Lisp_Object object)
If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal
events (FOCUS_IN_EVENT).
If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse
- movements and toolkit scroll bar thumb drags. */
+ movements and toolkit scroll bar thumb drags.
+
+ On X, this also returns if the selection event chain is full, since
+ that's also "keyboard input". */
static bool
get_input_pending (int flags)
@@ -12600,6 +12629,8 @@ See also `pre-command-hook'. */);
DEFSYM (Qtouchscreen_end, "touchscreen-end");
DEFSYM (Qtouchscreen_update, "touchscreen-update");
DEFSYM (Qpinch, "pinch");
+ DEFSYM (Qdisplay_monitors_changed_functions,
+ "display-monitors-changed-functions");
DEFSYM (Qcoding, "coding");
@@ -12840,6 +12871,14 @@ Called with three arguments:
- the context (a string which normally goes at the start of the message),
- the Lisp function within which the error was signaled.
+For instance, to make error messages stand out more in the echo area,
+you could say something like:
+
+ (setq command-error-function
+ (lambda (data _ _)
+ (message "%s" (propertize (error-message-string data)
+ \\='face \\='error))))
+
Also see `set-message-function' (which controls how non-error messages
are displayed). */);
Vcommand_error_function = intern ("command-error-default-function");
@@ -12854,11 +12893,12 @@ and tool-bar buttons. */);
DEFVAR_LISP ("select-active-regions",
Vselect_active_regions,
- doc: /* If non-nil, an active region automatically sets the primary selection.
-If the value is `only', only temporarily active regions (usually made
-by mouse-dragging or shift-selection) set the window selection.
+ doc: /* If non-nil, any active region automatically sets the primary selection.
+This variable only has an effect when Transient Mark mode is enabled.
-This takes effect only when Transient Mark mode is enabled. */);
+If the value is `only', only temporarily active regions (usually made
+by mouse-dragging or shift-selection) set the window system's primary
+selection. */);
Vselect_active_regions = Qt;
DEFVAR_LISP ("saved-region-selection",
@@ -12943,6 +12983,15 @@ Otherwise, a wheel event will be sent every time the mouse wheel is
moved. */);
mwheel_coalesce_scroll_events = true;
+ DEFVAR_LISP ("display-monitors-changed-functions", Vdisplay_monitors_changed_functions,
+ doc: /* Abnormal hook run when the monitor configuration changes.
+This can happen if a monitor is rotated, moved, plugged in or removed
+from a multi-monitor setup, if the primary monitor changes, or if the
+resolution of a monitor changes. The hook should accept a single
+argument, which is the terminal on which the monitor configuration
+changed. */);
+ Vdisplay_monitors_changed_functions = Qnil;
+
pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
}
diff --git a/src/keyboard.h b/src/keyboard.h
index cd5f677b963..6ae2dc9c4c6 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -358,6 +358,11 @@ enum menu_item_idx
MENU_ITEMS_ITEM_LENGTH
};
+enum
+ {
+ KBD_BUFFER_SIZE = 4096
+ };
+
extern void unuse_menu_items (void);
/* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
@@ -419,6 +424,10 @@ extern void unuse_menu_items (void);
happens. */
extern struct timespec *input_available_clear_time;
+extern union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
+extern union buffered_input_event *kbd_fetch_ptr;
+extern union buffered_input_event *kbd_store_ptr;
+
extern bool ignore_mouse_drag_p;
extern Lisp_Object parse_modifiers (Lisp_Object);
@@ -472,9 +481,6 @@ kbd_buffer_store_event_hold (struct input_event *event,
kbd_buffer_store_buffered_event ((union buffered_input_event *) event,
hold_quit);
}
-#ifdef HAVE_X11
-extern void kbd_buffer_unget_event (struct selection_input_event *);
-#endif
extern void poll_for_input_1 (void);
extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object);
diff --git a/src/keymap.c b/src/keymap.c
index da0a52bd2c1..c8b01eed6fd 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -395,7 +395,7 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
if (noinherit || NILP (retval))
/* If NOINHERIT, stop here, the rest is inherited. */
break;
- else if (!EQ (retval, Qunbound))
+ else if (!BASE_EQ (retval, Qunbound))
{
Lisp_Object parent_entry;
eassert (KEYMAPP (retval));
@@ -454,7 +454,7 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
}
/* If we found a binding, clean it up and return it. */
- if (!EQ (val, Qunbound))
+ if (!BASE_EQ (val, Qunbound))
{
if (EQ (val, Qt))
/* A Qt binding is just like an explicit nil binding
@@ -466,12 +466,12 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
if (!KEYMAPP (val))
{
- if (NILP (retval) || EQ (retval, Qunbound))
+ if (NILP (retval) || BASE_EQ (retval, Qunbound))
retval = val;
if (!NILP (val))
break; /* Shadows everything that follows. */
}
- else if (NILP (retval) || EQ (retval, Qunbound))
+ else if (NILP (retval) || BASE_EQ (retval, Qunbound))
retval = val;
else if (CONSP (retval_tail))
{
@@ -487,7 +487,8 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
maybe_quit ();
}
- return EQ (Qunbound, retval) ? get_keyelt (t_binding, autoload) : retval;
+ return BASE_EQ (Qunbound, retval)
+ ? get_keyelt (t_binding, autoload) : retval;
}
}
@@ -496,7 +497,7 @@ access_keymap (Lisp_Object map, Lisp_Object idx,
bool t_ok, bool noinherit, bool autoload)
{
Lisp_Object val = access_keymap_1 (map, idx, t_ok, noinherit, autoload);
- return EQ (val, Qunbound) ? Qnil : val;
+ return BASE_EQ (val, Qunbound) ? Qnil : val;
}
static void
@@ -1550,7 +1551,7 @@ current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr)
for ( ; CONSP (alist); alist = XCDR (alist))
if ((assoc = XCAR (alist), CONSP (assoc))
&& (var = XCAR (assoc), SYMBOLP (var))
- && (val = find_symbol_value (var), !EQ (val, Qunbound))
+ && (val = find_symbol_value (var), !BASE_EQ (val, Qunbound))
&& !NILP (val))
{
Lisp_Object temp;
diff --git a/src/lisp.h b/src/lisp.h
index 8832e76b447..361a3f63b28 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -621,7 +621,6 @@ extern Lisp_Object char_table_ref (Lisp_Object, int) ATTRIBUTE_PURE;
extern void char_table_set (Lisp_Object, int, Lisp_Object);
/* Defined in data.c. */
-extern bool symbols_with_pos_enabled;
extern AVOID args_out_of_range_3 (Lisp_Object, Lisp_Object, Lisp_Object);
extern AVOID wrong_type_argument (Lisp_Object, Lisp_Object);
extern Lisp_Object default_value (Lisp_Object symbol);
@@ -2097,19 +2096,17 @@ XSUB_CHAR_TABLE (Lisp_Object a)
INLINE Lisp_Object
CHAR_TABLE_REF_ASCII (Lisp_Object ct, ptrdiff_t idx)
{
- struct Lisp_Char_Table *tbl = NULL;
- Lisp_Object val;
- do
+ for (struct Lisp_Char_Table *tbl = XCHAR_TABLE (ct); ;
+ tbl = XCHAR_TABLE (tbl->parent))
{
- tbl = tbl ? XCHAR_TABLE (tbl->parent) : XCHAR_TABLE (ct);
- val = (! SUB_CHAR_TABLE_P (tbl->ascii) ? tbl->ascii
- : XSUB_CHAR_TABLE (tbl->ascii)->contents[idx]);
+ Lisp_Object val = (SUB_CHAR_TABLE_P (tbl->ascii)
+ ? XSUB_CHAR_TABLE (tbl->ascii)->contents[idx]
+ : tbl->ascii);
if (NILP (val))
val = tbl->defalt;
+ if (!NILP (val) || NILP (tbl->parent))
+ return val;
}
- while (NILP (val) && ! NILP (tbl->parent));
-
- return val;
}
/* Almost equivalent to Faref (CT, IDX) with optimization for ASCII
@@ -3639,6 +3636,10 @@ struct handler
struct bc_frame *act_rec;
int poll_suppress_count;
int interrupt_input_blocked;
+
+#ifdef HAVE_X_WINDOWS
+ int x_error_handler_depth;
+#endif
};
extern Lisp_Object memory_signal_data;
@@ -4492,6 +4493,7 @@ extern void dir_warning (const char *, Lisp_Object);
extern void init_obarray_once (void);
extern void init_lread (void);
extern void syms_of_lread (void);
+extern void mark_lread (void);
INLINE Lisp_Object
intern (const char *str)
@@ -5098,9 +5100,7 @@ extern void syms_of_w32cygwinx (void);
extern Lisp_Object Vface_alternative_font_family_alist;
extern Lisp_Object Vface_alternative_font_registry_alist;
extern void syms_of_xfaces (void);
-#ifdef HAVE_PDUMPER
extern void init_xfaces (void);
-#endif
#ifdef HAVE_X_WINDOWS
/* Defined in xfns.c. */
@@ -5503,7 +5503,7 @@ struct for_each_tail_internal
intended for use only by the above macros.
Use Brent’s teleporting tortoise-hare algorithm. See:
- Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190
+ Brent RP. BIT. 1980;20(2):176-184. doi:10.1007/BF01933190
https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf
This macro uses maybe_quit because of an excess of caution. The
@@ -5520,7 +5520,7 @@ struct for_each_tail_internal
|| ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \
|| (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \
li.tortoise = (tail), false)) \
- && EQ (tail, li.tortoise)) \
+ && BASE_EQ (tail, li.tortoise)) \
? (cycle) : (void) 0))
/* Do a `for' loop over alist values. */
diff --git a/src/lread.c b/src/lread.c
index f1ffdef04e4..dfabe75113e 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -656,10 +656,6 @@ struct subst
static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object,
Lisp_Object, bool);
static Lisp_Object read0 (Lisp_Object, bool);
-static Lisp_Object read1 (Lisp_Object, int *, bool, bool);
-
-static Lisp_Object read_list (bool, Lisp_Object, bool);
-static Lisp_Object read_vector (Lisp_Object, bool, bool);
static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object);
static void substitute_in_interval (INTERVAL, void *);
@@ -940,7 +936,7 @@ lisp_file_lexically_bound_p (Lisp_Object readcharfun)
ch = READCHAR;
if (ch == '\n') ch = READCHAR;
/* It is OK to leave the position after a #! line, since
- that is what read1 does. */
+ that is what read0 does. */
}
if (ch != ';')
@@ -1248,10 +1244,9 @@ Return t if the file exists and loads successfully. */)
CHECK_STRING (file);
/* If file name is magic, call the handler. */
- /* This shouldn't be necessary any more now that `openp' handles it right.
- handler = Ffind_file_name_handler (file, Qload);
- if (!NILP (handler))
- return call5 (handler, Qload, file, noerror, nomessage, nosuffix); */
+ handler = Ffind_file_name_handler (file, Qload);
+ if (!NILP (handler))
+ return call5 (handler, Qload, file, noerror, nomessage, nosuffix);
/* The presence of this call is the result of a historical accident:
it used to be in every file-operation and when it got removed
@@ -2221,7 +2216,7 @@ readevalloop (Lisp_Object readcharfun,
lexical environment, otherwise, turn off lexical binding. */
lex_bound = find_symbol_value (Qlexical_binding);
specbind (Qinternal_interpreter_environment,
- (NILP (lex_bound) || EQ (lex_bound, Qunbound)
+ (NILP (lex_bound) || BASE_EQ (lex_bound, Qunbound)
? Qnil : list1 (Qt)));
specbind (Qmacroexp__dynvars, Vmacroexp__dynvars);
@@ -2286,6 +2281,7 @@ readevalloop (Lisp_Object readcharfun,
if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r'
|| c == NO_BREAK_SPACE)
goto read_next;
+ UNREAD (c);
if (! HASH_TABLE_P (read_objects_map)
|| XHASH_TABLE (read_objects_map)->count)
@@ -2300,12 +2296,9 @@ readevalloop (Lisp_Object readcharfun,
DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
Qnil, false);
if (!NILP (Vpurify_flag) && c == '(')
- {
- val = read_list (0, readcharfun, false);
- }
+ val = read0 (readcharfun, false);
else
{
- UNREAD (c);
if (!NILP (readfun))
{
val = call1 (readfun, readcharfun);
@@ -2349,7 +2342,7 @@ readevalloop (Lisp_Object readcharfun,
{
Vvalues = Fcons (val, Vvalues);
if (EQ (Vstandard_output, Qt))
- Fprin1 (val, Qnil);
+ Fprin1 (val, Qnil, Qnil);
else
Fprint (val, Qnil);
}
@@ -2582,24 +2575,6 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end,
return retval;
}
-
-/* Use this for recursive reads, in contexts where internal tokens
- are not allowed. */
-
-static Lisp_Object
-read0 (Lisp_Object readcharfun, bool locate_syms)
-{
- register Lisp_Object val;
- int c;
-
- val = read1 (readcharfun, &c, 0, locate_syms);
- if (!c)
- return val;
-
- invalid_syntax_lisp (Fmake_string (make_fixnum (1), make_fixnum (c), Qnil),
- readcharfun);
-}
-
/* Grow a read buffer BUF that contains OFFSET useful bytes of data,
by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and
*BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is
@@ -2658,7 +2633,7 @@ enum { UNICODE_CHARACTER_NAME_LENGTH_BOUND = 200 };
If the escape sequence forces unibyte, return eight-bit char. */
static int
-read_escape (Lisp_Object readcharfun, bool stringp)
+read_escape (Lisp_Object readcharfun)
{
int c = READCHAR;
/* \u allows up to four hex digits, \U up to eight. Default to the
@@ -2688,12 +2663,10 @@ read_escape (Lisp_Object readcharfun, bool stringp)
return '\t';
case 'v':
return '\v';
+
case '\n':
- return -1;
- case ' ':
- if (stringp)
- return -1;
- return ' ';
+ /* ?\LF is an error; it's probably a user mistake. */
+ error ("Invalid escape character syntax");
case 'M':
c = READCHAR;
@@ -2701,7 +2674,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
error ("Invalid escape character syntax");
c = READCHAR;
if (c == '\\')
- c = read_escape (readcharfun, 0);
+ c = read_escape (readcharfun);
return c | meta_modifier;
case 'S':
@@ -2710,7 +2683,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
error ("Invalid escape character syntax");
c = READCHAR;
if (c == '\\')
- c = read_escape (readcharfun, 0);
+ c = read_escape (readcharfun);
return c | shift_modifier;
case 'H':
@@ -2719,7 +2692,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
error ("Invalid escape character syntax");
c = READCHAR;
if (c == '\\')
- c = read_escape (readcharfun, 0);
+ c = read_escape (readcharfun);
return c | hyper_modifier;
case 'A':
@@ -2728,19 +2701,19 @@ read_escape (Lisp_Object readcharfun, bool stringp)
error ("Invalid escape character syntax");
c = READCHAR;
if (c == '\\')
- c = read_escape (readcharfun, 0);
+ c = read_escape (readcharfun);
return c | alt_modifier;
case 's':
c = READCHAR;
- if (stringp || c != '-')
+ if (c != '-')
{
UNREAD (c);
return ' ';
}
c = READCHAR;
if (c == '\\')
- c = read_escape (readcharfun, 0);
+ c = read_escape (readcharfun);
return c | super_modifier;
case 'C':
@@ -2751,7 +2724,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
case '^':
c = READCHAR;
if (c == '\\')
- c = read_escape (readcharfun, 0);
+ c = read_escape (readcharfun);
if ((c & ~CHAR_MODIFIER_MASK) == '?')
return 0177 | (c & CHAR_MODIFIER_MASK);
else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK)))
@@ -2902,8 +2875,8 @@ read_escape (Lisp_Object readcharfun, bool stringp)
invalid_syntax ("Empty character name", readcharfun);
name[length] = '\0';
- /* character_name_to_code can invoke read1, recursively.
- This is why read1's buffer is not static. */
+ /* character_name_to_code can invoke read0, recursively.
+ This is why read0's buffer is not static. */
return character_name_to_code (name, length, readcharfun);
}
@@ -2932,20 +2905,17 @@ digit_to_number (int character, int base)
return digit < base ? digit : -1;
}
-static char const invalid_radix_integer_format[] = "integer, radix %"pI"d";
-
-/* Small, as read1 is recursive (Bug#31995). But big enough to hold
- the invalid_radix_integer string. */
-enum { stackbufsize = max (64,
- (sizeof invalid_radix_integer_format
- - sizeof "%"pI"d"
- + INT_STRLEN_BOUND (EMACS_INT) + 1)) };
+/* Size of the fixed-size buffer used during reading.
+ It should be at least big enough for `invalid_radix_integer' but
+ can usefully be much bigger than that. */
+enum { stackbufsize = 1024 };
static void
invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)],
Lisp_Object readcharfun)
{
- sprintf (stackbuf, invalid_radix_integer_format, radix);
+ int n = snprintf (stackbuf, stackbufsize, "integer, radix %"pI"d", radix);
+ eassert (n < stackbufsize);
invalid_syntax (stackbuf, readcharfun);
}
@@ -3011,780 +2981,1110 @@ read_integer (Lisp_Object readcharfun, int radix,
*p = '\0';
return unbind_to (count, string_to_number (read_buffer, radix, NULL));
}
+
-/* If the next token is ')' or ']' or '.', we store that character
- in *PCH and the return value is not interesting. Else, we store
- zero in *PCH and we read and return one lisp object.
-
- FIRST_IN_LIST is true if this is the first element of a list.
- LOCATE_SYMS true means read symbol occurrences as symbols with
- position. */
-
+/* Read a character literal (preceded by `?'). */
static Lisp_Object
-read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms)
+read_char_literal (Lisp_Object readcharfun)
{
- int c;
- bool uninterned_symbol = false;
- bool skip_shorthand = false;
- bool multibyte;
- char stackbuf[stackbufsize];
- current_thread->stack_top = stackbuf;
+ int ch = READCHAR;
+ if (ch < 0)
+ end_of_file_error ();
- *pch = 0;
+ /* Accept `single space' syntax like (list ? x) where the
+ whitespace character is SPC or TAB.
+ Other literal whitespace like NL, CR, and FF are not accepted,
+ as there are well-established escape sequences for these. */
+ if (ch == ' ' || ch == '\t')
+ return make_fixnum (ch);
- retry:
+ if ( ch == '(' || ch == ')' || ch == '[' || ch == ']'
+ || ch == '"' || ch == ';')
+ {
+ CHECK_LIST (Vlread_unescaped_character_literals);
+ Lisp_Object char_obj = make_fixed_natnum (ch);
+ if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals)))
+ Vlread_unescaped_character_literals =
+ Fcons (char_obj, Vlread_unescaped_character_literals);
+ }
- c = READCHAR_REPORT_MULTIBYTE (&multibyte);
- if (c < 0)
- end_of_file_error ();
+ if (ch == '\\')
+ ch = read_escape (readcharfun);
- switch (c)
- {
- case '(':
- return read_list (0, readcharfun, locate_syms);
+ int modifiers = ch & CHAR_MODIFIER_MASK;
+ ch &= ~CHAR_MODIFIER_MASK;
+ if (CHAR_BYTE8_P (ch))
+ ch = CHAR_TO_BYTE8 (ch);
+ ch |= modifiers;
- case '[':
- return read_vector (readcharfun, 0, locate_syms);
+ int nch = READCHAR;
+ UNREAD (nch);
+ if (nch <= 32
+ || nch == '"' || nch == '\'' || nch == ';' || nch == '('
+ || nch == ')' || nch == '[' || nch == ']' || nch == '#'
+ || nch == '?' || nch == '`' || nch == ',' || nch == '.')
+ return make_fixnum (ch);
- case ')':
- case ']':
- {
- *pch = c;
- return Qnil;
- }
+ invalid_syntax ("?", readcharfun);
+}
- case '#':
- c = READCHAR;
- if (c == 's')
+/* Read a string literal (preceded by '"'). */
+static Lisp_Object
+read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)],
+ Lisp_Object readcharfun)
+{
+ char *read_buffer = stackbuf;
+ ptrdiff_t read_buffer_size = stackbufsize;
+ specpdl_ref count = SPECPDL_INDEX ();
+ char *heapbuf = NULL;
+ char *p = read_buffer;
+ char *end = read_buffer + read_buffer_size;
+ /* True if we saw an escape sequence specifying
+ a multibyte character. */
+ bool force_multibyte = false;
+ /* True if we saw an escape sequence specifying
+ a single-byte character. */
+ bool force_singlebyte = false;
+ bool cancel = false;
+ ptrdiff_t nchars = 0;
+
+ int ch;
+ while ((ch = READCHAR) >= 0 && ch != '\"')
+ {
+ if (end - p < MAX_MULTIBYTE_LENGTH)
{
- c = READCHAR;
- if (c == '(')
+ ptrdiff_t offset = p - read_buffer;
+ read_buffer = grow_read_buffer (read_buffer, offset,
+ &heapbuf, &read_buffer_size,
+ count);
+ p = read_buffer + offset;
+ end = read_buffer + read_buffer_size;
+ }
+
+ if (ch == '\\')
+ {
+ /* First apply string-specific escape rules: */
+ ch = READCHAR;
+ switch (ch)
{
- /* Accept extended format for hash tables (extensible to
- other types), e.g.
- #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
- Lisp_Object tmp = read_list (0, readcharfun, false);
- Lisp_Object head = CAR_SAFE (tmp);
- Lisp_Object data = Qnil;
- Lisp_Object val = Qnil;
- /* The size is 2 * number of allowed keywords to
- make-hash-table. */
- Lisp_Object params[12];
- Lisp_Object ht;
- Lisp_Object key = Qnil;
- int param_count = 0;
-
- if (!EQ (head, Qhash_table))
+ case 's':
+ /* `\s' is always a space in strings. */
+ ch = ' ';
+ break;
+ case ' ':
+ case '\n':
+ /* `\SPC' and `\LF' generate no characters at all. */
+ if (p == read_buffer)
+ cancel = true;
+ continue;
+ default:
+ UNREAD (ch);
+ ch = read_escape (readcharfun);
+ break;
+ }
+
+ int modifiers = ch & CHAR_MODIFIER_MASK;
+ ch &= ~CHAR_MODIFIER_MASK;
+
+ if (CHAR_BYTE8_P (ch))
+ force_singlebyte = true;
+ else if (! ASCII_CHAR_P (ch))
+ force_multibyte = true;
+ else /* I.e. ASCII_CHAR_P (ch). */
+ {
+ /* Allow `\C-SPC' and `\^SPC'. This is done here because
+ the literals ?\C-SPC and ?\^SPC (rather inconsistently)
+ yield (' ' | CHAR_CTL); see bug#55738. */
+ if (modifiers == CHAR_CTL && ch == ' ')
+ {
+ ch = 0;
+ modifiers = 0;
+ }
+ if (modifiers & CHAR_SHIFT)
{
- ptrdiff_t size = XFIXNUM (Flength (tmp));
- Lisp_Object record = Fmake_record (CAR_SAFE (tmp),
- make_fixnum (size - 1),
- Qnil);
- for (int i = 1; i < size; i++)
+ /* Shift modifier is valid only with [A-Za-z]. */
+ if (ch >= 'A' && ch <= 'Z')
+ modifiers &= ~CHAR_SHIFT;
+ else if (ch >= 'a' && ch <= 'z')
{
- tmp = Fcdr (tmp);
- ASET (record, i, Fcar (tmp));
+ ch -= ('a' - 'A');
+ modifiers &= ~CHAR_SHIFT;
}
- return record;
}
- tmp = CDR_SAFE (tmp);
+ if (modifiers & CHAR_META)
+ {
+ /* Move the meta bit to the right place for a
+ string. */
+ modifiers &= ~CHAR_META;
+ ch = BYTE8_TO_CHAR (ch | 0x80);
+ force_singlebyte = true;
+ }
+ }
- /* This is repetitive but fast and simple. */
- params[param_count] = QCsize;
- params[param_count + 1] = Fplist_get (tmp, Qsize);
- if (!NILP (params[param_count + 1]))
- param_count += 2;
+ /* Any modifiers remaining are invalid. */
+ if (modifiers)
+ invalid_syntax ("Invalid modifier in string", readcharfun);
+ p += CHAR_STRING (ch, (unsigned char *) p);
+ }
+ else
+ {
+ p += CHAR_STRING (ch, (unsigned char *) p);
+ if (CHAR_BYTE8_P (ch))
+ force_singlebyte = true;
+ else if (! ASCII_CHAR_P (ch))
+ force_multibyte = true;
+ }
+ nchars++;
+ }
- params[param_count] = QCtest;
- params[param_count + 1] = Fplist_get (tmp, Qtest);
- if (!NILP (params[param_count + 1]))
- param_count += 2;
+ if (ch < 0)
+ end_of_file_error ();
- params[param_count] = QCweakness;
- params[param_count + 1] = Fplist_get (tmp, Qweakness);
- if (!NILP (params[param_count + 1]))
- param_count += 2;
+ /* If purifying, and string starts with \ newline,
+ return zero instead. This is for doc strings
+ that we are really going to find in etc/DOC.nn.nn. */
+ if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
+ {
+ unbind_to (count, Qnil);
+ return make_fixnum (0);
+ }
- params[param_count] = QCrehash_size;
- params[param_count + 1] = Fplist_get (tmp, Qrehash_size);
- if (!NILP (params[param_count + 1]))
- param_count += 2;
+ if (!force_multibyte && force_singlebyte)
+ {
+ /* READ_BUFFER contains raw 8-bit bytes and no multibyte
+ forms. Convert it to unibyte. */
+ nchars = str_as_unibyte ((unsigned char *) read_buffer,
+ p - read_buffer);
+ p = read_buffer + nchars;
+ }
- params[param_count] = QCrehash_threshold;
- params[param_count + 1] = Fplist_get (tmp, Qrehash_threshold);
- if (!NILP (params[param_count + 1]))
- param_count += 2;
+ Lisp_Object obj = make_specified_string (read_buffer, nchars, p - read_buffer,
+ (force_multibyte
+ || (p - read_buffer != nchars)));
+ return unbind_to (count, obj);
+}
- params[param_count] = QCpurecopy;
- params[param_count + 1] = Fplist_get (tmp, Qpurecopy);
- if (!NILP (params[param_count + 1]))
- param_count += 2;
+/* Make a hash table from the constructor plist. */
+static Lisp_Object
+hash_table_from_plist (Lisp_Object plist)
+{
+ Lisp_Object params[12];
+ Lisp_Object *par = params;
+
+ /* This is repetitive but fast and simple. */
+#define ADDPARAM(name) \
+ do { \
+ Lisp_Object val = Fplist_get (plist, Q ## name); \
+ if (!NILP (val)) \
+ { \
+ *par++ = QC ## name; \
+ *par++ = val; \
+ } \
+ } while (0)
+
+ ADDPARAM (size);
+ ADDPARAM (test);
+ ADDPARAM (weakness);
+ ADDPARAM (rehash_size);
+ ADDPARAM (rehash_threshold);
+ ADDPARAM (purecopy);
+
+ Lisp_Object data = Fplist_get (plist, Qdata);
+
+ /* Now use params to make a new hash table and fill it. */
+ Lisp_Object ht = Fmake_hash_table (par - params, params);
+
+ Lisp_Object last = data;
+ FOR_EACH_TAIL_SAFE (data)
+ {
+ Lisp_Object key = XCAR (data);
+ data = XCDR (data);
+ if (!CONSP (data))
+ break;
+ Lisp_Object val = XCAR (data);
+ last = XCDR (data);
+ Fputhash (key, val, ht);
+ }
+ if (!NILP (last))
+ error ("Hash table data is not a list of even length");
- /* This is the hash table data. */
- data = Fplist_get (tmp, Qdata);
+ return ht;
+}
- /* Now use params to make a new hash table and fill it. */
- ht = Fmake_hash_table (param_count, params);
+static Lisp_Object
+record_from_list (Lisp_Object elems)
+{
+ ptrdiff_t size = list_length (elems);
+ Lisp_Object obj = Fmake_record (XCAR (elems),
+ make_fixnum (size - 1),
+ Qnil);
+ Lisp_Object tl = XCDR (elems);
+ for (int i = 1; i < size; i++)
+ {
+ ASET (obj, i, XCAR (tl));
+ tl = XCDR (tl);
+ }
+ return obj;
+}
- Lisp_Object last = data;
- FOR_EACH_TAIL_SAFE (data)
- {
- key = XCAR (data);
- data = XCDR (data);
- if (!CONSP (data))
- break;
- val = XCAR (data);
- last = XCDR (data);
- Fputhash (key, val, ht);
- }
- if (!NILP (last))
- error ("Hash table data is not a list of even length");
+/* Turn a reversed list into a vector. */
+static Lisp_Object
+vector_from_rev_list (Lisp_Object elems)
+{
+ ptrdiff_t size = list_length (elems);
+ Lisp_Object obj = make_nil_vector (size);
+ Lisp_Object *vec = XVECTOR (obj)->contents;
+ for (ptrdiff_t i = size - 1; i >= 0; i--)
+ {
+ vec[i] = XCAR (elems);
+ Lisp_Object next = XCDR (elems);
+ free_cons (XCONS (elems));
+ elems = next;
+ }
+ return obj;
+}
- return ht;
- }
- UNREAD (c);
- invalid_syntax ("#", readcharfun);
- }
- if (c == '^')
- {
- c = READCHAR;
- if (c == '[')
- {
- Lisp_Object tmp;
- tmp = read_vector (readcharfun, 0, false);
- if (ASIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS)
- error ("Invalid size char-table");
- XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE);
- return tmp;
- }
- else if (c == '^')
- {
- c = READCHAR;
- if (c == '[')
- {
- /* Sub char-table can't be read as a regular
- vector because of a two C integer fields. */
- Lisp_Object tbl, tmp = read_list (1, readcharfun, false);
- ptrdiff_t size = list_length (tmp);
- int i, depth, min_char;
- struct Lisp_Cons *cell;
-
- if (size == 0)
- error ("Zero-sized sub char-table");
-
- if (! RANGED_FIXNUMP (1, XCAR (tmp), 3))
- error ("Invalid depth in sub char-table");
- depth = XFIXNUM (XCAR (tmp));
- if (chartab_size[depth] != size - 2)
- error ("Invalid size in sub char-table");
- cell = XCONS (tmp), tmp = XCDR (tmp), size--;
- free_cons (cell);
-
- if (! RANGED_FIXNUMP (0, XCAR (tmp), MAX_CHAR))
- error ("Invalid minimum character in sub-char-table");
- min_char = XFIXNUM (XCAR (tmp));
- cell = XCONS (tmp), tmp = XCDR (tmp), size--;
- free_cons (cell);
-
- tbl = make_uninit_sub_char_table (depth, min_char);
- for (i = 0; i < size; i++)
- {
- XSUB_CHAR_TABLE (tbl)->contents[i] = XCAR (tmp);
- cell = XCONS (tmp), tmp = XCDR (tmp);
- free_cons (cell);
- }
- return tbl;
- }
- invalid_syntax ("#^^", readcharfun);
- }
- invalid_syntax ("#^", readcharfun);
- }
- if (c == '&')
+static Lisp_Object
+bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
+{
+ Lisp_Object obj = vector_from_rev_list (elems);
+ Lisp_Object *vec = XVECTOR (obj)->contents;
+ ptrdiff_t size = ASIZE (obj);
+
+ if (!(size >= COMPILED_STACK_DEPTH + 1 && size <= COMPILED_INTERACTIVE + 1
+ && (FIXNUMP (vec[COMPILED_ARGLIST])
+ || CONSP (vec[COMPILED_ARGLIST])
+ || NILP (vec[COMPILED_ARGLIST]))
+ && FIXNATP (vec[COMPILED_STACK_DEPTH])))
+ invalid_syntax ("Invalid byte-code object", readcharfun);
+
+ if (load_force_doc_strings
+ && NILP (vec[COMPILED_CONSTANTS])
+ && STRINGP (vec[COMPILED_BYTECODE]))
+ {
+ /* Lazily-loaded bytecode is represented by the constant slot being nil
+ and the bytecode slot a (lazily loaded) string containing the
+ print representation of (BYTECODE . CONSTANTS). Unpack the
+ pieces by coerceing the string to unibyte and reading the result. */
+ Lisp_Object enc = vec[COMPILED_BYTECODE];
+ Lisp_Object pair = Fread (Fcons (enc, readcharfun));
+ if (!CONSP (pair))
+ invalid_syntax ("Invalid byte-code object", readcharfun);
+
+ vec[COMPILED_BYTECODE] = XCAR (pair);
+ vec[COMPILED_CONSTANTS] = XCDR (pair);
+ }
+
+ if (!((STRINGP (vec[COMPILED_BYTECODE])
+ && VECTORP (vec[COMPILED_CONSTANTS]))
+ || CONSP (vec[COMPILED_BYTECODE])))
+ invalid_syntax ("Invalid byte-code object", readcharfun);
+
+ if (STRINGP (vec[COMPILED_BYTECODE]))
+ {
+ if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE]))
{
- Lisp_Object length;
- length = read1 (readcharfun, pch, first_in_list, false);
- c = READCHAR;
- if (c == '"')
- {
- Lisp_Object tmp, val;
- EMACS_INT size_in_chars = bool_vector_bytes (XFIXNAT (length));
- unsigned char *data;
-
- UNREAD (c);
- tmp = read1 (readcharfun, pch, first_in_list, false);
- if (STRING_MULTIBYTE (tmp)
- || (size_in_chars != SCHARS (tmp)
- /* We used to print 1 char too many
- when the number of bits was a multiple of 8.
- Accept such input in case it came from an old
- version. */
- && ! (XFIXNAT (length)
- == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
- invalid_syntax ("#&...", readcharfun);
-
- val = make_uninit_bool_vector (XFIXNAT (length));
- data = bool_vector_uchar_data (val);
- memcpy (data, SDATA (tmp), size_in_chars);
- /* Clear the extraneous bits in the last byte. */
- if (XFIXNUM (length) != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR)
- data[size_in_chars - 1]
- &= (1 << (XFIXNUM (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
- return val;
- }
- invalid_syntax ("#&...", readcharfun);
+ /* BYTESTR must have been produced by Emacs 20.2 or earlier
+ because it produced a raw 8-bit string for byte-code and
+ now such a byte-code string is loaded as multibyte with
+ raw 8-bit characters converted to multibyte form.
+ Convert them back to the original unibyte form. */
+ vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]);
}
- if (c == '[')
- {
- /* Accept compiled functions at read-time so that we don't have to
- build them using function calls. */
- Lisp_Object tmp;
- struct Lisp_Vector *vec;
- tmp = read_vector (readcharfun, 1, false);
- vec = XVECTOR (tmp);
- if (! (COMPILED_STACK_DEPTH < ASIZE (tmp)
- && (FIXNUMP (AREF (tmp, COMPILED_ARGLIST))
- || CONSP (AREF (tmp, COMPILED_ARGLIST))
- || NILP (AREF (tmp, COMPILED_ARGLIST)))
- && ((STRINGP (AREF (tmp, COMPILED_BYTECODE))
- && VECTORP (AREF (tmp, COMPILED_CONSTANTS)))
- || CONSP (AREF (tmp, COMPILED_BYTECODE)))
- && FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH))))
- invalid_syntax ("Invalid byte-code object", readcharfun);
-
- if (STRINGP (AREF (tmp, COMPILED_BYTECODE)))
- {
- if (STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
- {
- /* BYTESTR must have been produced by Emacs 20.2 or earlier
- because it produced a raw 8-bit string for byte-code and
- now such a byte-code string is loaded as multibyte with
- raw 8-bit characters converted to multibyte form.
- Convert them back to the original unibyte form. */
- ASET (tmp, COMPILED_BYTECODE,
- Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE)));
- }
- // Bytecode must be immovable.
- pin_string (AREF (tmp, COMPILED_BYTECODE));
- }
+ // Bytecode must be immovable.
+ pin_string (vec[COMPILED_BYTECODE]);
+ }
- XSETPVECTYPE (vec, PVEC_COMPILED);
- return tmp;
- }
- if (c == '(')
- {
- Lisp_Object tmp;
- int ch;
-
- /* Read the string itself. */
- tmp = read1 (readcharfun, &ch, 0, false);
- if (ch != 0 || !STRINGP (tmp))
- invalid_syntax ("#", readcharfun);
- /* Read the intervals and their properties. */
- while (1)
- {
- Lisp_Object beg, end, plist;
+ XSETPVECTYPE (XVECTOR (obj), PVEC_COMPILED);
+ return obj;
+}
- beg = read1 (readcharfun, &ch, 0, false);
- end = plist = Qnil;
- if (ch == ')')
- break;
- if (ch == 0)
- end = read1 (readcharfun, &ch, 0, false);
- if (ch == 0)
- plist = read1 (readcharfun, &ch, 0, false);
- if (ch)
- invalid_syntax ("Invalid string property list", readcharfun);
- Fset_text_properties (beg, end, plist, tmp);
- }
+static Lisp_Object
+char_table_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
+{
+ Lisp_Object obj = vector_from_rev_list (elems);
+ if (ASIZE (obj) < CHAR_TABLE_STANDARD_SLOTS)
+ invalid_syntax ("Invalid size char-table", readcharfun);
+ XSETPVECTYPE (XVECTOR (obj), PVEC_CHAR_TABLE);
+ return obj;
- return tmp;
- }
+}
- /* #@NUMBER is used to skip NUMBER following bytes.
- That's used in .elc files to skip over doc strings
- and function definitions. */
- if (c == '@')
+static Lisp_Object
+sub_char_table_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
+{
+ /* A sub-char-table can't be read as a regular vector because of two
+ C integer fields. */
+ elems = Fnreverse (elems);
+ ptrdiff_t size = list_length (elems);
+ if (size < 2)
+ error ("Invalid size of sub-char-table");
+
+ if (!RANGED_FIXNUMP (1, XCAR (elems), 3))
+ error ("Invalid depth in sub-char-table");
+ int depth = XFIXNUM (XCAR (elems));
+
+ if (chartab_size[depth] != size - 2)
+ error ("Invalid size in sub-char-table");
+ elems = XCDR (elems);
+
+ if (!RANGED_FIXNUMP (0, XCAR (elems), MAX_CHAR))
+ error ("Invalid minimum character in sub-char-table");
+ int min_char = XFIXNUM (XCAR (elems));
+ elems = XCDR (elems);
+
+ Lisp_Object tbl = make_uninit_sub_char_table (depth, min_char);
+ for (int i = 0; i < size - 2; i++)
+ {
+ XSUB_CHAR_TABLE (tbl)->contents[i] = XCAR (elems);
+ elems = XCDR (elems);
+ }
+ return tbl;
+}
+
+static Lisp_Object
+string_props_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
+{
+ elems = Fnreverse (elems);
+ if (NILP (elems) || !STRINGP (XCAR (elems)))
+ invalid_syntax ("#", readcharfun);
+ Lisp_Object obj = XCAR (elems);
+ for (Lisp_Object tl = XCDR (elems); !NILP (tl);)
+ {
+ Lisp_Object beg = XCAR (tl);
+ tl = XCDR (tl);
+ if (NILP (tl))
+ invalid_syntax ("Invalid string property list", readcharfun);
+ Lisp_Object end = XCAR (tl);
+ tl = XCDR (tl);
+ if (NILP (tl))
+ invalid_syntax ("Invalid string property list", readcharfun);
+ Lisp_Object plist = XCAR (tl);
+ tl = XCDR (tl);
+ Fset_text_properties (beg, end, plist, obj);
+ }
+ return obj;
+}
+
+/* Read a bool vector (preceded by "#&"). */
+static Lisp_Object
+read_bool_vector (char stackbuf[VLA_ELEMS (stackbufsize)],
+ Lisp_Object readcharfun)
+{
+ ptrdiff_t length = 0;
+ for (;;)
+ {
+ int c = READCHAR;
+ if (c < '0' || c > '9')
{
- enum { extra = 100 };
- ptrdiff_t i, nskip = 0, digits = 0;
+ if (c != '"')
+ invalid_syntax ("#&", readcharfun);
+ break;
+ }
+ if (INT_MULTIPLY_WRAPV (length, 10, &length)
+ | INT_ADD_WRAPV (length, c - '0', &length))
+ invalid_syntax ("#&", readcharfun);
+ }
- /* Read a decimal integer. */
- while ((c = READCHAR) >= 0
- && c >= '0' && c <= '9')
- {
- if ((STRING_BYTES_BOUND - extra) / 10 <= nskip)
- string_overflow ();
- digits++;
- nskip *= 10;
- nskip += c - '0';
- if (digits == 2 && nskip == 0)
- { /* We've just seen #@00, which means "skip to end". */
- skip_dyn_eof (readcharfun);
- return Qnil;
- }
- }
+ ptrdiff_t size_in_chars = bool_vector_bytes (length);
+ Lisp_Object str = read_string_literal (stackbuf, readcharfun);
+ if (STRING_MULTIBYTE (str)
+ || !(size_in_chars == SCHARS (str)
+ /* We used to print 1 char too many when the number of bits
+ was a multiple of 8. Accept such input in case it came
+ from an old version. */
+ || length == (SCHARS (str) - 1) * BOOL_VECTOR_BITS_PER_CHAR))
+ invalid_syntax ("#&...", readcharfun);
+
+ Lisp_Object obj = make_uninit_bool_vector (length);
+ unsigned char *data = bool_vector_uchar_data (obj);
+ memcpy (data, SDATA (str), size_in_chars);
+ /* Clear the extraneous bits in the last byte. */
+ if (length != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR)
+ data[size_in_chars - 1] &= (1 << (length % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
+ return obj;
+}
+
+/* Skip (and optionally remember) a lazily-loaded string
+ preceded by "#@". */
+static void
+skip_lazy_string (Lisp_Object readcharfun)
+{
+ ptrdiff_t nskip = 0;
+ ptrdiff_t digits = 0;
+ for (;;)
+ {
+ int c = READCHAR;
+ if (c < '0' || c > '9')
+ {
if (nskip > 0)
/* We can't use UNREAD here, because in the code below we side-step
- READCHAR. Instead, assume the first char after #@NNN occupies
- a single byte, which is the case normally since it's just
- a space. */
+ READCHAR. Instead, assume the first char after #@NNN occupies
+ a single byte, which is the case normally since it's just
+ a space. */
nskip--;
else
UNREAD (c);
-
- if (load_force_doc_strings
- && (FROM_FILE_P (readcharfun)))
- {
- /* If we are supposed to force doc strings into core right now,
- record the last string that we skipped,
- and record where in the file it comes from. */
-
- /* But first exchange saved_doc_string
- with prev_saved_doc_string, so we save two strings. */
- {
- char *temp = saved_doc_string;
- ptrdiff_t temp_size = saved_doc_string_size;
- file_offset temp_pos = saved_doc_string_position;
- ptrdiff_t temp_len = saved_doc_string_length;
-
- saved_doc_string = prev_saved_doc_string;
- saved_doc_string_size = prev_saved_doc_string_size;
- saved_doc_string_position = prev_saved_doc_string_position;
- saved_doc_string_length = prev_saved_doc_string_length;
-
- prev_saved_doc_string = temp;
- prev_saved_doc_string_size = temp_size;
- prev_saved_doc_string_position = temp_pos;
- prev_saved_doc_string_length = temp_len;
- }
-
- if (saved_doc_string_size == 0)
- {
- saved_doc_string = xmalloc (nskip + extra);
- saved_doc_string_size = nskip + extra;
- }
- if (nskip > saved_doc_string_size)
- {
- saved_doc_string = xrealloc (saved_doc_string, nskip + extra);
- saved_doc_string_size = nskip + extra;
- }
-
- FILE *instream = infile->stream;
- saved_doc_string_position = (file_tell (instream)
- - infile->lookahead);
-
- /* Copy that many bytes into saved_doc_string. */
- i = 0;
- for (int n = min (nskip, infile->lookahead); 0 < n; n--)
- saved_doc_string[i++]
- = c = infile->buf[--infile->lookahead];
- block_input ();
- for (; i < nskip && 0 <= c; i++)
- saved_doc_string[i] = c = getc (instream);
- unblock_input ();
-
- saved_doc_string_length = i;
- }
- else
- /* Skip that many bytes. */
- skip_dyn_bytes (readcharfun, nskip);
-
- goto retry;
+ break;
}
- if (c == '!')
+ if (INT_MULTIPLY_WRAPV (nskip, 10, &nskip)
+ | INT_ADD_WRAPV (nskip, c - '0', &nskip))
+ invalid_syntax ("#@", readcharfun);
+ digits++;
+ if (digits == 2 && nskip == 0)
{
- /* #! appears at the beginning of an executable file.
- Skip the first line. */
- while (c != '\n' && c >= 0)
- c = READCHAR;
- goto retry;
+ /* #@00 means "skip to end" */
+ skip_dyn_eof (readcharfun);
+ return;
}
- if (c == '$')
- return Vload_file_name;
- if (c == '\'')
- return list2 (Qfunction, read0 (readcharfun, locate_syms));
- /* #:foo is the uninterned symbol named foo. */
- if (c == ':')
+ }
+
+ if (load_force_doc_strings && FROM_FILE_P (readcharfun))
+ {
+ /* If we are supposed to force doc strings into core right now,
+ record the last string that we skipped,
+ and record where in the file it comes from. */
+
+ /* But first exchange saved_doc_string
+ with prev_saved_doc_string, so we save two strings. */
+ {
+ char *temp = saved_doc_string;
+ ptrdiff_t temp_size = saved_doc_string_size;
+ file_offset temp_pos = saved_doc_string_position;
+ ptrdiff_t temp_len = saved_doc_string_length;
+
+ saved_doc_string = prev_saved_doc_string;
+ saved_doc_string_size = prev_saved_doc_string_size;
+ saved_doc_string_position = prev_saved_doc_string_position;
+ saved_doc_string_length = prev_saved_doc_string_length;
+
+ prev_saved_doc_string = temp;
+ prev_saved_doc_string_size = temp_size;
+ prev_saved_doc_string_position = temp_pos;
+ prev_saved_doc_string_length = temp_len;
+ }
+
+ enum { extra = 100 };
+ if (saved_doc_string_size == 0)
{
- uninterned_symbol = true;
- read_hash_prefixed_symbol:
- c = READCHAR;
- if (!(c > 040
- && c != NO_BREAK_SPACE
- && (c >= 0200
- || strchr ("\"';()[]#`,", c) == NULL)))
- {
- /* No symbol character follows, this is the empty
- symbol. */
- UNREAD (c);
- return Fmake_symbol (empty_unibyte_string);
- }
- goto read_symbol;
+ saved_doc_string = xmalloc (nskip + extra);
+ saved_doc_string_size = nskip + extra;
}
- /* #_foo is really the symbol foo, regardless of shorthands */
- if (c == '_')
+ if (nskip > saved_doc_string_size)
{
- skip_shorthand = true;
- goto read_hash_prefixed_symbol;
+ saved_doc_string = xrealloc (saved_doc_string, nskip + extra);
+ saved_doc_string_size = nskip + extra;
}
- /* ## is the empty symbol. */
- if (c == '#')
- return Fintern (empty_unibyte_string, Qnil);
- if (c >= '0' && c <= '9')
- {
- EMACS_INT n = c - '0';
- bool overflow = false;
+ FILE *instream = infile->stream;
+ saved_doc_string_position = (file_tell (instream) - infile->lookahead);
- /* Read a non-negative integer. */
- while ('0' <= (c = READCHAR) && c <= '9')
- {
- overflow |= INT_MULTIPLY_WRAPV (n, 10, &n);
- overflow |= INT_ADD_WRAPV (n, c - '0', &n);
- }
+ /* Copy that many bytes into saved_doc_string. */
+ ptrdiff_t i = 0;
+ int c = 0;
+ for (int n = min (nskip, infile->lookahead); n > 0; n--)
+ saved_doc_string[i++] = c = infile->buf[--infile->lookahead];
+ block_input ();
+ for (; i < nskip && c >= 0; i++)
+ saved_doc_string[i] = c = getc (instream);
+ unblock_input ();
- if (!overflow)
- {
- if (c == 'r' || c == 'R')
- {
- if (! (2 <= n && n <= 36))
- invalid_radix_integer (n, stackbuf, readcharfun);
- return read_integer (readcharfun, n, stackbuf);
- }
+ saved_doc_string_length = i;
+ }
+ else
+ /* Skip that many bytes. */
+ skip_dyn_bytes (readcharfun, nskip);
+}
- if (n <= MOST_POSITIVE_FIXNUM && ! NILP (Vread_circle))
- {
- /* Reader forms that can reuse previously read objects. */
- /* #n=object returns object, but associates it with
- n for #n#. */
- if (c == '=')
- {
- /* Make a placeholder for #n# to use temporarily. */
- /* Note: We used to use AUTO_CONS to allocate
- placeholder, but that is a bad idea, since it
- will place a stack-allocated cons cell into
- the list in read_objects_map, which is a
- staticpro'd global variable, and thus each of
- its elements is marked during each GC. A
- stack-allocated object will become garbled
- when its stack slot goes out of scope, and
- some other function reuses it for entirely
- different purposes, which will cause crashes
- in GC. */
- Lisp_Object placeholder = Fcons (Qnil, Qnil);
- struct Lisp_Hash_Table *h
- = XHASH_TABLE (read_objects_map);
- Lisp_Object number = make_fixnum (n), hash;
-
- ptrdiff_t i = hash_lookup (h, number, &hash);
- if (i >= 0)
- /* Not normal, but input could be malformed. */
- set_hash_value_slot (h, i, placeholder);
- else
- hash_put (h, number, placeholder, hash);
-
- /* Read the object itself. */
- Lisp_Object tem = read0 (readcharfun, locate_syms);
-
- if (CONSP (tem))
- {
- if (BASE_EQ (tem, placeholder))
- /* Catch silly games like #1=#1# */
- invalid_syntax ("nonsensical self-reference",
- readcharfun);
+/* Length of prefix only consisting of symbol constituent characters. */
+static ptrdiff_t
+symbol_char_span (const char *s)
+{
+ const char *p = s;
+ while ( *p == '^' || *p == '*' || *p == '+' || *p == '-' || *p == '/'
+ || *p == '<' || *p == '=' || *p == '>' || *p == '_' || *p == '|')
+ p++;
+ return p - s;
+}
- /* Optimisation: since the placeholder is already
- a cons, repurpose it as the actual value.
- This allows us to skip the substition below,
- since the placeholder is already referenced
- inside TEM at the appropriate places. */
- Fsetcar (placeholder, XCAR (tem));
- Fsetcdr (placeholder, XCDR (tem));
-
- struct Lisp_Hash_Table *h2
- = XHASH_TABLE (read_objects_completed);
- ptrdiff_t i = hash_lookup (h2, placeholder, &hash);
- eassert (i < 0);
- hash_put (h2, placeholder, Qnil, hash);
- return placeholder;
- }
-
- /* If it can be recursive, remember it for
- future substitutions. */
- if (! SYMBOLP (tem)
- && ! NUMBERP (tem)
- && ! (STRINGP (tem) && !string_intervals (tem)))
- {
- struct Lisp_Hash_Table *h2
- = XHASH_TABLE (read_objects_completed);
- i = hash_lookup (h2, tem, &hash);
- eassert (i < 0);
- hash_put (h2, tem, Qnil, hash);
- }
-
- /* Now put it everywhere the placeholder was... */
- Flread__substitute_object_in_subtree
- (tem, placeholder, read_objects_completed);
-
- /* ...and #n# will use the real value from now on. */
- i = hash_lookup (h, number, &hash);
- eassert (i >= 0);
- set_hash_value_slot (h, i, tem);
-
- return tem;
- }
+static void
+skip_space_and_comments (Lisp_Object readcharfun)
+{
+ int c;
+ do
+ {
+ c = READCHAR;
+ if (c == ';')
+ do
+ c = READCHAR;
+ while (c >= 0 && c != '\n');
+ if (c < 0)
+ end_of_file_error ();
+ }
+ while (c <= 32 || c == NO_BREAK_SPACE);
+ UNREAD (c);
+}
- /* #n# returns a previously read object. */
- if (c == '#')
- {
- struct Lisp_Hash_Table *h
- = XHASH_TABLE (read_objects_map);
- ptrdiff_t i = hash_lookup (h, make_fixnum (n), NULL);
- if (i >= 0)
- return HASH_VALUE (h, i);
- }
- }
- }
- /* Fall through to error message. */
+/* When an object is read, the type of the top read stack entry indicates
+ the syntactic context. */
+enum read_entry_type
+{
+ /* preceding syntactic context */
+ RE_list_start, /* "(" */
+
+ RE_list, /* "(" (+ OBJECT) */
+ RE_list_dot, /* "(" (+ OBJECT) "." */
+
+ RE_vector, /* "[" (* OBJECT) */
+ RE_record, /* "#s(" (* OBJECT) */
+ RE_char_table, /* "#^[" (* OBJECT) */
+ RE_sub_char_table, /* "#^^[" (* OBJECT) */
+ RE_byte_code, /* "#[" (* OBJECT) */
+ RE_string_props, /* "#(" (* OBJECT) */
+
+ RE_special, /* "'" | "#'" | "`" | "," | ",@" */
+
+ RE_numbered, /* "#" (+ DIGIT) "=" */
+};
+
+struct read_stack_entry
+{
+ enum read_entry_type type;
+ union {
+ /* RE_list, RE_list_dot */
+ struct {
+ Lisp_Object head; /* first cons of list */
+ Lisp_Object tail; /* last cons of list */
+ } list;
+
+ /* RE_vector, RE_record, RE_char_table, RE_sub_char_table,
+ RE_byte_code, RE_string_props */
+ struct {
+ Lisp_Object elems; /* list of elements in reverse order */
+ bool old_locate_syms; /* old value of locate_syms */
+ } vector;
+
+ /* RE_special */
+ struct {
+ Lisp_Object symbol; /* symbol from special syntax */
+ } special;
+
+ /* RE_numbered */
+ struct {
+ Lisp_Object number; /* number as a fixnum */
+ Lisp_Object placeholder; /* placeholder object */
+ } numbered;
+ } u;
+};
+
+struct read_stack
+{
+ struct read_stack_entry *stack; /* base of stack */
+ ptrdiff_t size; /* allocated size in entries */
+ ptrdiff_t sp; /* current number of entries */
+};
+
+static struct read_stack rdstack = {NULL, 0, 0};
+
+void
+mark_lread (void)
+{
+ /* Mark the read stack, which may contain data not otherwise traced */
+ for (ptrdiff_t i = 0; i < rdstack.sp; i++)
+ {
+ struct read_stack_entry *e = &rdstack.stack[i];
+ switch (e->type)
+ {
+ case RE_list_start:
+ break;
+ case RE_list:
+ case RE_list_dot:
+ mark_object (e->u.list.head);
+ mark_object (e->u.list.tail);
+ break;
+ case RE_vector:
+ case RE_record:
+ case RE_char_table:
+ case RE_sub_char_table:
+ case RE_byte_code:
+ case RE_string_props:
+ mark_object (e->u.vector.elems);
+ break;
+ case RE_special:
+ mark_object (e->u.special.symbol);
+ break;
+ case RE_numbered:
+ mark_object (e->u.numbered.number);
+ mark_object (e->u.numbered.placeholder);
+ break;
}
- else if (c == 'x' || c == 'X')
- return read_integer (readcharfun, 16, stackbuf);
- else if (c == 'o' || c == 'O')
- return read_integer (readcharfun, 8, stackbuf);
- else if (c == 'b' || c == 'B')
- return read_integer (readcharfun, 2, stackbuf);
-
- char acm_buf[15]; /* FIXME!!! 2021-11-27. */
- sprintf (acm_buf, "#%c", c);
- invalid_syntax (acm_buf, readcharfun);
- UNREAD (c);
- invalid_syntax ("#", readcharfun);
+ }
+}
- case ';':
- while ((c = READCHAR) >= 0 && c != '\n');
- goto retry;
+static inline struct read_stack_entry *
+read_stack_top (void)
+{
+ eassume (rdstack.sp > 0);
+ return &rdstack.stack[rdstack.sp - 1];
+}
- case '\'':
- return list2 (Qquote, read0 (readcharfun, locate_syms));
+static inline struct read_stack_entry *
+read_stack_pop (void)
+{
+ eassume (rdstack.sp > 0);
+ return &rdstack.stack[--rdstack.sp];
+}
- case '`':
- return list2 (Qbackquote, read0 (readcharfun, locate_syms));
+static inline bool
+read_stack_empty_p (ptrdiff_t base_sp)
+{
+ return rdstack.sp <= base_sp;
+}
- case ',':
- {
- Lisp_Object comma_type = Qnil;
- Lisp_Object value;
- int ch = READCHAR;
+NO_INLINE static void
+grow_read_stack (void)
+{
+ struct read_stack *rs = &rdstack;
+ eassert (rs->sp == rs->size);
+ rs->stack = xpalloc (rs->stack, &rs->size, 1, -1, sizeof *rs->stack);
+ eassert (rs->sp < rs->size);
+}
- if (ch == '@')
- comma_type = Qcomma_at;
- else
- {
- if (ch >= 0) UNREAD (ch);
- comma_type = Qcomma;
- }
+static inline void
+read_stack_push (struct read_stack_entry e)
+{
+ if (rdstack.sp >= rdstack.size)
+ grow_read_stack ();
+ rdstack.stack[rdstack.sp++] = e;
+}
- value = read0 (readcharfun, locate_syms);
- return list2 (comma_type, value);
- }
- case '?':
- {
- int modifiers;
- int next_char;
- bool ok;
- c = READCHAR;
- if (c < 0)
- end_of_file_error ();
-
- /* Accept `single space' syntax like (list ? x) where the
- whitespace character is SPC or TAB.
- Other literal whitespace like NL, CR, and FF are not accepted,
- as there are well-established escape sequences for these. */
- if (c == ' ' || c == '\t')
- return make_fixnum (c);
-
- if (c == '(' || c == ')' || c == '[' || c == ']'
- || c == '"' || c == ';')
+/* Read a Lisp object.
+ If LOCATE_SYMS is true, symbols are read with position. */
+static Lisp_Object
+read0 (Lisp_Object readcharfun, bool locate_syms)
+{
+ char stackbuf[stackbufsize];
+ char *read_buffer = stackbuf;
+ ptrdiff_t read_buffer_size = sizeof stackbuf;
+ char *heapbuf = NULL;
+ specpdl_ref count = SPECPDL_INDEX ();
+
+ ptrdiff_t base_sp = rdstack.sp;
+
+ bool uninterned_symbol;
+ bool skip_shorthand;
+
+ /* Read an object into `obj'. */
+ read_obj: ;
+ Lisp_Object obj;
+ bool multibyte;
+ int c = READCHAR_REPORT_MULTIBYTE (&multibyte);
+ if (c < 0)
+ end_of_file_error ();
+
+ switch (c)
+ {
+ case '(':
+ read_stack_push ((struct read_stack_entry) {.type = RE_list_start});
+ goto read_obj;
+
+ case ')':
+ if (read_stack_empty_p (base_sp))
+ invalid_syntax (")", readcharfun);
+ switch (read_stack_top ()->type)
+ {
+ case RE_list_start:
+ read_stack_pop ();
+ obj = Qnil;
+ break;
+ case RE_list:
+ obj = read_stack_pop ()->u.list.head;
+ break;
+ case RE_record:
{
- CHECK_LIST (Vlread_unescaped_character_literals);
- Lisp_Object char_obj = make_fixed_natnum (c);
- if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals)))
- Vlread_unescaped_character_literals =
- Fcons (char_obj, Vlread_unescaped_character_literals);
+ locate_syms = read_stack_top ()->u.vector.old_locate_syms;
+ Lisp_Object elems = Fnreverse (read_stack_pop ()->u.vector.elems);
+ if (NILP (elems))
+ invalid_syntax ("#s", readcharfun);
+
+ if (BASE_EQ (XCAR (elems), Qhash_table))
+ obj = hash_table_from_plist (XCDR (elems));
+ else
+ obj = record_from_list (elems);
+ break;
}
+ case RE_string_props:
+ locate_syms = read_stack_top ()->u.vector.old_locate_syms;
+ obj = string_props_from_rev_list (read_stack_pop () ->u.vector.elems,
+ readcharfun);
+ break;
+ default:
+ invalid_syntax (")", readcharfun);
+ }
+ break;
- if (c == '\\')
- c = read_escape (readcharfun, 0);
- modifiers = c & CHAR_MODIFIER_MASK;
- c &= ~CHAR_MODIFIER_MASK;
- if (CHAR_BYTE8_P (c))
- c = CHAR_TO_BYTE8 (c);
- c |= modifiers;
-
- next_char = READCHAR;
- ok = (next_char <= 040
- || (next_char < 0200
- && strchr ("\"';()[]#?`,.", next_char) != NULL));
- UNREAD (next_char);
- if (ok)
- return make_fixnum (c);
-
- invalid_syntax ("?", readcharfun);
- }
+ case '[':
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_vector,
+ .u.vector.elems = Qnil,
+ .u.vector.old_locate_syms = locate_syms,
+ });
+ /* FIXME: should vectors be read with locate_syms=false? */
+ goto read_obj;
- case '"':
+ case ']':
+ if (read_stack_empty_p (base_sp))
+ invalid_syntax ("]", readcharfun);
+ switch (read_stack_top ()->type)
+ {
+ case RE_vector:
+ locate_syms = read_stack_top ()->u.vector.old_locate_syms;
+ obj = vector_from_rev_list (read_stack_pop ()->u.vector.elems);
+ break;
+ case RE_byte_code:
+ locate_syms = read_stack_top ()->u.vector.old_locate_syms;
+ obj = bytecode_from_rev_list (read_stack_pop ()->u.vector.elems,
+ readcharfun);
+ break;
+ case RE_char_table:
+ locate_syms = read_stack_top ()->u.vector.old_locate_syms;
+ obj = char_table_from_rev_list (read_stack_pop ()->u.vector.elems,
+ readcharfun);
+ break;
+ case RE_sub_char_table:
+ locate_syms = read_stack_top ()->u.vector.old_locate_syms;
+ obj = sub_char_table_from_rev_list (read_stack_pop ()->u.vector.elems,
+ readcharfun);
+ break;
+ default:
+ invalid_syntax ("]", readcharfun);
+ break;
+ }
+ break;
+
+ case '#':
{
- specpdl_ref count = SPECPDL_INDEX ();
- char *read_buffer = stackbuf;
- ptrdiff_t read_buffer_size = sizeof stackbuf;
- char *heapbuf = NULL;
- char *p = read_buffer;
- char *end = read_buffer + read_buffer_size;
- int ch;
- /* True if we saw an escape sequence specifying
- a multibyte character. */
- bool force_multibyte = false;
- /* True if we saw an escape sequence specifying
- a single-byte character. */
- bool force_singlebyte = false;
- bool cancel = false;
- ptrdiff_t nchars = 0;
-
- while ((ch = READCHAR) >= 0
- && ch != '\"')
+ int ch = READCHAR;
+ switch (ch)
{
- if (end - p < MAX_MULTIBYTE_LENGTH)
+ case '\'':
+ /* #'X -- special syntax for (function X) */
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_special,
+ .u.special.symbol = Qfunction,
+ });
+ goto read_obj;
+
+ case '#':
+ /* ## -- the empty symbol */
+ obj = Fintern (empty_unibyte_string, Qnil);
+ break;
+
+ case 's':
+ /* #s(...) -- a record or hash-table */
+ ch = READCHAR;
+ if (ch != '(')
{
- ptrdiff_t offset = p - read_buffer;
- read_buffer = grow_read_buffer (read_buffer, offset,
- &heapbuf, &read_buffer_size,
- count);
- p = read_buffer + offset;
- end = read_buffer + read_buffer_size;
+ UNREAD (ch);
+ invalid_syntax ("#s", readcharfun);
}
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_record,
+ .u.vector.elems = Qnil,
+ .u.vector.old_locate_syms = locate_syms,
+ });
+ locate_syms = false;
+ goto read_obj;
+
+ case '^':
+ /* #^[...] -- char-table
+ #^^[...] -- sub-char-table */
+ ch = READCHAR;
+ if (ch == '^')
+ {
+ ch = READCHAR;
+ if (ch == '[')
+ {
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_sub_char_table,
+ .u.vector.elems = Qnil,
+ .u.vector.old_locate_syms = locate_syms,
+ });
+ locate_syms = false;
+ goto read_obj;
+ }
+ else
+ {
+ UNREAD (ch);
+ invalid_syntax ("#^^", readcharfun);
+ }
+ }
+ else if (ch == '[')
+ {
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_char_table,
+ .u.vector.elems = Qnil,
+ .u.vector.old_locate_syms = locate_syms,
+ });
+ locate_syms = false;
+ goto read_obj;
+ }
+ else
+ {
+ UNREAD (ch);
+ invalid_syntax ("#^", readcharfun);
+ }
+
+ case '(':
+ /* #(...) -- string with properties */
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_string_props,
+ .u.vector.elems = Qnil,
+ .u.vector.old_locate_syms = locate_syms,
+ });
+ locate_syms = false;
+ goto read_obj;
+
+ case '[':
+ /* #[...] -- byte-code */
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_byte_code,
+ .u.vector.elems = Qnil,
+ .u.vector.old_locate_syms = locate_syms,
+ });
+ locate_syms = false;
+ goto read_obj;
+
+ case '&':
+ /* #&N"..." -- bool-vector */
+ obj = read_bool_vector (stackbuf, readcharfun);
+ break;
+
+ case '!':
+ /* #! appears at the beginning of an executable file.
+ Skip the rest of the line. */
+ {
+ int c;
+ do
+ c = READCHAR;
+ while (c >= 0 && c != '\n');
+ goto read_obj;
+ }
- if (ch == '\\')
+ case 'x':
+ case 'X':
+ obj = read_integer (readcharfun, 16, stackbuf);
+ break;
+
+ case 'o':
+ case 'O':
+ obj = read_integer (readcharfun, 8, stackbuf);
+ break;
+
+ case 'b':
+ case 'B':
+ obj = read_integer (readcharfun, 2, stackbuf);
+ break;
+
+ case '@':
+ /* #@NUMBER is used to skip NUMBER following bytes.
+ That's used in .elc files to skip over doc strings
+ and function definitions that can be loaded lazily. */
+ skip_lazy_string (readcharfun);
+ goto read_obj;
+
+ case '$':
+ /* #$ -- reference to lazy-loaded string */
+ obj = Vload_file_name;
+ break;
+
+ case ':':
+ /* #:X -- uninterned symbol */
+ c = READCHAR;
+ if (c <= 32 || c == NO_BREAK_SPACE
+ || c == '"' || c == '\'' || c == ';' || c == '#'
+ || c == '(' || c == ')' || c == '[' || c == ']'
+ || c == '`' || c == ',')
{
- int modifiers;
+ /* No symbol character follows: this is the empty symbol. */
+ UNREAD (c);
+ obj = Fmake_symbol (empty_unibyte_string);
+ break;
+ }
+ uninterned_symbol = true;
+ skip_shorthand = false;
+ goto read_symbol;
- ch = read_escape (readcharfun, 1);
+ case '_':
+ /* #_X -- symbol without shorthand */
+ c = READCHAR;
+ if (c <= 32 || c == NO_BREAK_SPACE
+ || c == '"' || c == '\'' || c == ';' || c == '#'
+ || c == '(' || c == ')' || c == '[' || c == ']'
+ || c == '`' || c == ',')
+ {
+ /* No symbol character follows: this is the empty symbol. */
+ UNREAD (c);
+ obj = Fintern (empty_unibyte_string, Qnil);
+ break;
+ }
+ uninterned_symbol = false;
+ skip_shorthand = true;
+ goto read_symbol;
- /* CH is -1 if \ newline or \ space has just been seen. */
- if (ch == -1)
+ default:
+ if (ch >= '0' && ch <= '9')
+ {
+ /* #N=OBJ or #N# -- first read the number N */
+ EMACS_INT n = ch - '0';
+ int c;
+ for (;;)
{
- if (p == read_buffer)
- cancel = true;
- continue;
+ c = READCHAR;
+ if (c < '0' || c > '9')
+ break;
+ if (INT_MULTIPLY_WRAPV (n, 10, &n)
+ || INT_ADD_WRAPV (n, c - '0', &n))
+ invalid_syntax ("#", readcharfun);
}
-
- modifiers = ch & CHAR_MODIFIER_MASK;
- ch = ch & ~CHAR_MODIFIER_MASK;
-
- if (CHAR_BYTE8_P (ch))
- force_singlebyte = true;
- else if (! ASCII_CHAR_P (ch))
- force_multibyte = true;
- else /* I.e. ASCII_CHAR_P (ch). */
+ if (c == 'r' || c == 'R')
{
- /* Allow `\C- ' and `\C-?'. */
- if (modifiers == CHAR_CTL)
- {
- if (ch == ' ')
- ch = 0, modifiers = 0;
- else if (ch == '?')
- ch = 127, modifiers = 0;
- }
- if (modifiers & CHAR_SHIFT)
+ /* #NrDIGITS -- radix-N number */
+ if (n < 0 || n > 36)
+ invalid_radix_integer (n, stackbuf, readcharfun);
+ obj = read_integer (readcharfun, n, stackbuf);
+ break;
+ }
+ else if (n <= MOST_POSITIVE_FIXNUM && !NILP (Vread_circle))
+ {
+ if (c == '=')
{
- /* Shift modifier is valid only with [A-Za-z]. */
- if (ch >= 'A' && ch <= 'Z')
- modifiers &= ~CHAR_SHIFT;
- else if (ch >= 'a' && ch <= 'z')
- ch -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT;
+ /* #N=OBJ -- assign number N to OBJ */
+ Lisp_Object placeholder = Fcons (Qnil, Qnil);
+
+ struct Lisp_Hash_Table *h
+ = XHASH_TABLE (read_objects_map);
+ Lisp_Object number = make_fixnum (n);
+ Lisp_Object hash;
+ ptrdiff_t i = hash_lookup (h, number, &hash);
+ if (i >= 0)
+ /* Not normal, but input could be malformed. */
+ set_hash_value_slot (h, i, placeholder);
+ else
+ hash_put (h, number, placeholder, hash);
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_numbered,
+ .u.numbered.number = number,
+ .u.numbered.placeholder = placeholder,
+ });
+ goto read_obj;
}
-
- if (modifiers & CHAR_META)
+ else if (c == '#')
{
- /* Move the meta bit to the right place for a
- string. */
- modifiers &= ~CHAR_META;
- ch = BYTE8_TO_CHAR (ch | 0x80);
- force_singlebyte = true;
+ /* #N# -- reference to numbered object */
+ struct Lisp_Hash_Table *h
+ = XHASH_TABLE (read_objects_map);
+ ptrdiff_t i = hash_lookup (h, make_fixnum (n), NULL);
+ if (i < 0)
+ invalid_syntax ("#", readcharfun);
+ obj = HASH_VALUE (h, i);
+ break;
}
+ else
+ invalid_syntax ("#", readcharfun);
}
-
- /* Any modifiers remaining are invalid. */
- if (modifiers)
- invalid_syntax ("Invalid modifier in string", readcharfun);
- p += CHAR_STRING (ch, (unsigned char *) p);
+ else
+ invalid_syntax ("#", readcharfun);
}
else
- {
- p += CHAR_STRING (ch, (unsigned char *) p);
- if (CHAR_BYTE8_P (ch))
- force_singlebyte = true;
- else if (! ASCII_CHAR_P (ch))
- force_multibyte = true;
- }
- nchars++;
+ invalid_syntax ("#", readcharfun);
}
+ break;
+ }
- if (ch < 0)
- end_of_file_error ();
+ case '?':
+ obj = read_char_literal (readcharfun);
+ break;
- /* If purifying, and string starts with \ newline,
- return zero instead. This is for doc strings
- that we are really going to find in etc/DOC.nn.nn. */
- if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
- return unbind_to (count, make_fixnum (0));
+ case '"':
+ obj = read_string_literal (stackbuf, readcharfun);
+ break;
+
+ case '\'':
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_special,
+ .u.special.symbol = Qquote,
+ });
+ goto read_obj;
- if (! force_multibyte && force_singlebyte)
+ case '`':
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_special,
+ .u.special.symbol = Qbackquote,
+ });
+ goto read_obj;
+
+ case ',':
+ {
+ int ch = READCHAR;
+ Lisp_Object sym;
+ if (ch == '@')
+ sym = Qcomma_at;
+ else
{
- /* READ_BUFFER contains raw 8-bit bytes and no multibyte
- forms. Convert it to unibyte. */
- nchars = str_as_unibyte ((unsigned char *) read_buffer,
- p - read_buffer);
- p = read_buffer + nchars;
+ if (ch >= 0)
+ UNREAD (ch);
+ sym = Qcomma;
}
+ read_stack_push ((struct read_stack_entry) {
+ .type = RE_special,
+ .u.special.symbol = sym,
+ });
+ goto read_obj;
+ }
- Lisp_Object result
- = make_specified_string (read_buffer, nchars, p - read_buffer,
- (force_multibyte
- || (p - read_buffer != nchars)));
- return unbind_to (count, result);
+ case ';':
+ {
+ int c;
+ do
+ c = READCHAR;
+ while (c >= 0 && c != '\n');
+ goto read_obj;
}
case '.':
{
- int next_char = READCHAR;
- UNREAD (next_char);
-
- if (next_char <= 040
- || (next_char < 0200
- && strchr ("\"';([#?`,", next_char) != NULL))
+ int nch = READCHAR;
+ UNREAD (nch);
+ if (nch <= 32 || nch == NO_BREAK_SPACE
+ || nch == '"' || nch == '\'' || nch == ';'
+ || nch == '(' || nch == '[' || nch == '#'
+ || nch == '?' || nch == '`' || nch == ',')
{
- *pch = c;
- return Qnil;
+ if (!read_stack_empty_p (base_sp)
+ && read_stack_top ()->type == RE_list)
+ {
+ read_stack_top ()->type = RE_list_dot;
+ goto read_obj;
+ }
+ invalid_syntax (".", readcharfun);
}
}
- /* The atom-reading loop below will now loop at least once,
- assuring that we will not try to UNREAD two characters in a
- row. */
+ /* may be a number or symbol starting with a dot */
FALLTHROUGH;
+
default:
- if (c <= 040) goto retry;
- if (c == NO_BREAK_SPACE)
- goto retry;
+ if (c <= 32 || c == NO_BREAK_SPACE)
+ goto read_obj;
+ uninterned_symbol = false;
+ skip_shorthand = false;
+ /* symbol or number */
read_symbol:
{
- specpdl_ref count = SPECPDL_INDEX ();
- char *read_buffer = stackbuf;
- ptrdiff_t read_buffer_size = sizeof stackbuf;
- char *heapbuf = NULL;
char *p = read_buffer;
char *end = read_buffer + read_buffer_size;
bool quoted = false;
@@ -3805,7 +4105,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms)
if (c == '\\')
{
c = READCHAR;
- if (c == -1)
+ if (c < 0)
end_of_file_error ();
quoted = true;
}
@@ -3816,94 +4116,205 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms)
*p++ = c;
c = READCHAR;
}
- while (c > 040
+ while (c > 32
&& c != NO_BREAK_SPACE
- && (c >= 0200
- || strchr ("\"';()[]#`,", c) == NULL));
+ && (c >= 128
+ || !( c == '"' || c == '\'' || c == ';' || c == '#'
+ || c == '(' || c == ')' || c == '[' || c == ']'
+ || c == '`' || c == ',')));
*p = 0;
ptrdiff_t nbytes = p - read_buffer;
UNREAD (c);
- if (!quoted && !uninterned_symbol && !skip_shorthand)
+ /* Only attempt to parse the token as a number if it starts as one. */
+ char c0 = read_buffer[0];
+ if (((c0 >= '0' && c0 <= '9') || c0 == '.' || c0 == '-' || c0 == '+')
+ && !quoted && !uninterned_symbol && !skip_shorthand)
{
ptrdiff_t len;
Lisp_Object result = string_to_number (read_buffer, 10, &len);
- if (! NILP (result) && len == nbytes)
- return unbind_to (count, result);
+ if (!NILP (result) && len == nbytes)
+ {
+ obj = result;
+ break;
+ }
}
- {
- Lisp_Object result;
- ptrdiff_t nchars
- = (multibyte
- ? multibyte_chars_in_text ((unsigned char *) read_buffer,
- nbytes)
- : nbytes);
-
- if (uninterned_symbol)
- {
- Lisp_Object name
- = ((! NILP (Vpurify_flag)
- ? make_pure_string : make_specified_string)
- (read_buffer, nchars, nbytes, multibyte));
- result = Fmake_symbol (name);
- }
- else
- {
- /* Don't create the string object for the name unless
- we're going to retain it in a new symbol.
-
- Like intern_1 but supports multibyte names. */
- Lisp_Object obarray = check_obarray (Vobarray);
-
- char* longhand = NULL;
- ptrdiff_t longhand_chars = 0;
- ptrdiff_t longhand_bytes = 0;
-
- Lisp_Object tem;
- if (skip_shorthand
- /* The following ASCII characters are used in the
- only "core" Emacs Lisp symbols that are comprised
- entirely of characters that have the 'symbol
- constituent' syntax. We exempt them from
- transforming according to shorthands. */
- || strspn (read_buffer, "^*+-/<=>_|") >= nbytes)
- tem = oblookup (obarray, read_buffer, nchars, nbytes);
- else
- tem = oblookup_considering_shorthand (obarray, read_buffer,
+
+ /* symbol, possibly uninterned */
+ ptrdiff_t nchars
+ = (multibyte
+ ? multibyte_chars_in_text ((unsigned char *)read_buffer, nbytes)
+ : nbytes);
+ Lisp_Object result;
+ if (uninterned_symbol)
+ {
+ Lisp_Object name
+ = (!NILP (Vpurify_flag)
+ ? make_pure_string (read_buffer, nchars, nbytes, multibyte)
+ : make_specified_string (read_buffer, nchars, nbytes,
+ multibyte));
+ result = Fmake_symbol (name);
+ }
+ else
+ {
+ /* Don't create the string object for the name unless
+ we're going to retain it in a new symbol.
+
+ Like intern_1 but supports multibyte names. */
+ Lisp_Object obarray = check_obarray (Vobarray);
+
+ char *longhand = NULL;
+ ptrdiff_t longhand_chars = 0;
+ ptrdiff_t longhand_bytes = 0;
+
+ Lisp_Object found;
+ if (skip_shorthand
+ /* We exempt characters used in the "core" Emacs Lisp
+ symbols that are comprised entirely of characters
+ that have the 'symbol constituent' syntax from
+ transforming according to shorthands. */
+ || symbol_char_span (read_buffer) >= nbytes)
+ found = oblookup (obarray, read_buffer, nchars, nbytes);
+ else
+ found = oblookup_considering_shorthand (obarray, read_buffer,
nchars, nbytes, &longhand,
&longhand_chars,
&longhand_bytes);
- if (SYMBOLP (tem))
- result = tem;
- else if (longhand)
- {
- Lisp_Object name
- = make_specified_string (longhand, longhand_chars,
- longhand_bytes, multibyte);
- xfree (longhand);
- result = intern_driver (name, obarray, tem);
- }
- else
- {
- Lisp_Object name
- = make_specified_string (read_buffer, nchars, nbytes,
- multibyte);
- result = intern_driver (name, obarray, tem);
- }
- }
- if (locate_syms
- && !NILP (result)
- )
- result = build_symbol_with_pos (result,
- make_fixnum (start_position));
+ if (SYMBOLP (found))
+ result = found;
+ else if (longhand)
+ {
+ Lisp_Object name = make_specified_string (longhand,
+ longhand_chars,
+ longhand_bytes,
+ multibyte);
+ xfree (longhand);
+ result = intern_driver (name, obarray, found);
+ }
+ else
+ {
+ Lisp_Object name = make_specified_string (read_buffer, nchars,
+ nbytes, multibyte);
+ result = intern_driver (name, obarray, found);
+ }
+ }
+ if (locate_syms && !NILP (result))
+ result = build_symbol_with_pos (result,
+ make_fixnum (start_position));
- return unbind_to (count, result);
- }
+ obj = result;
+ break;
}
}
+
+ /* We have read an object in `obj'. Use the stack to decide what to
+ do with it. */
+ while (rdstack.sp > base_sp)
+ {
+ struct read_stack_entry *e = read_stack_top ();
+ switch (e->type)
+ {
+ case RE_list_start:
+ e->type = RE_list;
+ e->u.list.head = e->u.list.tail = Fcons (obj, Qnil);
+ goto read_obj;
+
+ case RE_list:
+ {
+ Lisp_Object tl = Fcons (obj, Qnil);
+ XSETCDR (e->u.list.tail, tl);
+ e->u.list.tail = tl;
+ goto read_obj;
+ }
+
+ case RE_list_dot:
+ {
+ skip_space_and_comments (readcharfun);
+ int ch = READCHAR;
+ if (ch != ')')
+ invalid_syntax ("expected )", readcharfun);
+ XSETCDR (e->u.list.tail, obj);
+ read_stack_pop ();
+ obj = e->u.list.head;
+ break;
+ }
+
+ case RE_vector:
+ case RE_record:
+ case RE_char_table:
+ case RE_sub_char_table:
+ case RE_byte_code:
+ case RE_string_props:
+ e->u.vector.elems = Fcons (obj, e->u.vector.elems);
+ goto read_obj;
+
+ case RE_special:
+ read_stack_pop ();
+ obj = list2 (e->u.special.symbol, obj);
+ break;
+
+ case RE_numbered:
+ {
+ read_stack_pop ();
+ Lisp_Object placeholder = e->u.numbered.placeholder;
+ if (CONSP (obj))
+ {
+ if (BASE_EQ (obj, placeholder))
+ /* Catch silly games like #1=#1# */
+ invalid_syntax ("nonsensical self-reference", readcharfun);
+
+ /* Optimisation: since the placeholder is already
+ a cons, repurpose it as the actual value.
+ This allows us to skip the substitution below,
+ since the placeholder is already referenced
+ inside OBJ at the appropriate places. */
+ Fsetcar (placeholder, XCAR (obj));
+ Fsetcdr (placeholder, XCDR (obj));
+
+ struct Lisp_Hash_Table *h2
+ = XHASH_TABLE (read_objects_completed);
+ Lisp_Object hash;
+ ptrdiff_t i = hash_lookup (h2, placeholder, &hash);
+ eassert (i < 0);
+ hash_put (h2, placeholder, Qnil, hash);
+ obj = placeholder;
+ }
+ else
+ {
+ /* If it can be recursive, remember it for future
+ substitutions. */
+ if (!SYMBOLP (obj) && !NUMBERP (obj)
+ && !(STRINGP (obj) && !string_intervals (obj)))
+ {
+ struct Lisp_Hash_Table *h2
+ = XHASH_TABLE (read_objects_completed);
+ Lisp_Object hash;
+ ptrdiff_t i = hash_lookup (h2, obj, &hash);
+ eassert (i < 0);
+ hash_put (h2, obj, Qnil, hash);
+ }
+
+ /* Now put it everywhere the placeholder was... */
+ Flread__substitute_object_in_subtree (obj, placeholder,
+ read_objects_completed);
+
+ /* ...and #n# will use the real value from now on. */
+ struct Lisp_Hash_Table *h = XHASH_TABLE (read_objects_map);
+ Lisp_Object hash;
+ ptrdiff_t i = hash_lookup (h, e->u.numbered.number, &hash);
+ eassert (i >= 0);
+ set_hash_value_slot (h, i, obj);
+ }
+ break;
+ }
+ }
+ }
+
+ return unbind_to (count, obj);
}
+
DEFUN ("lread--substitute-object-in-subtree",
Flread__substitute_object_in_subtree,
@@ -4150,214 +4561,6 @@ string_to_number (char const *string, int base, ptrdiff_t *plen)
}
-static Lisp_Object
-read_vector (Lisp_Object readcharfun, bool bytecodeflag, bool locate_syms)
-{
- Lisp_Object tem = read_list (1, readcharfun, locate_syms);
- ptrdiff_t size = list_length (tem);
- Lisp_Object vector = make_nil_vector (size);
-
- /* Avoid accessing past the end of a vector if the vector is too
- small to be valid for bytecode. */
- bytecodeflag &= COMPILED_STACK_DEPTH < size;
-
- Lisp_Object *ptr = XVECTOR (vector)->contents;
- for (ptrdiff_t i = 0; i < size; i++)
- {
- Lisp_Object item = Fcar (tem);
- /* If `load-force-doc-strings' is t when reading a lazily-loaded
- bytecode object, the docstring containing the bytecode and
- constants values must be treated as unibyte and passed to
- Fread, to get the actual bytecode string and constants vector. */
- if (bytecodeflag && load_force_doc_strings)
- {
- if (i == COMPILED_BYTECODE)
- {
- if (!STRINGP (item))
- error ("Invalid byte code");
-
- /* Delay handling the bytecode slot until we know whether
- it is lazily-loaded (we can tell by whether the
- constants slot is nil). */
- ASET (vector, COMPILED_CONSTANTS, item);
- item = Qnil;
- }
- else if (i == COMPILED_CONSTANTS)
- {
- Lisp_Object bytestr = ptr[COMPILED_CONSTANTS];
-
- if (NILP (item))
- {
- /* Coerce string to unibyte (like string-as-unibyte,
- but without generating extra garbage and
- guaranteeing no change in the contents). */
- STRING_SET_CHARS (bytestr, SBYTES (bytestr));
- STRING_SET_UNIBYTE (bytestr);
-
- item = Fread (Fcons (bytestr, readcharfun));
- if (!CONSP (item))
- error ("Invalid byte code");
-
- struct Lisp_Cons *otem = XCONS (item);
- bytestr = XCAR (item);
- item = XCDR (item);
- free_cons (otem);
- }
-
- /* Now handle the bytecode slot. */
- ASET (vector, COMPILED_BYTECODE, bytestr);
- }
- else if (i == COMPILED_DOC_STRING
- && STRINGP (item)
- && ! STRING_MULTIBYTE (item))
- {
- if (EQ (readcharfun, Qget_emacs_mule_file_char))
- item = Fdecode_coding_string (item, Qemacs_mule, Qnil, Qnil);
- else
- item = Fstring_as_multibyte (item);
- }
- }
- ASET (vector, i, item);
- struct Lisp_Cons *otem = XCONS (tem);
- tem = Fcdr (tem);
- free_cons (otem);
- }
- return vector;
-}
-
-/* FLAG means check for ']' to terminate rather than ')' and '.'.
- LOCATE_SYMS true means read symbol occurrencess as symbols with
- position. */
-
-static Lisp_Object
-read_list (bool flag, Lisp_Object readcharfun, bool locate_syms)
-{
- Lisp_Object val, tail;
- Lisp_Object elt, tem;
- /* 0 is the normal case.
- 1 means this list is a doc reference; replace it with the number 0.
- 2 means this list is a doc reference; replace it with the doc string. */
- int doc_reference = 0;
-
- /* Initialize this to 1 if we are reading a list. */
- bool first_in_list = flag <= 0;
-
- val = Qnil;
- tail = Qnil;
-
- while (1)
- {
- int ch;
- elt = read1 (readcharfun, &ch, first_in_list, locate_syms);
-
- first_in_list = 0;
-
- /* While building, if the list starts with #$, treat it specially. */
- if (EQ (elt, Vload_file_name)
- && ! NILP (elt))
- {
- if (!NILP (Vpurify_flag))
- doc_reference = 0;
- else if (load_force_doc_strings)
- doc_reference = 2;
- }
- if (ch)
- {
- if (flag > 0)
- {
- if (ch == ']')
- return val;
- invalid_syntax (") or . in a vector", readcharfun);
- }
- if (ch == ')')
- return val;
- if (ch == '.')
- {
- if (!NILP (tail))
- XSETCDR (tail, read0 (readcharfun, locate_syms));
- else
- val = read0 (readcharfun, locate_syms);
- read1 (readcharfun, &ch, 0, locate_syms);
-
- if (ch == ')')
- {
- if (doc_reference == 2 && FIXNUMP (XCDR (val)))
- {
- char *saved = NULL;
- file_offset saved_position;
- /* Get a doc string from the file we are loading.
- If it's in saved_doc_string, get it from there.
-
- Here, we don't know if the string is a
- bytecode string or a doc string. As a
- bytecode string must be unibyte, we always
- return a unibyte string. If it is actually a
- doc string, caller must make it
- multibyte. */
-
- /* Position is negative for user variables. */
- EMACS_INT pos = eabs (XFIXNUM (XCDR (val)));
- if (pos >= saved_doc_string_position
- && pos < (saved_doc_string_position
- + saved_doc_string_length))
- {
- saved = saved_doc_string;
- saved_position = saved_doc_string_position;
- }
- /* Look in prev_saved_doc_string the same way. */
- else if (pos >= prev_saved_doc_string_position
- && pos < (prev_saved_doc_string_position
- + prev_saved_doc_string_length))
- {
- saved = prev_saved_doc_string;
- saved_position = prev_saved_doc_string_position;
- }
- if (saved)
- {
- ptrdiff_t start = pos - saved_position;
- ptrdiff_t from, to;
-
- /* Process quoting with ^A,
- and find the end of the string,
- which is marked with ^_ (037). */
- for (from = start, to = start;
- saved[from] != 037;)
- {
- int c = saved[from++];
- if (c == 1)
- {
- c = saved[from++];
- saved[to++] = (c == 1 ? c
- : c == '0' ? 0
- : c == '_' ? 037
- : c);
- }
- else
- saved[to++] = c;
- }
-
- return make_unibyte_string (saved + start,
- to - start);
- }
- else
- return get_doc_string (val, 1, 0);
- }
-
- return val;
- }
- invalid_syntax (". in wrong context", readcharfun);
- }
- invalid_syntax ("] in a list", readcharfun);
- }
- tem = list1 (elt);
- if (!NILP (tail))
- XSETCDR (tail, tem);
- else
- val = tem;
- tail = tem;
- }
-}
-
static Lisp_Object initial_obarray;
/* `oblookup' stores the bucket number here, for the sake of Funintern. */
@@ -4464,7 +4667,7 @@ define_symbol (Lisp_Object sym, char const *str)
/* Qunbound is uninterned, so that it's not confused with any symbol
'unbound' created by a Lisp program. */
- if (! EQ (sym, Qunbound))
+ if (! BASE_EQ (sym, Qunbound))
{
Lisp_Object bucket = oblookup (initial_obarray, str, len, len);
eassert (FIXNUMP (bucket));
diff --git a/src/menu.c b/src/menu.c
index 398bf9329ff..eeb0c9a7e5b 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -1118,7 +1118,7 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
Lisp_Object title;
const char *error_name = NULL;
Lisp_Object selection = Qnil;
- struct frame *f = NULL;
+ struct frame *f;
Lisp_Object x, y, window;
int menuflags = 0;
specpdl_ref specpdl_count = SPECPDL_INDEX ();
@@ -1269,9 +1269,9 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
}
}
else
- /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
+ /* ??? Not really clean; should be Qwindow_or_framep
but I don't want to make one now. */
- CHECK_WINDOW (window);
+ wrong_type_argument (Qwindowp, window);
xpos += check_integer_range (x,
(xpos < INT_MIN - MOST_NEGATIVE_FIXNUM
diff --git a/src/minibuf.c b/src/minibuf.c
index df82bcb121a..1f77a6cdc18 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -201,20 +201,12 @@ move_minibuffers_onto_frame (struct frame *of, bool for_deletion)
return;
if (FRAME_LIVE_P (f)
&& !EQ (f->minibuffer_window, of->minibuffer_window)
- && WINDOW_LIVE_P (f->minibuffer_window) /* F not a tootip frame */
+ && WINDOW_LIVE_P (f->minibuffer_window) /* F not a tooltip frame */
&& WINDOW_LIVE_P (of->minibuffer_window))
{
zip_minibuffer_stacks (f->minibuffer_window, of->minibuffer_window);
if (for_deletion && XFRAME (MB_frame) != of)
MB_frame = selected_frame;
- if (!for_deletion
- && MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of))))
- {
- Lisp_Object old_frame;
- XSETFRAME (old_frame, of);
- Fset_frame_selected_window (old_frame,
- Fframe_first_window (old_frame), Qnil);
- }
}
}
@@ -265,7 +257,7 @@ without invoking the usual minibuffer commands. */)
static void read_minibuf_unwind (void);
static void minibuffer_unwind (void);
-static void run_exit_minibuf_hook (void);
+static void run_exit_minibuf_hook (Lisp_Object minibuf);
/* Read a Lisp object from VAL and return it. If VAL is an empty
@@ -749,7 +741,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
separately from read_minibuf_unwind because we need to make sure that
read_minibuf_unwind is fully executed even if exit-minibuffer-hook
signals an error. --Stef */
- record_unwind_protect_void (run_exit_minibuf_hook);
+ record_unwind_protect (run_exit_minibuf_hook, minibuffer);
/* Now that we can restore all those variables, start changing them. */
@@ -768,7 +760,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
/* If variable is unbound, make it nil. */
histval = find_symbol_value (histvar);
- if (EQ (histval, Qunbound))
+ if (BASE_EQ (histval, Qunbound))
{
Fset (histvar, Qnil);
histval = Qnil;
@@ -1076,9 +1068,14 @@ static EMACS_INT minibuf_c_loop_level (EMACS_INT depth)
}
static void
-run_exit_minibuf_hook (void)
+run_exit_minibuf_hook (Lisp_Object minibuf)
{
+ specpdl_ref count = SPECPDL_INDEX ();
+ record_unwind_current_buffer ();
+ if (BUFFER_LIVE_P (XBUFFER (minibuf)))
+ Fset_buffer (minibuf);
safe_run_hooks (Qminibuffer_exit_hook);
+ unbind_to (count, Qnil);
}
/* This variable records the expired minibuffer's frame between the
@@ -1696,7 +1693,8 @@ or from one of the possible completions. */)
else /* if (type == hash_table) */
{
while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection))
- && EQ (HASH_KEY (XHASH_TABLE (collection), idx), Qunbound))
+ && BASE_EQ (HASH_KEY (XHASH_TABLE (collection), idx),
+ Qunbound))
idx++;
if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection)))
break;
@@ -1933,7 +1931,8 @@ with a space are ignored unless STRING itself starts with a space. */)
else /* if (type == 3) */
{
while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection))
- && EQ (HASH_KEY (XHASH_TABLE (collection), idx), Qunbound))
+ && BASE_EQ (HASH_KEY (XHASH_TABLE (collection), idx),
+ Qunbound))
idx++;
if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection)))
break;
@@ -2012,6 +2011,8 @@ REQUIRE-MATCH can take the following values:
input, but she needs to confirm her choice if she called
`minibuffer-complete' right before `minibuffer-complete-and-exit'
and the input is not an element of COLLECTION.
+- a function, which will be called with the input as the parameter.
+ If it returns a non-nil value, the minibuffer is exited with that value.
- anything else behaves like t except that typing RET does not exit if it
does non-null completion.
@@ -2140,7 +2141,7 @@ the values STRING, PREDICATE and `lambda'. */)
for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
{
tem = HASH_KEY (h, i);
- if (EQ (tem, Qunbound)) continue;
+ if (BASE_EQ (tem, Qunbound)) continue;
Lisp_Object strkey = (SYMBOLP (tem) ? Fsymbol_name (tem) : tem);
if (!STRINGP (strkey)) continue;
if (EQ (Fcompare_strings (string, Qnil, Qnil,
diff --git a/src/nsfns.m b/src/nsfns.m
index a67dafe0950..5ab2b2ee35a 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -47,12 +47,42 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
#ifdef NS_IMPL_COCOA
#include <IOKit/graphics/IOGraphicsLib.h>
#include "macfont.h"
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
+#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 120000
+#define IOMasterPort IOMainPort
+#endif
+#endif
#endif
#ifdef HAVE_NS
static EmacsTooltip *ns_tooltip = nil;
+/* The frame of the currently visible tooltip, or nil if none. */
+static Lisp_Object tip_frame;
+
+/* The X and Y deltas of the last call to `x-show-tip'. */
+static Lisp_Object tip_dx, tip_dy;
+
+/* The window-system window corresponding to the frame of the
+ currently visible tooltip. */
+static NSWindow *tip_window;
+
+/* A timer that hides or deletes the currently visible tooltip when it
+ fires. */
+static Lisp_Object tip_timer;
+
+/* STRING argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_string;
+
+/* Normalized FRAME argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_frame;
+
+/* PARMS argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_parms;
+
/* Static variables to handle AppleScript execution. */
static Lisp_Object as_script, *as_result;
static int as_status;
@@ -769,11 +799,13 @@ ns_implicitly_set_icon_type (struct frame *f)
Lisp_Object chain, elt;
NSAutoreleasePool *pool;
BOOL setMini = YES;
+ NSWorkspace *workspace;
NSTRACE ("ns_implicitly_set_icon_type");
block_input ();
pool = [[NSAutoreleasePool alloc] init];
+ workspace = [NSWorkspace sharedWorkspace];
if (f->output_data.ns->miniimage
&& [[NSString stringWithLispString:f->name]
isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
@@ -818,7 +850,21 @@ ns_implicitly_set_icon_type (struct frame *f)
if (image == nil)
{
- image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain];
+#ifndef NS_IMPL_GNUSTEP
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+ if ([workspace respondsToSelector: @selector (iconForContentType:)])
+#endif
+ image = [[workspace iconForContentType:
+ [UTType typeWithIdentifier: @"text"]] retain];
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+ else
+#endif
+#endif
+#endif
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+ image = [[workspace iconForFileType: @"text"] retain];
+#endif
setMini = NO;
}
@@ -1021,7 +1067,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
/* Handler for signals raised during x_create_frame.
FRAME is the frame which is partially constructed. */
-static void
+static Lisp_Object
unwind_create_frame (Lisp_Object frame)
{
struct frame *f = XFRAME (frame);
@@ -1030,7 +1076,7 @@ unwind_create_frame (Lisp_Object frame)
display is disconnected after the frame has become official, but
before x_create_frame removes the unwind protect. */
if (!FRAME_LIVE_P (f))
- return;
+ return Qnil;
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
@@ -1057,7 +1103,18 @@ unwind_create_frame (Lisp_Object frame)
/* Check that reference counts are indeed correct. */
eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
#endif
+
+ return Qt;
}
+
+ return Qnil;
+}
+
+
+static void
+do_unwind_create_frame (Lisp_Object frame)
+{
+ unwind_create_frame (frame);
}
/*
@@ -1191,7 +1248,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
FRAME_DISPLAY_INFO (f) = dpyinfo;
/* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */
- record_unwind_protect (unwind_create_frame, frame);
+ record_unwind_protect (do_unwind_create_frame, frame);
f->output_data.ns->window_desc = desc_ctr++;
if (TYPE_RANGED_FIXNUMP (Window, parent))
@@ -1726,7 +1783,20 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */)
ns_fd_data.ret = NO;
#ifdef NS_IMPL_COCOA
if (! NILP (mustmatch) || ! NILP (dir_only_p))
- [panel setAllowedFileTypes: nil];
+ {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+ if ([panel respondsToSelector: @selector (setAllowedContentTypes:)])
+#endif
+ [panel setAllowedContentTypes: [NSArray array]];
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+ else
+#endif
+#endif
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+ [panel setAllowedFileTypes: nil];
+#endif
+ }
if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]];
if (initS && NILP (Ffile_directory_p (init)))
[panel setNameFieldStringValue: [initS lastPathComponent]];
@@ -1792,7 +1862,7 @@ ns_get_defaults_value (const char *key)
DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0,
doc: /* Return the value of the property NAME of OWNER from the defaults database.
If OWNER is nil, Emacs is assumed. */)
- (Lisp_Object owner, Lisp_Object name)
+ (Lisp_Object owner, Lisp_Object name)
{
const char *value;
@@ -1813,7 +1883,7 @@ DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0,
doc: /* Set property NAME of OWNER to VALUE, from the defaults database.
If OWNER is nil, Emacs is assumed.
If VALUE is nil, the default is removed. */)
- (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
+ (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
{
check_window_system (NULL);
if (NILP (owner))
@@ -1840,7 +1910,7 @@ DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
Sx_server_max_request_size,
0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
- (Lisp_Object terminal)
+ (Lisp_Object terminal)
{
check_ns_display_info (terminal);
/* This function has no real equivalent under Nextstep. Return nil to
@@ -2702,7 +2772,8 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
}
else
{
- // Flip y coordinate as NS has y starting from the bottom.
+ /* Flip y coordinate as NS screen coordinates originate from
+ the bottom. */
y = (short) (primary_display_height - fr.size.height - fr.origin.y);
vy = (short) (primary_display_height -
vfr.size.height - vfr.origin.y);
@@ -2714,11 +2785,12 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
m->geom.height = (unsigned short) fr.size.height;
m->work.x = (short) vfr.origin.x;
- // y is flipped on NS, so vy - y are pixels missing at the bottom,
- // and fr.size.height - vfr.size.height are pixels missing in total.
- // Pixels missing at top are
- // fr.size.height - vfr.size.height - vy + y.
- // work.y is then pixels missing at top + y.
+ /* y is flipped on NS, so vy - y are pixels missing at the
+ bottom, and fr.size.height - vfr.size.height are pixels
+ missing in total.
+
+ Pixels missing at top are fr.size.height - vfr.size.height -
+ vy + y. work.y is then pixels missing at top + y. */
m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
m->work.width = (unsigned short) vfr.size.width;
m->work.height = (unsigned short) vfr.size.height;
@@ -2733,13 +2805,14 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
}
#else
- // Assume 92 dpi as x-display-mm-height/x-display-mm-width does.
+ /* Assume 92 dpi as x-display-mm-height and x-display-mm-width
+ do. */
m->mm_width = (int) (25.4 * fr.size.width / 92.0);
m->mm_height = (int) (25.4 * fr.size.height / 92.0);
#endif
}
- // Primary monitor is always first for NS.
+ /* Primary monitor is always ordered first for NS. */
attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
0, "NS");
@@ -2769,16 +2842,10 @@ DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
return make_fixnum (1 << min (dpyinfo->n_planes, 24));
}
-/* TODO: move to xdisp or similar */
static void
-compute_tip_xy (struct frame *f,
- Lisp_Object parms,
- Lisp_Object dx,
- Lisp_Object dy,
- int width,
- int height,
- int *root_x,
- int *root_y)
+compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
+ Lisp_Object dy, int width, int height, int *root_x,
+ int *root_y)
{
Lisp_Object left, top, right, bottom;
NSPoint pt;
@@ -2847,6 +2914,299 @@ compute_tip_xy (struct frame *f,
*root_y = screen.frame.origin.y + screen.frame.size.height - height;
}
+static void
+unwind_create_tip_frame (Lisp_Object frame)
+{
+ Lisp_Object deleted;
+
+ deleted = unwind_create_frame (frame);
+ if (EQ (deleted, Qt))
+ {
+ tip_window = NULL;
+ tip_frame = Qnil;
+ }
+}
+
+/* Create a frame for a tooltip on the display described by DPYINFO.
+ PARMS is a list of frame parameters. TEXT is the string to
+ display in the tip frame. Value is the frame.
+
+ Note that functions called here, esp. gui_default_parameter can
+ signal errors, for instance when a specified color name is
+ undefined. We have to make sure that we're in a consistent state
+ when this happens. */
+
+static Lisp_Object
+ns_create_tip_frame (struct ns_display_info *dpyinfo, Lisp_Object parms)
+{
+ struct frame *f;
+ Lisp_Object frame;
+ Lisp_Object name;
+ specpdl_ref count = SPECPDL_INDEX ();
+ bool face_change_before = face_change;
+
+ if (!dpyinfo->terminal->name)
+ error ("Terminal is not live, can't create new frames on it");
+
+ parms = Fcopy_alist (parms);
+
+ /* Get the name of the frame to use for resource lookup. */
+ name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
+ RES_TYPE_STRING);
+ if (!STRINGP (name)
+ && !EQ (name, Qunbound)
+ && !NILP (name))
+ error ("Invalid frame name--not a string or nil");
+
+ frame = Qnil;
+ f = make_frame (false);
+ f->wants_modeline = false;
+ XSETFRAME (frame, f);
+ record_unwind_protect (unwind_create_tip_frame, frame);
+
+ f->terminal = dpyinfo->terminal;
+
+ f->output_method = output_ns;
+ f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
+ f->tooltip = true;
+
+ FRAME_FONTSET (f) = -1;
+ FRAME_DISPLAY_INFO (f) = dpyinfo;
+
+ block_input ();
+#ifdef NS_IMPL_COCOA
+ mac_register_font_driver (f);
+#else
+ register_font_driver (&nsfont_driver, f);
+#endif
+ unblock_input ();
+
+ image_cache_refcount =
+ FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
+
+ gui_default_parameter (f, parms, Qfont_backend, Qnil,
+ "fontBackend", "FontBackend", RES_TYPE_STRING);
+
+ {
+#ifdef NS_IMPL_COCOA
+ /* use for default font name */
+ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
+ gui_default_parameter (f, parms, Qfontsize,
+ make_fixnum (0 /* (int)[font pointSize] */),
+ "fontSize", "FontSize", RES_TYPE_NUMBER);
+ // Remove ' Regular', not handled by backends.
+ char *fontname = xstrdup ([[font displayName] UTF8String]);
+ int len = strlen (fontname);
+ if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
+ fontname[len-8] = '\0';
+ gui_default_parameter (f, parms, Qfont,
+ build_string (fontname),
+ "font", "Font", RES_TYPE_STRING);
+ xfree (fontname);
+#else
+ gui_default_parameter (f, parms, Qfont,
+ build_string ("fixed"),
+ "font", "Font", RES_TYPE_STRING);
+#endif
+ }
+
+ gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
+ "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
+
+ /* This defaults to 1 in order to match xterm. We recognize either
+ internalBorderWidth or internalBorder (which is what xterm calls
+ it). */
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ {
+ Lisp_Object value;
+
+ value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
+ "internalBorder", "internalBorder",
+ RES_TYPE_NUMBER);
+ if (! EQ (value, Qunbound))
+ parms = Fcons (Fcons (Qinternal_border_width, value),
+ parms);
+ }
+
+ gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
+ "internalBorderWidth", "internalBorderWidth",
+ RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
+ NULL, NULL, RES_TYPE_NUMBER);
+
+ /* Also do the stuff which must be set before the window exists. */
+ gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
+ "foreground", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
+ "background", "Background", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
+ "pointerColor", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
+ "cursorColor", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
+ "borderColor", "BorderColor", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+
+ /* Init faces before gui_default_parameter is called for the
+ scroll-bar-width parameter because otherwise we end up in
+ init_iterator with a null face cache, which should not happen. */
+ init_frame_faces (f);
+
+ f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
+
+ gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
+ "inhibitDoubleBuffering", "InhibitDoubleBuffering",
+ RES_TYPE_BOOLEAN);
+
+ gui_figure_window_size (f, parms, false, false);
+
+ block_input ();
+ [[EmacsView alloc] initFrameFromEmacs: f];
+ ns_icon (f, parms);
+ unblock_input ();
+
+ gui_default_parameter (f, parms, Qauto_raise, Qnil,
+ "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qauto_lower, Qnil,
+ "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qcursor_type, Qbox,
+ "cursorType", "CursorType", RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qalpha, Qnil,
+ "alpha", "Alpha", RES_TYPE_NUMBER);
+
+ /* Add `tooltip' frame parameter's default value. */
+ if (NILP (Fframe_parameter (frame, Qtooltip)))
+ {
+ AUTO_FRAME_ARG (arg, Qtooltip, Qt);
+ Fmodify_frame_parameters (frame, arg);
+ }
+
+ /* FIXME - can this be done in a similar way to normal frames?
+ https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
+
+ /* Set the `display-type' frame parameter before setting up faces. */
+ {
+ Lisp_Object disptype = intern ("color");
+
+ if (NILP (Fframe_parameter (frame, Qdisplay_type)))
+ {
+ AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
+ Fmodify_frame_parameters (frame, arg);
+ }
+ }
+
+ /* Set up faces after all frame parameters are known. This call
+ also merges in face attributes specified for new frames.
+
+ Frame parameters may be changed if .Xdefaults contains
+ specifications for the default font. For example, if there is an
+ `Emacs.default.attributeBackground: pink', the `background-color'
+ attribute of the frame gets set, which let's the internal border
+ of the tooltip frame appear in pink. Prevent this. */
+ {
+ Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
+
+ call2 (Qface_set_after_frame_default, frame, Qnil);
+
+ if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
+ {
+ AUTO_FRAME_ARG (arg, Qbackground_color, bg);
+ Fmodify_frame_parameters (frame, arg);
+ }
+ }
+
+ f->no_split = true;
+
+ /* Now that the frame will be official, it counts as a reference to
+ its display and terminal. */
+ f->terminal->reference_count++;
+
+ /* It is now ok to make the frame official even if we get an error
+ below. And the frame needs to be on Vframe_list or making it
+ visible won't work. */
+ Vframe_list = Fcons (frame, Vframe_list);
+ f->can_set_window_size = true;
+ adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+ 0, true, Qtip_frame);
+
+ /* Setting attributes of faces of the tooltip frame from resources
+ and similar will set face_change, which leads to the clearing of
+ all current matrices. Since this isn't necessary here, avoid it
+ by resetting face_change to the value it had before we created
+ the tip frame. */
+ face_change = face_change_before;
+
+ /* Discard the unwind_protect. */
+ return unbind_to (count, frame);
+}
+
+static Lisp_Object
+x_hide_tip (bool delete)
+{
+ if (!NILP (tip_timer))
+ {
+ call1 (intern ("cancel-timer"), tip_timer);
+ tip_timer = Qnil;
+ }
+
+ if (!(ns_tooltip == nil || ![ns_tooltip isActive]))
+ {
+ [ns_tooltip hide];
+ tip_last_frame = Qnil;
+ return Qt;
+ }
+
+ if ((NILP (tip_last_frame) && NILP (tip_frame))
+ || (!use_system_tooltips
+ && !delete
+ && !NILP (tip_frame)
+ && FRAME_LIVE_P (XFRAME (tip_frame))
+ && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
+ /* Either there's no tooltip to hide or it's an already invisible
+ Emacs tooltip and we don't want to change its type. Return
+ quickly. */
+ return Qnil;
+ else
+ {
+ specpdl_ref count;
+ Lisp_Object was_open = Qnil;
+
+ count = SPECPDL_INDEX ();
+ specbind (Qinhibit_redisplay, Qt);
+ specbind (Qinhibit_quit, Qt);
+
+ /* Now look whether there's an Emacs tip around. */
+ if (!NILP (tip_frame))
+ {
+ struct frame *f = XFRAME (tip_frame);
+
+ if (FRAME_LIVE_P (f))
+ {
+ if (delete || use_system_tooltips)
+ {
+ /* Delete the Emacs tooltip frame when DELETE is true
+ or we change the tooltip type from an Emacs one to
+ a GTK+ system one. */
+ delete_frame (tip_frame, Qnil);
+ tip_frame = Qnil;
+ }
+ else
+ ns_make_frame_invisible (f);
+
+ was_open = Qt;
+ }
+ else
+ tip_frame = Qnil;
+ }
+ else
+ tip_frame = Qnil;
+
+ return unbind_to (count, was_open);
+ }
+}
DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
doc: /* SKIP: real doc in xfns.c. */)
@@ -2854,11 +3214,18 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
{
int root_x, root_y;
specpdl_ref count = SPECPDL_INDEX ();
- struct frame *f;
+ struct frame *f, *tip_f;
+ struct window *w;
+ struct buffer *old_buffer;
+ struct text_pos pos;
+ int width, height;
+ int old_windows_or_buffers_changed = windows_or_buffers_changed;
+ specpdl_ref count_1;
+ Lisp_Object window, size, tip_buf;
char *str;
- NSSize size;
- NSColor *color;
- Lisp_Object t;
+ NSWindow *nswindow;
+
+ AUTO_STRING (tip, " *tip*");
specbind (Qinhibit_redisplay, Qt);
@@ -2879,32 +3246,253 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
else
CHECK_FIXNUM (dy);
- block_input ();
- if (ns_tooltip == nil)
- ns_tooltip = [[EmacsTooltip alloc] init];
+ tip_dx = dx;
+ tip_dy = dy;
+
+ if (use_system_tooltips)
+ {
+ NSSize size;
+ NSColor *color;
+ Lisp_Object t;
+
+ block_input ();
+ if (ns_tooltip == nil)
+ ns_tooltip = [[EmacsTooltip alloc] init];
+ else
+ Fx_hide_tip ();
+
+ t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL,
+ RES_TYPE_STRING);
+ if (ns_lisp_to_color (t, &color) == 0)
+ [ns_tooltip setBackgroundColor: color];
+
+ t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL,
+ RES_TYPE_STRING);
+ if (ns_lisp_to_color (t, &color) == 0)
+ [ns_tooltip setForegroundColor: color];
+
+ [ns_tooltip setText: str];
+ size = [ns_tooltip frame].size;
+
+ /* Move the tooltip window where the mouse pointer is. Resize and
+ show it. */
+ compute_tip_xy (f, parms, dx, dy, (int) size.width, (int) size.height,
+ &root_x, &root_y);
+
+ [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)];
+ unblock_input ();
+ }
else
- Fx_hide_tip ();
+ {
+ if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ if (FRAME_VISIBLE_P (XFRAME (tip_frame))
+ && EQ (frame, tip_last_frame)
+ && !NILP (Fequal_including_properties (tip_last_string, string))
+ && !NILP (Fequal (tip_last_parms, parms)))
+ {
+ /* Only DX and DY have changed. */
+ tip_f = XFRAME (tip_frame);
+ if (!NILP (tip_timer))
+ {
+ call1 (intern ("cancel-timer"), tip_timer);
+ tip_timer = Qnil;
+ }
+
+ nswindow = [FRAME_NS_VIEW (tip_f) window];
+
+ block_input ();
+ compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
+ FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
+ [nswindow setFrame: NSMakeRect (root_x, root_y,
+ FRAME_PIXEL_WIDTH (tip_f),
+ FRAME_PIXEL_HEIGHT (tip_f))
+ display: YES];
+ [nswindow setLevel: NSPopUpMenuWindowLevel];
+ [nswindow orderFront: NSApp];
+ [nswindow display];
+
+ SET_FRAME_VISIBLE (tip_f, 1);
+ unblock_input ();
+
+ goto start_timer;
+ }
+ else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
+ {
+ bool delete = false;
+ Lisp_Object tail, elt, parm, last;
+
+ /* Check if every parameter in PARMS has the same value in
+ tip_last_parms. This may destruct tip_last_parms which,
+ however, will be recreated below. */
+ for (tail = parms; CONSP (tail); tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ parm = Fcar (elt);
+ /* The left, top, right and bottom parameters are handled
+ by compute_tip_xy so they can be ignored here. */
+ if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
+ && !EQ (parm, Qright) && !EQ (parm, Qbottom))
+ {
+ last = Fassq (parm, tip_last_parms);
+ if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
+ {
+ /* We lost, delete the old tooltip. */
+ delete = true;
+ break;
+ }
+ else
+ tip_last_parms =
+ call2 (intern ("assq-delete-all"), parm, tip_last_parms);
+ }
+ else
+ tip_last_parms =
+ call2 (intern ("assq-delete-all"), parm, tip_last_parms);
+ }
+
+ /* Now check if every parameter in what is left of
+ tip_last_parms with a non-nil value has an association in
+ PARMS. */
+ for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ parm = Fcar (elt);
+ if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
+ && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
+ {
+ /* We lost, delete the old tooltip. */
+ delete = true;
+ break;
+ }
+ }
+
+ x_hide_tip (delete);
+ }
+ else
+ x_hide_tip (true);
+ }
+ else
+ x_hide_tip (true);
- t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL,
- RES_TYPE_STRING);
- if (ns_lisp_to_color (t, &color) == 0)
- [ns_tooltip setBackgroundColor: color];
+ tip_last_frame = frame;
+ tip_last_string = string;
+ tip_last_parms = parms;
- t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL,
- RES_TYPE_STRING);
- if (ns_lisp_to_color (t, &color) == 0)
- [ns_tooltip setForegroundColor: color];
+ if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ /* Add default values to frame parameters. */
+ if (NILP (Fassq (Qname, parms)))
+ parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms);
+ if (NILP (Fassq (Qborder_width, parms)))
+ parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
+ if (NILP (Fassq (Qborder_color, parms)))
+ parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
+ if (NILP (Fassq (Qbackground_color, parms)))
+ parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+ parms);
+
+ /* Create a frame for the tooltip, and record it in the global
+ variable tip_frame. */
+ if (NILP (tip_frame = ns_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
+ /* Creating the tip frame failed. */
+ return unbind_to (count, Qnil);
+ }
- [ns_tooltip setText: str];
- size = [ns_tooltip frame].size;
+ tip_f = XFRAME (tip_frame);
+ window = FRAME_ROOT_WINDOW (tip_f);
+ tip_buf = Fget_buffer_create (tip, Qnil);
+ /* We will mark the tip window a "pseudo-window" below, and such
+ windows cannot have display margins. */
+ bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
+ bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
+ set_window_buffer (window, tip_buf, false, false);
+ w = XWINDOW (window);
+ w->pseudo_window_p = true;
+ /* Try to avoid that `other-window' select us (Bug#47207). */
+ Fset_window_parameter (window, Qno_other_window, Qt);
+
+ /* Set up the frame's root window. Note: The following code does not
+ try to size the window or its frame correctly. Its only purpose is
+ to make the subsequent text size calculations work. The right
+ sizes should get installed when the toolkit gets back to us. */
+ w->left_col = 0;
+ w->top_line = 0;
+ w->pixel_left = 0;
+ w->pixel_top = 0;
+
+ if (CONSP (Vx_max_tooltip_size)
+ && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
+ && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
+ {
+ w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
+ w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
+ }
+ else
+ {
+ w->total_cols = 80;
+ w->total_lines = 40;
+ }
- /* Move the tooltip window where the mouse pointer is. Resize and
- show it. */
- compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height,
- &root_x, &root_y);
+ w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
+ w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
+ FRAME_TOTAL_COLS (tip_f) = w->total_cols;
+ adjust_frame_glyphs (tip_f);
+
+ /* Insert STRING into root window's buffer and fit the frame to the
+ buffer. */
+ count_1 = SPECPDL_INDEX ();
+ old_buffer = current_buffer;
+ set_buffer_internal_1 (XBUFFER (w->contents));
+ bset_truncate_lines (current_buffer, Qnil);
+ specbind (Qinhibit_read_only, Qt);
+ specbind (Qinhibit_modification_hooks, Qt);
+ specbind (Qinhibit_point_motion_hooks, Qt);
+ Ferase_buffer ();
+ Finsert (1, &string);
+ clear_glyph_matrix (w->desired_matrix);
+ clear_glyph_matrix (w->current_matrix);
+ SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
+ try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+ /* Calculate size of tooltip window. */
+ size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
+ make_fixnum (w->pixel_height), Qnil,
+ Qnil);
+ /* Add the frame's internal border to calculated size. */
+ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+ height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+
+ /* Calculate position of tooltip frame. */
+ compute_tip_xy (tip_f, parms, dx, dy, width,
+ height, &root_x, &root_y);
+
+ block_input ();
+ nswindow = [FRAME_NS_VIEW (tip_f) window];
+ [nswindow setFrame: NSMakeRect (root_x, root_y,
+ width, height)
+ display: YES];
+ [nswindow setLevel: NSPopUpMenuWindowLevel];
+ [nswindow orderFront: NSApp];
+ [nswindow display];
+
+ SET_FRAME_VISIBLE (tip_f, YES);
+ FRAME_PIXEL_WIDTH (tip_f) = width;
+ FRAME_PIXEL_HEIGHT (tip_f) = height;
+ unblock_input ();
- [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)];
- unblock_input ();
+ w->must_be_updated_p = true;
+ update_single_window (w);
+ flush_frame (tip_f);
+ set_buffer_internal_1 (old_buffer);
+ unbind_to (count_1, Qnil);
+ windows_or_buffers_changed = old_windows_or_buffers_changed;
+
+ start_timer:
+ /* Let the tip disappear after timeout seconds. */
+ tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
+ intern ("x-hide-tip"));
+ }
return unbind_to (count, Qnil);
}
@@ -2914,10 +3502,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
doc: /* SKIP: real doc in xfns.c. */)
(void)
{
- if (ns_tooltip == nil || ![ns_tooltip isActive])
- return Qnil;
- [ns_tooltip hide];
- return Qt;
+ return x_hide_tip (!tooltip_reuse_hidden_frame);
}
/* Return geometric attributes of FRAME. According to the value of
@@ -3215,6 +3800,48 @@ all_nonzero_ascii (unsigned char *str, ptrdiff_t n)
}
@end
+void
+ns_move_tooltip_to_mouse_location (NSPoint screen_point)
+{
+ int root_x, root_y;
+ NSSize size;
+ NSWindow *window;
+ struct frame *tip_f;
+
+ window = nil;
+
+ if (!FIXNUMP (tip_dx) || !FIXNUMP (tip_dy))
+ return;
+
+ if (ns_tooltip)
+ size = [ns_tooltip frame].size;
+ else if (!FRAMEP (tip_frame)
+ || !FRAME_LIVE_P (XFRAME (tip_frame))
+ || !FRAME_VISIBLE_P (XFRAME (tip_frame)))
+ return;
+ else
+ {
+ tip_f = XFRAME (tip_frame);
+ window = [FRAME_NS_VIEW (tip_f) window];
+ size = [window frame].size;
+ }
+
+ root_x = screen_point.x;
+ root_y = screen_point.y;
+
+ /* We can directly use `compute_tip_xy' here, since it doesn't cons
+ nearly as much as it does on X. */
+ compute_tip_xy (NULL, Qnil, tip_dx, tip_dy, (int) size.width,
+ (int) size.height, &root_x, &root_y);
+
+ if (ns_tooltip)
+ [ns_tooltip moveTo: NSMakePoint (root_x, root_y)];
+ else
+ [window setFrame: NSMakeRect (root_x, root_y,
+ size.width, size.height)
+ display: YES];
+}
+
/* ==========================================================================
Lisp interface declaration
@@ -3260,6 +3887,10 @@ be used as the image of the icon representing the frame. */);
Default is t. */);
ns_use_proxy_icon = true;
+ DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
+ doc: /* SKIP: real doc in xfns.c. */);
+ Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+
defsubr (&Sns_read_file_name);
defsubr (&Sns_get_resource);
defsubr (&Sns_set_resource);
@@ -3309,6 +3940,21 @@ Default is t. */);
defsubr (&Sx_show_tip);
defsubr (&Sx_hide_tip);
+ tip_timer = Qnil;
+ staticpro (&tip_timer);
+ tip_frame = Qnil;
+ staticpro (&tip_frame);
+ tip_last_frame = Qnil;
+ staticpro (&tip_last_frame);
+ tip_last_string = Qnil;
+ staticpro (&tip_last_string);
+ tip_last_parms = Qnil;
+ staticpro (&tip_last_parms);
+ tip_dx = Qnil;
+ staticpro (&tip_dx);
+ tip_dy = Qnil;
+ staticpro (&tip_dy);
+
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
defsubr (&Ssystem_move_file_to_trash);
#endif
diff --git a/src/nsfont.m b/src/nsfont.m
index e913a50cb69..ae5e134e15b 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -1177,9 +1177,6 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
face = s->face;
r.origin.x = x;
- if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
- r.origin.x += max (s->face->box_vertical_line_width, 0);
-
r.origin.y = y;
r.size.height = FONT_HEIGHT (font);
diff --git a/src/nsmenu.m b/src/nsmenu.m
index b0ab12bb87d..d02d7bae4b5 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -52,6 +52,10 @@ EmacsMenu *svcsMenu;
/* Nonzero means a menu is currently active. */
static int popup_activated_flag;
+/* The last frame whose menubar was updated. (This is the frame whose
+ menu bar is currently being displayed.) */
+static struct frame *last_menubar_frame;
+
/* NOTE: toolbar implementation is at end,
following complete menu implementation. */
@@ -71,6 +75,12 @@ void
free_frame_menubar (struct frame *f)
{
id menu = [NSApp mainMenu];
+
+ if (f != last_menubar_frame)
+ return;
+
+ last_menubar_frame = NULL;
+
for (int i = [menu numberOfItems] - 1 ; i >= 0; i--)
{
NSMenuItem *item = (NSMenuItem *)[menu itemAtIndex:i];
@@ -135,9 +145,9 @@ ns_update_menubar (struct frame *f, bool deep_p)
#endif
return;
}
- XSETFRAME (Vmenu_updating_frame, f);
-/*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
+ XSETFRAME (Vmenu_updating_frame, f);
+ last_menubar_frame = f;
block_input ();
/* Menu may have been created automatically; if so, discard it. */
@@ -155,7 +165,7 @@ ns_update_menubar (struct frame *f, bool deep_p)
#if NSMENUPROFILE
ftime (&tb);
- t = -(1000*tb.time+tb.millitm);
+ t = -(1000 * tb.time + tb.millitm);
#endif
if (deep_p)
@@ -413,7 +423,7 @@ ns_update_menubar (struct frame *f, bool deep_p)
#if NSMENUPROFILE
ftime (&tb);
- t += 1000*tb.time+tb.millitm;
+ t += 1000 * tb.time + tb.millitm;
fprintf (stderr, "Menu update took %ld msec.\n", t);
#endif
@@ -741,15 +751,15 @@ prettify_key (const char *key)
/* p = [view convertPoint:p fromView: nil]; */
p.y = NSHeight ([view frame]) - p.y;
e = [[view window] currentEvent];
- event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
- location: p
- modifierFlags: 0
- timestamp: [e timestamp]
- windowNumber: [[view window] windowNumber]
- context: nil
- eventNumber: 0 /* [e eventNumber] */
- clickCount: 1
- pressure: 0];
+ event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
+ location: p
+ modifierFlags: 0
+ timestamp: [e timestamp]
+ windowNumber: [[view window] windowNumber]
+ context: nil
+ eventNumber: 0 /* [e eventNumber] */
+ clickCount: 1
+ pressure: 0];
context_menu_value = -1;
[NSMenu popUpContextMenu: self withEvent: event forView: view];
@@ -765,13 +775,33 @@ prettify_key (const char *key)
NSInteger idx = [item tag];
struct frame *f = SELECTED_FRAME ();
Lisp_Object vec = f->menu_bar_vector;
- Lisp_Object help, frame;
-
- if (idx >= ASIZE (vec))
- return;
+ Lisp_Object help, frame, *client_data;
XSETFRAME (frame, f);
- help = AREF (vec, idx + MENU_ITEMS_ITEM_HELP);
+
+ /* This menu isn't a menubar, so use the pointer to the popup menu
+ data. */
+ if (context_menu_value != 0)
+ {
+ client_data = (Lisp_Object *) idx;
+
+ if (client_data)
+ help = client_data[MENU_ITEMS_ITEM_HELP];
+ else
+ help = Qnil;
+ }
+ /* Just dismiss any help-echo that might already be in progress if
+ no menu item will be highlighted. */
+ else if (item == nil || idx <= 0)
+ help = Qnil;
+ else
+ {
+ if (idx >= ASIZE (vec))
+ return;
+
+ /* Otherwise, get the help data from the menu bar vector. */
+ help = AREF (vec, idx + MENU_ITEMS_ITEM_HELP);
+ }
popup_activated_flag++;
if (STRINGP (help) || NILP (help))
@@ -849,37 +879,35 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
EmacsMenu *pmenu;
NSPoint p;
Lisp_Object tem;
- specpdl_ref specpdl_count = SPECPDL_INDEX ();
+ specpdl_ref specpdl_count;
widget_value *wv, *first_wv = 0;
+ widget_value *save_wv = 0, *prev_wv = 0;
+ widget_value **submenu_stack;
+ int submenu_depth = 0;
+ int first_pane = 1;
+ int i;
bool keymaps = (menuflags & MENU_KEYMAPS);
+ USE_SAFE_ALLOCA;
+
NSTRACE ("ns_menu_show");
block_input ();
p.x = x; p.y = y;
- /* Don't GC due to a mysterious bug. */
- inhibit_garbage_collection ();
-
/* now parse stage 2 as in ns_update_menubar */
wv = make_widget_value ("contextmenu", NULL, true, Qnil);
wv->button_type = BUTTON_TYPE_NONE;
first_wv = wv;
-#if 0
- /* FIXME: a couple of one-line differences prevent reuse. */
- wv = digest_single_submenu (0, menu_items_used, 0);
-#else
- {
- widget_value *save_wv = 0, *prev_wv = 0;
- widget_value **submenu_stack
- = alloca (menu_items_used * sizeof *submenu_stack);
- /* Lisp_Object *subprefix_stack
- = alloca (menu_items_used * sizeof *subprefix_stack); */
- int submenu_depth = 0;
- int first_pane = 1;
- int i;
+ submenu_stack
+ = SAFE_ALLOCA (menu_items_used * sizeof *submenu_stack);
+
+ specpdl_count = SPECPDL_INDEX ();
+
+ /* Don't GC due to a mysterious bug. */
+ inhibit_garbage_collection ();
/* Loop over all panes and items, filling in the tree. */
i = 0;
@@ -1009,8 +1037,6 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
i += MENU_ITEMS_ITEM_LENGTH;
}
}
- }
-#endif
if (!NILP (title))
{
@@ -1045,6 +1071,8 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
[[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
unbind_to (specpdl_count, Qnil);
unblock_input ();
+
+ SAFE_FREE ();
return tem;
}
@@ -1469,6 +1497,15 @@ update_frame_tool_bar (struct frame *f)
[timer retain];
}
+- (void) moveTo: (NSPoint) screen_point
+{
+ [win setFrame: NSMakeRect (screen_point.x,
+ screen_point.y,
+ [self frame].size.width,
+ [self frame].size.height)
+ display: YES];
+}
+
- (void) hide
{
[win close];
@@ -1508,31 +1545,38 @@ pop_down_menu (void *arg)
if (popup_activated_flag)
{
- block_input ();
popup_activated_flag = 0;
[panel close];
+ /* For some reason this is required on macOS, or the selected
+ frame gets the keyboard focus but doesn't become
+ highlighted. */
+#ifdef NS_IMPL_COCOA
[[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
- unblock_input ();
+#endif
+ discard_menu_items ();
}
}
-
Lisp_Object
ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
{
- id dialog;
+ EmacsDialogPanel *dialog;
Lisp_Object tem, title;
NSPoint p;
- BOOL isQ;
+ BOOL is_question;
+ const char *error_name;
+ specpdl_ref specpdl_count;
NSTRACE ("ns_popup_dialog");
+ specpdl_count = SPECPDL_INDEX ();
- isQ = NILP (header);
-
+ is_question = NILP (header);
check_window_system (f);
- p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2;
- p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2;
+ p.x = ((int) f->left_pos
+ + ((int) FRAME_COLUMN_WIDTH (f) * f->text_cols) / 2);
+ p.y = ((int) f->top_pos
+ + (FRAME_LINE_HEIGHT (f) * f->text_lines) / 2);
title = Fcar (contents);
CHECK_STRING (title);
@@ -1542,21 +1586,30 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
the dialog. */
contents = list2 (title, Fcons (build_string ("Ok"), Qt));
- block_input ();
- dialog = [[EmacsDialogPanel alloc] initFromContents: contents
- isQuestion: isQ];
+ record_unwind_protect_void (unuse_menu_items);
+ list_of_panes (list1 (contents));
- {
- specpdl_ref specpdl_count = SPECPDL_INDEX ();
-
- record_unwind_protect_ptr (pop_down_menu, dialog);
- popup_activated_flag = 1;
- tem = [dialog runDialogAt: p];
- unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */
- }
+ block_input ();
+ dialog = [[EmacsDialogPanel alloc] initWithTitle: SSDATA (title)
+ isQuestion: is_question];
+ [dialog processMenuItems: menu_items
+ used: menu_items_used
+ withErrorOutput: &error_name];
+ [dialog resizeBoundsPriorToDisplay];
unblock_input ();
+ if (error_name)
+ {
+ discard_menu_items ();
+ [dialog close];
+ error ("%s", error_name);
+ }
+
+ record_unwind_protect_ptr (pop_down_menu, dialog);
+ popup_activated_flag = 1;
+ tem = [dialog runDialogAt: p];
+ unbind_to (specpdl_count, Qnil);
return tem;
}
@@ -1597,7 +1650,6 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
NSImage *img;
dialog_return = Qundefined;
- button_values = NULL;
area.origin.x = 3*SPACER;
area.origin.y = 2*SPACER;
area.size.width = ICONSIZE;
@@ -1681,58 +1733,65 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
}
-- (BOOL)windowShouldClose: (id)sender
+- (BOOL)windowShouldClose: (id) sender
{
window_closed = YES;
- [NSApp stop:self];
+ [NSApp stop: self];
return NO;
}
-- (void)dealloc
+- (void) dealloc
{
- xfree (button_values);
[super dealloc];
}
-- (void)process_dialog: (Lisp_Object) list
+- (void) processMenuItems: (Lisp_Object) menu_items
+ used: (ptrdiff_t) menu_items_used
+ withErrorOutput: (const char **) error_name
{
- Lisp_Object item, lst = list;
- int row = 0;
- int buttons = 0, btnnr = 0;
+ int i, nb_buttons = 0, row = 0;
+ Lisp_Object item_name, enable;
- for (; CONSP (lst); lst = XCDR (lst))
+ i = MENU_ITEMS_PANE_LENGTH;
+ *error_name = NULL;
+
+ /* Loop over all panes and items, filling in the tree. */
+ while (i < menu_items_used)
{
- item = XCAR (list);
- if (CONSP (item))
- ++buttons;
- }
+ item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+ enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
- if (buttons > 0)
- button_values = xmalloc (buttons * sizeof *button_values);
+ if (NILP (item_name))
+ {
+ *error_name = "Submenu in dialog items";
+ return;
+ }
- for (; CONSP (list); list = XCDR (list))
- {
- item = XCAR (list);
- if (STRINGP (item))
- {
- [self addString: SSDATA (item) row: row++];
- }
- else if (CONSP (item))
- {
- button_values[btnnr] = XCDR (item);
- [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++];
- ++btnnr;
- }
- else if (NILP (item))
- {
- [self addSplit];
- row = 0;
- }
+ if (EQ (item_name, Qquote))
+ /* This is the boundary between elements on the left and those
+ on the right, but that boundary is currently not handled on
+ NS. */
+ continue;
+
+ if (nb_buttons > 9)
+ {
+ *error_name = "Too many dialog items";
+ return;
+ }
+
+ [self addButton: SSDATA (item_name)
+ value: (NSInteger) aref_addr (menu_items, i)
+ row: row++
+ enable: !NILP (enable)];
+
+ i += MENU_ITEMS_ITEM_LENGTH;
+ nb_buttons++;
}
}
-- (void)addButton: (char *)str value: (int)tag row: (int)row
+- (void) addButton: (char *) str value: (NSInteger) tag
+ row: (int) row enable: (BOOL) enable
{
id cell;
@@ -1741,7 +1800,8 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
[matrix addRow];
rows++;
}
- cell = [matrix cellAtRow: row column: cols-1];
+
+ cell = [matrix cellAtRow: row column: cols - 1];
[cell setTarget: self];
[cell setAction: @selector (clicked: )];
[cell setTitle: [NSString stringWithUTF8String: str]];
@@ -1751,7 +1811,7 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
}
-- (void)addString: (char *)str row: (int)row
+- (void)addString: (char *) str row: (int) row
{
id cell;
@@ -1774,96 +1834,95 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
}
-- (void)clicked: sender
+- (void) clicked: sender
{
NSArray *sellist = nil;
- EMACS_INT seltag;
+ NSUInteger seltag;
+ Lisp_Object *selarray;
sellist = [sender selectedCells];
+
if ([sellist count] < 1)
return;
seltag = [[sellist objectAtIndex: 0] tag];
- dialog_return = button_values[seltag];
- [NSApp stop:self];
+ selarray = (void *) seltag;
+ dialog_return = selarray[MENU_ITEMS_ITEM_VALUE];
+ [NSApp stop: self];
}
-- (instancetype)initFromContents: (Lisp_Object)contents isQuestion: (BOOL)isQ
+- (instancetype) initWithTitle: (char *) title_string
+ isQuestion: (BOOL) is_question
{
- Lisp_Object head;
[super init];
- if (CONSP (contents))
- {
- head = Fcar (contents);
- [self process_dialog: Fcdr (contents)];
- }
- else
- head = contents;
+ if (title_string)
+ [title setStringValue:
+ [NSString stringWithUTF8String: title_string]];
- if (STRINGP (head))
- [title setStringValue:
- [NSString stringWithUTF8String: SSDATA (head)]];
- else if (isQ == YES)
- [title setStringValue: @"Question"];
+ if (is_question)
+ [command setStringValue: @"Question"];
else
- [title setStringValue: @"Information"];
+ [command setStringValue: @"Information"];
- {
- int i;
- NSRect r, s, t;
+ return self;
+}
- if (cols == 1 && rows > 1) /* Never told where to split. */
- {
- [matrix addColumn];
- for (i = 0; i < rows/2; i++)
- {
- [matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0]
- atRow: i column: 1];
- [matrix removeRow: (rows+1)/2];
- }
- }
+- (void) resizeBoundsPriorToDisplay
+{
+ int i;
+ NSRect r, s, t;
+ NSSize csize;
- [matrix sizeToFit];
+ if (cols == 1 && rows > 1)
{
- NSSize csize = [matrix cellSize];
- if (csize.width < MINCELLWIDTH)
- {
- csize.width = MINCELLWIDTH;
- [matrix setCellSize: csize];
- [matrix sizeToCells];
- }
+ [matrix addColumn];
+ for (i = 0; i < rows / 2; i++)
+ {
+ [matrix putCell: [matrix cellAtRow: (rows + 1) /2
+ column: 0]
+ atRow: i column: 1];
+ [matrix removeRow: (rows + 1) / 2];
+ }
}
- [title sizeToFit];
- [command sizeToFit];
+ [matrix sizeToFit];
- t = [matrix frame];
- r = [title frame];
- if (r.size.width+r.origin.x > t.size.width+t.origin.x)
- {
- t.origin.x = r.origin.x;
- t.size.width = r.size.width;
- }
- r = [command frame];
- if (r.size.width+r.origin.x > t.size.width+t.origin.x)
- {
- t.origin.x = r.origin.x;
- t.size.width = r.size.width;
- }
+ csize = [matrix cellSize];
+ if (csize.width < MINCELLWIDTH)
+ {
+ csize.width = MINCELLWIDTH;
+ [matrix setCellSize: csize];
+ [matrix sizeToCells];
+ }
- r = [self frame];
- s = [(NSView *)[self contentView] frame];
- r.size.width += t.origin.x+t.size.width +2*SPACER-s.size.width;
- r.size.height += t.origin.y+t.size.height+SPACER-s.size.height;
- [self setFrame: r display: NO];
- }
+ [title sizeToFit];
+ [command sizeToFit];
- return self;
-}
+ t = [matrix frame];
+ r = [title frame];
+ if (r.size.width + r.origin.x > t.size.width + t.origin.x)
+ {
+ t.origin.x = r.origin.x;
+ t.size.width = r.size.width;
+ }
+ r = [command frame];
+ if (r.size.width + r.origin.x > t.size.width + t.origin.x)
+ {
+ t.origin.x = r.origin.x;
+ t.size.width = r.size.width;
+ }
+ r = [self frame];
+ s = [(NSView *) [self contentView] frame];
+ r.size.width += (t.origin.x + t.size.width
+ + 2 * SPACER - s.size.width);
+ r.size.height += (t.origin.y + t.size.height
+ + SPACER - s.size.height);
+ [self setFrame: r display: NO];
+}
- (void)timeout_handler: (NSTimer *)timedEntry
{
@@ -1881,11 +1940,11 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
/* We use stop because stopModal/abortModal out of the main loop
does not seem to work in 10.6. But as we use stop we must send a
real event so the stop is seen and acted upon. */
- [NSApp stop:self];
+ [NSApp stop: self];
[NSApp postEvent: nxev atStart: NO];
}
-- (Lisp_Object)runDialogAt: (NSPoint)p
+- (Lisp_Object) runDialogAt: (NSPoint) p
{
Lisp_Object ret = Qundefined;
@@ -1905,13 +1964,17 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
[[NSRunLoop currentRunLoop] addTimer: tmo
forMode: NSModalPanelRunLoopMode];
}
+
timer_fired = NO;
dialog_return = Qundefined;
[NSApp runModalForWindow: self];
ret = dialog_return;
- if (! timer_fired)
+
+ if (!timer_fired)
{
- if (tmo != nil) [tmo invalidate]; /* Cancels timer. */
+ if (tmo != nil)
+ [tmo invalidate]; /* Cancels timer. */
+
break;
}
}
diff --git a/src/nsselect.m b/src/nsselect.m
index a7ef9df0e0e..c46bfeaf42a 100644
--- a/src/nsselect.m
+++ b/src/nsselect.m
@@ -17,13 +17,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-/*
-Originally by Carl Edman
-Updated by Christian Limpach (chris@nice.ch)
-OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
-macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
-GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
-*/
+/* Originally by Carl Edman
+ Updated by Christian Limpach (chris@nice.ch)
+ OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
+ macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
+ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) */
/* This should be the first include, as it may set up #defines affecting
interpretation of even the system includes. */
@@ -559,6 +557,225 @@ nxatoms_of_nsselect (void)
nil] retain];
}
+static void
+ns_decode_data_to_pasteboard (Lisp_Object type, Lisp_Object data,
+ NSPasteboard *pasteboard)
+{
+ NSArray *types, *new;
+ NSMutableArray *temp;
+ Lisp_Object tem;
+ specpdl_ref count;
+#if !NS_USE_NSPasteboardTypeFileURL
+ NSURL *url;
+#endif
+
+ types = [pasteboard types];
+ count = SPECPDL_INDEX ();
+
+ CHECK_SYMBOL (type);
+
+ if (EQ (type, Qstring))
+ {
+ CHECK_STRING (data);
+
+ new = [types arrayByAddingObject: NSPasteboardTypeString];
+
+ [pasteboard declareTypes: new
+ owner: nil];
+ [pasteboard setString: [NSString stringWithLispString: data]
+ forType: NSPasteboardTypeString];
+ }
+ else if (EQ (type, Qfile))
+ {
+#if NS_USE_NSPasteboardTypeFileURL
+ if (CONSP (data))
+ new = [types arrayByAddingObject: NSPasteboardTypeURL];
+ else
+ new = [types arrayByAddingObject: NSPasteboardTypeFileURL];
+#else
+ new = [types arrayByAddingObject: NSFilenamesPboardType];
+#endif
+
+ [pasteboard declareTypes: new
+ owner: nil];
+
+ if (STRINGP (data))
+ {
+#if NS_USE_NSPasteboardTypeFileURL
+ [pasteboard setString: [NSString stringWithLispString: data]
+ forType: NSPasteboardTypeFileURL];
+#else
+ url = [NSURL URLWithString: [NSString stringWithLispString: data]];
+
+ if (!url)
+ signal_error ("Invalid file URL", data);
+
+ [pasteboard setString: [url path]
+ forType: NSFilenamesPboardType];
+#endif
+ }
+ else
+ {
+ CHECK_LIST (data);
+ temp = [[NSMutableArray alloc] init];
+ record_unwind_protect_ptr (ns_release_object, temp);
+
+ for (tem = data; CONSP (tem); tem = XCDR (tem))
+ {
+ CHECK_STRING (XCAR (tem));
+
+ [temp addObject: [NSString stringWithLispString: XCAR (tem)]];
+ }
+ CHECK_LIST_END (tem, data);
+#if NS_USE_NSPasteboardTypeFileURL
+ [pasteboard setPropertyList: temp
+ /* We have to use this deprecated pasteboard
+ type, since Apple doesn't let us use
+ dragImage:at: to drag multiple file URLs. */
+ forType: @"NSFilenamesPboardType"];
+#else
+ [pasteboard setPropertyList: temp
+ forType: NSFilenamesPboardType];
+#endif
+ unbind_to (count, Qnil);
+ }
+ }
+ else
+ signal_error ("Unknown pasteboard type", type);
+}
+
+static void
+ns_lisp_to_pasteboard (Lisp_Object object,
+ NSPasteboard *pasteboard)
+{
+ Lisp_Object tem, type, data;
+
+ [pasteboard declareTypes: [NSArray array]
+ owner: nil];
+
+ CHECK_LIST (object);
+ for (tem = object; CONSP (tem); tem = XCDR (tem))
+ {
+ maybe_quit ();
+
+ type = Fcar (Fcar (tem));
+ data = Fcdr (Fcar (tem));
+
+ ns_decode_data_to_pasteboard (type, data, pasteboard);
+ }
+ CHECK_LIST_END (tem, object);
+}
+
+static NSDragOperation
+ns_dnd_action_to_operation (Lisp_Object action)
+{
+ if (EQ (action, QXdndActionCopy))
+ return NSDragOperationCopy;
+
+ if (EQ (action, QXdndActionMove))
+ return NSDragOperationMove;
+
+ if (EQ (action, QXdndActionLink))
+ return NSDragOperationLink;
+
+ signal_error ("Unsupported drag-and-drop action", action);
+}
+
+static Lisp_Object
+ns_dnd_action_from_operation (NSDragOperation operation)
+{
+ switch (operation)
+ {
+ case NSDragOperationCopy:
+ return QXdndActionCopy;
+
+ case NSDragOperationMove:
+ return QXdndActionMove;
+
+ case NSDragOperationLink:
+ return QXdndActionLink;
+
+ case NSDragOperationNone:
+ return Qnil;
+
+ default:
+ return QXdndActionPrivate;
+ }
+}
+
+DEFUN ("ns-begin-drag", Fns_begin_drag, Sns_begin_drag, 3, 6, 0,
+ doc: /* Begin a drag-and-drop operation on FRAME.
+
+FRAME must be a window system frame. PBOARD is an alist of (TYPE
+. DATA), where TYPE is one of the following data types that determine
+the meaning of DATA:
+
+ - `string' means DATA should be a string describing text that will
+ be dragged to another program.
+
+ - `file' means DATA should be a file URL that will be dragged to
+ another program. DATA may also be a list of file names; that
+ means each file in the list will be dragged to another program.
+
+ACTION is the action that will be taken by the drop target towards the
+data inside PBOARD.
+
+Return the action that the drop target actually chose to perform, or
+nil if no action was performed (either because there was no drop
+target, or the drop was rejected). If RETURN-FRAME is the symbol
+`now', also return any frame that mouse moves into during the
+drag-and-drop operation, whilst simultaneously cancelling it. Any
+other non-nil value means to do the same, but to wait for the mouse to
+leave FRAME first.
+
+If ALLOW-SAME-FRAME is nil, dropping on FRAME will result in the drop
+being ignored.
+
+FOLLOW-TOOLTIP means the same thing it does in `x-begin-drag'. */)
+ (Lisp_Object frame, Lisp_Object pboard, Lisp_Object action,
+ Lisp_Object return_frame, Lisp_Object allow_same_frame,
+ Lisp_Object follow_tooltip)
+{
+ struct frame *f, *return_to;
+ NSPasteboard *pasteboard;
+ EmacsWindow *window;
+ NSDragOperation operation;
+ enum ns_return_frame_mode mode;
+ Lisp_Object val;
+
+ if (EQ (return_frame, Qnow))
+ mode = RETURN_FRAME_NOW;
+ else if (!NILP (return_frame))
+ mode = RETURN_FRAME_EVENTUALLY;
+ else
+ mode = RETURN_FRAME_NEVER;
+
+ if (NILP (pboard))
+ signal_error ("Empty pasteboard", pboard);
+
+ f = decode_window_system_frame (frame);
+ pasteboard = [NSPasteboard pasteboardWithName: NSPasteboardNameDrag];
+ window = (EmacsWindow *) [FRAME_NS_VIEW (f) window];
+
+ operation = ns_dnd_action_to_operation (action);
+ ns_lisp_to_pasteboard (pboard, pasteboard);
+
+ operation = [window beginDrag: operation
+ forPasteboard: pasteboard
+ withMode: mode
+ returnFrameTo: &return_to
+ prohibitSame: (BOOL) NILP (allow_same_frame)
+ followTooltip: (BOOL) !NILP (follow_tooltip)];
+
+ if (return_to)
+ {
+ XSETFRAME (val, return_to);
+ return val;
+ }
+
+ return ns_dnd_action_from_operation (operation);
+}
+
void
syms_of_nsselect (void)
{
@@ -568,12 +785,18 @@ syms_of_nsselect (void)
DEFSYM (QFILE_NAME, "FILE_NAME");
DEFSYM (QTARGETS, "TARGETS");
+ DEFSYM (QXdndActionCopy, "XdndActionCopy");
+ DEFSYM (QXdndActionMove, "XdndActionMove");
+ DEFSYM (QXdndActionLink, "XdndActionLink");
+ DEFSYM (QXdndActionPrivate, "XdndActionPrivate");
+ DEFSYM (Qnow, "now");
defsubr (&Sns_disown_selection_internal);
defsubr (&Sns_get_selection);
defsubr (&Sns_own_selection_internal);
defsubr (&Sns_selection_exists_p);
defsubr (&Sns_selection_owner_p);
+ defsubr (&Sns_begin_drag);
Vselection_alist = Qnil;
staticpro (&Vselection_alist);
diff --git a/src/nsterm.h b/src/nsterm.h
index 9d8a6f486fc..c4fdc7054f7 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -408,23 +408,48 @@ typedef id instancetype;
@end
#endif
+enum ns_return_frame_mode
+ {
+ RETURN_FRAME_NEVER,
+ RETURN_FRAME_EVENTUALLY,
+ RETURN_FRAME_NOW,
+ };
+
/* EmacsWindow */
@interface EmacsWindow : NSWindow
{
NSPoint grabOffset;
+ NSEvent *last_drag_event;
+ NSDragOperation drag_op;
+ NSDragOperation selected_op;
+
+ struct frame *dnd_return_frame;
+ enum ns_return_frame_mode dnd_mode;
+ BOOL dnd_allow_same_frame;
+ BOOL dnd_move_tooltip_with_frame;
}
#ifdef NS_IMPL_GNUSTEP
- (NSInteger) orderedIndex;
#endif
-- (instancetype)initWithEmacsFrame:(struct frame *)f;
-- (instancetype)initWithEmacsFrame:(struct frame *)f fullscreen:(BOOL)fullscreen screen:(NSScreen *)screen;
-- (void)createToolbar:(struct frame *)f;
-- (void)setParentChildRelationships;
-- (NSInteger)borderWidth;
-- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above;
-- (void)setAppearance;
+- (instancetype) initWithEmacsFrame: (struct frame *) f;
+- (instancetype) initWithEmacsFrame: (struct frame *) f
+ fullscreen: (BOOL) fullscreen
+ screen: (NSScreen *) screen;
+- (void) createToolbar: (struct frame *) f;
+- (void) setParentChildRelationships;
+- (NSInteger) borderWidth;
+- (BOOL) restackWindow: (NSWindow *) win above: (BOOL) above;
+- (void) setAppearance;
+- (void) setLastDragEvent: (NSEvent *) event;
+- (NSDragOperation) beginDrag: (NSDragOperation) op
+ forPasteboard: (NSPasteboard *) pasteboard
+ withMode: (enum ns_return_frame_mode) mode
+ returnFrameTo: (struct frame **) frame_return
+ prohibitSame: (BOOL) prohibit_same_frame
+ followTooltip: (BOOL) follow_tooltip;
+- (BOOL) mustNotDropOn: (NSView *) receiver;
@end
@@ -574,22 +599,32 @@ typedef id instancetype;
========================================================================== */
@interface EmacsDialogPanel : NSPanel
- {
- NSTextField *command;
- NSTextField *title;
- NSMatrix *matrix;
- int rows, cols;
- BOOL timer_fired, window_closed;
- Lisp_Object dialog_return;
- Lisp_Object *button_values;
- }
-- (instancetype)initFromContents: (Lisp_Object)menu isQuestion: (BOOL)isQ;
-- (void)process_dialog: (Lisp_Object)list;
-- (void)addButton: (char *)str value: (int)tag row: (int)row;
-- (void)addString: (char *)str row: (int)row;
-- (void)addSplit;
-- (Lisp_Object)runDialogAt: (NSPoint)p;
-- (void)timeout_handler: (NSTimer *)timedEntry;
+{
+ NSTextField *command;
+ NSTextField *title;
+ NSMatrix *matrix;
+ int rows, cols;
+ BOOL timer_fired, window_closed;
+ Lisp_Object dialog_return;
+}
+
+- (instancetype) initWithTitle: (char *) title_str
+ isQuestion: (BOOL) is_question;
+- (void) processMenuItems: (Lisp_Object) menu_items
+ used: (ptrdiff_t) menu_items_used
+ withErrorOutput: (const char **) error_name;
+
+- (void) addButton: (char *) str
+ value: (NSInteger) tag
+ row: (int) row
+ enable: (BOOL) enable;
+- (void) addString: (char *) str
+ row: (int) row;
+- (void) addSplit;
+- (void) resizeBoundsPriorToDisplay;
+
+- (Lisp_Object) runDialogAt: (NSPoint) p;
+- (void) timeout_handler: (NSTimer *) timedEntry;
@end
#ifdef NS_IMPL_COCOA
@@ -597,19 +632,21 @@ typedef id instancetype;
#else
@interface EmacsTooltip : NSObject
#endif
- {
- NSWindow *win;
- NSTextField *textField;
- NSTimer *timer;
- }
+{
+ NSWindow *win;
+ NSTextField *textField;
+ NSTimer *timer;
+}
+
- (instancetype) init;
-- (void) setText: (char *)text;
-- (void) setBackgroundColor: (NSColor *)col;
-- (void) setForegroundColor: (NSColor *)col;
-- (void) showAtX: (int)x Y: (int)y for: (int)seconds;
+- (void) setText: (char *) text;
+- (void) setBackgroundColor: (NSColor *) col;
+- (void) setForegroundColor: (NSColor *) col;
+- (void) showAtX: (int) x Y: (int) y for: (int) seconds;
- (void) hide;
- (BOOL) isActive;
- (NSRect) frame;
+- (void) moveTo: (NSPoint) screen_point;
@end
@@ -1107,6 +1144,9 @@ extern const char *ns_get_pending_menu_title (void);
#endif
/* Implemented in nsfns, published in nsterm. */
+#ifdef __OBJC__
+extern void ns_move_tooltip_to_mouse_location (NSPoint);
+#endif
extern void ns_implicitly_set_name (struct frame *f, Lisp_Object arg,
Lisp_Object oldval);
extern void ns_set_scroll_bar_default_width (struct frame *f);
@@ -1176,6 +1216,7 @@ extern size_t ns_image_size_in_bytes (void *img);
/* This in nsterm.m */
extern float ns_antialias_threshold;
extern void ns_make_frame_visible (struct frame *f);
+extern void ns_make_frame_invisible (struct frame *f);
extern void ns_iconify_frame (struct frame *f);
extern void ns_set_undecorated (struct frame *f, Lisp_Object new_value,
Lisp_Object old_value);
@@ -1312,6 +1353,7 @@ enum NSWindowTabbingMode
#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_13)
/* Deprecated in macOS 10.13. */
#define NSPasteboardNameGeneral NSGeneralPboard
+#define NSPasteboardNameDrag NSDragPboard
#endif
#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_14)
@@ -1329,5 +1371,6 @@ enum NSWindowTabbingMode
#define NSControlStateValueOn NSOnState
#define NSControlStateValueOff NSOffState
#define NSBezelStyleRounded NSRoundedBezelStyle
+#define NSButtonTypeMomentaryPushIn NSMomentaryPushInButton
#endif
#endif /* HAVE_NS */
diff --git a/src/nsterm.m b/src/nsterm.m
index fef7f0dc6c8..891d52ea3f0 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -79,6 +79,9 @@ static EmacsMenu *dockMenu;
static EmacsMenu *mainMenu;
#endif
+/* The last known monitor attributes list. */
+static Lisp_Object last_known_monitors;
+
/* ==========================================================================
NSTRACE, Trace support.
@@ -89,8 +92,8 @@ static EmacsMenu *mainMenu;
/* The following use "volatile" since they can be accessed from
parallel threads. */
-volatile int nstrace_num = 0;
-volatile int nstrace_depth = 0;
+volatile int nstrace_num;
+volatile int nstrace_depth;
/* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
NSTRACE_UNLESS to silence functions called.
@@ -101,33 +104,41 @@ volatile int nstrace_depth = 0;
volatile int nstrace_enabled_global = 1;
/* Called when nstrace_enabled goes out of scope. */
-void nstrace_leave(int * pointer_to_nstrace_enabled)
+void
+nstrace_leave (int *pointer_to_nstrace_enabled)
{
if (*pointer_to_nstrace_enabled)
- {
- --nstrace_depth;
- }
+ --nstrace_depth;
}
/* Called when nstrace_saved_enabled_global goes out of scope. */
-void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
+void
+nstrace_restore_global_trace_state (int *pointer_to_saved_enabled_global)
{
nstrace_enabled_global = *pointer_to_saved_enabled_global;
}
-char const * nstrace_fullscreen_type_name (int fs_type)
+const char *
+nstrace_fullscreen_type_name (int fs_type)
{
switch (fs_type)
{
- case -1: return "-1";
- case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
- case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
- case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
- case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
- case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
- default: return "FULLSCREEN_?????";
+ case -1:
+ return "-1";
+ case FULLSCREEN_NONE:
+ return "FULLSCREEN_NONE";
+ case FULLSCREEN_WIDTH:
+ return "FULLSCREEN_WIDTH";
+ case FULLSCREEN_HEIGHT:
+ return "FULLSCREEN_HEIGHT";
+ case FULLSCREEN_BOTH:
+ return "FULLSCREEN_BOTH";
+ case FULLSCREEN_MAXIMIZED:
+ return "FULLSCREEN_MAXIMIZED";
+ default:
+ return "FULLSCREEN_?????";
}
}
#endif
@@ -429,28 +440,28 @@ ev_modifiers_helper (unsigned int flags, unsigned int left_mask,
/* This is a piece of code which is common to all the event handling
methods. Maybe it should even be a function. */
-#define EV_TRAILER(e) \
- { \
- XSETFRAME (emacs_event->frame_or_window, emacsframe); \
- EV_TRAILER2 (e); \
+#define EV_TRAILER(e) \
+ { \
+ XSETFRAME (emacs_event->frame_or_window, emacsframe); \
+ EV_TRAILER2 (e); \
}
#define EV_TRAILER2(e) \
{ \
- if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
- if (q_event_ptr) \
- { \
- Lisp_Object tem = Vinhibit_quit; \
- Vinhibit_quit = Qt; \
- n_emacs_events_pending++; \
- kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
- Vinhibit_quit = tem; \
- } \
- else \
- hold_event (emacs_event); \
- EVENT_INIT (*emacs_event); \
- ns_send_appdefined (-1); \
- }
+ if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
+ if (q_event_ptr) \
+ { \
+ Lisp_Object tem = Vinhibit_quit; \
+ Vinhibit_quit = Qt; \
+ n_emacs_events_pending++; \
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
+ Vinhibit_quit = tem; \
+ } \
+ else \
+ hold_event (emacs_event); \
+ EVENT_INIT (*emacs_event); \
+ ns_send_appdefined (-1); \
+ }
/* TODO: Get rid of need for these forward declarations. */
@@ -1517,7 +1528,7 @@ ns_make_frame_visible (struct frame *f)
}
-static void
+void
ns_make_frame_invisible (struct frame *f)
/* --------------------------------------------------------------------------
Hide the window (X11 semantics)
@@ -1708,10 +1719,8 @@ ns_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
static void
-ns_set_window_size (struct frame *f,
- bool change_gravity,
- int width,
- int height)
+ns_set_window_size (struct frame *f, bool change_gravity,
+ int width, int height)
/* --------------------------------------------------------------------------
Adjust window pixel size based on native sizes WIDTH and HEIGHT.
Impl is a bit more complex than other terms, need to do some
@@ -2288,6 +2297,11 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
struct frame *f = NULL;
struct ns_display_info *dpyinfo;
bool return_no_frame_flag = false;
+#ifdef NS_IMPL_COCOA
+ NSPoint screen_position;
+ NSInteger window_number;
+ NSWindow *w;
+#endif
NSTRACE ("ns_mouse_position");
@@ -2314,18 +2328,29 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
This doesn't work on GNUstep, although in recent versions there
is compatibility code that makes it a noop. */
- NSPoint screen_position = [NSEvent mouseLocation];
- NSInteger window_number = 0;
+ screen_position = [NSEvent mouseLocation];
+ window_number = 0;
+
do
{
- NSWindow *w;
+ window_number = [NSWindow windowNumberAtPoint: screen_position
+ belowWindowWithWindowNumber: window_number];
+ w = [NSApp windowWithWindowNumber: window_number];
- window_number = [NSWindow windowNumberAtPoint:screen_position
- belowWindowWithWindowNumber:window_number];
- w = [NSApp windowWithWindowNumber:window_number];
+ if ((EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping))
+ && w && [[w delegate] isKindOfClass: [EmacsTooltip class]])
+ continue;
- if (w && [[w delegate] isKindOfClass:[EmacsView class]])
- f = ((EmacsView *)[w delegate])->emacsframe;
+ if (w && [[w delegate] isKindOfClass: [EmacsView class]])
+ f = ((EmacsView *) [w delegate])->emacsframe;
+ else if (EQ (track_mouse, Qdrag_source))
+ break;
+
+ if (f && (EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping))
+ && FRAME_TOOLTIP_P (f))
+ continue;
}
while (window_number > 0 && !f);
#endif
@@ -2340,6 +2365,9 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
if (!FRAME_NS_P (f))
f = NULL;
+ if (f && FRAME_TOOLTIP_P (f))
+ f = dpyinfo->last_mouse_frame;
+
/* While dropping, use the last mouse frame only if there is no
currently focused frame. */
if (!f && (EQ (track_mouse, Qdropping)
@@ -3079,7 +3107,9 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
break;
case HOLLOW_BOX_CURSOR:
draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
- [NSBezierPath strokeRect: r];
+
+ /* This works like it does in PostScript, not X Windows. */
+ [NSBezierPath strokeRect: NSInsetRect (r, 0.5, 0.5)];
break;
case HBAR_CURSOR:
NSRectFill (r);
@@ -3448,36 +3478,35 @@ ns_draw_box (NSRect r, CGFloat hthickness, CGFloat vthickness,
static void
ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
- char top_p, char bottom_p, char left_p, char right_p,
- struct glyph_string *s)
+ char top_p, char bottom_p, char left_p, char right_p,
+ struct glyph_string *s)
/* --------------------------------------------------------------------------
Draw a relief rect inside r, optionally leaving some sides open.
Note we can't just use an NSDrawBezel command, because of the possibility
of some sides not being drawn, and because the rect will be filled.
-------------------------------------------------------------------------- */
{
- static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
- NSColor *newBaseCol = nil;
+ static NSColor *baseCol, *lightCol, *darkCol;
+ NSColor *newBaseCol;
NSRect inner;
+ NSBezierPath *p;
+
+ baseCol = nil;
+ lightCol = nil;
+ newBaseCol = nil;
+ p = nil;
NSTRACE ("ns_draw_relief");
/* set up colors */
if (s->face->use_box_color_for_shadows_p)
- {
- newBaseCol = [NSColor colorWithUnsignedLong:s->face->box_color];
- }
-/* else if (s->first_glyph->type == IMAGE_GLYPH
- && s->img->pixmap
- && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
- {
- newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
- } */
+ newBaseCol = [NSColor colorWithUnsignedLong: s->face->box_color];
else
- {
- newBaseCol = [NSColor colorWithUnsignedLong:s->face->background];
- }
+ newBaseCol = [NSColor colorWithUnsignedLong: s->face->background];
+
+ if (s->hl == DRAW_CURSOR)
+ newBaseCol = FRAME_CURSOR_COLOR (s->f);
if (newBaseCol == nil)
newBaseCol = [NSColor grayColor];
@@ -3487,35 +3516,49 @@ ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
[baseCol release];
baseCol = [newBaseCol retain];
[lightCol release];
- lightCol = [[baseCol highlightWithLevel: 0.2] retain];
+ lightCol = [[baseCol highlightWithLevel: 0.4] retain];
[darkCol release];
- darkCol = [[baseCol shadowWithLevel: 0.3] retain];
+ darkCol = [[baseCol shadowWithLevel: 0.4] retain];
}
/* Calculate the inner rectangle. */
- inner = NSMakeRect (NSMinX (outer) + (left_p ? hthickness : 0),
- NSMinY (outer) + (top_p ? vthickness : 0),
- NSWidth (outer) - (left_p ? hthickness : 0)
- - (right_p ? hthickness : 0),
- NSHeight (outer) - (top_p ? vthickness : 0)
- - (bottom_p ? vthickness : 0));
+ inner = outer;
+
+ if (left_p)
+ {
+ inner.origin.x += vthickness;
+ inner.size.width -= vthickness;
+ }
+
+ if (right_p)
+ inner.size.width -= vthickness;
+
+ if (top_p)
+ {
+ inner.origin.y += hthickness;
+ inner.size.height -= hthickness;
+ }
+
+ if (bottom_p)
+ inner.size.height -= hthickness;
[(raised_p ? lightCol : darkCol) set];
if (top_p || left_p)
{
- NSBezierPath *p = [NSBezierPath bezierPath];
- [p moveToPoint:NSMakePoint (NSMinX (outer), NSMinY (outer))];
+ p = [NSBezierPath bezierPath];
+
+ [p moveToPoint: NSMakePoint (NSMinX (outer), NSMinY (outer))];
if (top_p)
{
- [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))];
- [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))];
+ [p lineToPoint: NSMakePoint (NSMaxX (outer), NSMinY (outer))];
+ [p lineToPoint: NSMakePoint (NSMaxX (inner), NSMinY (inner))];
}
- [p lineToPoint:NSMakePoint (NSMinX (inner), NSMinY (inner))];
+ [p lineToPoint: NSMakePoint (NSMinX (inner), NSMinY (inner))];
if (left_p)
{
- [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))];
- [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))];
+ [p lineToPoint: NSMakePoint (NSMinX (inner), NSMaxY (inner))];
+ [p lineToPoint: NSMakePoint (NSMinX (outer), NSMaxY (outer))];
}
[p closePath];
[p fill];
@@ -3523,24 +3566,93 @@ ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
[(raised_p ? darkCol : lightCol) set];
- if (bottom_p || right_p)
+ if (bottom_p || right_p)
{
- NSBezierPath *p = [NSBezierPath bezierPath];
- [p moveToPoint:NSMakePoint (NSMaxX (outer), NSMaxY (outer))];
+ p = [NSBezierPath bezierPath];
+
+ [p moveToPoint: NSMakePoint (NSMaxX (outer), NSMaxY (outer))];
if (right_p)
{
- [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))];
- [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))];
+ [p lineToPoint: NSMakePoint (NSMaxX (outer), NSMinY (outer))];
+ [p lineToPoint: NSMakePoint (NSMaxX (inner), NSMinY (inner))];
}
[p lineToPoint:NSMakePoint (NSMaxX (inner), NSMaxY (inner))];
if (bottom_p)
{
- [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))];
- [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))];
+ [p lineToPoint: NSMakePoint (NSMinX (inner), NSMaxY (inner))];
+ [p lineToPoint: NSMakePoint (NSMinX (outer), NSMaxY (outer))];
}
[p closePath];
[p fill];
}
+
+ /* If one of h/vthickness are more than 1, draw the outermost line
+ on the respective sides in the black relief color. */
+
+ if (p)
+ [p removeAllPoints];
+ else
+ p = [NSBezierPath bezierPath];
+
+ if (hthickness > 1 && top_p)
+ {
+ [p moveToPoint: NSMakePoint (NSMinX (outer),
+ NSMinY (outer) + 0.5)];
+ [p lineToPoint: NSMakePoint (NSMaxX (outer),
+ NSMinY (outer) + 0.5)];
+ }
+
+ if (hthickness > 1 && bottom_p)
+ {
+ [p moveToPoint: NSMakePoint (NSMinX (outer),
+ NSMaxY (outer) - 0.5)];
+ [p lineToPoint: NSMakePoint (NSMaxX (outer),
+ NSMaxY (outer) - 0.5)];
+ }
+
+ if (vthickness > 1 && left_p)
+ {
+ [p moveToPoint: NSMakePoint (NSMinX (outer) + 0.5,
+ NSMinY (outer) + 0.5)];
+ [p lineToPoint: NSMakePoint (NSMinX (outer) + 0.5,
+ NSMaxY (outer) - 0.5)];
+ }
+
+ if (vthickness > 1 && left_p)
+ {
+ [p moveToPoint: NSMakePoint (NSMinX (outer) + 0.5,
+ NSMinY (outer) + 0.5)];
+ [p lineToPoint: NSMakePoint (NSMinX (outer) + 0.5,
+ NSMaxY (outer) - 0.5)];
+ }
+
+ [darkCol set];
+ [p stroke];
+
+ if (vthickness > 1 && hthickness > 1)
+ {
+ [FRAME_BACKGROUND_COLOR (s->f) set];
+
+ if (left_p && top_p)
+ [NSBezierPath fillRect: NSMakeRect (NSMinX (outer),
+ NSMinY (outer),
+ 1, 1)];
+
+ if (right_p && top_p)
+ [NSBezierPath fillRect: NSMakeRect (NSMaxX (outer) - 1,
+ NSMinY (outer),
+ 1, 1)];
+
+ if (right_p && bottom_p)
+ [NSBezierPath fillRect: NSMakeRect (NSMaxX (outer) - 1,
+ NSMaxY (outer) - 1,
+ 1, 1)];
+
+ if (left_p && bottom_p)
+ [NSBezierPath fillRect: NSMakeRect (NSMinX (outer),
+ NSMaxY (outer) - 1,
+ 1, 1)];
+ }
}
@@ -3622,6 +3734,7 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
{
int box_line_width = max (s->face->box_horizontal_line_width, 0);
+
if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
/* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
dimensions, since the actual glyphs might be much
@@ -3648,7 +3761,7 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
NSRect r = NSMakeRect (s->x, s->y + box_line_width,
s->background_width,
- s->height-2*box_line_width);
+ s->height - 2 * box_line_width);
NSRectFill (r);
s->background_filled_p = 1;
@@ -3656,6 +3769,92 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
}
}
+static void
+ns_draw_image_relief (struct glyph_string *s)
+{
+ int x1, y1, thick;
+ bool raised_p, top_p, bot_p, left_p, right_p;
+ int extra_x, extra_y;
+ int x = s->x;
+ int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += max (s->face->box_vertical_line_width, 0);
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ if (s->slice.x == 0)
+ x += s->img->hmargin;
+ if (s->slice.y == 0)
+ y += s->img->vmargin;
+
+ if (s->hl == DRAW_IMAGE_SUNKEN
+ || s->hl == DRAW_IMAGE_RAISED)
+ {
+ if (s->face->id == TAB_BAR_FACE_ID)
+ thick = (tab_bar_button_relief < 0
+ ? DEFAULT_TAB_BAR_BUTTON_RELIEF
+ : min (tab_bar_button_relief, 1000000));
+ else
+ thick = (tool_bar_button_relief < 0
+ ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
+ : min (tool_bar_button_relief, 1000000));
+ raised_p = s->hl == DRAW_IMAGE_RAISED;
+ }
+ else
+ {
+ thick = eabs (s->img->relief);
+ raised_p = s->img->relief > 0;
+ }
+
+ x1 = x + s->slice.width - 1;
+ y1 = y + s->slice.height - 1;
+
+ extra_x = extra_y = 0;
+ if (s->face->id == TAB_BAR_FACE_ID)
+ {
+ if (CONSP (Vtab_bar_button_margin)
+ && FIXNUMP (XCAR (Vtab_bar_button_margin))
+ && FIXNUMP (XCDR (Vtab_bar_button_margin)))
+ {
+ extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
+ extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
+ }
+ else if (FIXNUMP (Vtab_bar_button_margin))
+ extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
+ }
+
+ if (s->face->id == TOOL_BAR_FACE_ID)
+ {
+ if (CONSP (Vtool_bar_button_margin)
+ && FIXNUMP (XCAR (Vtool_bar_button_margin))
+ && FIXNUMP (XCDR (Vtool_bar_button_margin)))
+ {
+ extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
+ extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
+ }
+ else if (FIXNUMP (Vtool_bar_button_margin))
+ extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
+ }
+
+ top_p = bot_p = left_p = right_p = false;
+
+ if (s->slice.x == 0)
+ x -= thick + extra_x, left_p = true;
+ if (s->slice.y == 0)
+ y -= thick + extra_y, top_p = true;
+ if (s->slice.x + s->slice.width == s->img->width)
+ x1 += thick + extra_x, right_p = true;
+ if (s->slice.y + s->slice.height == s->img->height)
+ y1 += thick + extra_y, bot_p = true;
+
+ ns_draw_relief (NSMakeRect (x, y, x1 - x + 1, y1 - y + 1), thick,
+ thick, raised_p, top_p, bot_p, left_p, right_p, s);
+}
static void
ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
@@ -3667,8 +3866,6 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
int box_line_vwidth = max (s->face->box_horizontal_line_width, 0);
int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
int bg_x, bg_y, bg_height;
- int th;
- char raised_p;
NSRect br;
struct face *face = s->face;
NSColor *tdCol;
@@ -3762,51 +3959,29 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
if (s->hl == DRAW_CURSOR)
{
[FRAME_CURSOR_COLOR (s->f) set];
- tdCol = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)];
+ tdCol = [NSColor colorWithUnsignedLong: NS_FACE_BACKGROUND (face)];
}
else
- {
- tdCol = [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)];
- }
+ tdCol = [NSColor colorWithUnsignedLong: NS_FACE_FOREGROUND (face)];
/* Draw underline, overline, strike-through. */
ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
- /* Draw relief, if requested */
- if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
- {
- if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
- {
- th = (tool_bar_button_relief < 0
- ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
- : min (tool_bar_button_relief, 1000000));
- raised_p = (s->hl == DRAW_IMAGE_RAISED);
- }
- else
- {
- th = abs (s->img->relief);
- raised_p = (s->img->relief > 0);
- }
-
- r.origin.x = x - th;
- r.origin.y = y - th;
- r.size.width = s->slice.width + 2*th-1;
- r.size.height = s->slice.height + 2*th-1;
- ns_draw_relief (r, th, th, raised_p,
- s->slice.y == 0,
- s->slice.y + s->slice.height == s->img->height,
- s->slice.x == 0,
- s->slice.x + s->slice.width == s->img->width, s);
- }
+ /* If we must draw a relief around the image, do it. */
+ if (s->img->relief
+ || s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ ns_draw_image_relief (s);
- /* If there is no mask, the background won't be seen,
- so draw a rectangle on the image for the cursor.
- Do this for all images, getting transparency right is not reliable. */
+ /* If there is no mask, the background won't be seen, so draw a
+ rectangle on the image for the cursor. Do this for all images,
+ getting transparency right is not reliable. */
if (s->hl == DRAW_CURSOR)
{
int thickness = abs (s->img->relief);
if (thickness == 0) thickness = 1;
- ns_draw_box (br, thickness, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
+ ns_draw_box (br, thickness, thickness,
+ FRAME_CURSOR_COLOR (s->f), 1, 1);
}
}
@@ -4035,6 +4210,10 @@ ns_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
YES, YES);
x += glyph->pixel_width;
}
+
+ /* GCC 12 complains even though nothing ever uses s->char2b after
+ this function returns. */
+ s->char2b = NULL;
}
static void
@@ -4363,11 +4542,14 @@ check_native_fs ()
static int
-ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
+ns_read_socket_1 (struct terminal *terminal, struct input_event *hold_quit,
+ BOOL no_release)
/* --------------------------------------------------------------------------
External (hook): Post an event to ourself and keep reading events until
we read it back again. In effect process all events which were waiting.
From 21+ we have to manage the event buffer ourselves.
+
+ NO_RELEASE means not to touch the global autorelease pool.
-------------------------------------------------------------------------- */
{
struct input_event ev;
@@ -4398,11 +4580,14 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
ns_init_events (&ev);
q_event_ptr = hold_quit;
- /* We manage autorelease pools by allocate/reallocate each time around
- the loop; strict nesting is occasionally violated but seems not to
- matter... earlier methods using full nesting caused major memory leaks. */
- [outerpool release];
- outerpool = [[NSAutoreleasePool alloc] init];
+ if (!no_release)
+ {
+ /* We manage autorelease pools by allocate/reallocate each time around
+ the loop; strict nesting is occasionally violated but seems not to
+ matter... earlier methods using full nesting caused major memory leaks. */
+ [outerpool release];
+ outerpool = [[NSAutoreleasePool alloc] init];
+ }
/* If have pending open-file requests, attend to the next one of those. */
if (ns_pending_files && [ns_pending_files count] != 0
@@ -4441,6 +4626,12 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
return nevents;
}
+static int
+ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
+{
+ return ns_read_socket_1 (terminal, hold_quit, NO);
+}
+
static int
ns_select_1 (int nfds, fd_set *readfds, fd_set *writefds,
@@ -5022,11 +5213,22 @@ ns_update_window_end (struct window *w, bool cursor_on_p,
}
#endif
-/* This and next define (many of the) public functions in this file. */
-/* gui_* are generic versions in xdisp.c that we, and other terms, get away
- with using despite presence in the "system dependent" redisplay
- interface. In addition, many of the ns_ methods have code that is
- shared with all terms, indicating need for further refactoring. */
+static void
+ns_flush_display (struct frame *f)
+{
+ struct input_event ie;
+
+ EVENT_INIT (ie);
+ ns_read_socket_1 (FRAME_TERMINAL (f), &ie, YES);
+}
+
+/* This and next define (many of the) public functions in this
+ file. */
+/* gui_* are generic versions in xdisp.c that we, and other terms, get
+ away with using despite presence in the "system dependent"
+ redisplay interface. In addition, many of the ns_ methods have
+ code that is shared with all terms, indicating need for further
+ refactoring. */
extern frame_parm_handler ns_frame_parm_handlers[];
static struct redisplay_interface ns_redisplay_interface =
{
@@ -5043,7 +5245,7 @@ static struct redisplay_interface ns_redisplay_interface =
#else
ns_update_window_end,
#endif
- 0, /* flush_display */
+ ns_flush_display,
gui_clear_window_mouse_face,
gui_get_glyph_overhangs,
gui_fix_overlapping_area,
@@ -5064,6 +5266,39 @@ static struct redisplay_interface ns_redisplay_interface =
ns_default_font_parameter
};
+#ifdef NS_IMPL_COCOA
+static void
+ns_displays_reconfigured (CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void *user_info)
+{
+ struct input_event ie;
+ union buffered_input_event *ev;
+ Lisp_Object new_monitors;
+
+ EVENT_INIT (ie);
+
+ new_monitors = Fns_display_monitor_attributes_list (Qnil);
+
+ if (!NILP (Fequal (new_monitors, last_known_monitors)))
+ return;
+
+ last_known_monitors = new_monitors;
+
+ ev = (kbd_store_ptr == kbd_buffer
+ ? kbd_buffer + KBD_BUFFER_SIZE - 1
+ : kbd_store_ptr - 1);
+
+ if (kbd_store_ptr != kbd_fetch_ptr
+ && ev->ie.kind == MONITORS_CHANGED_EVENT)
+ return;
+
+ ie.kind = MONITORS_CHANGED_EVENT;
+ XSETTERMINAL (ie.arg, x_display_list->terminal);
+
+ kbd_buffer_store_event (&ie);
+}
+#endif
static void
ns_delete_display (struct ns_display_info *dpyinfo)
@@ -5419,6 +5654,16 @@ ns_term_init (Lisp_Object display_name)
catch_child_signal ();
#endif
+#ifdef NS_IMPL_COCOA
+ /* Begin listening for display reconfiguration, so we can run the
+ appropriate hooks. FIXME: is this called when the resolution of
+ a monitor changes? */
+
+ CGDisplayRegisterReconfigurationCallback (ns_displays_reconfigured,
+ NULL);
+#endif
+ last_known_monitors = Fns_display_monitor_attributes_list (Qnil);
+
NSTRACE_MSG ("ns_term_init done");
unblock_input ();
@@ -5459,6 +5704,10 @@ ns_term_shutdown (int sig)
- (id)init
{
+#ifdef NS_IMPL_GNUSTEP
+ NSNotificationCenter *notification_center;
+#endif
+
NSTRACE ("[EmacsApp init]");
if ((self = [super init]))
@@ -5471,6 +5720,14 @@ ns_term_shutdown (int sig)
#endif
}
+#ifdef NS_IMPL_GNUSTEP
+ notification_center = [NSNotificationCenter defaultCenter];
+ [notification_center addObserver: self
+ selector: @selector(updateMonitors:)
+ name: NSApplicationDidChangeScreenParametersNotification
+ object: nil];
+#endif
+
return self;
}
@@ -5483,11 +5740,11 @@ ns_term_shutdown (int sig)
#define NSAppKitVersionNumber10_9 1265
#endif
- if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
- {
- [super run];
- return;
- }
+ if ((int) NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
+ {
+ [super run];
+ return;
+ }
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -5671,6 +5928,36 @@ ns_term_shutdown (int sig)
return YES;
}
+#ifdef NS_IMPL_GNUSTEP
+- (void) updateMonitors: (NSNotification *) notification
+{
+ struct input_event ie;
+ union buffered_input_event *ev;
+ Lisp_Object new_monitors;
+
+ EVENT_INIT (ie);
+
+ new_monitors = Fns_display_monitor_attributes_list (Qnil);
+
+ if (!NILP (Fequal (new_monitors, last_known_monitors)))
+ return;
+
+ last_known_monitors = new_monitors;
+
+ ev = (kbd_store_ptr == kbd_buffer
+ ? kbd_buffer + KBD_BUFFER_SIZE - 1
+ : kbd_store_ptr - 1);
+
+ if (kbd_store_ptr != kbd_fetch_ptr
+ && ev->ie.kind == MONITORS_CHANGED_EVENT)
+ return;
+
+ ie.kind = MONITORS_CHANGED_EVENT;
+ XSETTERMINAL (ie.arg, x_display_list->terminal);
+
+ kbd_buffer_store_event (&ie);
+}
+#endif
/* **************************************************************************
@@ -6814,17 +7101,24 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
{
struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
+ EmacsWindow *window;
NSTRACE ("[EmacsView mouseDown:]");
if (!emacs_event)
return;
+ if (FRAME_TOOLTIP_P (emacsframe))
+ return;
+
dpyinfo->last_mouse_frame = emacsframe;
/* Appears to be needed to prevent spurious movement events generated on
button clicks. */
emacsframe->mouse_moved = 0;
+ window = (EmacsWindow *) [self window];
+ [window setLastDragEvent: theEvent];
+
if ([theEvent type] == NSEventTypeScrollWheel)
{
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
@@ -7017,7 +7311,8 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
tab_bar_p = EQ (window, emacsframe->tab_bar_window);
if (tab_bar_p)
- tab_bar_arg = handle_tab_bar_click (emacsframe, x, y, EV_UDMODIFIERS (theEvent) & down_modifier,
+ tab_bar_arg = handle_tab_bar_click (emacsframe, x, y,
+ EV_UDMODIFIERS (theEvent) & down_modifier,
EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent));
}
@@ -7092,6 +7387,9 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
NSPoint pt;
BOOL dragging;
+ if (FRAME_TOOLTIP_P (emacsframe))
+ return;
+
NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
@@ -8330,13 +8628,30 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
-(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
{
+ id source;
+
NSTRACE ("[EmacsView draggingEntered:]");
+
+ source = [sender draggingSource];
+
+ if (source && [source respondsToSelector: @selector(mustNotDropOn:)]
+ && [source mustNotDropOn: self])
+ return NSDragOperationNone;
+
return NSDragOperationGeneric;
}
--(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
+-(BOOL) prepareForDragOperation: (id <NSDraggingInfo>) sender
{
+ id source;
+
+ source = [sender draggingSource];
+
+ if (source && [source respondsToSelector: @selector(mustNotDropOn:)]
+ && [source mustNotDropOn: self])
+ return NO;
+
return YES;
}
@@ -8347,12 +8662,24 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
- (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>) sender
{
+#ifdef NS_IMPL_GNUSTEP
struct input_event ie;
+#else
+ Lisp_Object frame;
+#endif
NSPoint position;
int x, y;
+ NSAutoreleasePool *ap;
+ specpdl_ref count;
+ ap = [[NSAutoreleasePool alloc] init];
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (ns_release_autorelease_pool, ap);
+
+#ifdef NS_IMPL_GNUSTEP
EVENT_INIT (ie);
ie.kind = DRAG_N_DROP_EVENT;
+#endif
/* Get rid of mouse face. */
[self mouseExited: [[self window] currentEvent]];
@@ -8362,6 +8689,7 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
x = lrint (position.x);
y = lrint (position.y);
+#ifdef NS_IMPL_GNUSTEP
XSETINT (ie.x, x);
XSETINT (ie.y, y);
XSETFRAME (ie.frame_or_window, emacsframe);
@@ -8369,28 +8697,44 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
ie.modifiers = 0;
kbd_buffer_store_event (&ie);
+#else
+ /* Input events won't be processed until the drop happens on macOS,
+ so call this function instead. */
+ XSETFRAME (frame, emacsframe);
+
+ safe_call (4, Vns_drag_motion_function, frame,
+ make_fixnum (x), make_fixnum (y));
+
+ redisplay ();
+#endif
+
+ unbind_to (count, Qnil);
return NSDragOperationGeneric;
}
--(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
+- (BOOL) performDragOperation: (id <NSDraggingInfo>) sender
{
- id pb;
+ id pb, source;
int x, y;
NSString *type;
- NSEvent *theEvent = [[self window] currentEvent];
NSPoint position;
NSDragOperation op = [sender draggingSourceOperationMask];
Lisp_Object operations = Qnil;
Lisp_Object strings = Qnil;
Lisp_Object type_sym;
+ struct input_event ie;
- NSTRACE ("[EmacsView performDragOperation:]");
+ NSTRACE (@"[EmacsView performDragOperation:]");
- if (!emacs_event)
+ source = [sender draggingSource];
+
+ if (source && [source respondsToSelector: @selector(mustNotDropOn:)]
+ && [source mustNotDropOn: self])
return NO;
position = [self convertPoint: [sender draggingLocation] fromView: nil];
- x = lrint (position.x); y = lrint (position.y);
+ x = lrint (position.x);
+ y = lrint (position.y);
pb = [sender draggingPasteboard];
type = [pb availableTypeFromArray: ns_drag_types];
@@ -8406,11 +8750,9 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
if (op & NSDragOperationGeneric || NILP (operations))
operations = Fcons (Qns_drag_operation_generic, operations);
- if (type == 0)
- {
- return NO;
- }
-#if NS_USE_NSPasteboardTypeFileURL != 0
+ if (!type)
+ return NO;
+#if NS_USE_NSPasteboardTypeFileURL
else if ([type isEqualToString: NSPasteboardTypeFileURL])
{
type_sym = Qfile;
@@ -8425,18 +8767,29 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
#else // !NS_USE_NSPasteboardTypeFileURL
else if ([type isEqualToString: NSFilenamesPboardType])
{
- NSArray *files;
+ id files;
NSEnumerator *fenum;
NSString *file;
- if (!(files = [pb propertyListForType: type]))
+ files = [pb propertyListForType: type];
+
+ if (!files)
return NO;
type_sym = Qfile;
- fenum = [files objectEnumerator];
- while ( (file = [fenum nextObject]) )
- strings = Fcons ([file lispString], strings);
+ /* On GNUstep, files might be a string. */
+
+ if ([files respondsToSelector: @selector (objectEnumerator:)])
+ {
+ fenum = [files objectEnumerator];
+
+ while ((file = [fenum nextObject]))
+ strings = Fcons ([file lispString], strings);
+ }
+ else
+ /* Then `files' is an NSString. */
+ strings = list1 ([files lispString]);
}
#endif // !NS_USE_NSPasteboardTypeFileURL
else if ([type isEqualToString: NSPasteboardTypeURL])
@@ -8453,29 +8806,26 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
{
NSString *data;
- if (! (data = [pb stringForType: type]))
+ data = [pb stringForType: type];
+
+ if (!data)
return NO;
type_sym = Qnil;
-
strings = list1 ([data lispString]);
}
else
- {
- fputs ("Invalid data type in dragging pasteboard\n", stderr);
- return NO;
- }
-
- emacs_event->kind = DRAG_N_DROP_EVENT;
- XSETINT (emacs_event->x, x);
- XSETINT (emacs_event->y, y);
- emacs_event->modifiers = 0;
+ return NO;
- emacs_event->arg = Fcons (type_sym,
- Fcons (operations,
- strings));
- EV_TRAILER (theEvent);
+ EVENT_INIT (ie);
+ ie.kind = DRAG_N_DROP_EVENT;
+ ie.arg = Fcons (type_sym, Fcons (operations,
+ strings));
+ XSETINT (ie.x, x);
+ XSETINT (ie.y, y);
+ XSETFRAME (ie.frame_or_window, emacsframe);
+ kbd_buffer_store_event (&ie);
return YES;
}
@@ -8582,17 +8932,18 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
@implementation EmacsWindow
-- (instancetype) initWithEmacsFrame:(struct frame *)f
+- (instancetype) initWithEmacsFrame: (struct frame *) f
{
return [self initWithEmacsFrame:f fullscreen:NO screen:nil];
}
-- (instancetype) initWithEmacsFrame:(struct frame *)f
- fullscreen:(BOOL)fullscreen
- screen:(NSScreen *)screen
+- (instancetype) initWithEmacsFrame: (struct frame *) f
+ fullscreen: (BOOL) fullscreen
+ screen: (NSScreen *) screen
{
NSWindowStyleMask styleMask;
+ int width, height;
NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]");
@@ -8605,20 +8956,24 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
styleMask |= NSWindowStyleMaskResizable;
#endif
}
+ else if (f->tooltip)
+ styleMask = 0;
else
- styleMask = NSWindowStyleMaskTitled
- | NSWindowStyleMaskResizable
- | NSWindowStyleMaskMiniaturizable
- | NSWindowStyleMaskClosable;
-
- self = [super initWithContentRect:
- NSMakeRect (0, 0,
- FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
- FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines))
- styleMask:styleMask
- backing:NSBackingStoreBuffered
- defer:YES
- screen:screen];
+ styleMask = (NSWindowStyleMaskTitled
+ | NSWindowStyleMaskResizable
+ | NSWindowStyleMaskMiniaturizable
+ | NSWindowStyleMaskClosable);
+
+ last_drag_event = nil;
+
+ width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols);
+ height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines);
+
+ self = [super initWithContentRect: NSMakeRect (0, 0, width, height)
+ styleMask: styleMask
+ backing: NSBackingStoreBuffered
+ defer: YES
+ screen: screen];
if (self)
{
NSString *name;
@@ -8726,6 +9081,11 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
/* We need to release the toolbar ourselves. */
[[self toolbar] release];
+
+ /* Also the last button press event . */
+ if (last_drag_event)
+ [last_drag_event release];
+
[super dealloc];
}
@@ -9250,6 +9610,153 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
return YES;
}
+- (void) setLastDragEvent: (NSEvent *) event
+{
+ if (last_drag_event)
+ [last_drag_event release];
+ last_drag_event = [event copy];
+}
+
+- (NSDragOperation) draggingSourceOperationMaskForLocal: (BOOL) is_local
+{
+ return drag_op;
+}
+
+- (void) draggedImage: (NSImage *) image
+ endedAt: (NSPoint) screen_point
+ operation: (NSDragOperation) operation
+{
+ selected_op = operation;
+}
+
+- (void) draggedImage: (NSImage *) dragged_image
+ movedTo: (NSPoint) screen_point
+{
+ NSPoint mouse_loc;
+#ifdef NS_IMPL_COCOA
+ NSInteger window_number;
+ NSWindow *w;
+#endif
+
+ mouse_loc = [NSEvent mouseLocation];
+
+#ifdef NS_IMPL_COCOA
+ if (dnd_mode != RETURN_FRAME_NEVER)
+ {
+ window_number = [NSWindow windowNumberAtPoint: mouse_loc
+ belowWindowWithWindowNumber: 0];
+ w = [NSApp windowWithWindowNumber: window_number];
+
+ if (!w || w != self)
+ dnd_mode = RETURN_FRAME_NOW;
+
+ if (dnd_mode != RETURN_FRAME_NOW
+ || ![[w delegate] isKindOfClass: [EmacsView class]]
+ || ((EmacsView *) [w delegate])->emacsframe->tooltip)
+ goto out;
+
+ dnd_return_frame = ((EmacsView *) [w delegate])->emacsframe;
+
+ /* FIXME: there must be a better way to leave the event loop. */
+ [NSException raise: @""
+ format: @"Must return DND frame"];
+ }
+
+ out:
+#endif
+
+ if (dnd_move_tooltip_with_frame)
+ ns_move_tooltip_to_mouse_location (mouse_loc);
+}
+
+- (BOOL) mustNotDropOn: (NSView *) receiver
+{
+ return ([receiver window] == self
+ ? !dnd_allow_same_frame : NO);
+}
+
+- (NSDragOperation) beginDrag: (NSDragOperation) op
+ forPasteboard: (NSPasteboard *) pasteboard
+ withMode: (enum ns_return_frame_mode) mode
+ returnFrameTo: (struct frame **) frame_return
+ prohibitSame: (BOOL) prohibit_same_frame
+ followTooltip: (BOOL) follow_tooltip
+{
+ NSImage *image;
+#ifdef NS_IMPL_COCOA
+ NSInteger window_number;
+ NSWindow *w;
+#endif
+ drag_op = op;
+ selected_op = NSDragOperationNone;
+ image = [[NSImage alloc] initWithSize: NSMakeSize (1.0, 1.0)];
+ dnd_mode = mode;
+ dnd_return_frame = NULL;
+ dnd_allow_same_frame = !prohibit_same_frame;
+ dnd_move_tooltip_with_frame = follow_tooltip;
+
+ /* Now draw transparency onto the image. */
+ [image lockFocus];
+ [[NSColor colorWithUnsignedLong: 0] set];
+ NSRectFillUsingOperation (NSMakeRect (0, 0, 1, 1),
+ NSCompositingOperationCopy);
+ [image unlockFocus];
+
+ block_input ();
+#ifdef NS_IMPL_COCOA
+ if (mode == RETURN_FRAME_NOW)
+ {
+ window_number = [NSWindow windowNumberAtPoint: [NSEvent mouseLocation]
+ belowWindowWithWindowNumber: 0];
+ w = [NSApp windowWithWindowNumber: window_number];
+
+ if (w && [[w delegate] isKindOfClass: [EmacsView class]]
+ && !((EmacsView *) [w delegate])->emacsframe->tooltip)
+ {
+ *frame_return = ((EmacsView *) [w delegate])->emacsframe;
+ [image release];
+ unblock_input ();
+
+ return NSDragOperationNone;
+ }
+ }
+
+ @try
+ {
+#endif
+ if (last_drag_event)
+ [self dragImage: image
+ at: NSMakePoint (0, 0)
+ offset: NSMakeSize (0, 0)
+ event: last_drag_event
+ pasteboard: pasteboard
+ source: self
+ slideBack: NO];
+#ifdef NS_IMPL_COCOA
+ }
+ @catch (NSException *e)
+ {
+ /* Ignore. This is probably the wrong way to leave the
+ drag-and-drop run loop. */
+ }
+#endif
+ unblock_input ();
+
+ /* The drop happened, so delete the tooltip. */
+ if (follow_tooltip)
+ Fx_hide_tip ();
+
+ /* Assume all buttons have been released since the drag-and-drop
+ operation is now over. */
+ if (!dnd_return_frame)
+ x_display_list->grabbed = 0;
+
+ [image release];
+
+ *frame_return = dnd_return_frame;
+ return selected_op;
+}
+
@end /* EmacsWindow */
@@ -10182,6 +10689,7 @@ syms_of_nsterm (void)
DEFSYM (Qns_drag_operation_copy, "ns-drag-operation-copy");
DEFSYM (Qns_drag_operation_link, "ns-drag-operation-link");
DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic");
+ DEFSYM (Qns_handle_drag_motion, "ns-handle-drag-motion");
Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
@@ -10189,117 +10697,117 @@ syms_of_nsterm (void)
Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
Fput (Qcontrol, Qmodifier_value, make_fixnum (ctrl_modifier));
- DEFVAR_LISP ("ns-input-file", ns_input_file,
- "The file specified in the last NS event.");
- ns_input_file =Qnil;
+ DEFVAR_LISP ("ns-input-font", ns_input_font,
+ doc: /* The font specified in the last NS event. */);
+ ns_input_font = Qnil;
- DEFVAR_LISP ("ns-working-text", ns_working_text,
- "String for visualizing working composition sequence.");
- ns_working_text =Qnil;
+ DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
+ doc: /* The fontsize specified in the last NS event. */);
+ ns_input_fontsize = Qnil;
- DEFVAR_LISP ("ns-input-font", ns_input_font,
- "The font specified in the last NS event.");
- ns_input_font =Qnil;
+ DEFVAR_LISP ("ns-input-line", ns_input_line,
+ doc: /* The line specified in the last NS event. */);
+ ns_input_line = Qnil;
- DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
- "The fontsize specified in the last NS event.");
- ns_input_fontsize =Qnil;
+ DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
+ doc: /* The service name specified in the last NS event. */);
+ ns_input_spi_name = Qnil;
- DEFVAR_LISP ("ns-input-line", ns_input_line,
- "The line specified in the last NS event.");
- ns_input_line =Qnil;
+ DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
+ doc: /* The service argument specified in the last NS event. */);
+ ns_input_spi_arg = Qnil;
- DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
- "The service name specified in the last NS event.");
- ns_input_spi_name =Qnil;
+ DEFVAR_LISP ("ns-input-file", ns_input_file,
+ doc: /* The file specified in the last NS event. */);
+ ns_input_file = Qnil;
- DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
- "The service argument specified in the last NS event.");
- ns_input_spi_arg =Qnil;
+ DEFVAR_LISP ("ns-working-text", ns_working_text,
+ doc: /* String for visualizing working composition sequence. */);
+ ns_working_text = Qnil;
DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
- "This variable describes the behavior of the alternate or option key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the alternate or option key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_alternate_modifier = Qmeta;
DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
- "This variable describes the behavior of the right alternate or option key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-It can also be `left' to use the value of `ns-alternate-modifier' instead.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the right alternate or option key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+It can also be `left' to use the value of `ns-alternate-modifier' instead.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_right_alternate_modifier = Qleft;
DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
- "This variable describes the behavior of the command key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the command key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_command_modifier = Qsuper;
DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
- "This variable describes the behavior of the right command key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-It can also be `left' to use the value of `ns-command-modifier' instead.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the right command key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+It can also be `left' to use the value of `ns-command-modifier' instead.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_right_command_modifier = Qleft;
DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
- "This variable describes the behavior of the control key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the control key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_control_modifier = Qcontrol;
DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
- "This variable describes the behavior of the right control key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-It can also be `left' to use the value of `ns-control-modifier' instead.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the right control key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+It can also be `left' to use the value of `ns-control-modifier' instead.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_right_control_modifier = Qleft;
DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
- "This variable describes the behavior of the function (fn) key.\n\
-Either SYMBOL, describing the behavior for any event,\n\
-or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\
-separately for ordinary keys, function keys, and mouse events.\n\
-\n\
-Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\
-If `none', the key is ignored by Emacs and retains its standard meaning.");
+ doc: /* This variable describes the behavior of the function (fn) key.
+Either SYMBOL, describing the behavior for any event,
+or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
+separately for ordinary keys, function keys, and mouse events.
+
+Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
+If `none', the key is ignored by Emacs and retains its standard meaning. */);
ns_function_modifier = Qnone;
DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
- "Non-nil (the default) means to render text antialiased.");
+ doc: /* Non-nil (the default) means to render text antialiased. */);
ns_antialias_text = Qt;
DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
- "Non-nil turns on a font smoothing method that produces thinner strokes.");
+ doc: /* Non-nil turns on a font smoothing method that produces thinner strokes. */);
ns_use_thin_smoothing = Qnil;
DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
- "Whether to confirm application quit using dialog.");
+ doc: /* Whether to confirm application quit using dialog. */);
ns_confirm_quit = Qnil;
DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
@@ -10369,6 +10877,16 @@ This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
mice with smooth scrolling capability. */);
Vns_scroll_event_delta_factor = make_float (1.0);
+ DEFVAR_LISP ("ns-drag-motion-function", Vns_drag_motion_function,
+ doc: /* Function called when another program drags items over Emacs.
+
+It is called with three arguments FRAME, X, and Y, whenever the user
+moves the mouse over an Emacs frame as part of a drag-and-drop
+operation. FRAME is the frame the mouse is on top of, and X and Y are
+the frame-relative positions of the mouse in the X and Y axises
+respectively. */);
+ Vns_drag_motion_function = Qns_handle_drag_motion;
+
/* Tell Emacs about this window system. */
Fprovide (Qns, Qnil);
@@ -10389,4 +10907,6 @@ This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
syms_of_nsfont ();
#endif
+ last_known_monitors = Qnil;
+ staticpro (&last_known_monitors);
}
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index f79873235cb..be0eba0bcb1 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -69,10 +69,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
[configuration.preferences setValue:@YES
forKey:@"developerExtrasEnabled"];
+#if 0 /* Plugins are not supported by Mac OS X anymore. */
Lisp_Object enablePlugins =
Fintern (build_string ("xwidget-webkit-enable-plugins"), Qnil);
+
if (!EQ (Fsymbol_value (enablePlugins), Qnil))
configuration.preferences.plugInsEnabled = YES;
+#endif
self = [super initWithFrame:frame configuration:configuration];
if (self)
diff --git a/src/pdumper.c b/src/pdumper.c
index 5923d9b1d82..50ae4f85e7e 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -1069,7 +1069,7 @@ dump_queue_enqueue (struct dump_queue *dump_queue,
}
}
- if (!EQ (weights, orig_weights))
+ if (!BASE_EQ (weights, orig_weights))
Fputhash (object, weights, dump_queue->link_weights);
}
@@ -1383,7 +1383,7 @@ print_paths_to_root_1 (struct dump_context *ctx,
{
Lisp_Object referrer = XCAR (referrers);
referrers = XCDR (referrers);
- Lisp_Object repr = Fprin1_to_string (referrer, Qnil);
+ Lisp_Object repr = Fprin1_to_string (referrer, Qnil, Qnil);
for (int i = 0; i < level; ++i)
putc (' ', stderr);
fwrite (SDATA (repr), 1, SBYTES (repr), stderr);
@@ -3758,7 +3758,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
reloc.u.dump_offset = dump_recall_object (ctx, target_value);
if (reloc.u.dump_offset <= 0)
{
- Lisp_Object repr = Fprin1_to_string (target_value, Qnil);
+ Lisp_Object repr = Fprin1_to_string (target_value, Qnil, Qnil);
error ("relocation target was not dumped: %s", SDATA (repr));
}
dump_check_dump_off (ctx, reloc.u.dump_offset);
@@ -5543,7 +5543,10 @@ pdumper_load (const char *dump_filename, char *argv0)
struct dump_header header_buf = { 0 };
struct dump_header *header = &header_buf;
- struct dump_memory_map sections[NUMBER_DUMP_SECTIONS] = { 0 };
+ struct dump_memory_map sections[NUMBER_DUMP_SECTIONS];
+
+ /* Use memset instead of "= { 0 }" to work around GCC bug 105961. */
+ memset (sections, 0, sizeof sections);
const struct timespec start_time = current_timespec ();
char *dump_filename_copy;
diff --git a/src/pgtkfns.c b/src/pgtkfns.c
index a0fcf70f31b..294bdb37917 100644
--- a/src/pgtkfns.c
+++ b/src/pgtkfns.c
@@ -566,15 +566,23 @@ pgtk_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
static void
pgtk_set_child_frame_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
- int border = check_int_nonnegative (arg);
+ int border;
+
+ if (NILP (arg))
+ border = -1;
+ else if (RANGED_FIXNUMP (0, arg, INT_MAX))
+ border = XFIXNAT (arg);
+ else
+ signal_error ("Invalid child frame border width", arg);
if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f))
{
f->child_frame_border_width = border;
- if (FRAME_X_WINDOW (f))
+ if (FRAME_GTK_WIDGET (f))
{
- adjust_frame_size (f, -1, -1, 3, false, Qchild_frame_border_width);
+ adjust_frame_size (f, -1, -1, 3,
+ false, Qchild_frame_border_width);
pgtk_clear_under_internal_border (f);
}
}
@@ -848,7 +856,7 @@ pgtk_set_scroll_bar_background (struct frame *f, Lisp_Object new_value,
error ("Unknown color.");
/* On pgtk, this frame parameter should be ignored, and honor
- gtk theme. (It honors the GTK theme if not explictly set, so
+ gtk theme. (It honors the GTK theme if not explicitly set, so
I see no harm in letting users tinker a bit more.) */
char css[64];
sprintf (css, "scrollbar trough { background-color: #%06x; }",
@@ -1060,7 +1068,7 @@ pgtk_default_font_parameter (struct frame *f, Lisp_Object parms)
gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
RES_TYPE_STRING);
Lisp_Object font = Qnil;
- if (EQ (font_param, Qunbound))
+ if (BASE_EQ (font_param, Qunbound))
font_param = Qnil;
if (NILP (font_param))
@@ -1213,10 +1221,10 @@ This function is an internal primitive--use `make-frame' instead. */ )
display =
gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_NUMBER);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display =
gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display = Qnil;
dpyinfo = check_pgtk_display_info (display);
kb = dpyinfo->terminal->kboard;
@@ -1227,7 +1235,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
name =
gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
- if (!STRINGP (name) && !EQ (name, Qunbound) && !NILP (name))
+ if (!STRINGP (name) && !BASE_EQ (name, Qunbound) && !NILP (name))
error ("Invalid frame name--not a string or nil");
if (STRINGP (name))
@@ -1237,7 +1245,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
parent =
gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL,
RES_TYPE_NUMBER);
- if (EQ (parent, Qunbound))
+ if (BASE_EQ (parent, Qunbound))
parent = Qnil;
if (!NILP (parent))
CHECK_NUMBER (parent);
@@ -1263,7 +1271,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
RES_TYPE_SYMBOL);
/* Accept parent-frame iff parent-id was not specified. */
if (!NILP (parent)
- || EQ (parent_frame, Qunbound)
+ || BASE_EQ (parent_frame, Qunbound)
|| NILP (parent_frame)
|| !FRAMEP (parent_frame)
|| !FRAME_LIVE_P (XFRAME (parent_frame))
@@ -1277,7 +1285,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
(tem =
(gui_display_get_arg
(dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN)))
- && !(EQ (tem, Qunbound)))
+ && !(BASE_EQ (tem, Qunbound)))
undecorated = true;
FRAME_UNDECORATED (f) = undecorated;
@@ -1287,7 +1295,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
(tem =
(gui_display_get_arg
(dpyinfo, parms, Qoverride_redirect, NULL, NULL, RES_TYPE_BOOLEAN)))
- && !(EQ (tem, Qunbound)))
+ && !(BASE_EQ (tem, Qunbound)))
override_redirect = true;
FRAME_OVERRIDE_REDIRECT (f) = override_redirect;
@@ -1363,7 +1371,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
{
fset_name (f, build_string (dpyinfo->x_id_name));
f->explicit_name = false;
@@ -1406,7 +1414,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (!EQ (value, Qunbound))
+ if (!BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value), parms);
}
@@ -1423,14 +1431,13 @@ This function is an internal primitive--use `make-frame' instead. */ )
value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width,
"childFrameBorder", "childFrameBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qchild_frame_border_width, value),
parms);
}
- gui_default_parameter (f, parms, Qchild_frame_border_width,
- make_fixnum (0),
+ gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil,
"childFrameBorderWidth", "childFrameBorderWidth",
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
@@ -1688,7 +1695,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
}
else
{
- if (EQ (visibility, Qunbound))
+ if (BASE_EQ (visibility, Qunbound))
visibility = Qt;
if (!NILP (visibility))
@@ -1702,7 +1709,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
from `x-create-frame-with-faces' (see above comment). */
f->was_invisible
= (f->was_invisible
- && (!EQ (height, Qunbound) || !EQ (width, Qunbound)));
+ && (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound)));
store_frame_param (f, Qvisibility, visibility);
}
@@ -2670,7 +2677,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
- && !EQ (name, Qunbound)
+ && !BASE_EQ (name, Qunbound)
&& !NILP (name))
error ("Invalid frame name--not a string or nil");
@@ -2721,7 +2728,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
{
fset_name (f, build_string (dpyinfo->x_id_name));
f->explicit_name = false;
@@ -2762,7 +2769,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
@@ -2853,7 +2860,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
Frame parameters may be changed if .Xdefaults contains
specifications for the default font. For example, if there is an
`Emacs.default.attributeBackground: pink', the `background-color'
- attribute of the frame get's set, which let's the internal border
+ attribute of the frame gets set, which lets the internal border
of the tooltip frame appear in pink. Prevent this. */
{
Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
diff --git a/src/pgtkmenu.c b/src/pgtkmenu.c
index eec9f419d07..2eabf6ac1bc 100644
--- a/src/pgtkmenu.c
+++ b/src/pgtkmenu.c
@@ -610,11 +610,6 @@ pgtk_menu_show (struct frame *f, int x, int y, int menuflags,
*error_name = NULL;
- if (!FRAME_GTK_OUTER_WIDGET (f)) {
- *error_name = "Can't popup from child frames.";
- return Qnil;
- }
-
if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
{
*error_name = "Empty menu";
@@ -919,11 +914,6 @@ pgtk_dialog_show (struct frame *f, Lisp_Object title,
*error_name = NULL;
- if (!FRAME_GTK_OUTER_WIDGET (f)) {
- *error_name = "Can't popup from child frames.";
- return Qnil;
- }
-
if (menu_items_n_panes > 1)
{
*error_name = "Multiple panes in dialog box";
diff --git a/src/pgtkselect.c b/src/pgtkselect.c
index 4c87aaa7ea6..76901b9eb1d 100644
--- a/src/pgtkselect.c
+++ b/src/pgtkselect.c
@@ -323,7 +323,7 @@ nil, it defaults to the selected frame. */)
gtk_target_list_unref (list);
}
- if (!EQ (Vpgtk_sent_selection_hooks, Qunbound))
+ if (!BASE_EQ (Vpgtk_sent_selection_hooks, Qunbound))
{
/* FIXME: Use run-hook-with-args! */
for (rest = Vpgtk_sent_selection_hooks; CONSP (rest);
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index c8c8bd0d85e..da958a6664a 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -1333,9 +1333,7 @@ pgtk_draw_glyph_string_background (struct glyph_string *s, bool force_p)
if (s->stippled_p)
{
/* Fill background with a stipple pattern. */
-
- fill_background (s,
- s->x, s->y + box_line_width,
+ fill_background (s, s->x, s->y + box_line_width,
s->background_width,
s->height - 2 * box_line_width);
s->background_filled_p = true;
@@ -1589,6 +1587,10 @@ pgtk_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
false);
x += glyph->pixel_width;
}
+
+ /* Pacify GCC 12 even though s->char2b is not used after this
+ function returns. */
+ s->char2b = NULL;
}
/* Brightness beyond which a color won't have its highlight brightness
@@ -2501,9 +2503,7 @@ pgtk_draw_glyph_string (struct glyph_string *s)
if (s->face->underline_defaulted_p)
pgtk_draw_underwave (s, s->xgcv.foreground);
else
- {
- pgtk_draw_underwave (s, s->face->underline_color);
- }
+ pgtk_draw_underwave (s, s->face->underline_color);
}
else if (s->face->underline == FACE_UNDER_LINE)
{
@@ -2555,7 +2555,7 @@ pgtk_draw_glyph_string (struct glyph_string *s)
}
/* Ignore minimum_offset if the amount of pixels was
- explictly specified. */
+ explicitly specified. */
if (!s->face->underline_pixels_above_descent_line)
position = max (position, underline_minimum_offset);
}
@@ -2670,6 +2670,11 @@ pgtk_draw_glyph_string (struct glyph_string *s)
}
}
+ /* TODO: figure out in which cases the stipple is actually drawn on
+ PGTK. */
+ if (!s->row->stipple_p)
+ s->row->stipple_p = s->face->stipple;
+
/* Reset clipping. */
pgtk_end_cr_clip (s->f);
s->num_clips = 0;
@@ -3346,15 +3351,10 @@ pgtk_mouse_position (struct frame **fp, int insist, Lisp_Object * bar_window,
if (gui_mouse_grabbed (dpyinfo)
&& (!EQ (track_mouse, Qdropping)
&& !EQ (track_mouse, Qdrag_source)))
- {
- /* 1.1. use last_mouse_frame as frame where the pointer is
- on. */
- f1 = dpyinfo->last_mouse_frame;
- }
+ f1 = dpyinfo->last_mouse_frame;
else
{
f1 = *fp;
- /* 1.2. get frame where the pointer is on. */
win = gtk_widget_get_window (FRAME_GTK_WIDGET (*fp));
seat = gdk_display_get_default_seat (dpyinfo->gdpy);
device = gdk_seat_get_pointer (seat);
@@ -3380,19 +3380,17 @@ pgtk_mouse_position (struct frame **fp, int insist, Lisp_Object * bar_window,
return;
}
- /* 2. get the display and the device. */
win = gtk_widget_get_window (FRAME_GTK_WIDGET (f1));
- GdkDisplay *gdpy = gdk_window_get_display (win);
- seat = gdk_display_get_default_seat (gdpy);
+ seat = gdk_display_get_default_seat (dpyinfo->gdpy);
device = gdk_seat_get_pointer (seat);
- /* 3. get x, y relative to edit window of the frame. */
- win = gdk_window_get_device_position (win, device, &win_x, &win_y, &mask);
+ win = gdk_window_get_device_position (win, device,
+ &win_x, &win_y, &mask);
if (f1 != NULL)
{
- dpyinfo = FRAME_DISPLAY_INFO (f1);
- remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph);
+ remember_mouse_glyph (f1, win_x, win_y,
+ &dpyinfo->last_mouse_glyph);
dpyinfo->last_mouse_glyph_frame = f1;
*bar_window = Qnil;
@@ -3505,9 +3503,7 @@ pgtk_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
mono-displays, the fill style may have been changed to
FillSolid in pgtk_draw_glyph_string_background. */
if (face->stipple)
- {
- fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
- }
+ fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
else
{
pgtk_set_cr_source_with_color (f, face->background, true);
@@ -6164,6 +6160,20 @@ drag_data_received (GtkWidget *widget, GdkDragContext *context,
gtk_drag_finish (context, TRUE, FALSE, time);
}
+static void
+pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data)
+{
+ struct terminal *terminal;
+ union buffered_input_event inev;
+
+ EVENT_INIT (inev.ie);
+ terminal = user_data;
+ inev.ie.kind = MONITORS_CHANGED_EVENT;
+ XSETTERMINAL (inev.ie.arg, terminal);
+
+ evq_enqueue (&inev);
+}
+
void
pgtk_set_event_handler (struct frame *f)
{
@@ -6282,26 +6292,6 @@ same_x_server (const char *name1, const char *name2)
&& (*name2 == '.' || *name2 == '\0'));
}
-#define GNOME_INTERFACE_SCHEMA "org.gnome.desktop.interface"
-
-static gdouble pgtk_text_scaling_factor (void)
-{
- GSettingsSchemaSource *schema_source = g_settings_schema_source_get_default ();
- if (schema_source != NULL)
- {
- GSettingsSchema *schema = g_settings_schema_source_lookup (schema_source,
- GNOME_INTERFACE_SCHEMA, true);
- if (schema != NULL)
- {
- g_settings_schema_unref (schema);
- GSettings *set = g_settings_new (GNOME_INTERFACE_SCHEMA);
- return g_settings_get_double (set, "text-scaling-factor");
- }
- }
- return 1;
-}
-
-
/* Open a connection to X display DISPLAY_NAME, and return
the structure that describes the open display.
If we cannot contact the display, return null. */
@@ -6318,6 +6308,8 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name)
char *dpy_name;
static void *handle = NULL;
Lisp_Object lisp_dpy_name = Qnil;
+ GdkScreen *gscr;
+ gdouble dpi;
block_input ();
@@ -6468,21 +6460,22 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name)
reset_mouse_highlight (&dpyinfo->mouse_highlight);
- {
- GdkScreen *gscr = gdk_display_get_default_screen (dpyinfo->gdpy);
+ gscr = gdk_display_get_default_screen (dpyinfo->gdpy);
+ dpi = gdk_screen_get_resolution (gscr);
- gdouble dpi = gdk_screen_get_resolution (gscr);
- if (dpi < 0)
- dpi = 96.0;
+ if (dpi < 0)
+ dpi = 96.0;
- dpi *= pgtk_text_scaling_factor ();
- dpyinfo->resx = dpi;
- dpyinfo->resy = dpi;
- }
+ dpyinfo->resx = dpi;
+ dpyinfo->resy = dpi;
+
+ g_signal_connect (G_OBJECT (gscr), "monitors-changed",
+ G_CALLBACK (pgtk_monitors_changed_cb),
+ terminal);
- /* smooth scroll setting */
- dpyinfo->scroll.x_per_char = 2;
- dpyinfo->scroll.y_per_line = 2;
+ /* Set up scrolling increments. */
+ dpyinfo->scroll.x_per_char = 1;
+ dpyinfo->scroll.y_per_line = 1;
dpyinfo->connection = -1;
@@ -6608,9 +6601,9 @@ pgtk_xlfd_to_fontname (const char *xlfd)
}
bool
-pgtk_defined_color (struct frame *f,
- const char *name,
- Emacs_Color * color_def, bool alloc, bool makeIndex)
+pgtk_defined_color (struct frame *f, const char *name,
+ Emacs_Color *color_def, bool alloc,
+ bool makeIndex)
/* --------------------------------------------------------------------------
Return true if named color found, and set color_def rgb accordingly.
If makeIndex and alloc are nonzero put the color in the color_table,
diff --git a/src/pgtkterm.h b/src/pgtkterm.h
index 20c161e63b9..e31e62ae193 100644
--- a/src/pgtkterm.h
+++ b/src/pgtkterm.h
@@ -96,7 +96,7 @@ struct scroll_bar
editing large files, we establish a minimum height by always
drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
where they would be normally; the bottom and top are in a
- different co-ordinate system. */
+ different coordinate system. */
int start, end;
/* If the scroll bar handle is currently being dragged by the user,
diff --git a/src/print.c b/src/print.c
index 81b524d79fe..5aee5731e40 100644
--- a/src/print.c
+++ b/src/print.c
@@ -624,7 +624,86 @@ If PRINTCHARFUN is omitted or nil, the value of `standard-output' is used. */)
return val;
}
-DEFUN ("prin1", Fprin1, Sprin1, 1, 2, 0,
+static Lisp_Object Vprint_variable_mapping;
+
+static void
+print_bind_all_defaults (void)
+{
+ for (Lisp_Object vars = Vprint_variable_mapping; !NILP (vars);
+ vars = XCDR (vars))
+ {
+ Lisp_Object elem = XCDR (XCAR (vars));
+ specbind (XCAR (elem), XCAR (XCDR (elem)));
+ }
+}
+
+static void
+print_create_variable_mapping (void)
+{
+ Lisp_Object total[] = {
+ list3 (intern ("length"), intern ("print-length"), Qnil),
+ list3 (intern ("level"), intern ("print-level"), Qnil),
+ list3 (intern ("circle"), intern ("print-circle"), Qnil),
+ list3 (intern ("quoted"), intern ("print-quoted"), Qt),
+ list3 (intern ("escape-newlines"), intern ("print-escape-newlines"), Qnil),
+ list3 (intern ("escape-control-characters"),
+ intern ("print-escape-control-characters"), Qnil),
+ list3 (intern ("escape-nonascii"), intern ("print-escape-nonascii"), Qnil),
+ list3 (intern ("escape-multibyte"),
+ intern ("print-escape-multibyte"), Qnil),
+ list3 (intern ("charset-text-property"),
+ intern ("print-charset-text-property"), Qnil),
+ list3 (intern ("unreadeable-function"),
+ intern ("print-unreadable-function"), Qnil),
+ list3 (intern ("gensym"), intern ("print-gensym"), Qnil),
+ list3 (intern ("continuous-numbering"),
+ intern ("print-continuous-numbering"), Qnil),
+ list3 (intern ("number-table"), intern ("print-number-table"), Qnil),
+ list3 (intern ("float-format"), intern ("float-output-format"), Qnil),
+ list3 (intern ("integers-as-characters"),
+ intern ("print-integers-as-characters"), Qnil),
+ };
+
+ Vprint_variable_mapping = CALLMANY (Flist, total);
+}
+
+static void
+print_bind_overrides (Lisp_Object overrides)
+{
+ if (NILP (Vprint_variable_mapping))
+ print_create_variable_mapping ();
+
+ if (EQ (overrides, Qt))
+ print_bind_all_defaults ();
+ else if (!CONSP (overrides))
+ xsignal (Qwrong_type_argument, Qconsp);
+ else
+ {
+ while (!NILP (overrides))
+ {
+ Lisp_Object setting = XCAR (overrides);
+ if (EQ (setting, Qt))
+ print_bind_all_defaults ();
+ else if (!CONSP (setting))
+ xsignal (Qwrong_type_argument, Qconsp);
+ else
+ {
+ Lisp_Object key = XCAR (setting),
+ value = XCDR (setting);
+ Lisp_Object map = Fassq (key, Vprint_variable_mapping);
+ if (NILP (map))
+ xsignal2 (Qwrong_type_argument, Qsymbolp, map);
+ specbind (XCAR (XCDR (map)), value);
+ }
+
+ if (!NILP (XCDR (overrides)) && !CONSP (XCDR (overrides)))
+ xsignal (Qwrong_type_argument, Qconsp);
+ overrides = XCDR (overrides);
+ }
+ }
+}
+
+DEFUN ("prin1", Fprin1, Sprin1, 1, 3, 0,
doc: /* Output the printed representation of OBJECT, any Lisp object.
Quoting characters are printed when needed to make output that `read'
can handle, whenever this is possible. For complex objects, the behavior
@@ -646,21 +725,43 @@ of these:
- t, in which case the output is displayed in the echo area.
If PRINTCHARFUN is omitted, the value of `standard-output' (which see)
-is used instead. */)
- (Lisp_Object object, Lisp_Object printcharfun)
+is used instead.
+
+Optional argument OVERRIDES should be a list of settings for print-related
+variables. An element in this list can be the symbol t, which means "reset
+all the values to their defaults". Otherwise, an element should be a pair,
+where the `car' or the pair is the setting symbol, and the `cdr' is the
+value of of the setting to use for this `prin1' call.
+
+For instance:
+
+ (prin1 object nil \\='((length . 100) (circle . t))).
+
+See the manual entry `(elisp)Output Overrides' for a list of possible
+values.
+
+As a special case, OVERRIDES can also simply be the symbol t, which
+means "use default values for all the print-related settings". */)
+ (Lisp_Object object, Lisp_Object printcharfun, Lisp_Object overrides)
{
+ specpdl_ref count = SPECPDL_INDEX ();
+
if (NILP (printcharfun))
printcharfun = Vstandard_output;
+ if (!NILP (overrides))
+ print_bind_overrides (overrides);
+
PRINTPREPARE;
print (object, printcharfun, 1);
PRINTFINISH;
- return object;
+
+ return unbind_to (count, object);
}
/* A buffer which is used to hold output being built by prin1-to-string. */
Lisp_Object Vprin1_to_string_buffer;
-DEFUN ("prin1-to-string", Fprin1_to_string, Sprin1_to_string, 1, 2, 0,
+DEFUN ("prin1-to-string", Fprin1_to_string, Sprin1_to_string, 1, 3, 0,
doc: /* Return a string containing the printed representation of OBJECT.
OBJECT can be any Lisp object. This function outputs quoting characters
when necessary to make output that `read' can handle, whenever possible,
@@ -670,13 +771,18 @@ the behavior is controlled by `print-level' and `print-length', which see.
OBJECT is any of the Lisp data types: a number, a string, a symbol,
a list, a buffer, a window, a frame, etc.
+See `prin1' for the meaning of OVERRIDES.
+
A printed representation of an object is text which describes that object. */)
- (Lisp_Object object, Lisp_Object noescape)
+ (Lisp_Object object, Lisp_Object noescape, Lisp_Object overrides)
{
specpdl_ref count = SPECPDL_INDEX ();
specbind (Qinhibit_modification_hooks, Qt);
+ if (!NILP (overrides))
+ print_bind_overrides (overrides);
+
/* Save and restore this: we are altering a buffer
but we don't want to deactivate the mark just for that.
No need for specbind, since errors deactivate the mark. */
@@ -732,7 +838,13 @@ is used instead. */)
if (NILP (printcharfun))
printcharfun = Vstandard_output;
PRINTPREPARE;
- print (object, printcharfun, 0);
+ if (STRINGP (object)
+ && !string_intervals (object)
+ && NILP (Vprint_continuous_numbering))
+ /* fast path for plain strings */
+ print_string (object, printcharfun);
+ else
+ print (object, printcharfun, 0);
PRINTFINISH;
return object;
}
@@ -851,7 +963,7 @@ append to existing target file. */)
void
debug_print (Lisp_Object arg)
{
- Fprin1 (arg, Qexternal_debugging_output);
+ Fprin1 (arg, Qexternal_debugging_output, Qnil);
fputs ("\r\n", stderr);
}
@@ -999,7 +1111,7 @@ print_error_message (Lisp_Object data, Lisp_Object stream, const char *context,
|| EQ (errname, Qend_of_file) || EQ (errname, Quser_error))
Fprinc (obj, stream);
else
- Fprin1 (obj, stream);
+ Fprin1 (obj, stream, Qnil);
}
}
}
@@ -1147,7 +1259,6 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
{
/* Construct Vprint_number_table.
This increments print_number_index for the objects added. */
- print_depth = 0;
print_preprocess (obj);
if (HASH_TABLE_P (Vprint_number_table))
@@ -1159,7 +1270,7 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
{
Lisp_Object key = HASH_KEY (h, i);
- if (!EQ (key, Qunbound)
+ if (!BASE_EQ (key, Qunbound)
&& EQ (HASH_VALUE (h, i), Qt))
Fremhash (key, Vprint_number_table);
}
@@ -1171,10 +1282,7 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
}
#define PRINT_CIRCLE_CANDIDATE_P(obj) \
- ((STRINGP (obj) \
- && (string_intervals (obj) \
- || print_depth > 1 \
- || !NILP (Vprint_continuous_numbering))) \
+ (STRINGP (obj) \
|| CONSP (obj) \
|| (VECTORLIKEP (obj) \
&& (VECTORP (obj) || COMPILEDP (obj) \
@@ -1185,6 +1293,78 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
&& SYMBOLP (obj) \
&& !SYMBOL_INTERNED_P (obj)))
+/* The print preprocess stack, used to traverse data structures. */
+
+struct print_pp_entry {
+ ptrdiff_t n; /* number of values, or 0 if a single value */
+ union {
+ Lisp_Object value; /* when n = 0 */
+ Lisp_Object *values; /* when n > 0 */
+ } u;
+};
+
+struct print_pp_stack {
+ struct print_pp_entry *stack; /* base of stack */
+ ptrdiff_t size; /* allocated size in entries */
+ ptrdiff_t sp; /* current number of entries */
+};
+
+static struct print_pp_stack ppstack = {NULL, 0, 0};
+
+NO_INLINE static void
+grow_pp_stack (void)
+{
+ struct print_pp_stack *ps = &ppstack;
+ eassert (ps->sp == ps->size);
+ ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
+ eassert (ps->sp < ps->size);
+}
+
+static inline void
+pp_stack_push_value (Lisp_Object value)
+{
+ if (ppstack.sp >= ppstack.size)
+ grow_pp_stack ();
+ ppstack.stack[ppstack.sp++] = (struct print_pp_entry){.n = 0,
+ .u.value = value};
+}
+
+static inline void
+pp_stack_push_values (Lisp_Object *values, ptrdiff_t n)
+{
+ eassume (n >= 0);
+ if (n == 0)
+ return;
+ if (ppstack.sp >= ppstack.size)
+ grow_pp_stack ();
+ ppstack.stack[ppstack.sp++] = (struct print_pp_entry){.n = n,
+ .u.values = values};
+}
+
+static inline bool
+pp_stack_empty_p (void)
+{
+ return ppstack.sp <= 0;
+}
+
+static inline Lisp_Object
+pp_stack_pop (void)
+{
+ eassume (!pp_stack_empty_p ());
+ struct print_pp_entry *e = &ppstack.stack[ppstack.sp - 1];
+ if (e->n == 0) /* single value */
+ {
+ --ppstack.sp;
+ return e->u.value;
+ }
+ /* Array of values: pop them left to right, which seems to be slightly
+ faster than right to left. */
+ e->n--;
+ if (e->n == 0)
+ --ppstack.sp; /* last value consumed */
+ return (++e->u.values)[-1];
+}
+
/* Construct Vprint_number_table for the print-circle feature
according to the structure of OBJ. OBJ itself and all its elements
will be added to Vprint_number_table recursively if it is a list,
@@ -1196,86 +1376,81 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
static void
print_preprocess (Lisp_Object obj)
{
- int i;
- ptrdiff_t size;
- int loop_count = 0;
- Lisp_Object halftail;
-
eassert (!NILP (Vprint_circle));
+ ptrdiff_t base_sp = ppstack.sp;
- print_depth++;
- halftail = obj;
-
- loop:
- if (PRINT_CIRCLE_CANDIDATE_P (obj))
+ for (;;)
{
- if (!HASH_TABLE_P (Vprint_number_table))
- Vprint_number_table = CALLN (Fmake_hash_table, QCtest, Qeq);
-
- Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil);
- if (!NILP (num)
- /* If Vprint_continuous_numbering is non-nil and OBJ is a gensym,
- always print the gensym with a number. This is a special for
- the lisp function byte-compile-output-docform. */
- || (!NILP (Vprint_continuous_numbering)
- && SYMBOLP (obj)
- && !SYMBOL_INTERNED_P (obj)))
- { /* OBJ appears more than once. Let's remember that. */
- if (!FIXNUMP (num))
- {
- print_number_index++;
- /* Negative number indicates it hasn't been printed yet. */
- Fputhash (obj, make_fixnum (- print_number_index),
- Vprint_number_table);
+ if (PRINT_CIRCLE_CANDIDATE_P (obj))
+ {
+ if (!HASH_TABLE_P (Vprint_number_table))
+ Vprint_number_table = CALLN (Fmake_hash_table, QCtest, Qeq);
+
+ Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil);
+ if (!NILP (num)
+ /* If Vprint_continuous_numbering is non-nil and OBJ is a gensym,
+ always print the gensym with a number. This is a special for
+ the lisp function byte-compile-output-docform. */
+ || (!NILP (Vprint_continuous_numbering)
+ && SYMBOLP (obj)
+ && !SYMBOL_INTERNED_P (obj)))
+ { /* OBJ appears more than once. Let's remember that. */
+ if (!FIXNUMP (num))
+ {
+ print_number_index++;
+ /* Negative number indicates it hasn't been printed yet. */
+ Fputhash (obj, make_fixnum (- print_number_index),
+ Vprint_number_table);
+ }
}
- print_depth--;
- return;
- }
- else
- /* OBJ is not yet recorded. Let's add to the table. */
- Fputhash (obj, Qt, Vprint_number_table);
+ else
+ {
+ /* OBJ is not yet recorded. Let's add to the table. */
+ Fputhash (obj, Qt, Vprint_number_table);
- switch (XTYPE (obj))
- {
- case Lisp_String:
- /* A string may have text properties, which can be circular. */
- traverse_intervals_noorder (string_intervals (obj),
- print_preprocess_string, NULL);
- break;
+ switch (XTYPE (obj))
+ {
+ case Lisp_String:
+ /* A string may have text properties,
+ which can be circular. */
+ traverse_intervals_noorder (string_intervals (obj),
+ print_preprocess_string, NULL);
+ break;
- case Lisp_Cons:
- /* Use HALFTAIL and LOOP_COUNT to detect circular lists,
- just as in print_object. */
- if (loop_count && EQ (obj, halftail))
- break;
- print_preprocess (XCAR (obj));
- obj = XCDR (obj);
- loop_count++;
- if (!(loop_count & 1))
- halftail = XCDR (halftail);
- goto loop;
-
- case Lisp_Vectorlike:
- size = ASIZE (obj);
- if (size & PSEUDOVECTOR_FLAG)
- size &= PSEUDOVECTOR_SIZE_MASK;
- for (i = (SUB_CHAR_TABLE_P (obj)
- ? SUB_CHAR_TABLE_OFFSET : 0); i < size; i++)
- print_preprocess (AREF (obj, i));
- if (HASH_TABLE_P (obj))
- { /* For hash tables, the key_and_value slot is past
- `size' because it needs to be marked specially in case
- the table is weak. */
- struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
- print_preprocess (h->key_and_value);
- }
- break;
+ case Lisp_Cons:
+ if (!NILP (XCDR (obj)))
+ pp_stack_push_value (XCDR (obj));
+ obj = XCAR (obj);
+ continue;
- default:
- break;
+ case Lisp_Vectorlike:
+ {
+ struct Lisp_Vector *vec = XVECTOR (obj);
+ ptrdiff_t size = ASIZE (obj);
+ if (size & PSEUDOVECTOR_FLAG)
+ size &= PSEUDOVECTOR_SIZE_MASK;
+ ptrdiff_t start = (SUB_CHAR_TABLE_P (obj)
+ ? SUB_CHAR_TABLE_OFFSET : 0);
+ pp_stack_push_values (vec->contents + start, size - start);
+ if (HASH_TABLE_P (obj))
+ {
+ struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
+ obj = h->key_and_value;
+ continue;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
}
+
+ if (ppstack.sp <= base_sp)
+ break;
+ obj = pp_stack_pop ();
}
- print_depth--;
}
DEFUN ("print--preprocess", Fprint_preprocess, Sprint_preprocess, 1, 1, 0,
@@ -1467,162 +1642,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
}
return true;
- case PVEC_HASH_TABLE:
- {
- struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
- /* Implement a readable output, e.g.:
- #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
- /* Always print the size. */
- int len = sprintf (buf, "#s(hash-table size %"pD"d",
- HASH_TABLE_SIZE (h));
- strout (buf, len, len, printcharfun);
-
- if (!NILP (h->test.name))
- {
- print_c_string (" test ", printcharfun);
- print_object (h->test.name, printcharfun, escapeflag);
- }
-
- if (!NILP (h->weak))
- {
- print_c_string (" weakness ", printcharfun);
- print_object (h->weak, printcharfun, escapeflag);
- }
-
- print_c_string (" rehash-size ", printcharfun);
- print_object (Fhash_table_rehash_size (obj),
- printcharfun, escapeflag);
-
- print_c_string (" rehash-threshold ", printcharfun);
- print_object (Fhash_table_rehash_threshold (obj),
- printcharfun, escapeflag);
-
- if (h->purecopy)
- {
- print_c_string (" purecopy ", printcharfun);
- print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
- }
-
- print_c_string (" data ", printcharfun);
-
- /* Print the data here as a plist. */
- ptrdiff_t real_size = HASH_TABLE_SIZE (h);
- ptrdiff_t size = h->count;
-
- /* Don't print more elements than the specified maximum. */
- if (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size)
- size = XFIXNAT (Vprint_length);
-
- printchar ('(', printcharfun);
- ptrdiff_t j = 0;
- for (ptrdiff_t i = 0; i < real_size; i++)
- {
- Lisp_Object key = HASH_KEY (h, i);
- if (!EQ (key, Qunbound))
- {
- if (j++) printchar (' ', printcharfun);
- print_object (key, printcharfun, escapeflag);
- printchar (' ', printcharfun);
- print_object (HASH_VALUE (h, i), printcharfun, escapeflag);
- if (j == size)
- break;
- }
- }
-
- if (j < h->count)
- {
- if (j)
- printchar (' ', printcharfun);
- print_c_string ("...", printcharfun);
- }
-
- print_c_string ("))", printcharfun);
- }
- return true;
-
- case PVEC_RECORD:
- {
- ptrdiff_t size = PVSIZE (obj);
-
- /* Don't print more elements than the specified maximum. */
- ptrdiff_t n
- = (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size
- ? XFIXNAT (Vprint_length) : size);
-
- print_c_string ("#s(", printcharfun);
- for (ptrdiff_t i = 0; i < n; i ++)
- {
- if (i) printchar (' ', printcharfun);
- print_object (AREF (obj, i), printcharfun, escapeflag);
- }
- if (n < size)
- print_c_string (" ...", printcharfun);
- printchar (')', printcharfun);
- }
- return true;
-
- case PVEC_SUB_CHAR_TABLE:
- case PVEC_COMPILED:
- case PVEC_CHAR_TABLE:
- case PVEC_NORMAL_VECTOR:
- {
- ptrdiff_t size = ASIZE (obj);
- if (COMPILEDP (obj))
- {
- printchar ('#', printcharfun);
- size &= PSEUDOVECTOR_SIZE_MASK;
- }
- if (CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj))
- {
- /* Print a char-table as if it were a vector,
- lumping the parent and default slots in with the
- character slots. But add #^ as a prefix. */
-
- /* Make each lowest sub_char_table start a new line.
- Otherwise we'll make a line extremely long, which
- results in slow redisplay. */
- if (SUB_CHAR_TABLE_P (obj)
- && XSUB_CHAR_TABLE (obj)->depth == 3)
- printchar ('\n', printcharfun);
- print_c_string ("#^", printcharfun);
- if (SUB_CHAR_TABLE_P (obj))
- printchar ('^', printcharfun);
- size &= PSEUDOVECTOR_SIZE_MASK;
- }
- if (size & PSEUDOVECTOR_FLAG)
- return false;
-
- printchar ('[', printcharfun);
-
- int idx = SUB_CHAR_TABLE_P (obj) ? SUB_CHAR_TABLE_OFFSET : 0;
- Lisp_Object tem;
- ptrdiff_t real_size = size;
-
- /* For a sub char-table, print heading non-Lisp data first. */
- if (SUB_CHAR_TABLE_P (obj))
- {
- int i = sprintf (buf, "%d %d", XSUB_CHAR_TABLE (obj)->depth,
- XSUB_CHAR_TABLE (obj)->min_char);
- strout (buf, i, i, printcharfun);
- }
-
- /* Don't print more elements than the specified maximum. */
- if (FIXNATP (Vprint_length)
- && XFIXNAT (Vprint_length) < size)
- size = XFIXNAT (Vprint_length);
-
- for (int i = idx; i < size; i++)
- {
- if (i) printchar (' ', printcharfun);
- tem = AREF (obj, i);
- print_object (tem, printcharfun, escapeflag);
- }
- if (size < real_size)
- print_c_string (" ...", printcharfun);
- printchar (']', printcharfun);
- }
- return true;
-
default:
break;
}
@@ -2028,32 +2047,132 @@ named_escape (int i)
return 0;
}
+enum print_entry_type
+ {
+ PE_list, /* print rest of list */
+ PE_rbrac, /* print ")" */
+ PE_vector, /* print rest of vector */
+ PE_hash, /* print rest of hash data */
+ };
+
+struct print_stack_entry
+{
+ enum print_entry_type type;
+
+ union
+ {
+ struct
+ {
+ Lisp_Object last; /* cons whose car was just printed */
+ intmax_t maxlen; /* max number of elements left to print */
+ /* State for Brent cycle detection. See
+ Brent RP. BIT. 1980;20(2):176-184. doi:10.1007/BF01933190
+ https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */
+ Lisp_Object tortoise; /* slow pointer */
+ ptrdiff_t n; /* tortoise step countdown */
+ ptrdiff_t m; /* tortoise step period */
+ intmax_t tortoise_idx; /* index of tortoise */
+ } list;
+
+ struct
+ {
+ Lisp_Object obj; /* object to print after " . " */
+ } dotted_cdr;
+
+ struct
+ {
+ Lisp_Object obj; /* vector object */
+ ptrdiff_t size; /* length of vector */
+ ptrdiff_t idx; /* index of next element */
+ const char *end; /* string to print at end */
+ bool truncated; /* whether to print "..." before end */
+ } vector;
+
+ struct
+ {
+ Lisp_Object obj; /* hash-table object */
+ ptrdiff_t nobjs; /* number of keys and values to print */
+ ptrdiff_t idx; /* index of key-value pair */
+ ptrdiff_t printed; /* number of keys and values printed */
+ bool truncated; /* whether to print "..." before end */
+ } hash;
+ } u;
+};
+
+struct print_stack
+{
+ struct print_stack_entry *stack; /* base of stack */
+ ptrdiff_t size; /* allocated size in entries */
+ ptrdiff_t sp; /* current number of entries */
+};
+
+static struct print_stack prstack = {NULL, 0, 0};
+
+NO_INLINE static void
+grow_print_stack (void)
+{
+ struct print_stack *ps = &prstack;
+ eassert (ps->sp == ps->size);
+ ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
+ eassert (ps->sp < ps->size);
+}
+
+static inline void
+print_stack_push (struct print_stack_entry e)
+{
+ if (prstack.sp >= prstack.size)
+ grow_print_stack ();
+ prstack.stack[prstack.sp++] = e;
+}
+
+static void
+print_stack_push_vector (const char *lbrac, const char *rbrac,
+ Lisp_Object obj, ptrdiff_t start, ptrdiff_t size,
+ Lisp_Object printcharfun)
+{
+ print_c_string (lbrac, printcharfun);
+
+ ptrdiff_t print_size = ((FIXNATP (Vprint_length)
+ && XFIXNAT (Vprint_length) < size)
+ ? XFIXNAT (Vprint_length) : size);
+ print_stack_push ((struct print_stack_entry){
+ .type = PE_vector,
+ .u.vector.obj = obj,
+ .u.vector.size = print_size,
+ .u.vector.idx = start,
+ .u.vector.end = rbrac,
+ .u.vector.truncated = (print_size < size),
+ });
+}
+
static void
print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
{
+ ptrdiff_t base_depth = print_depth;
+ ptrdiff_t base_sp = prstack.sp;
char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT),
max (sizeof " . #" + INT_STRLEN_BOUND (intmax_t),
max ((sizeof " with data 0x"
+ (sizeof (uintmax_t) * CHAR_BIT + 4 - 1) / 4),
40)))];
current_thread->stack_top = buf;
+
+ print_obj:
maybe_quit ();
/* Detect circularities and truncate them. */
if (NILP (Vprint_circle))
{
/* Simple but incomplete way. */
- int i;
-
if (print_depth >= PRINT_CIRCLE)
error ("Apparently circular structure being printed");
- for (i = 0; i < print_depth; i++)
+ for (int i = 0; i < print_depth; i++)
if (BASE_EQ (obj, being_printed[i]))
{
int len = sprintf (buf, "#%d", i);
strout (buf, len, len, printcharfun);
- return;
+ goto next_obj;
}
being_printed[print_depth] = obj;
}
@@ -2077,7 +2196,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
/* Just print #n# if OBJ has already been printed. */
int len = sprintf (buf, "#%"pI"d#", n);
strout (buf, len, len, printcharfun);
- return;
+ goto next_obj;
}
}
}
@@ -2151,7 +2270,8 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
for (i = 0, i_byte = 0; i_byte < size_byte;)
{
/* Here, we must convert each multi-byte form to the
- corresponding character code before handing it to printchar. */
+ corresponding character code before handing it to
+ printchar. */
int c = fetch_string_char_advance (obj, &i, &i_byte);
maybe_quit ();
@@ -2171,7 +2291,8 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
else if (multibyte
&& ! ASCII_CHAR_P (c) && print_escape_multibyte)
{
- /* When requested, print multibyte chars using hex escapes. */
+ /* When requested, print multibyte chars using
+ hex escapes. */
char outbuf[sizeof "\\x" + INT_STRLEN_BOUND (c)];
int len = sprintf (outbuf, "\\x%04x", c + 0u);
strout (outbuf, len, len, printcharfun);
@@ -2282,14 +2403,22 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
&& EQ (XCAR (obj), Qquote))
{
printchar ('\'', printcharfun);
- print_object (XCAR (XCDR (obj)), printcharfun, escapeflag);
+ obj = XCAR (XCDR (obj));
+ --print_depth; /* tail recursion */
+ goto print_obj;
}
else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
&& EQ (XCAR (obj), Qfunction))
{
print_c_string ("#'", printcharfun);
- print_object (XCAR (XCDR (obj)), printcharfun, escapeflag);
+ obj = XCAR (XCDR (obj));
+ --print_depth; /* tail recursion */
+ goto print_obj;
}
+ /* FIXME: Do we really need the new_backquote_output gating of
+ special syntax for comma and comma-at? There is basically no
+ benefit from it at all, and it would be nice to get rid of
+ the recursion here without additional complexity. */
else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
&& EQ (XCAR (obj), Qbackquote))
{
@@ -2299,9 +2428,9 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
new_backquote_output--;
}
else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
- && new_backquote_output
&& (EQ (XCAR (obj), Qcomma)
- || EQ (XCAR (obj), Qcomma_at)))
+ || EQ (XCAR (obj), Qcomma_at))
+ && new_backquote_output)
{
print_object (XCAR (obj), printcharfun, false);
new_backquote_output--;
@@ -2311,70 +2440,135 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
else
{
printchar ('(', printcharfun);
-
/* Negative values of print-length are invalid in CL.
Treat them like nil, as CMUCL does. */
intmax_t print_length = (FIXNATP (Vprint_length)
? XFIXNAT (Vprint_length)
: INTMAX_MAX);
- Lisp_Object objtail = Qnil;
- intmax_t i = 0;
- FOR_EACH_TAIL_SAFE (obj)
+ if (print_length == 0)
+ print_c_string ("...)", printcharfun);
+ else
{
- if (i != 0)
- {
- printchar (' ', printcharfun);
-
- if (!NILP (Vprint_circle))
- {
- /* With the print-circle feature. */
- Lisp_Object num = Fgethash (obj, Vprint_number_table,
- Qnil);
- if (FIXNUMP (num))
- {
- print_c_string (". ", printcharfun);
- print_object (obj, printcharfun, escapeflag);
- goto end_of_list;
- }
- }
- }
-
- if (print_length <= i)
- {
- print_c_string ("...", printcharfun);
- goto end_of_list;
- }
-
- i++;
- print_object (XCAR (obj), printcharfun, escapeflag);
- objtail = XCDR (obj);
+ print_stack_push ((struct print_stack_entry){
+ .type = PE_list,
+ .u.list.last = obj,
+ .u.list.maxlen = print_length,
+ .u.list.tortoise = obj,
+ .u.list.n = 2,
+ .u.list.m = 2,
+ .u.list.tortoise_idx = 0,
+ });
+ /* print the car */
+ obj = XCAR (obj);
+ goto print_obj;
}
+ }
+ break;
- /* OBJTAIL non-nil here means it's the end of a dotted list
- or FOR_EACH_TAIL_SAFE detected a circular list. */
- if (!NILP (objtail))
- {
- print_c_string (" . ", printcharfun);
+ case Lisp_Vectorlike:
+ /* First do all the vectorlike types that have a readable syntax. */
+ switch (PSEUDOVECTOR_TYPE (XVECTOR (obj)))
+ {
+ case PVEC_NORMAL_VECTOR:
+ {
+ print_stack_push_vector ("[", "]", obj, 0, ASIZE (obj),
+ printcharfun);
+ goto next_obj;
+ }
+ case PVEC_RECORD:
+ {
+ print_stack_push_vector ("#s(", ")", obj, 0, PVSIZE (obj),
+ printcharfun);
+ goto next_obj;
+ }
+ case PVEC_COMPILED:
+ {
+ print_stack_push_vector ("#[", "]", obj, 0, PVSIZE (obj),
+ printcharfun);
+ goto next_obj;
+ }
+ case PVEC_CHAR_TABLE:
+ {
+ print_stack_push_vector ("#^[", "]", obj, 0, PVSIZE (obj),
+ printcharfun);
+ goto next_obj;
+ }
+ case PVEC_SUB_CHAR_TABLE:
+ {
+ /* Make each lowest sub_char_table start a new line.
+ Otherwise we'll make a line extremely long, which
+ results in slow redisplay. */
+ if (XSUB_CHAR_TABLE (obj)->depth == 3)
+ printchar ('\n', printcharfun);
+ print_c_string ("#^^[", printcharfun);
+ int n = sprintf (buf, "%d %d",
+ XSUB_CHAR_TABLE (obj)->depth,
+ XSUB_CHAR_TABLE (obj)->min_char);
+ strout (buf, n, n, printcharfun);
+ print_stack_push_vector ("", "]", obj,
+ SUB_CHAR_TABLE_OFFSET, PVSIZE (obj),
+ printcharfun);
+ goto next_obj;
+ }
+ case PVEC_HASH_TABLE:
+ {
+ struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
+ /* Implement a readable output, e.g.:
+ #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
+ /* Always print the size. */
+ int len = sprintf (buf, "#s(hash-table size %"pD"d",
+ HASH_TABLE_SIZE (h));
+ strout (buf, len, len, printcharfun);
- if (CONSP (objtail) && NILP (Vprint_circle))
- {
- int len = sprintf (buf, "#%"PRIdMAX, i >> 1);
- strout (buf, len, len, printcharfun);
- goto end_of_list;
- }
+ if (!NILP (h->test.name))
+ {
+ print_c_string (" test ", printcharfun);
+ print_object (h->test.name, printcharfun, escapeflag);
+ }
- print_object (objtail, printcharfun, escapeflag);
- }
+ if (!NILP (h->weak))
+ {
+ print_c_string (" weakness ", printcharfun);
+ print_object (h->weak, printcharfun, escapeflag);
+ }
- end_of_list:
- printchar (')', printcharfun);
+ print_c_string (" rehash-size ", printcharfun);
+ print_object (Fhash_table_rehash_size (obj),
+ printcharfun, escapeflag);
+
+ print_c_string (" rehash-threshold ", printcharfun);
+ print_object (Fhash_table_rehash_threshold (obj),
+ printcharfun, escapeflag);
+
+ if (h->purecopy)
+ print_c_string (" purecopy t", printcharfun);
+
+ print_c_string (" data (", printcharfun);
+
+ ptrdiff_t size = h->count;
+ /* Don't print more elements than the specified maximum. */
+ if (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size)
+ size = XFIXNAT (Vprint_length);
+
+ print_stack_push ((struct print_stack_entry){
+ .type = PE_hash,
+ .u.hash.obj = obj,
+ .u.hash.nobjs = size * 2,
+ .u.hash.idx = 0,
+ .u.hash.printed = 0,
+ .u.hash.truncated = (size < h->count),
+ });
+ goto next_obj;
+ }
+
+ default:
+ break;
}
- break;
- case Lisp_Vectorlike:
if (print_vectorlike (obj, printcharfun, escapeflag, buf))
break;
FALLTHROUGH;
+
default:
{
int len;
@@ -2389,10 +2583,157 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
print_c_string ((" Save your buffers immediately"
" and please report this bug>"),
printcharfun);
+ break;
}
}
-
print_depth--;
+
+ next_obj:
+ if (prstack.sp > base_sp)
+ {
+ /* Handle a continuation on the print stack. */
+ struct print_stack_entry *e = &prstack.stack[prstack.sp - 1];
+ switch (e->type)
+ {
+ case PE_list:
+ {
+ /* after "(" ELEM (* " " ELEM) */
+ Lisp_Object next = XCDR (e->u.list.last);
+ if (NILP (next))
+ {
+ /* end of list: print ")" */
+ printchar (')', printcharfun);
+ --prstack.sp;
+ --print_depth;
+ goto next_obj;
+ }
+ else if (CONSP (next))
+ {
+ if (!NILP (Vprint_circle))
+ {
+ /* With the print-circle feature. */
+ Lisp_Object num = Fgethash (next, Vprint_number_table,
+ Qnil);
+ if (FIXNUMP (num))
+ {
+ print_c_string (" . ", printcharfun);
+ obj = next;
+ e->type = PE_rbrac;
+ goto print_obj;
+ }
+ }
+
+ /* list continues: print " " ELEM ... */
+
+ printchar (' ', printcharfun);
+
+ --e->u.list.maxlen;
+ if (e->u.list.maxlen <= 0)
+ {
+ print_c_string ("...)", printcharfun);
+ --prstack.sp;
+ --print_depth;
+ goto next_obj;
+ }
+
+ e->u.list.last = next;
+ e->u.list.n--;
+ if (e->u.list.n == 0)
+ {
+ /* Double tortoise update period and teleport it. */
+ e->u.list.tortoise_idx += e->u.list.m;
+ e->u.list.m <<= 1;
+ e->u.list.n = e->u.list.m;
+ e->u.list.tortoise = next;
+ }
+ else if (BASE_EQ (next, e->u.list.tortoise))
+ {
+ /* FIXME: This #N tail index is somewhat ambiguous;
+ see bug#55395. */
+ int len = sprintf (buf, ". #%" PRIdMAX ")",
+ e->u.list.tortoise_idx);
+ strout (buf, len, len, printcharfun);
+ --prstack.sp;
+ --print_depth;
+ goto next_obj;
+ }
+ obj = XCAR (next);
+ }
+ else
+ {
+ /* non-nil ending: print " . " ELEM ")" */
+ print_c_string (" . ", printcharfun);
+ obj = next;
+ e->type = PE_rbrac;
+ }
+ break;
+ }
+
+ case PE_rbrac:
+ printchar (')', printcharfun);
+ --prstack.sp;
+ --print_depth;
+ goto next_obj;
+
+ case PE_vector:
+ if (e->u.vector.idx >= e->u.vector.size)
+ {
+ if (e->u.vector.truncated)
+ {
+ if (e->u.vector.idx > 0)
+ printchar (' ', printcharfun);
+ print_c_string ("...", printcharfun);
+ }
+ print_c_string (e->u.vector.end, printcharfun);
+ --prstack.sp;
+ --print_depth;
+ goto next_obj;
+ }
+ if (e->u.vector.idx > 0)
+ printchar (' ', printcharfun);
+ obj = AREF (e->u.vector.obj, e->u.vector.idx);
+ e->u.vector.idx++;
+ break;
+
+ case PE_hash:
+ if (e->u.hash.printed >= e->u.hash.nobjs)
+ {
+ if (e->u.hash.truncated)
+ {
+ if (e->u.hash.printed)
+ printchar (' ', printcharfun);
+ print_c_string ("...", printcharfun);
+ }
+ print_c_string ("))", printcharfun);
+ --prstack.sp;
+ --print_depth;
+ goto next_obj;
+ }
+
+ if (e->u.hash.printed)
+ printchar (' ', printcharfun);
+
+ struct Lisp_Hash_Table *h = XHASH_TABLE (e->u.hash.obj);
+ if ((e->u.hash.printed & 1) == 0)
+ {
+ Lisp_Object key;
+ ptrdiff_t idx = e->u.hash.idx;
+ while (BASE_EQ ((key = HASH_KEY (h, idx)), Qunbound))
+ idx++;
+ e->u.hash.idx = idx;
+ obj = key;
+ }
+ else
+ {
+ obj = HASH_VALUE (h, e->u.hash.idx);
+ e->u.hash.idx++;
+ }
+ e->u.hash.printed++;
+ break;
+ }
+ goto print_obj;
+ }
+ eassert (print_depth == base_depth);
}
@@ -2602,4 +2943,7 @@ be printed. */);
DEFSYM (Qprint_unreadable_function, "print-unreadable-function");
defsubr (&Sflush_standard_output);
+
+ /* Initialized in print_create_variable_mapping. */
+ staticpro (&Vprint_variable_mapping);
}
diff --git a/src/process.c b/src/process.c
index 08a02ad9423..ccfc0bdf547 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1071,13 +1071,24 @@ record_deleted_pid (pid_t pid, Lisp_Object filename)
}
-DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
+DEFUN ("delete-process", Fdelete_process, Sdelete_process, 0, 1,
+ "(list 'message)",
doc: /* Delete PROCESS: kill it and forget about it immediately.
PROCESS may be a process, a buffer, the name of a process or buffer, or
-nil, indicating the current buffer's process. */)
+nil, indicating the current buffer's process.
+
+Interactively, it will kill the current buffer's process. */)
(register Lisp_Object process)
{
register struct Lisp_Process *p;
+ bool mess = false;
+
+ /* We use this to see whether we were called interactively. */
+ if (EQ (process, Qmessage))
+ {
+ mess = true;
+ process = Qnil;
+ }
process = get_process (process);
p = XPROCESS (process);
@@ -1131,6 +1142,8 @@ nil, indicating the current buffer's process. */)
}
}
remove_process (process);
+ if (mess)
+ message ("Deleted process");
return Qnil;
}
@@ -2132,6 +2145,10 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
inchannel = p->open_fd[READ_FROM_SUBPROCESS];
forkout = p->open_fd[SUBPROCESS_STDOUT];
+#if defined(GNU_LINUX) && defined(F_SETPIPE_SZ)
+ fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max);
+#endif
+
if (!NILP (p->stderrproc))
{
struct Lisp_Process *pp = XPROCESS (p->stderrproc);
@@ -4766,7 +4783,7 @@ corresponding connection was closed. */)
SDATA (proc->name),
STRINGP (proc_thread_name)
? SDATA (proc_thread_name)
- : SDATA (Fprin1_to_string (proc->thread, Qt)));
+ : SDATA (Fprin1_to_string (proc->thread, Qt, Qnil)));
}
}
else
@@ -8618,7 +8635,10 @@ returns non-nil. */);
DEFVAR_INT ("read-process-output-max", read_process_output_max,
doc: /* Maximum number of bytes to read from subprocess in a single chunk.
Enlarge the value only if the subprocess generates very large (megabytes)
-amounts of data in one go. */);
+amounts of data in one go.
+
+On GNU/Linux systems, the value should not exceed
+/proc/sys/fs/pipe-max-size. See pipe(7) manpage for details. */);
read_process_output_max = 4096;
DEFVAR_INT ("process-error-pause-time", process_error_pause_time,
@@ -8637,6 +8657,7 @@ sentinel or a process filter function has an error. */);
DEFSYM (Qnull, "null");
DEFSYM (Qpipe_process_p, "pipe-process-p");
+ DEFSYM (Qmessage, "message");
defsubr (&Sprocessp);
defsubr (&Sget_process);
diff --git a/src/profiler.c b/src/profiler.c
index 31a46d1b5e5..5cb42d54fa6 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -132,7 +132,7 @@ static void evict_lower_half (log_t *log)
XSET_HASH_TABLE (tmp, log); /* FIXME: Use make_lisp_ptr. */
Fremhash (key, tmp);
}
- eassert (EQ (Qunbound, HASH_KEY (log, i)));
+ eassert (BASE_EQ (Qunbound, HASH_KEY (log, i)));
eassert (log->next_free == i);
eassert (VECTORP (key));
@@ -158,7 +158,7 @@ record_backtrace (log_t *log, EMACS_INT count)
/* Get a "working memory" vector. */
Lisp_Object backtrace = HASH_VALUE (log, index);
- eassert (EQ (Qunbound, HASH_KEY (log, index)));
+ eassert (BASE_EQ (Qunbound, HASH_KEY (log, index)));
get_backtrace (backtrace);
{ /* We basically do a `gethash+puthash' here, except that we have to be
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index 700a6c357de..8662fe8d6d0 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -1244,21 +1244,22 @@ static int analyze_first (re_char *p, re_char *pend,
return REG_ESIZE; \
ptrdiff_t b_off = b - old_buffer; \
ptrdiff_t begalt_off = begalt - old_buffer; \
- bool fixup_alt_jump_set = !!fixup_alt_jump; \
- bool laststart_set = !!laststart; \
- bool pending_exact_set = !!pending_exact; \
- ptrdiff_t fixup_alt_jump_off, laststart_off, pending_exact_off; \
- if (fixup_alt_jump_set) fixup_alt_jump_off = fixup_alt_jump - old_buffer; \
- if (laststart_set) laststart_off = laststart - old_buffer; \
- if (pending_exact_set) pending_exact_off = pending_exact - old_buffer; \
+ ptrdiff_t fixup_alt_jump_off = \
+ fixup_alt_jump ? fixup_alt_jump - old_buffer : -1; \
+ ptrdiff_t laststart_off = laststart ? laststart - old_buffer : -1; \
+ ptrdiff_t pending_exact_off = \
+ pending_exact ? pending_exact - old_buffer : -1; \
bufp->buffer = xpalloc (bufp->buffer, &bufp->allocated, \
requested_extension, MAX_BUF_SIZE, 1); \
unsigned char *new_buffer = bufp->buffer; \
b = new_buffer + b_off; \
begalt = new_buffer + begalt_off; \
- if (fixup_alt_jump_set) fixup_alt_jump = new_buffer + fixup_alt_jump_off; \
- if (laststart_set) laststart = new_buffer + laststart_off; \
- if (pending_exact_set) pending_exact = new_buffer + pending_exact_off; \
+ if (0 <= fixup_alt_jump_off) \
+ fixup_alt_jump = new_buffer + fixup_alt_jump_off; \
+ if (0 <= laststart_off) \
+ laststart = new_buffer + laststart_off; \
+ if (0 <= pending_exact_off) \
+ pending_exact = new_buffer + pending_exact_off; \
} while (false)
diff --git a/src/sort.c b/src/sort.c
index c7ccfc23055..d10ae692d33 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -783,7 +783,7 @@ merge_at (merge_state *ms, const ptrdiff_t i)
}
-/* Compute the "power" of the first of two adjacent runs begining at
+/* Compute the "power" of the first of two adjacent runs beginning at
index S1, with the first having length N1 and the second (starting
at index S1+N1) having length N2. The run has total length N. */
diff --git a/src/sysstdio.h b/src/sysstdio.h
index 727a466be52..efedc3e450b 100644
--- a/src/sysstdio.h
+++ b/src/sysstdio.h
@@ -28,7 +28,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <attribute.h>
#include <unlocked-io.h>
-extern FILE *emacs_fopen (char const *, char const *) ATTRIBUTE_MALLOC;
+extern FILE *emacs_fopen (char const *, char const *)
+ ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC (fclose, 1);
extern void errputc (int);
extern void errwrite (void const *, ptrdiff_t);
extern void close_output_streams (void);
diff --git a/src/term.c b/src/term.c
index bad1127c93b..3bea621dbda 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2287,9 +2287,9 @@ A suspended tty may be resumed by calling `resume-tty' on it. */)
delete_keyboard_wait_descriptor (fileno (f));
#ifndef MSDOS
- fclose (f);
if (f != t->display_info.tty->output)
fclose (t->display_info.tty->output);
+ fclose (f);
#endif
t->display_info.tty->input = 0;
diff --git a/src/termhooks.h b/src/termhooks.h
index 8c193914ba8..d7190e77362 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -31,7 +31,8 @@ struct glyph;
INLINE_HEADER_BEGIN
-enum scroll_bar_part {
+enum scroll_bar_part
+{
scroll_bar_nowhere,
scroll_bar_above_handle,
scroll_bar_handle,
@@ -223,6 +224,11 @@ enum event_kind
gives the timestamp where the drop
happened.
+ .modifiers gives a number that
+ determines if an event was already
+ handled by
+ `x_dnd_begin_drag_and_drop'.
+
.x and .y give the coordinates of
the drop originating from the root
window. */
@@ -296,8 +302,9 @@ enum event_kind
#endif
#ifdef HAVE_XWIDGETS
- /* events generated by xwidgets*/
+ /* An event generated by an xwidget to tell us something. */
, XWIDGET_EVENT
+
/* Event generated when WebKit asks us to display another widget. */
, XWIDGET_DISPLAY_EVENT
#endif
@@ -344,6 +351,11 @@ enum event_kind
positive delta represents a change clockwise, and a negative
delta represents a change counter-clockwise. */
, PINCH_EVENT
+
+ /* In a MONITORS_CHANGED_EVENT, .arg gives the terminal on which the
+ monitor configuration changed. .timestamp gives the time on
+ which the monitors changed. */
+ , MONITORS_CHANGED_EVENT
};
/* Bit width of an enum event_kind tag at the start of structs and unions. */
diff --git a/src/terminal.c b/src/terminal.c
index 80f3aed7006..dcde8e9f557 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -290,13 +290,13 @@ create_terminal (enum output_method type, struct redisplay_interface *rif)
keyboard_coding =
find_symbol_value (intern ("default-keyboard-coding-system"));
if (NILP (keyboard_coding)
- || EQ (keyboard_coding, Qunbound)
+ || BASE_EQ (keyboard_coding, Qunbound)
|| NILP (Fcoding_system_p (keyboard_coding)))
keyboard_coding = Qno_conversion;
terminal_coding =
find_symbol_value (intern ("default-terminal-coding-system"));
if (NILP (terminal_coding)
- || EQ (terminal_coding, Qunbound)
+ || BASE_EQ (terminal_coding, Qunbound)
|| NILP (Fcoding_system_p (terminal_coding)))
terminal_coding = Qundecided;
diff --git a/src/textprop.c b/src/textprop.c
index 072aac28667..c11ee98f020 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -341,7 +341,7 @@ set_properties (Lisp_Object properties, INTERVAL interval, Lisp_Object object)
for (sym = properties;
PLIST_ELT_P (sym, value);
sym = XCDR (value))
- if (EQ (property_value (interval->plist, XCAR (sym)), Qunbound))
+ if (BASE_EQ (property_value (interval->plist, XCAR (sym)), Qunbound))
{
record_property_change (interval->position, LENGTH (interval),
XCAR (sym), Qnil,
diff --git a/src/tparam.h b/src/tparam.h
index 653f01bdde0..4f4bdc8820f 100644
--- a/src/tparam.h
+++ b/src/tparam.h
@@ -20,6 +20,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#ifndef EMACS_TPARAM_H
#define EMACS_TPARAM_H
+#include <stdlib.h>
+
#include <attribute.h>
/* Don't try to include termcap.h. On some systems, configure finds a
@@ -32,7 +34,8 @@ int tgetnum (const char *);
char *tgetstr (const char *, char **);
char *tgoto (const char *, int, int);
-char *tparam (const char *, char *, int, int, int, int, int) ATTRIBUTE_MALLOC;
+char *tparam (const char *, char *, int, int, int, int, int)
+ ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE;
extern char PC;
extern char *BC;
diff --git a/src/w32.c b/src/w32.c
index 1b10b9965fb..590d9e85d93 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -10297,7 +10297,8 @@ check_windows_init_file (void)
openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0, 0);
if (fd < 0)
{
- Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
+ Lisp_Object load_path_print = Fprin1_to_string (Vload_path,
+ Qnil, Qnil);
char *init_file_name = SSDATA (init_file);
char *load_path = SSDATA (load_path_print);
char *buffer = alloca (1024
diff --git a/src/w32fns.c b/src/w32fns.c
index 0f25c1a594a..8716b762eb0 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -247,6 +247,8 @@ static HWND w32_visible_system_caret_hwnd;
static int w32_unicode_gui;
+static bool w32_selection_dialog_open;
+
/* From w32menu.c */
int menubar_in_use = 0;
@@ -4184,6 +4186,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
update_rect.left, update_rect.top,
update_rect.right, update_rect.bottom));
#endif
+ /* Under double-buffering, update the frame from the back
+ buffer, to prevent a "ghost" of the selection dialog to
+ be left on display while the user selects in the dialog. */
+ if (w32_selection_dialog_open
+ && !w32_disable_double_buffering
+ && FRAME_OUTPUT_DATA (f)->paint_dc)
+ BitBlt (FRAME_OUTPUT_DATA (f)->paint_buffer_handle,
+ 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f),
+ FRAME_OUTPUT_DATA (f)->paint_dc, 0, 0, SRCCOPY);
+
EndPaint (hwnd, &paintStruct);
leave_crit ();
@@ -5536,11 +5548,11 @@ my_create_window (struct frame * f)
RES_TYPE_NUMBER);
top = gui_display_get_arg (dpyinfo, Qnil, Qtop, "top", "Top",
RES_TYPE_NUMBER);
- if (EQ (left, Qunbound))
+ if (BASE_EQ (left, Qunbound))
coords[0] = CW_USEDEFAULT;
else
coords[0] = XFIXNUM (left);
- if (EQ (top, Qunbound))
+ if (BASE_EQ (top, Qunbound))
coords[1] = CW_USEDEFAULT;
else
coords[1] = XFIXNUM (top);
@@ -5656,12 +5668,12 @@ w32_icon (struct frame *f, Lisp_Object parms)
RES_TYPE_NUMBER);
icon_y = gui_display_get_arg (dpyinfo, parms, Qicon_top, 0, 0,
RES_TYPE_NUMBER);
- if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
+ if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound))
{
CHECK_FIXNUM (icon_x);
CHECK_FIXNUM (icon_y);
}
- else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
+ else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound))
error ("Both left and top icon corners of icon must be specified");
block_input ();
@@ -5756,7 +5768,7 @@ w32_default_font_parameter (struct frame *f, Lisp_Object parms)
parms, Qfont, NULL, NULL,
RES_TYPE_STRING);
Lisp_Object font;
- if (EQ (font_param, Qunbound))
+ if (BASE_EQ (font_param, Qunbound))
font_param = Qnil;
font = !NILP (font_param) ? font_param
: gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font",
@@ -5821,10 +5833,10 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
display = gui_display_get_arg (dpyinfo, parameters, Qterminal, 0, 0,
RES_TYPE_NUMBER);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display = gui_display_get_arg (dpyinfo, parameters, Qdisplay, 0, 0,
RES_TYPE_STRING);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display = Qnil;
dpyinfo = check_x_display_info (display);
kb = dpyinfo->terminal->kboard;
@@ -5835,7 +5847,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
name = gui_display_get_arg (dpyinfo, parameters, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
- && ! EQ (name, Qunbound)
+ && ! BASE_EQ (name, Qunbound)
&& ! NILP (name))
error ("Invalid frame name--not a string or nil");
@@ -5845,7 +5857,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
/* See if parent window is specified. */
parent = gui_display_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL,
RES_TYPE_NUMBER);
- if (EQ (parent, Qunbound))
+ if (BASE_EQ (parent, Qunbound))
parent = Qnil;
else if (!NILP (parent))
CHECK_FIXNUM (parent);
@@ -5888,14 +5900,14 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
tem = gui_display_get_arg (dpyinfo, parameters, Qundecorated, NULL, NULL,
RES_TYPE_BOOLEAN);
- FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound);
+ FRAME_UNDECORATED (f) = !NILP (tem) && !BASE_EQ (tem, Qunbound);
store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil);
tem = gui_display_get_arg (dpyinfo, parameters, Qskip_taskbar, NULL, NULL,
RES_TYPE_BOOLEAN);
- FRAME_SKIP_TASKBAR (f) = !NILP (tem) && !EQ (tem, Qunbound);
+ FRAME_SKIP_TASKBAR (f) = !NILP (tem) && !BASE_EQ (tem, Qunbound);
store_frame_param (f, Qskip_taskbar,
- (NILP (tem) || EQ (tem, Qunbound)) ? Qnil : Qt);
+ (NILP (tem) || BASE_EQ (tem, Qunbound)) ? Qnil : Qt);
/* By default, make scrollbars the system standard width and height. */
FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
@@ -5951,7 +5963,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
{
fset_name (f, build_string (dpyinfo->w32_id_name));
f->explicit_name = false;
@@ -5991,7 +6003,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
value = gui_display_get_arg (dpyinfo, parameters, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parameters = Fcons (Fcons (Qinternal_border_width, value),
parameters);
}
@@ -6008,7 +6020,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
value = gui_display_get_arg (dpyinfo, parameters, Qchild_frame_border_width,
"childFrameBorder", "childFrameBorder",
RES_TYPE_NUMBER);
- if (!EQ (value, Qunbound))
+ if (!BASE_EQ (value, Qunbound))
parameters = Fcons (Fcons (Qchild_frame_border_width, value),
parameters);
}
@@ -6207,7 +6219,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
w32_iconify_frame (f);
else
{
- if (EQ (visibility, Qunbound))
+ if (BASE_EQ (visibility, Qunbound))
visibility = Qt;
if (!NILP (visibility))
@@ -6999,7 +7011,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
- && !EQ (name, Qunbound)
+ && !BASE_EQ (name, Qunbound)
&& !NILP (name))
error ("Invalid frame name--not a string or nil");
Vx_resource_name = name;
@@ -7033,7 +7045,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
{
fset_name (f, build_string (dpyinfo->w32_id_name));
f->explicit_name = false;
@@ -7072,7 +7084,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
@@ -7755,6 +7767,15 @@ w32_dialog_in_progress (Lisp_Object in_progress)
{
Lisp_Object frames, frame;
+ /* Indicate to w32_wnd_proc that the selection dialog is about to be
+ open (or was closed, if IN_PROGRESS is nil). */
+ if (!w32_disable_double_buffering)
+ {
+ enter_crit ();
+ w32_selection_dialog_open = !NILP (in_progress);
+ leave_crit ();
+ }
+
/* Don't let frames in `above' z-group obscure dialog windows. */
FOR_EACH_FRAME (frames, frame)
{
@@ -10769,21 +10790,6 @@ bass-down, bass-boost, bass-up, treble-down, treble-up */);
doc: /* SKIP: real doc in xfns.c. */);
Vx_pixel_size_width_font_regexp = Qnil;
- DEFVAR_LISP ("w32-bdf-filename-alist",
- Vw32_bdf_filename_alist,
- doc: /* List of bdf fonts and their corresponding filenames. */);
- Vw32_bdf_filename_alist = Qnil;
-
- DEFVAR_BOOL ("w32-strict-fontnames",
- w32_strict_fontnames,
- doc: /* Non-nil means only use fonts that are exact matches for those requested.
-Default is nil, which allows old fontnames that are not XLFD compliant,
-and allows third-party CJK display to work by specifying false charset
-fields to trick Emacs into translating to Big5, SJIS etc.
-Setting this to t will prevent wrong fonts being selected when
-fontsets are automatically created. */);
- w32_strict_fontnames = 0;
-
DEFVAR_BOOL ("w32-strict-painting",
w32_strict_painting,
doc: /* Non-nil means use strict rules for repainting frames.
diff --git a/src/w32font.c b/src/w32font.c
index 1f93f6d5e05..611a0c89658 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -1540,6 +1540,19 @@ add_font_entity_to_list (ENUMLOGFONTEX *logical_font,
|| physical_font->ntmFontSig.fsUsb[1]
|| physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff;
+ /* Kludgey fix for Arial Unicode MS font that claims support for
+ scripts it doesn't actually cover. */
+ if (strncmp (logical_font->elfLogFont.lfFaceName,
+ "Arial Unicode MS", 16) == 0)
+ {
+ /* Reset bits 4 (Phonetic), 12 (Vai), 14 (Nko), 27 (Balinese). */
+ physical_font->ntmFontSig.fsUsb[0] &= 0xf7ffafef;
+ /* Reset bits 53 (Phags-pa) and 58 (Phoenician). */
+ physical_font->ntmFontSig.fsUsb[1] &= 0xfbdfffff;
+ /* Set bit 70 (Tibetan). */
+ physical_font->ntmFontSig.fsUsb[2] |= 0x00000040;
+ }
+
/* Skip non matching fonts. */
/* For uniscribe backend, consider only truetype or opentype fonts
@@ -2834,18 +2847,18 @@ syms_of_w32font (void)
DEFSYM (Qhanunoo, "hanunoo");
DEFSYM (Qkharoshthi, "kharoshthi");
DEFSYM (Qlimbu, "limbu");
- DEFSYM (Qlinear_b, "linear_b");
+ DEFSYM (Qlinear_b, "linear-b");
DEFSYM (Qaegean_number, "aegean-number");
- DEFSYM (Qold_italic, "old_italic");
- DEFSYM (Qold_persian, "old_persian");
+ DEFSYM (Qold_italic, "old-italic");
+ DEFSYM (Qold_persian, "old-persian");
DEFSYM (Qosmanya, "osmanya");
DEFSYM (Qphags_pa, "phags-pa");
DEFSYM (Qphoenician, "phoenician");
DEFSYM (Qshavian, "shavian");
- DEFSYM (Qsyloti_nagri, "syloti_nagri");
+ DEFSYM (Qsyloti_nagri, "syloti-nagri");
DEFSYM (Qtagalog, "tagalog");
DEFSYM (Qtagbanwa, "tagbanwa");
- DEFSYM (Qtai_le, "tai_le");
+ DEFSYM (Qtai_le, "tai-le");
DEFSYM (Qtifinagh, "tifinagh");
DEFSYM (Qugaritic, "ugaritic");
DEFSYM (Qlycian, "lycian");
diff --git a/src/w32menu.c b/src/w32menu.c
index 5cd6c3310e3..b10239d5cc6 100644
--- a/src/w32menu.c
+++ b/src/w32menu.c
@@ -556,10 +556,8 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
HMENU menu;
POINT pos;
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
- widget_value **submenu_stack
- = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
- Lisp_Object *subprefix_stack
- = (Lisp_Object *) alloca (menu_items_used * word_size);
+ widget_value **submenu_stack;
+ Lisp_Object *subprefix_stack;
int submenu_depth = 0;
bool first_pane;
@@ -574,6 +572,11 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
return Qnil;
}
+ USE_SAFE_ALLOCA;
+
+ submenu_stack = SAFE_ALLOCA (menu_items_used * sizeof (widget_value *));
+ subprefix_stack = SAFE_ALLOCA (menu_items_used * word_size);
+
block_input ();
/* Create a tree of widget_value objects
@@ -816,6 +819,7 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
entry = Fcons (subprefix_stack[j], entry);
}
unblock_input ();
+ SAFE_FREE ();
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
@@ -830,6 +834,7 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
}
unblock_input ();
+ SAFE_FREE ();
return Qnil;
}
diff --git a/src/w32notify.c b/src/w32notify.c
index ccefecb6596..72e634f77c7 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -519,16 +519,16 @@ watched for some reason, this function signals a `file-error' error.
FILTER is a list of conditions for reporting an event. It can include
the following symbols:
- 'file-name' -- report file creation, deletion, or renaming
- 'directory-name' -- report directory creation, deletion, or renaming
- 'attributes' -- report changes in attributes
- 'size' -- report changes in file-size
- 'last-write-time' -- report changes in last-write time
- 'last-access-time' -- report changes in last-access time
- 'creation-time' -- report changes in creation time
- 'security-desc' -- report changes in security descriptor
-
-If FILE is a directory, and FILTER includes 'subtree', then all the
+ `file-name' -- report file creation, deletion, or renaming
+ `directory-name' -- report directory creation, deletion, or renaming
+ `attributes' -- report changes in attributes
+ `size' -- report changes in file-size
+ `last-write-time' -- report changes in last-write time
+ `last-access-time' -- report changes in last-access time
+ `creation-time' -- report changes in creation time
+ `security-desc' -- report changes in security descriptor
+
+If FILE is a directory, and FILTER includes `subtree', then all the
subdirectories will also be watched and changes in them reported.
When any event happens that satisfies the conditions specified by
@@ -541,11 +541,11 @@ DESCRIPTOR is the same object as the one returned by this function.
ACTION is the description of the event. It could be any one of the
following:
- 'added' -- FILE was added
- 'removed' -- FILE was deleted
- 'modified' -- FILE's contents or its attributes were modified
- 'renamed-from' -- a file was renamed whose old name was FILE
- 'renamed-to' -- a file was renamed and its new name is FILE
+ `added' -- FILE was added
+ `removed' -- FILE was deleted
+ `modified' -- FILE's contents or its attributes were modified
+ `renamed-from' -- a file was renamed whose old name was FILE
+ `renamed-to' -- a file was renamed and its new name is FILE
FILE is the name of the file whose event is being reported.
diff --git a/src/w32proc.c b/src/w32proc.c
index 781a19f480f..7acfba64d70 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -63,6 +63,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "w32term.h"
#include "coding.h"
+void w32_raise (int);
+
#define RVA_TO_PTR(var,section,filedata) \
((void *)((section)->PointerToRawData \
+ ((DWORD_PTR)(var) - (section)->VirtualAddress) \
@@ -311,6 +313,21 @@ sigismember (const sigset_t *set, int signo)
return (*set & (1U << signo)) != 0;
}
+/* A fuller emulation of 'raise', which supports signals that MS
+ runtime doesn't know about. */
+void
+w32_raise (int signo)
+{
+ if (!(signo == SIGCHLD || signo == SIGALRM || signo == SIGPROF))
+ raise (signo);
+
+ /* Call the handler directly for the signals that we handle
+ ourselves. */
+ signal_handler handler = sig_handlers[signo];
+ if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR))
+ handler (signo);
+}
+
pid_t
getpgrp (void)
{
diff --git a/src/w32term.c b/src/w32term.c
index 19786da3a6d..d0577efccc1 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -2682,13 +2682,13 @@ w32_draw_glyph_string (struct glyph_string *s)
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
- = (!(NILP (val) || EQ (val, Qunbound))
+ = (!(NILP (val) || BASE_EQ (val, Qunbound))
|| s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
use_underline_position_properties
- = !(NILP (val) || EQ (val, Qunbound));
+ = !(NILP (val) || BASE_EQ (val, Qunbound));
/* Get the underline thickness. Default is 1 pixel. */
if (font && font->underline_thickness > 0)
@@ -2720,7 +2720,7 @@ w32_draw_glyph_string (struct glyph_string *s)
if (!(s->face->underline_at_descent_line_p
/* Ignore minimum_offset if the amount of pixels
- was explictly specified. */
+ was explicitly specified. */
&& s->face->underline_pixels_above_descent_line))
position = max (position, minimum_offset);
}
@@ -5912,6 +5912,29 @@ w32_read_socket (struct terminal *terminal,
(short) HIWORD (msg.msg.lParam)));
}
+ /* According to the MS documentation, this message is sent
+ to each window whenever a monitor is added, removed, or
+ has its resolution change. Detect duplicate events when
+ there are multiple frames by ensuring only one event is
+ put in the keyboard buffer at any given time. */
+ {
+ union buffered_input_event *ev;
+
+ ev = (kbd_store_ptr == kbd_buffer
+ ? kbd_buffer + KBD_BUFFER_SIZE - 1
+ : kbd_store_ptr - 1);
+
+ if (kbd_store_ptr != kbd_fetch_ptr
+ && ev->ie.kind == MONITORS_CHANGED_EVENT
+ && XTERMINAL (ev->ie.arg) == dpyinfo->terminal)
+ /* Don't store a MONITORS_CHANGED_EVENT if there is
+ already an undelivered event on the queue. */
+ break;
+
+ inev.kind = MONITORS_CHANGED_EVENT;
+ XSETTERMINAL (inev.arg, dpyinfo->terminal);
+ }
+
check_visibility = 1;
break;
diff --git a/src/window.c b/src/window.c
index 15d6cf94b0e..ac8408a9a97 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1014,11 +1014,22 @@ WINDOW must be a valid window and defaults to the selected one. */)
return make_fixnum (decode_valid_window (window)->top_line);
}
+static enum window_body_unit
+window_body_unit_from_symbol (Lisp_Object unit)
+{
+ return
+ EQ (unit, Qremap)
+ ? WINDOW_BODY_IN_REMAPPED_CHARS
+ : (NILP (unit)
+ ? WINDOW_BODY_IN_CANONICAL_CHARS
+ : WINDOW_BODY_IN_PIXELS);
+}
+
/* Return the number of lines/pixels of W's body. Don't count any mode
or header line or horizontal divider of W. Rounds down to nearest
integer when not working pixelwise. */
static int
-window_body_height (struct window *w, bool pixelwise)
+window_body_height (struct window *w, enum window_body_unit pixelwise)
{
int height = (w->pixel_height
- WINDOW_TAB_LINE_HEIGHT (w)
@@ -1029,11 +1040,27 @@ window_body_height (struct window *w, bool pixelwise)
- WINDOW_MODE_LINE_HEIGHT (w)
- WINDOW_BOTTOM_DIVIDER_WIDTH (w));
+ int denom = 1;
+ if (pixelwise == WINDOW_BODY_IN_REMAPPED_CHARS)
+ {
+ if (!NILP (Vface_remapping_alist))
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ int face_id = lookup_named_face (NULL, f, Qdefault, true);
+ struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
+ if (face && face->font && face->font->height)
+ denom = face->font->height;
+ }
+ /* For performance, use canonical chars if no face remapping. */
+ else
+ pixelwise = WINDOW_BODY_IN_CANONICAL_CHARS;
+ }
+
+ if (pixelwise == WINDOW_BODY_IN_CANONICAL_CHARS)
+ denom = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w));
+
/* Don't return a negative value. */
- return max (pixelwise
- ? height
- : height / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)),
- 0);
+ return max (height / denom, 0);
}
/* Return the number of columns/pixels of W's body. Don't count columns
@@ -1042,7 +1069,7 @@ window_body_height (struct window *w, bool pixelwise)
fringes either. Round down to nearest integer when not working
pixelwise. */
int
-window_body_width (struct window *w, bool pixelwise)
+window_body_width (struct window *w, enum window_body_unit pixelwise)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
@@ -1059,50 +1086,76 @@ window_body_width (struct window *w, bool pixelwise)
? WINDOW_FRINGES_WIDTH (w)
: 0));
+ int denom = 1;
+ if (pixelwise == WINDOW_BODY_IN_REMAPPED_CHARS)
+ {
+ if (!NILP (Vface_remapping_alist))
+ {
+ int face_id = lookup_named_face (NULL, f, Qdefault, true);
+ struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
+ if (face && face->font)
+ {
+ if (face->font->average_width)
+ denom = face->font->average_width;
+ else if (face->font->space_width)
+ denom = face->font->space_width;
+ }
+ }
+ /* For performance, use canonical chars if no face remapping. */
+ else
+ pixelwise = WINDOW_BODY_IN_CANONICAL_CHARS;
+ }
+
+ if (pixelwise == WINDOW_BODY_IN_CANONICAL_CHARS)
+ denom = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w));
+
/* Don't return a negative value. */
- return max (pixelwise
- ? width
- : width / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)),
- 0);
+ return max (width / denom, 0);
}
DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
doc: /* Return the width of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one. Optional
-argument PIXELWISE non-nil means return the width in pixels. The return
-value does not include any vertical dividers, fringes or marginal areas,
-or scroll bars.
+WINDOW must be a live window and defaults to the selected one. The
+return value does not include any vertical dividers, fringes or
+marginal areas, or scroll bars.
-If PIXELWISE is nil, return the largest integer smaller than WINDOW's
-pixel width divided by the character width of WINDOW's frame. This
-means that if a column at the right of the text area is only partially
-visible, that column is not counted.
+The optional argument PIXELWISE defines the units to use for the
+width. If nil, return the largest integer smaller than WINDOW's pixel
+width in units of the character width of WINDOW's frame. If PIXELWISE
+is `remap' and the default face is remapped (see
+`face-remapping-alist'), use the remapped face to determine the
+character width. For any other non-nil value, return the width in
+pixels.
Note that the returned value includes the column reserved for the
continuation glyph.
-Also see `window-max-characters-per-line'. */)
+Also see `window-max-chars-per-line'. */)
(Lisp_Object window, Lisp_Object pixelwise)
{
- return make_fixnum (window_body_width (decode_live_window (window),
- !NILP (pixelwise)));
+ return (make_fixnum
+ (window_body_width (decode_live_window (window),
+ window_body_unit_from_symbol (pixelwise))));
}
DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0,
doc: /* Return the height of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one. Optional
-argument PIXELWISE non-nil means return the height of WINDOW's text area
-in pixels. The return value does not include the mode line or header
-line or any horizontal divider.
-
-If PIXELWISE is nil, return the largest integer smaller than WINDOW's
-pixel height divided by the character height of WINDOW's frame. This
-means that if a line at the bottom of the text area is only partially
-visible, that line is not counted. */)
+WINDOW must be a live window and defaults to the selected one. The
+return value does not include the mode line or header line or any
+horizontal divider.
+
+The optional argument PIXELWISE defines the units to use for the
+height. If nil, return the largest integer smaller than WINDOW's
+pixel height in units of the character height of WINDOW's frame. If
+PIXELWISE is `remap' and the default face is remapped (see
+`face-remapping-alist'), use the remapped face to determine the
+character height. For any other non-nil value, return the height in
+pixels. */)
(Lisp_Object window, Lisp_Object pixelwise)
{
- return make_fixnum (window_body_height (decode_live_window (window),
- !NILP (pixelwise)));
+ return (make_fixnum
+ (window_body_height (decode_live_window (window),
+ window_body_unit_from_symbol (pixelwise))));
}
DEFUN ("window-old-body-pixel-width",
@@ -2124,7 +2177,8 @@ though when run from an idle timer with a delay of zero seconds. */)
struct glyph_row *row, *end_row;
int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w);
Lisp_Object rows = Qnil;
- int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true);
+ int window_width = NILP (body)
+ ? w->pixel_width : window_body_width (w, WINDOW_BODY_IN_PIXELS);
int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w);
int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
int subtract = NILP (body) ? 0 : (tab_line_height + header_line_height);
@@ -3657,8 +3711,10 @@ window_change_record_windows (Lisp_Object window, int stamp, ptrdiff_t number)
wset_old_buffer (w, w->contents);
w->old_pixel_width = w->pixel_width;
w->old_pixel_height = w->pixel_height;
- w->old_body_pixel_width = window_body_width (w, true);
- w->old_body_pixel_height = window_body_height (w, true);
+ w->old_body_pixel_width
+ = window_body_width (w, WINDOW_BODY_IN_PIXELS);
+ w->old_body_pixel_height
+ = window_body_height (w, WINDOW_BODY_IN_PIXELS);
}
w = NILP (w->next) ? 0 : XWINDOW (w->next);
@@ -3903,8 +3959,10 @@ run_window_change_functions (void)
&& (window_buffer_change
|| w->pixel_width != w->old_pixel_width
|| w->pixel_height != w->old_pixel_height
- || window_body_width (w, true) != w->old_body_pixel_width
- || window_body_height (w, true) != w->old_body_pixel_height));
+ || (window_body_width (w, WINDOW_BODY_IN_PIXELS)
+ != w->old_body_pixel_width)
+ || (window_body_height (w, WINDOW_BODY_IN_PIXELS)
+ != w->old_body_pixel_height)));
/* The following two are needed when running the default
values for this frame below. */
@@ -4768,7 +4826,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
Lisp_Object mini = f->minibuffer_window;
struct window *m = WINDOWP (mini) ? XWINDOW (mini) : NULL;
int mini_height = ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
- ? unit + m->pixel_height - window_body_height (m, true)
+ ? (unit + m->pixel_height
+ - window_body_height (m, WINDOW_BODY_IN_PIXELS))
: 0);
new_pixel_size = max (horflag ? size : size - mini_height, unit);
@@ -5255,7 +5314,7 @@ void
grow_mini_window (struct window *w, int delta)
{
struct frame *f = XFRAME (w->frame);
- int old_height = window_body_height (w, true);
+ int old_height = window_body_height (w, WINDOW_BODY_IN_PIXELS);
int min_height = FRAME_LINE_HEIGHT (f);
eassert (MINI_WINDOW_P (w));
@@ -5289,7 +5348,8 @@ void
shrink_mini_window (struct window *w)
{
struct frame *f = XFRAME (w->frame);
- int delta = window_body_height (w, true) - FRAME_LINE_HEIGHT (f);
+ int delta = (window_body_height (w, WINDOW_BODY_IN_PIXELS)
+ - FRAME_LINE_HEIGHT (f));
eassert (MINI_WINDOW_P (w));
@@ -5636,7 +5696,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
if (w->vscroll < 0 && rtop > 0)
{
px = max (0, -w->vscroll - min (rtop, -dy));
- Fset_window_vscroll (window, make_fixnum (px), Qt);
+ Fset_window_vscroll (window, make_fixnum (px), Qt,
+ Qnil);
return;
}
}
@@ -5646,7 +5707,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
{
px = max (0, -w->vscroll + min (rbot, dy));
- Fset_window_vscroll (window, make_fixnum (px), Qt);
+ Fset_window_vscroll (window, make_fixnum (px), Qt,
+ Qnil);
return;
}
@@ -5655,7 +5717,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
{
ptrdiff_t spos;
- Fset_window_vscroll (window, make_fixnum (0), Qt);
+ Fset_window_vscroll (window, make_fixnum (0), Qt,
+ Qnil);
/* If there are other text lines above the current row,
move window start to current row. Else to next row. */
if (rbot > 0)
@@ -5674,7 +5737,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
}
}
/* Cancel previous vscroll. */
- Fset_window_vscroll (window, make_fixnum (0), Qt);
+ Fset_window_vscroll (window, make_fixnum (0), Qt, Qnil);
}
itdata = bidi_shelve_cache ();
@@ -6353,9 +6416,10 @@ by this function. This happens in an interactive call. */)
(register Lisp_Object arg, Lisp_Object set_minimum)
{
struct window *w = XWINDOW (selected_window);
- EMACS_INT requested_arg = (NILP (arg)
- ? window_body_width (w, 0) - 2
- : XFIXNUM (Fprefix_numeric_value (arg)));
+ EMACS_INT requested_arg =
+ (NILP (arg)
+ ? window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) - 2
+ : XFIXNUM (Fprefix_numeric_value (arg)));
Lisp_Object result = set_window_hscroll (w, w->hscroll + requested_arg);
if (!NILP (set_minimum))
@@ -6378,9 +6442,10 @@ by this function. This happens in an interactive call. */)
(register Lisp_Object arg, Lisp_Object set_minimum)
{
struct window *w = XWINDOW (selected_window);
- EMACS_INT requested_arg = (NILP (arg)
- ? window_body_width (w, 0) - 2
- : XFIXNUM (Fprefix_numeric_value (arg)));
+ EMACS_INT requested_arg =
+ (NILP (arg)
+ ? window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) - 2
+ : XFIXNUM (Fprefix_numeric_value (arg)));
Lisp_Object result = set_window_hscroll (w, w->hscroll - requested_arg);
if (!NILP (set_minimum))
@@ -7944,7 +8009,7 @@ optional second arg PIXELS-P means value is measured in pixels. */)
DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
- 2, 3, 0,
+ 2, 4, 0,
doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
This takes effect when displaying tall lines or images.
@@ -7954,8 +8019,12 @@ optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
If PIXELS-P is nil, VSCROLL may have to be rounded so that it
corresponds to an integral number of pixels. The return value is the
result of this rounding.
-If PIXELS-P is non-nil, the return value is VSCROLL. */)
- (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p)
+If PIXELS-P is non-nil, the return value is VSCROLL.
+
+PRESERVE-VSCROLL-P makes setting the start of WINDOW preserve the
+vscroll if its start is "frozen" due to a resized mini-window. */)
+ (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p,
+ Lisp_Object preserve_vscroll_p)
{
struct window *w = decode_live_window (window);
struct frame *f = XFRAME (w->frame);
@@ -7980,7 +8049,12 @@ If PIXELS-P is non-nil, the return value is VSCROLL. */)
/* Prevent redisplay shortcuts. */
XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true;
+
+ /* Mark W for redisplay. (bug#55299) */
+ wset_redisplay (w);
}
+
+ w->preserve_vscroll_p = !NILP (preserve_vscroll_p);
}
return Fwindow_vscroll (window, pixels_p);
@@ -8109,11 +8183,11 @@ compare_window_configurations (Lisp_Object configuration1,
return true;
}
-DEFUN ("compare-window-configurations", Fcompare_window_configurations,
- Scompare_window_configurations, 2, 2, 0,
- doc: /* Compare two window configurations as regards the structure of windows.
-This function ignores details such as the values of point
-and scrolling positions. */)
+DEFUN ("window-configuration-equal-p", Fwindow_configuration_equal_p,
+ Swindow_configuration_equal_p, 2, 2, 0,
+ doc: /* Say whether two window configurations have the same window layout.
+This function ignores details such as the values of point and
+scrolling positions. */)
(Lisp_Object x, Lisp_Object y)
{
if (compare_window_configurations (x, y))
@@ -8601,7 +8675,7 @@ displayed after a scrolling operation to be somewhat inaccurate. */);
defsubr (&Swindow_scroll_bars);
defsubr (&Swindow_vscroll);
defsubr (&Sset_window_vscroll);
- defsubr (&Scompare_window_configurations);
+ defsubr (&Swindow_configuration_equal_p);
defsubr (&Swindow_bump_use_time);
defsubr (&Swindow_list);
defsubr (&Swindow_list_1);
diff --git a/src/window.h b/src/window.h
index 387a3be36a9..298a80a5366 100644
--- a/src/window.h
+++ b/src/window.h
@@ -445,6 +445,10 @@ struct window
window. */
bool_bf suspend_auto_hscroll : 1;
+ /* True if vscroll should be preserved while forcing the start due
+ to a frozen window. */
+ bool_bf preserve_vscroll_p : 1;
+
/* Amount by which lines of this window are scrolled in
y-direction (smooth scrolling). */
int vscroll;
@@ -1182,7 +1186,13 @@ extern bool window_wants_mode_line (struct window *);
extern bool window_wants_header_line (struct window *);
extern bool window_wants_tab_line (struct window *);
extern int window_internal_height (struct window *);
-extern int window_body_width (struct window *w, bool);
+enum window_body_unit
+ {
+ WINDOW_BODY_IN_CANONICAL_CHARS,
+ WINDOW_BODY_IN_PIXELS,
+ WINDOW_BODY_IN_REMAPPED_CHARS
+ };
+extern int window_body_width (struct window *w, enum window_body_unit);
enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
extern int window_scroll_margin (struct window *, enum margin_unit);
extern void temp_output_buffer_show (Lisp_Object);
diff --git a/src/xdisp.c b/src/xdisp.c
index 50efa50c55b..b02375ab2d8 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -5894,7 +5894,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
location = tem;
}
- if (EQ (location, Qunbound))
+ if (BASE_EQ (location, Qunbound))
{
location = Qnil;
value = spec;
@@ -11234,7 +11234,7 @@ argument if the size of the buffer is large or unknown.
Optional argument MODE-LINES nil or omitted means do not include the
height of the mode-, tab- or header-line of WINDOW in the return value.
-If it is the symbol `mode-line', 'tab-line' or `header-line', include
+If it is the symbol `mode-line', `tab-line' or `header-line', include
only the height of that line, if present, in the return value. If t,
include the height of any of these, if present, in the return value.
@@ -13148,7 +13148,7 @@ store_mode_line_noprop (const char *string, int field_width, int precision)
Vicon_title_format if FRAME is iconified, otherwise it is
frame_title_format. */
-static void
+void
gui_consider_frame_title (Lisp_Object frame)
{
struct frame *f = XFRAME (frame);
@@ -13200,8 +13200,9 @@ gui_consider_frame_title (Lisp_Object frame)
mode_line_noprop_buf; then display the title. */
record_unwind_protect (unwind_format_mode_line,
format_mode_line_unwind_data
- (NULL, current_buffer, Qnil, false));
+ (f, current_buffer, selected_window, false));
+ Fselect_window (f->selected_window, Qt);
set_buffer_internal_1
(XBUFFER (XWINDOW (f->selected_window)->contents));
fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format;
@@ -17006,6 +17007,7 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
w->window_end_valid = true;
w->update_mode_line = false;
+ w->preserve_vscroll_p = false;
}
w->redisplay = !accurate_p;
@@ -17850,7 +17852,7 @@ cursor_row_fully_visible_p (struct window *w, bool force_p,
buffer_local_value (Qmake_cursor_line_fully_visible, w->contents);
/* If no local binding, use the global value. */
- if (EQ (mclfv_p, Qunbound))
+ if (BASE_EQ (mclfv_p, Qunbound))
mclfv_p = Vmake_cursor_line_fully_visible;
/* Follow mode sets the variable to a Lisp function in buffers that
are under Follow mode. */
@@ -19168,7 +19170,14 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
int new_vpos = -1;
w->force_start = false;
- w->vscroll = 0;
+
+ /* The vscroll should be preserved in this case, since
+ `pixel-scroll-precision-mode' must continue working normally
+ when a mini-window is resized. (bug#55312) */
+ if (!w->preserve_vscroll_p || !window_frozen_p (w))
+ w->vscroll = 0;
+
+ w->preserve_vscroll_p = false;
w->window_end_valid = false;
/* Forget any recorded base line for line number display. */
@@ -22463,6 +22472,13 @@ compute_line_metrics (struct it *it)
}
+static void
+clear_position (struct it *it)
+{
+ it->position.charpos = 0;
+ it->position.bytepos = 0;
+}
+
/* Append one space to the glyph row of iterator IT if doing a
window-based redisplay. The space has the same face as
IT->face_id. Value is true if a space was added.
@@ -22498,7 +22514,7 @@ append_space_for_newline (struct it *it, bool default_face_p)
struct face *face;
it->what = IT_CHARACTER;
- memset (&it->position, 0, sizeof it->position);
+ clear_position (it);
it->object = Qnil;
it->len = 1;
@@ -22827,7 +22843,7 @@ extend_face_to_end_of_line (struct it *it)
const int stretch_width =
indicator_column - it->current_x - char_width;
- memset (&it->position, 0, sizeof it->position);
+ clear_position (it);
/* Only generate a stretch glyph if there is distance
between current_x and the indicator position. */
@@ -22861,7 +22877,7 @@ extend_face_to_end_of_line (struct it *it)
if (stretch_width > 0)
{
- memset (&it->position, 0, sizeof it->position);
+ clear_position (it);
append_stretch_glyph (it, Qnil, stretch_width,
it->ascent + it->descent,
stretch_ascent);
@@ -22911,7 +22927,7 @@ extend_face_to_end_of_line (struct it *it)
(((it->ascent + it->descent)
* FONT_BASE (font)) / FONT_HEIGHT (font));
saved_pos = it->position;
- memset (&it->position, 0, sizeof it->position);
+ clear_position (it);
saved_avoid_cursor = it->avoid_cursor_p;
it->avoid_cursor_p = true;
saved_face_id = it->face_id;
@@ -22949,7 +22965,7 @@ extend_face_to_end_of_line (struct it *it)
enum display_element_type saved_what = it->what;
it->what = IT_CHARACTER;
- memset (&it->position, 0, sizeof it->position);
+ clear_position (it);
it->object = Qnil;
it->c = it->char_to_display = ' ';
it->len = 1;
@@ -28357,7 +28373,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
}
prop = buffer_local_value (prop, it->w->contents);
- if (EQ (prop, Qunbound))
+ if (BASE_EQ (prop, Qunbound))
prop = Qnil;
}
@@ -28420,13 +28436,13 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
}
car = buffer_local_value (car, it->w->contents);
- if (EQ (car, Qunbound))
+ if (BASE_EQ (car, Qunbound))
car = Qnil;
}
/* '(NUM)': absolute number of pixels. */
if (NUMBERP (car))
-{
+ {
double fact;
int offset =
width_p && align_to && *align_to < 0 ? it->lnum_pixel_width : 0;
@@ -32015,14 +32031,16 @@ gui_insert_glyphs (struct window *w, struct glyph_row *updated_row,
void
gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
- enum glyph_row_area updated_area, int to_x)
+ enum glyph_row_area updated_area, int to_x)
{
struct frame *f;
int max_x, min_y, max_y;
int from_x, from_y, to_y;
+ struct face *face;
eassert (updated_row);
f = XFRAME (w->frame);
+ face = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
if (updated_row->full_width_p)
max_x = (WINDOW_PIXEL_WIDTH (w)
@@ -32074,6 +32092,9 @@ gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
block_input ();
FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
to_x - from_x, to_y - from_y);
+
+ if (face && !updated_row->stipple_p)
+ updated_row->stipple_p = face->stipple;
unblock_input ();
}
}
@@ -32638,7 +32659,7 @@ display_and_set_cursor (struct window *w, bool on,
{
struct frame *f = XFRAME (w->frame);
int new_cursor_type;
- int new_cursor_width;
+ int new_cursor_width UNINIT;
bool active_cursor;
struct glyph_row *glyph_row;
struct glyph *glyph;
@@ -36229,7 +36250,7 @@ they return to their normal size when the minibuffer is closed, or the
echo area becomes empty.
This variable does not affect resizing of the minibuffer window of
-minibuffer-only frames. These are handled by 'resize-mini-frames'
+minibuffer-only frames. These are handled by `resize-mini-frames'
only. */);
/* Contrary to the doc string, we initialize this to nil, so that
loading loadup.el won't try to resize windows before loading
@@ -36453,7 +36474,7 @@ see biditest.el in the test suite. */);
doc: /* Non-nil means inhibit the Bidirectional Parentheses Algorithm.
Disabling the BPA makes redisplay faster, but might produce incorrect
display reordering of bidirectional text with embedded parentheses and
-other bracket characters whose 'paired-bracket' Unicode property is
+other bracket characters whose `paired-bracket' Unicode property is
non-nil, see `get-char-code-property'. */);
bidi_inhibit_bpa = false;
diff --git a/src/xfaces.c b/src/xfaces.c
index 05e0df4b7dc..7395ce157ec 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -6871,7 +6871,6 @@ DEFUN ("show-face-resources", Fshow_face_resources, Sshow_face_resources,
Initialization
***********************************************************************/
-#ifdef HAVE_PDUMPER
/* All the faces defined during loadup are recorded in
face-new-frame-defaults. We need to set next_lface_id to the next
face ID number, so that any new faces defined in this session will
@@ -6881,26 +6880,35 @@ DEFUN ("show-face-resources", Fshow_face_resources, Sshow_face_resources,
void
init_xfaces (void)
{
- int nfaces = XFIXNAT (Fhash_table_count (Vface_new_frame_defaults));
- if (nfaces > 0)
- {
- /* Allocate the lface_id_to_name[] array. */
- lface_id_to_name_size = next_lface_id = nfaces;
- lface_id_to_name = xnmalloc (next_lface_id, sizeof *lface_id_to_name);
+#ifdef HAVE_PDUMPER
+ int nfaces;
- /* Store the faces. */
- struct Lisp_Hash_Table* table = XHASH_TABLE (Vface_new_frame_defaults);
- for (ptrdiff_t idx = 0; idx < nfaces; ++idx)
+ if (dumped_with_pdumper_p ())
+ {
+ nfaces = XFIXNAT (Fhash_table_count (Vface_new_frame_defaults));
+ if (nfaces > 0)
{
- Lisp_Object lface = HASH_KEY (table, idx);
- Lisp_Object face_id = CAR (HASH_VALUE (table, idx));
- if (FIXNATP (face_id)) {
- int id = XFIXNAT (face_id);
- eassert (id >= 0);
- lface_id_to_name[id] = lface;
- }
+ /* Allocate the lface_id_to_name[] array. */
+ lface_id_to_name_size = next_lface_id = nfaces;
+ lface_id_to_name = xnmalloc (next_lface_id, sizeof *lface_id_to_name);
+
+ /* Store the faces. */
+ struct Lisp_Hash_Table* table = XHASH_TABLE (Vface_new_frame_defaults);
+ for (ptrdiff_t idx = 0; idx < nfaces; ++idx)
+ {
+ Lisp_Object lface = HASH_KEY (table, idx);
+ Lisp_Object face_id = CAR (HASH_VALUE (table, idx));
+ if (FIXNATP (face_id))
+ {
+ int id = XFIXNAT (face_id);
+ eassert (id >= 0);
+ lface_id_to_name[id] = lface;
+ }
+ }
}
}
+#endif
+
face_attr_sym[0] = Qface;
face_attr_sym[LFACE_FOUNDRY_INDEX] = QCfoundry;
face_attr_sym[LFACE_SWIDTH_INDEX] = QCwidth;
@@ -6921,7 +6929,6 @@ init_xfaces (void)
face_attr_sym[LFACE_DISTANT_FOREGROUND_INDEX] = QCdistant_foreground;
face_attr_sym[LFACE_EXTEND_INDEX] = QCextend;
}
-#endif
void
syms_of_xfaces (void)
diff --git a/src/xfns.c b/src/xfns.c
index dc8f02780ce..05023524a7e 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -973,7 +973,7 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
if (p)
{
window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
- gdk_x11_window_set_frame_sync_enabled (window, false);
+ gdk_x11_window_set_frame_sync_enabled (window, FALSE);
}
#endif
unblock_input ();
@@ -1261,25 +1261,27 @@ struct mouse_cursor_types {
};
/* This array must stay in sync with enum mouse_cursor above! */
-static const struct mouse_cursor_types mouse_cursor_types[] = {
- { "text", &Vx_pointer_shape, XC_xterm },
- { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr },
- { "hourglass", &Vx_hourglass_pointer_shape, XC_watch },
- { "modeline", &Vx_mode_pointer_shape, XC_xterm },
- { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 },
- { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow },
- { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow },
- { NULL, &Vx_window_left_edge_shape, XC_left_side },
- { NULL, &Vx_window_top_left_corner_shape, XC_top_left_corner },
- { NULL, &Vx_window_top_edge_shape, XC_top_side },
- { NULL, &Vx_window_top_right_corner_shape, XC_top_right_corner },
- { NULL, &Vx_window_right_edge_shape, XC_right_side },
- { NULL, &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner },
- { NULL, &Vx_window_bottom_edge_shape, XC_bottom_side },
- { NULL, &Vx_window_bottom_left_corner_shape, XC_bottom_left_corner },
-};
+static const struct mouse_cursor_types mouse_cursor_types[] =
+ {
+ { "text", &Vx_pointer_shape, XC_xterm },
+ { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr },
+ { "hourglass", &Vx_hourglass_pointer_shape, XC_watch },
+ { "modeline", &Vx_mode_pointer_shape, XC_xterm },
+ { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 },
+ { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow },
+ { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow },
+ { NULL, &Vx_window_left_edge_shape, XC_left_side },
+ { NULL, &Vx_window_top_left_corner_shape, XC_top_left_corner },
+ { NULL, &Vx_window_top_edge_shape, XC_top_side },
+ { NULL, &Vx_window_top_right_corner_shape, XC_top_right_corner },
+ { NULL, &Vx_window_right_edge_shape, XC_right_side },
+ { NULL, &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner },
+ { NULL, &Vx_window_bottom_edge_shape, XC_bottom_side },
+ { NULL, &Vx_window_bottom_left_corner_shape, XC_bottom_left_corner },
+ };
-struct mouse_cursor_data {
+struct mouse_cursor_data
+{
/* Last index for which XCreateFontCursor has been called, and thus
the last index for which x_request_serial[] is valid. */
int last_cursor_create_request;
@@ -1360,8 +1362,10 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
cursor_data.x_request_serial[i] = XNextRequest (dpy);
cursor_data.last_cursor_create_request = i;
- cursor_data.cursor[i] = XCreateFontCursor (dpy,
- cursor_data.cursor_num[i]);
+
+ cursor_data.cursor[i]
+ = x_create_font_cursor (FRAME_DISPLAY_INFO (f),
+ cursor_data.cursor_num[i]);
}
/* Now sync up and process all received errors from cursor
@@ -2372,6 +2376,63 @@ x_set_scroll_bar_default_height (struct frame *f)
#endif
}
+static void
+x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ double alpha = 1.0;
+ double newval[2];
+ int i;
+ Lisp_Object item;
+ bool alpha_identical_p;
+
+ alpha_identical_p = true;
+
+ for (i = 0; i < 2; i++)
+ {
+ newval[i] = 1.0;
+ if (CONSP (arg))
+ {
+ item = CAR (arg);
+ arg = CDR (arg);
+
+ alpha_identical_p = false;
+ }
+ else
+ item = arg;
+
+ if (NILP (item))
+ alpha = - 1.0;
+ else if (FLOATP (item))
+ {
+ alpha = XFLOAT_DATA (item);
+ if (! (0 <= alpha && alpha <= 1.0))
+ args_out_of_range (make_float (0.0), make_float (1.0));
+ }
+ else if (FIXNUMP (item))
+ {
+ EMACS_INT ialpha = XFIXNUM (item);
+ if (! (0 <= ialpha && ialpha <= 100))
+ args_out_of_range (make_fixnum (0), make_fixnum (100));
+ alpha = ialpha / 100.0;
+ }
+ else
+ wrong_type_argument (Qnumberp, item);
+ newval[i] = alpha;
+ }
+
+ for (i = 0; i < 2; i++)
+ f->alpha[i] = newval[i];
+
+ FRAME_X_OUTPUT (f)->alpha_identical_p = alpha_identical_p;
+
+ if (FRAME_TERMINAL (f)->set_frame_alpha_hook)
+ {
+ block_input ();
+ FRAME_TERMINAL (f)->set_frame_alpha_hook (f);
+ unblock_input ();
+ }
+}
+
/* Record in frame F the specified or default value according to ALIST
of the parameter named PROP (a Lisp symbol). If no value is
@@ -2389,7 +2450,7 @@ x_default_scroll_bar_color_parameter (struct frame *f,
tem = gui_display_get_arg (dpyinfo, alist, prop, xprop, xclass,
RES_TYPE_STRING);
- if (EQ (tem, Qunbound))
+ if (BASE_EQ (tem, Qunbound))
{
#ifdef USE_TOOLKIT_SCROLL_BARS
@@ -4163,12 +4224,12 @@ x_icon_verify (struct frame *f, Lisp_Object parms)
icons in an icon window. */
icon_x = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
icon_y = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
- if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
+ if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound))
{
CHECK_FIXNUM (icon_x);
CHECK_FIXNUM (icon_y);
}
- else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
+ else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound))
error ("Both left and top icon corners of icon must be specified");
}
@@ -4187,8 +4248,8 @@ x_icon (struct frame *f, Lisp_Object parms)
= gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
int icon_xval, icon_yval;
- bool xgiven = !EQ (icon_x, Qunbound);
- bool ygiven = !EQ (icon_y, Qunbound);
+ bool xgiven = !BASE_EQ (icon_x, Qunbound);
+ bool ygiven = !BASE_EQ (icon_y, Qunbound);
if (xgiven != ygiven)
error ("Both left and top icon corners of icon must be specified");
if (xgiven)
@@ -4373,7 +4434,7 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms)
Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
RES_TYPE_STRING);
Lisp_Object font = Qnil;
- if (EQ (font_param, Qunbound))
+ if (BASE_EQ (font_param, Qunbound))
font_param = Qnil;
if (NILP (font_param))
@@ -4490,6 +4551,9 @@ This function is an internal primitive--use `make-frame' instead. */)
struct x_display_info *dpyinfo = NULL;
Lisp_Object parent, parent_frame;
struct kboard *kb;
+#ifdef HAVE_GTK3
+ GdkWindow *gwin;
+#endif
parms = Fcopy_alist (parms);
@@ -4499,10 +4563,10 @@ This function is an internal primitive--use `make-frame' instead. */)
display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
RES_TYPE_NUMBER);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display = gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0,
RES_TYPE_STRING);
- if (EQ (display, Qunbound))
+ if (BASE_EQ (display, Qunbound))
display = Qnil;
dpyinfo = check_x_display_info (display);
kb = dpyinfo->terminal->kboard;
@@ -4513,7 +4577,7 @@ This function is an internal primitive--use `make-frame' instead. */)
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
- && ! EQ (name, Qunbound)
+ && ! BASE_EQ (name, Qunbound)
&& ! NILP (name))
error ("Invalid frame name--not a string or nil");
@@ -4523,7 +4587,7 @@ This function is an internal primitive--use `make-frame' instead. */)
/* See if parent window is specified. */
parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL,
RES_TYPE_NUMBER);
- if (EQ (parent, Qunbound))
+ if (BASE_EQ (parent, Qunbound))
parent = Qnil;
if (! NILP (parent))
CHECK_FIXNUM (parent);
@@ -4552,7 +4616,7 @@ This function is an internal primitive--use `make-frame' instead. */)
RES_TYPE_SYMBOL);
/* Accept parent-frame iff parent-id was not specified. */
if (!NILP (parent)
- || EQ (parent_frame, Qunbound)
+ || BASE_EQ (parent_frame, Qunbound)
|| NILP (parent_frame)
|| !FRAMEP (parent_frame)
|| !FRAME_LIVE_P (XFRAME (parent_frame))
@@ -4568,7 +4632,7 @@ This function is an internal primitive--use `make-frame' instead. */)
NULL,
NULL,
RES_TYPE_BOOLEAN)))
- && !(EQ (tem, Qunbound)))
+ && !(BASE_EQ (tem, Qunbound)))
undecorated = true;
FRAME_UNDECORATED (f) = undecorated;
@@ -4580,7 +4644,7 @@ This function is an internal primitive--use `make-frame' instead. */)
NULL,
NULL,
RES_TYPE_BOOLEAN)))
- && !(EQ (tem, Qunbound)))
+ && !(BASE_EQ (tem, Qunbound)))
override_redirect = true;
FRAME_OVERRIDE_REDIRECT (f) = override_redirect;
@@ -4661,7 +4725,7 @@ This function is an internal primitive--use `make-frame' instead. */)
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
{
fset_name (f, build_string (dpyinfo->x_id_name));
f->explicit_name = false;
@@ -4724,7 +4788,7 @@ This function is an internal primitive--use `make-frame' instead. */)
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
@@ -4746,7 +4810,7 @@ This function is an internal primitive--use `make-frame' instead. */)
value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width,
"childFrameBorder", "childFrameBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qchild_frame_border_width, value),
parms);
}
@@ -4917,6 +4981,10 @@ This function is an internal primitive--use `make-frame' instead. */)
gtk_container_set_resize_mode
(GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE);
#endif
+#ifdef HAVE_GTK3
+ gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+ gdk_x11_window_set_frame_sync_enabled (gwin, FALSE);
+#endif
unblock_input ();
}
@@ -4984,7 +5052,7 @@ This function is an internal primitive--use `make-frame' instead. */)
}
else
{
- if (EQ (visibility, Qunbound))
+ if (BASE_EQ (visibility, Qunbound))
visibility = Qt;
if (!NILP (visibility))
@@ -4998,7 +5066,7 @@ This function is an internal primitive--use `make-frame' instead. */)
from `x-create-frame-with-faces' (see above comment). */
f->was_invisible
= (f->was_invisible
- && (!EQ (height, Qunbound) || !EQ (width, Qunbound)));
+ && (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound)));
store_frame_param (f, Qvisibility, visibility);
}
@@ -5366,6 +5434,9 @@ for each physical monitor, use `display-monitor-attributes-list'. */)
{
struct x_display_info *dpyinfo = check_x_display_info (terminal);
+ if (dpyinfo->screen_mm_height)
+ return make_fixnum (dpyinfo->screen_mm_height);
+
return make_fixnum (HeightMMOfScreen (dpyinfo->screen));
}
@@ -5383,6 +5454,9 @@ for each physical monitor, use `display-monitor-attributes-list'. */)
{
struct x_display_info *dpyinfo = check_x_display_info (terminal);
+ if (dpyinfo->screen_mm_width)
+ return make_fixnum (dpyinfo->screen_mm_width);
+
return make_fixnum (WidthMMOfScreen (dpyinfo->screen));
}
@@ -6526,17 +6600,61 @@ menu bar or tool bar of FRAME. */)
* WINDOW to FRAMES and return FRAMES.
*/
static Lisp_Object
-x_frame_list_z_order (Display* dpy, Window window)
+x_frame_list_z_order (struct x_display_info *dpyinfo, Window window)
{
+ Display *dpy;
Window root, parent, *children;
unsigned int nchildren;
- int i;
- Lisp_Object frames = Qnil;
+ unsigned long i;
+ Lisp_Object frames, val;
+ Atom type;
+ Window *toplevels;
+ int format, rc;
+ unsigned long nitems, bytes_after;
+ unsigned char *data;
+ struct frame *f;
+
+ dpy = dpyinfo->display;
+ data = NULL;
+ frames = Qnil;
+
+ if (window == dpyinfo->root_window
+ && x_wm_supports_1 (dpyinfo,
+ dpyinfo->Xatom_net_client_list_stacking))
+ {
+ rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
+ dpyinfo->Xatom_net_client_list_stacking,
+ 0, LONG_MAX, False, XA_WINDOW, &type,
+ &format, &nitems, &bytes_after, &data);
+
+ if (rc != Success)
+ return Qnil;
+
+ if (format != 32 || type != XA_WINDOW)
+ {
+ XFree (data);
+ return Qnil;
+ }
+
+ toplevels = (Window *) data;
+
+ for (i = 0; i < nitems; ++i)
+ {
+ f = x_top_window_to_frame (dpyinfo, toplevels[i]);
+
+ if (f)
+ {
+ XSETFRAME (val, f);
+ frames = Fcons (val, frames);
+ }
+ }
+
+ XFree (data);
+ return frames;
+ }
- block_input ();
if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren))
{
- unblock_input ();
for (i = 0; i < nchildren; i++)
{
Lisp_Object frame, tail;
@@ -6554,10 +6672,9 @@ x_frame_list_z_order (Display* dpy, Window window)
}
}
- if (children) XFree ((char *)children);
+ if (children)
+ XFree (children);
}
- else
- unblock_input ();
return frames;
}
@@ -6578,7 +6695,6 @@ Frames are listed from topmost (first) to bottommost (last). */)
(Lisp_Object terminal)
{
struct x_display_info *dpyinfo = check_x_display_info (terminal);
- Display *dpy = dpyinfo->display;
Window window;
if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
@@ -6586,7 +6702,7 @@ Frames are listed from topmost (first) to bottommost (last). */)
else
window = dpyinfo->root_window;
- return x_frame_list_z_order (dpy, window);
+ return x_frame_list_z_order (dpyinfo, window);
}
/**
@@ -6715,7 +6831,7 @@ The coordinates X and Y are interpreted in pixels relative to a position
return Qnil;
}
-DEFUN ("x-begin-drag", Fx_begin_drag, Sx_begin_drag, 1, 5, 0,
+DEFUN ("x-begin-drag", Fx_begin_drag, Sx_begin_drag, 1, 6, 0,
doc: /* Begin dragging contents on FRAME, with targets TARGETS.
TARGETS is a list of strings, which defines the X selection targets
that will be available to the drop target. Block until the mouse
@@ -6724,8 +6840,9 @@ buttons are released, then return the action chosen by the target, or
starts when the mouse is pressed on FRAME, and the contents of the
selection `XdndSelection' will be sent to the X window underneath the
mouse pointer (the drop target) when the mouse button is released.
-ACTION is a symbol which tells the target what the source will do, and
-can be one of the following:
+
+ACTION is a symbol which tells the target what it should do, and can
+be one of the following:
- `XdndActionCopy', which means to copy the contents from the drag
source (FRAME) to the drop target.
@@ -6737,6 +6854,10 @@ can be one of the following:
`XdndActionPrivate' is also a valid return value, and means that the
drop target chose to perform an unspecified or unknown action.
+The source is also expected to cooperate with the target to perform
+the action chosen by the target. For example, callers should delete
+the buffer text that was dragged if `XdndActionMove' is returned.
+
There are also some other valid values of ACTION that depend on
details of both the drop target's implementation details and that of
Emacs. For that reason, they are not mentioned here. Consult
@@ -6759,20 +6880,29 @@ instead.
If ALLOW-CURRENT-FRAME is not specified or nil, then the drop target
is allowed to be FRAME. Otherwise, no action will be taken if the
-mouse buttons are released on top of FRAME. */)
+mouse buttons are released on top of FRAME.
+
+If FOLLOW-TOOLTIP is non-nil, any tooltip currently being displayed
+will be moved to follow the mouse pointer while the drag is in
+progress. Note that this does not work with system tooltips (tooltips
+created when `use-system-tooltips' is non-nil).
+
+This function will sometimes return immediately if no mouse buttons
+are currently held down. It should only be called when it is known
+that mouse buttons are being held down, such as immediately after a
+`down-mouse-1' (or similar) event. */)
(Lisp_Object targets, Lisp_Object action, Lisp_Object frame,
- Lisp_Object return_frame, Lisp_Object allow_current_frame)
+ Lisp_Object return_frame, Lisp_Object allow_current_frame,
+ Lisp_Object follow_tooltip)
{
struct frame *f = decode_window_system_frame (frame);
int ntargets = 0, nnames = 0;
- ptrdiff_t len;
char *target_names[2048];
Atom *target_atoms;
Lisp_Object lval, original, tem, t1, t2;
Atom xaction;
Atom action_list[2048];
char *name_list[2048];
- char *scratch;
USE_SAFE_ALLOCA;
@@ -6786,10 +6916,8 @@ mouse buttons are released on top of FRAME. */)
if (ntargets < 2048)
{
- scratch = SSDATA (XCAR (targets));
- len = strlen (scratch);
- target_names[ntargets] = SAFE_ALLOCA (len + 1);
- strncpy (target_names[ntargets], scratch, len + 1);
+ SAFE_ALLOCA_STRING (target_names[ntargets],
+ XCAR (targets));
ntargets++;
}
else
@@ -6839,10 +6967,8 @@ mouse buttons are released on top of FRAME. */)
else
signal_error ("Invalid drag-and-drop action", tem);
- scratch = SSDATA (ENCODE_UTF_8 (t2));
- len = strlen (scratch);
- name_list[nnames] = SAFE_ALLOCA (len + 1);
- strncpy (name_list[nnames], scratch, len + 1);
+ SAFE_ALLOCA_STRING (name_list[nnames],
+ ENCODE_SYSTEM (t2));
nnames++;
}
@@ -6854,18 +6980,22 @@ mouse buttons are released on top of FRAME. */)
else
signal_error ("Invalid drag-and-drop action", action);
- target_atoms = xmalloc (ntargets * sizeof *target_atoms);
+ target_atoms = SAFE_ALLOCA (ntargets * sizeof *target_atoms);
- block_input ();
+ /* Catch errors since interning lots of targets can potentially
+ generate a BadAlloc error. */
+ x_catch_errors (FRAME_X_DISPLAY (f));
XInternAtoms (FRAME_X_DISPLAY (f), target_names,
ntargets, False, target_atoms);
- unblock_input ();
+ x_check_errors (FRAME_X_DISPLAY (f),
+ "Failed to intern target atoms: %s");
+ x_uncatch_errors_after_check ();
- x_set_dnd_targets (target_atoms, ntargets);
lval = x_dnd_begin_drag_and_drop (f, FRAME_DISPLAY_INFO (f)->last_user_time,
xaction, return_frame, action_list,
(const char **) &name_list, nnames,
- !NILP (allow_current_frame));
+ !NILP (allow_current_frame), target_atoms,
+ ntargets, original, !NILP (follow_tooltip));
SAFE_FREE ();
return lval;
@@ -7184,19 +7314,28 @@ converted to an atom and the value of the atom is used. If an element
is a cons, it is converted to a 32 bit number where the car is the 16
top bits and the cdr is the lower 16 bits.
-FRAME nil or omitted means use the selected frame.
-If TYPE is given and non-nil, it is the name of the type of VALUE.
- If TYPE is not given or nil, the type is STRING.
-FORMAT gives the size in bits of each element if VALUE is a list.
- It must be one of 8, 16 or 32.
- If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8.
-If OUTER-P is non-nil, the property is changed for the outer X window of
- FRAME. Default is to change on the edit X window.
-If WINDOW-ID is non-nil, change the property of that window instead
- of FRAME's X window; the number 0 denotes the root window. This argument
- is separate from FRAME because window IDs are not unique across X
- displays or screens on the same display, so FRAME provides context
- for the window ID. */)
+FRAME nil or omitted means use the selected frame. If TYPE is given
+and non-nil, it is the name of the type of VALUE. If TYPE is not
+given or nil, the type is STRING.
+
+FORMAT gives the size in bits of each element if VALUE is a list. It
+must be one of 8, 16 or 32.
+
+If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to
+8. If OUTER-P is non-nil, the property is changed for the outer X
+window of FRAME. Default is to change on the edit X window.
+
+If WINDOW-ID is non-nil, change the property of that window instead of
+FRAME's X window; the number 0 denotes the root window. This argument
+is separate from FRAME because window IDs are not unique across X
+displays or screens on the same display, so FRAME provides context for
+the window ID.
+
+If VALUE is a string and FORMAT is 32, then the format of VALUE is
+system-specific. VALUE must contain unsigned integer data in native
+endian-ness in multiples of the size of the C type 'long': the low 32
+bits of each such number are used as the value of each element of the
+property. */)
(Lisp_Object prop, Lisp_Object value, Lisp_Object frame,
Lisp_Object type, Lisp_Object format, Lisp_Object outer_p,
Lisp_Object window_id)
@@ -7209,6 +7348,8 @@ If WINDOW-ID is non-nil, change the property of that window instead
int nelements;
Window target_window;
#ifdef USE_XCB
+ bool intern_prop;
+ bool intern_target;
xcb_intern_atom_cookie_t prop_atom_cookie;
xcb_intern_atom_cookie_t target_type_cookie;
xcb_intern_atom_reply_t *reply;
@@ -7279,41 +7420,62 @@ If WINDOW-ID is non-nil, change the property of that window instead
block_input ();
#ifndef USE_XCB
- prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False);
+ prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (prop), false);
if (! NILP (type))
{
CHECK_STRING (type);
- target_type = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (type), False);
+ target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (type), false);
}
#else
rc = true;
- prop_atom_cookie
- = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
- 0, SBYTES (prop), SSDATA (prop));
+ intern_target = true;
+ intern_prop = true;
+
+ prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (prop), true);
+
+ if (prop_atom != None)
+ intern_prop = false;
+ else
+ prop_atom_cookie
+ = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
+ 0, SBYTES (prop), SSDATA (prop));
if (!NILP (type))
{
CHECK_STRING (type);
- target_type_cookie
- = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
- 0, SBYTES (type), SSDATA (type));
- }
- reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
- prop_atom_cookie, &generic_error);
+ target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (type), true);
- if (reply)
- {
- prop_atom = (Atom) reply->atom;
- free (reply);
+ if (target_type)
+ intern_target = false;
+ else
+ target_type_cookie
+ = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
+ 0, SBYTES (type), SSDATA (type));
}
- else
+
+ if (intern_prop)
{
- free (generic_error);
- rc = false;
+ reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
+ prop_atom_cookie, &generic_error);
+
+ if (reply)
+ {
+ prop_atom = (Atom) reply->atom;
+ free (reply);
+ }
+ else
+ {
+ free (generic_error);
+ rc = false;
+ }
}
- if (!NILP (type))
+ if (!NILP (type) && intern_target)
{
reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
target_type_cookie, &generic_error);
@@ -7334,16 +7496,17 @@ If WINDOW-ID is non-nil, change the property of that window instead
error ("Failed to intern type or property atom");
#endif
+ x_catch_errors (FRAME_X_DISPLAY (f));
XChangeProperty (FRAME_X_DISPLAY (f), target_window,
prop_atom, target_type, element_format, PropModeReplace,
data, nelements);
if (CONSP (value)) xfree (data);
+ x_check_errors (FRAME_X_DISPLAY (f),
+ "Couldn't change window property: %s");
+ x_uncatch_errors_after_check ();
- /* Make sure the property is set when we return. */
- XFlush (FRAME_X_DISPLAY (f));
unblock_input ();
-
return value;
}
@@ -7375,13 +7538,16 @@ Value is PROP. */)
}
block_input ();
- prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False);
+ prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (prop), false);
+
+ x_catch_errors (FRAME_X_DISPLAY (f));
XDeleteProperty (FRAME_X_DISPLAY (f), target_window, prop_atom);
+ x_check_errors (FRAME_X_DISPLAY (f),
+ "Couldn't delete window property: %s");
+ x_uncatch_errors_after_check ();
- /* Make sure the property is removed when we return. */
- XFlush (FRAME_X_DISPLAY (f));
unblock_input ();
-
return prop;
}
@@ -7501,15 +7667,19 @@ if PROP has no value of TYPE (always a string in the MS Windows case). */)
}
block_input ();
+ x_catch_errors (FRAME_X_DISPLAY (f));
+
if (STRINGP (type))
{
if (strcmp ("AnyPropertyType", SSDATA (type)) == 0)
target_type = AnyPropertyType;
else
- target_type = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (type), False);
+ target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (type), false);
}
- prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False);
+ prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (prop), false);
prop_value = x_window_property_intern (f,
target_window,
prop_atom,
@@ -7531,6 +7701,9 @@ if PROP has no value of TYPE (always a string in the MS Windows case). */)
&found);
}
+ x_check_errors (FRAME_X_DISPLAY (f),
+ "Can't retrieve window property: %s");
+ x_uncatch_errors_after_check ();
unblock_input ();
return prop_value;
@@ -7576,7 +7749,9 @@ Otherwise, the return value is a vector with the following fields:
block_input ();
- prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False);
+ x_catch_errors (FRAME_X_DISPLAY (f));
+ prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
+ SSDATA (prop), false);
rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window,
prop_atom, 0, 0, False, AnyPropertyType,
&actual_type, &actual_format, &actual_size,
@@ -7606,6 +7781,10 @@ Otherwise, the return value is a vector with the following fields:
make_fixnum (bytes_remaining / (actual_format >> 3)));
}
+ x_check_errors (FRAME_X_DISPLAY (f),
+ "Can't retrieve window property: %s");
+ x_uncatch_errors_after_check ();
+
unblock_input ();
return prop_attr;
}
@@ -7618,12 +7797,15 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
Lisp_Object, int, int, int *, int *);
/* The frame of the currently visible tooltip, or nil if none. */
-static Lisp_Object tip_frame;
+Lisp_Object tip_frame;
/* The window-system window corresponding to the frame of the
currently visible tooltip. */
Window tip_window;
+/* The X and Y deltas of the last call to `x-show-tip'. */
+Lisp_Object tip_dx, tip_dy;
+
/* A timer that hides or deletes the currently visible tooltip when it
fires. */
static Lisp_Object tip_timer;
@@ -7679,7 +7861,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
- && !EQ (name, Qunbound)
+ && !BASE_EQ (name, Qunbound)
&& !NILP (name))
error ("Invalid frame name--not a string or nil");
@@ -7746,7 +7928,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
/* Set the name; the functions to which we pass f expect the name to
be set. */
- if (EQ (name, Qunbound) || NILP (name))
+ if (BASE_EQ (name, Qunbound) || NILP (name))
{
fset_name (f, build_string (dpyinfo->x_id_name));
f->explicit_name = false;
@@ -7802,7 +7984,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
- if (! EQ (value, Qunbound))
+ if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
@@ -8029,9 +8211,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
the display in *ROOT_X, and *ROOT_Y. */
static void
-compute_tip_xy (struct frame *f,
- Lisp_Object parms, Lisp_Object dx, Lisp_Object dy,
- int width, int height, int *root_x, int *root_y)
+compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
+ Lisp_Object dy, int width, int height, int *root_x,
+ int *root_y)
{
Lisp_Object left, top, right, bottom;
int win_x, win_y;
@@ -8057,7 +8239,7 @@ compute_tip_xy (struct frame *f,
&root, &child, root_x, root_y, &win_x, &win_y, &pmask);
unblock_input ();
- XSETFRAME(frame, f);
+ XSETFRAME (frame, f);
attributes = Fx_display_monitor_attributes_list (frame);
/* Try to determine the monitor where the mouse pointer is and
@@ -8072,11 +8254,13 @@ compute_tip_xy (struct frame *f,
min_y = XFIXNUM (Fnth (make_fixnum (2), geometry));
max_x = min_x + XFIXNUM (Fnth (make_fixnum (3), geometry));
max_y = min_y + XFIXNUM (Fnth (make_fixnum (4), geometry));
+
if (min_x <= *root_x && *root_x < max_x
&& min_y <= *root_y && *root_y < max_y)
{
break;
}
+
max_y = -1;
}
@@ -8086,7 +8270,7 @@ compute_tip_xy (struct frame *f,
/* It was not possible to determine the monitor's geometry, so we
assign some sane defaults here: */
- if ( max_y < 0 )
+ if (max_y < 0)
{
min_x = 0;
min_y = 0;
@@ -8335,6 +8519,9 @@ Text larger than the specified size is clipped. */)
else
CHECK_FIXNUM (dy);
+ tip_dx = dx;
+ tip_dy = dy;
+
#ifdef USE_GTK
if (use_system_tooltips)
{
@@ -8360,7 +8547,7 @@ Text larger than the specified size is clipped. */)
if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
{
if (FRAME_VISIBLE_P (XFRAME (tip_frame))
- && EQ (frame, tip_last_frame)
+ && BASE_EQ (frame, tip_last_frame)
&& !NILP (Fequal_including_properties (tip_last_string, string))
&& !NILP (Fequal (tip_last_parms, parms)))
{
@@ -8381,7 +8568,7 @@ Text larger than the specified size is clipped. */)
goto start_timer;
}
- else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
+ else if (tooltip_reuse_hidden_frame && BASE_EQ (frame, tip_last_frame))
{
bool delete = false;
Lisp_Object tail, elt, parm, last;
@@ -8714,6 +8901,9 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
/* Prevent redisplay. */
specbind (Qinhibit_redisplay, Qt);
+ /* Defer selection requests. */
+ DEFER_SELECTIONS;
+
block_input ();
/* Create the dialog with PROMPT as title, using DIR as initial
@@ -9368,7 +9558,7 @@ frame_parm_handler x_frame_parm_handlers[] =
x_set_wait_for_wm,
gui_set_fullscreen,
gui_set_font_backend,
- gui_set_alpha,
+ x_set_alpha,
x_set_sticky,
x_set_tool_bar_position,
#ifdef HAVE_XDBE
@@ -9638,11 +9828,11 @@ default and usually works with most desktops. Some desktop environments
however, may refuse to resize a child frame when Emacs is built with
GTK3. For those environments, the two settings below are provided.
-If this equals the symbol 'hide', Emacs temporarily hides the child
+If this equals the symbol `hide', Emacs temporarily hides the child
frame during resizing. This approach seems to work reliably, may
however induce some flicker when the frame is made visible again.
-If this equals the symbol 'resize-mode', Emacs uses GTK's resize mode to
+If this equals the symbol `resize-mode', Emacs uses GTK's resize mode to
always trigger an immediate resize of the child frame. This method is
deprecated by GTK and may not work in future versions of that toolkit.
It also may freeze Emacs when used with other desktop environments. It
@@ -9757,6 +9947,10 @@ eliminated in future versions of Emacs. */);
staticpro (&tip_last_string);
tip_last_parms = Qnil;
staticpro (&tip_last_parms);
+ tip_dx = Qnil;
+ staticpro (&tip_dx);
+ tip_dy = Qnil;
+ staticpro (&tip_dy);
defsubr (&Sx_uses_old_gtk_dialog);
#if defined (USE_MOTIF) || defined (USE_GTK)
diff --git a/src/xfont.c b/src/xfont.c
index 684c28ab21a..74237e8aa88 100644
--- a/src/xfont.c
+++ b/src/xfont.c
@@ -295,7 +295,7 @@ xfont_list_pattern (Display *display, const char *pattern,
{
Lisp_Object list = Qnil;
Lisp_Object chars = Qnil;
- struct charset *encoding, *repertory = NULL;
+ struct charset *encoding = NULL, *repertory = NULL;
int i, limit, num_fonts;
char **names;
/* Large enough to decode the longest XLFD (255 bytes). */
diff --git a/src/xftfont.c b/src/xftfont.c
index 31fb877c35b..6043ef9f94f 100644
--- a/src/xftfont.c
+++ b/src/xftfont.c
@@ -797,6 +797,15 @@ syms_of_xftfont (void)
This is needed with some fonts to correct vertical overlap of glyphs. */);
xft_font_ascent_descent_override = 0;
+ DEFVAR_LISP ("xft-color-font-whitelist", Vxft_color_font_whitelist,
+ doc: /* List of "color" font families that don't actually have color glyphs.
+Some fonts (such as Source Code Pro) are reported as color fonts, but
+do not actually have glyphs with colors that can cause Xft crashes.
+
+The font families in this list will not be ignored when
+`xft-ignore-color-fonts' is non-nil. */);
+ Vxft_color_font_whitelist = list1 (build_pure_c_string ("Source Code Pro"));
+
pdumper_do_now_and_after_load (syms_of_xftfont_for_pdumper);
}
diff --git a/src/xgselect.c b/src/xgselect.c
index 7252210c686..6e09a15fa84 100644
--- a/src/xgselect.c
+++ b/src/xgselect.c
@@ -33,6 +33,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
static ptrdiff_t threads_holding_glib_lock;
static GMainContext *glib_main_context;
+/* The depth of xg_select suppression. */
+static int xg_select_suppress_count;
+
void
release_select_lock (void)
{
@@ -69,6 +72,23 @@ acquire_select_lock (GMainContext *context)
#endif
}
+/* Call this to not use xg_select when using it would be a bad idea,
+ i.e. during drag-and-drop. */
+void
+suppress_xg_select (void)
+{
+ ++xg_select_suppress_count;
+}
+
+void
+release_xg_select (void)
+{
+ if (!xg_select_suppress_count)
+ emacs_abort ();
+
+ --xg_select_suppress_count;
+}
+
/* `xg_select' is a `pselect' replacement. Why do we need a separate function?
1. Timeouts. Glib and Gtk rely on timer events. If we did pselect
with a greater timeout then the one scheduled by Glib, we would
@@ -100,6 +120,9 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
bool already_has_events;
#endif
+ if (xg_select_suppress_count)
+ return pselect (fds_lim, rfds, wfds, efds, timeout, sigmask);
+
context = g_main_context_default ();
acquire_select_lock (context);
diff --git a/src/xgselect.h b/src/xgselect.h
index 15482cbf922..156d4bde59f 100644
--- a/src/xgselect.h
+++ b/src/xgselect.h
@@ -25,9 +25,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
struct timespec;
-extern int xg_select (int max_fds,
- fd_set *rfds, fd_set *wfds, fd_set *efds,
- struct timespec *timeout, sigset_t *sigmask);
+extern int xg_select (int, fd_set *, fd_set *, fd_set *,
+ struct timespec *, sigset_t *);
+extern void suppress_xg_select (void);
+extern void release_xg_select (void);
extern void release_select_lock (void);
diff --git a/src/xmenu.c b/src/xmenu.c
index aaf53569a72..7134bf22c83 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -198,6 +198,10 @@ x_menu_wait_for_event (void *data)
struct x_display_info *dpyinfo;
int n = 0;
+ /* ISTM that if timer_check is okay, this should be too, since
+ both can run random Lisp. */
+ x_handle_pending_selection_requests ();
+
FD_ZERO (&read_fds);
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
{
@@ -1579,6 +1583,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
}
#endif
+ DEFER_SELECTIONS;
+
/* Display the menu. */
gtk_widget_show_all (menu);
@@ -1868,6 +1874,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
{
specpdl_ref specpdl_count = SPECPDL_INDEX ();
+ DEFER_SELECTIONS;
+
record_unwind_protect_int (pop_down_menu, (int) menu_id);
#ifdef HAVE_XINPUT2
record_unwind_protect_ptr (leave_toolkit_menu, f);
@@ -1894,13 +1902,19 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
{
int i;
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
- widget_value **submenu_stack
- = alloca (menu_items_used * sizeof *submenu_stack);
- Lisp_Object *subprefix_stack
- = alloca (menu_items_used * sizeof *subprefix_stack);
+ widget_value **submenu_stack;
+ Lisp_Object *subprefix_stack;
int submenu_depth = 0;
+ specpdl_ref specpdl_count;
- specpdl_ref specpdl_count = SPECPDL_INDEX ();
+ USE_SAFE_ALLOCA;
+
+ submenu_stack = SAFE_ALLOCA (menu_items_used
+ * sizeof *submenu_stack);
+ subprefix_stack = SAFE_ALLOCA (menu_items_used
+ * sizeof *subprefix_stack);
+
+ specpdl_count = SPECPDL_INDEX ();
eassert (FRAME_X_P (f));
@@ -1909,6 +1923,7 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
{
*error_name = "Empty menu";
+ SAFE_FREE ();
return Qnil;
}
@@ -2141,6 +2156,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
entry = Fcons (subprefix_stack[j], entry);
}
unblock_input ();
+
+ SAFE_FREE ();
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
@@ -2155,6 +2172,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
}
unblock_input ();
+
+ SAFE_FREE ();
return Qnil;
}
@@ -2188,6 +2207,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
if (menu)
{
specpdl_ref specpdl_count = SPECPDL_INDEX ();
+
+ DEFER_SELECTIONS;
record_unwind_protect_ptr (pop_down_menu, menu);
/* Display the menu. */
@@ -2244,6 +2265,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
{
specpdl_ref count = SPECPDL_INDEX ();
+ DEFER_SELECTIONS;
+
/* xdialog_show_unwind is responsible for popping the dialog box down. */
record_unwind_protect_int (pop_down_menu, (int) dialog_id);
@@ -2704,18 +2727,18 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
y = max (y, 1);
XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
&ulx, &uly, &width, &height);
- if (ulx+width > dispwidth)
+ if (ulx + width > dispwidth)
{
x -= (ulx + width) - dispwidth;
ulx = dispwidth - width;
}
- if (uly+height > dispheight)
+ if (uly + height > dispheight)
{
y -= (uly + height) - dispheight;
uly = dispheight - height;
}
#ifndef HAVE_X_WINDOWS
- if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
+ if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 1)
{
/* Move the menu away of the echo area, to avoid overwriting the
menu with help echo messages or vice versa. */
@@ -2739,8 +2762,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
/* If position was not given by a mouse click, adjust so upper left
corner of the menu as a whole ends up at given coordinates. This
is what x-popup-menu says in its documentation. */
- x += width/2;
- y += 1.5*height/(maxlines+2);
+ x += width / 2;
+ y += 1.5 * height/ (maxlines + 2);
}
XMenuSetAEQ (menu, true);
@@ -2748,6 +2771,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
pane = selidx = 0;
#ifndef MSDOS
+ DEFER_SELECTIONS;
+
XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
#ifdef HAVE_XINPUT2
XMenuActivateSetTranslateFunction (x_menu_translate_generic_event);
diff --git a/src/xrdb.c b/src/xrdb.c
index aa79d719c8c..faeea04a539 100644
--- a/src/xrdb.c
+++ b/src/xrdb.c
@@ -486,11 +486,7 @@ x_get_resource (XrmDatabase rdb, const char *name, const char *class,
if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
&& (type == expected_type))
{
- if (type == x_rm_string)
- ret_value->addr = (char *) value.addr;
- else
- memcpy (ret_value->addr, value.addr, ret_value->size);
-
+ *ret_value = value;
return value.size;
}
diff --git a/src/xselect.c b/src/xselect.c
index 3acfcbe94b0..96c1e9830fb 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -112,96 +112,10 @@ selection_quantum (Display *display)
: MAX_SELECTION_QUANTUM);
}
-#define LOCAL_SELECTION(selection_symbol,dpyinfo) \
+#define LOCAL_SELECTION(selection_symbol, dpyinfo) \
assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist)
-/* Define a queue to save up SELECTION_REQUEST_EVENT events for later
- handling. */
-
-struct selection_event_queue
- {
- struct selection_input_event event;
- struct selection_event_queue *next;
- };
-
-static struct selection_event_queue *selection_queue;
-
-/* Nonzero means queue up SELECTION_REQUEST_EVENT events. */
-
-static int x_queue_selection_requests;
-
-/* True if the input events are duplicates. */
-
-static bool
-selection_input_event_equal (struct selection_input_event *a,
- struct selection_input_event *b)
-{
- return (a->kind == b->kind && a->dpyinfo == b->dpyinfo
- && a->requestor == b->requestor && a->selection == b->selection
- && a->target == b->target && a->property == b->property
- && a->time == b->time);
-}
-
-/* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later. */
-
-static void
-x_queue_event (struct selection_input_event *event)
-{
- struct selection_event_queue *queue_tmp;
-
- /* Don't queue repeated requests.
- This only happens for large requests which uses the incremental protocol. */
- for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next)
- {
- if (selection_input_event_equal (event, &queue_tmp->event))
- {
- TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp);
- x_decline_selection_request (event);
- return;
- }
- }
-
- queue_tmp = xmalloc (sizeof *queue_tmp);
- TRACE1 ("QUEUE SELECTION EVENT %p", queue_tmp);
- queue_tmp->event = *event;
- queue_tmp->next = selection_queue;
- selection_queue = queue_tmp;
-}
-
-/* Start queuing SELECTION_REQUEST_EVENT events. */
-
-static void
-x_start_queuing_selection_requests (void)
-{
- if (x_queue_selection_requests)
- emacs_abort ();
-
- x_queue_selection_requests++;
- TRACE1 ("x_start_queuing_selection_requests %d", x_queue_selection_requests);
-}
-
-/* Stop queuing SELECTION_REQUEST_EVENT events. */
-
-static void
-x_stop_queuing_selection_requests (void)
-{
- TRACE1 ("x_stop_queuing_selection_requests %d", x_queue_selection_requests);
- --x_queue_selection_requests;
-
- /* Take all the queued events and put them back
- so that they get processed afresh. */
-
- while (selection_queue != NULL)
- {
- struct selection_event_queue *queue_tmp = selection_queue;
- TRACE1 ("RESTORE SELECTION EVENT %p", queue_tmp);
- kbd_buffer_unget_event (&queue_tmp->event);
- selection_queue = queue_tmp->next;
- xfree (queue_tmp);
- }
-}
-
/* This converts a Lisp symbol to a server Atom, avoiding a server
roundtrip whenever possible. */
@@ -256,7 +170,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym)));
block_input ();
- val = XInternAtom (dpyinfo->display, SSDATA (SYMBOL_NAME (sym)), False);
+ val = x_intern_cached_atom (dpyinfo, SSDATA (SYMBOL_NAME (sym)), false);
unblock_input ();
return val;
}
@@ -265,7 +179,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
/* This converts a server Atom to a Lisp symbol, avoiding server roundtrips
and calls to intern whenever possible. */
-static Lisp_Object
+Lisp_Object
x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom)
{
char *str;
@@ -319,18 +233,17 @@ x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom)
if (atom == dpyinfo->Xatom_XmTRANSFER_FAILURE)
return QXmTRANSFER_FAILURE;
- block_input ();
x_catch_errors (dpyinfo->display);
- str = XGetAtomName (dpyinfo->display, atom);
+ str = x_get_atom_name (dpyinfo, atom, NULL);
x_uncatch_errors ();
- unblock_input ();
+
+ TRACE0 ("XGetAtomName --> NULL");
+ if (!str)
+ return Qnil;
TRACE1 ("XGetAtomName --> %s", str);
- if (! str) return Qnil;
+
val = intern (str);
- block_input ();
- /* This was allocated by Xlib, so use XFree. */
- XFree (str);
- unblock_input ();
+ xfree (str);
return val;
}
@@ -399,7 +312,7 @@ static Lisp_Object
x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
bool local_request, struct x_display_info *dpyinfo)
{
- Lisp_Object local_value;
+ Lisp_Object local_value, tem;
Lisp_Object handler_fn, value, check;
local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
@@ -426,10 +339,24 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
if (CONSP (handler_fn))
handler_fn = XCDR (handler_fn);
+ tem = XCAR (XCDR (local_value));
+
+ if (STRINGP (tem))
+ {
+ local_value = Fget_text_property (make_fixnum (0),
+ target_type, tem);
+
+ if (!NILP (local_value))
+ tem = local_value;
+ }
+
if (!NILP (handler_fn))
- value = call3 (handler_fn,
- selection_symbol, (local_request ? Qnil : target_type),
- XCAR (XCDR (local_value)));
+ value = call3 (handler_fn, selection_symbol,
+ ((local_request
+ && NILP (Vx_treat_local_requests_remotely))
+ ? Qnil
+ : target_type),
+ tem);
else
value = Qnil;
value = unbind_to (count, value);
@@ -492,14 +419,6 @@ x_decline_selection_request (struct selection_input_event *event)
unblock_input ();
}
-/* This is the selection request currently being processed.
- It is set to zero when the request is fully processed. */
-static struct selection_input_event *x_selection_current_request;
-
-/* Display info in x_selection_request. */
-
-static struct x_display_info *selection_request_dpyinfo;
-
/* Raw selection data, for sending to a requestor window. */
struct selection_data
@@ -517,12 +436,59 @@ struct selection_data
struct selection_data *next;
};
-/* Linked list of the above (in support of MULTIPLE targets). */
+struct x_selection_request
+{
+ /* The last element in this stack. */
+ struct x_selection_request *last;
+
+ /* Its display info. */
+ struct x_display_info *dpyinfo;
+
+ /* Its selection input event. */
+ struct selection_input_event *request;
+
+ /* Linked list of the above (in support of MULTIPLE targets). */
+ struct selection_data *converted_selections;
+
+ /* "Data" to send a requestor for a failed MULTIPLE subtarget. */
+ Atom conversion_fail_tag;
+
+ /* Whether or not conversion was successful. */
+ bool converted;
+};
+
+/* Stack of selections currently being processed.
+ NULL if all requests have been fully processed. */
-static struct selection_data *converted_selections;
+struct x_selection_request *selection_request_stack;
-/* "Data" to send a requestor for a failed MULTIPLE subtarget. */
-static Atom conversion_fail_tag;
+static void
+x_push_current_selection_request (struct selection_input_event *se,
+ struct x_display_info *dpyinfo)
+{
+ struct x_selection_request *frame;
+
+ frame = xmalloc (sizeof *frame);
+ frame->converted = false;
+ frame->last = selection_request_stack;
+ frame->request = se;
+ frame->dpyinfo = dpyinfo;
+ frame->converted_selections = NULL;
+ frame->conversion_fail_tag = None;
+
+ selection_request_stack = frame;
+}
+
+static void
+x_pop_current_selection_request (void)
+{
+ struct x_selection_request *tem;
+
+ tem = selection_request_stack;
+ selection_request_stack = selection_request_stack->last;
+
+ xfree (tem);
+}
/* Used as an unwind-protect clause so that, if a selection-converter signals
an error, we tell the requestor that we were unable to do what they wanted
@@ -532,19 +498,21 @@ static void
x_selection_request_lisp_error (void)
{
struct selection_data *cs, *next;
+ struct x_selection_request *frame;
+
+ frame = selection_request_stack;
- for (cs = converted_selections; cs; cs = next)
+ for (cs = frame->converted_selections; cs; cs = next)
{
next = cs->next;
if (! cs->nofree && cs->data)
xfree (cs->data);
xfree (cs);
}
- converted_selections = NULL;
+ frame->converted_selections = NULL;
- if (x_selection_current_request != 0
- && selection_request_dpyinfo->display)
- x_decline_selection_request (x_selection_current_request);
+ if (!frame->converted && frame->dpyinfo->display)
+ x_decline_selection_request (frame->request);
}
static void
@@ -610,6 +578,9 @@ x_reply_selection_request (struct selection_input_event *event,
int max_bytes = selection_quantum (display);
specpdl_ref count = SPECPDL_INDEX ();
struct selection_data *cs;
+ struct x_selection_request *frame;
+
+ frame = selection_request_stack;
reply->type = SelectionNotify;
reply->display = display;
@@ -633,7 +604,7 @@ x_reply_selection_request (struct selection_input_event *event,
(section 2.7.2 of ICCCM). Note that we store the data for a
MULTIPLE request in the opposite order; the ICCM says only that
the conversion itself must be done in the same order. */
- for (cs = converted_selections; cs; cs = cs->next)
+ for (cs = frame->converted_selections; cs; cs = cs->next)
{
if (cs->property == None)
continue;
@@ -688,7 +659,7 @@ x_reply_selection_request (struct selection_input_event *event,
be improved; there's a chance of deadlock if more than one
subtarget in a MULTIPLE selection requires an INCR transfer, and
the requestor and Emacs loop waiting on different transfers. */
- for (cs = converted_selections; cs; cs = cs->next)
+ for (cs = frame->converted_selections; cs; cs = cs->next)
if (cs->wait_object)
{
int format_bytes = cs->format / 8;
@@ -793,7 +764,6 @@ static void
x_handle_selection_request (struct selection_input_event *event)
{
Time local_selection_time;
-
struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
Atom selection = SELECTION_EVENT_SELECTION (event);
Lisp_Object selection_symbol = x_atom_to_symbol (dpyinfo, selection);
@@ -803,8 +773,12 @@ x_handle_selection_request (struct selection_input_event *event)
Lisp_Object local_selection_data;
bool success = false;
specpdl_ref count = SPECPDL_INDEX ();
+ bool pushed;
+
+ pushed = false;
- if (!dpyinfo) goto DONE;
+ if (!dpyinfo)
+ goto DONE;
/* This is how the XDND protocol recommends dropping text onto a
target that doesn't support XDND. */
@@ -824,14 +798,12 @@ x_handle_selection_request (struct selection_input_event *event)
&& local_selection_time > SELECTION_EVENT_TIME (event))
goto DONE;
- x_selection_current_request = event;
- selection_request_dpyinfo = dpyinfo;
+ block_input ();
+ pushed = true;
+ x_push_current_selection_request (event, dpyinfo);
+ record_unwind_protect_void (x_pop_current_selection_request);
record_unwind_protect_void (x_selection_request_lisp_error);
-
- /* We might be able to handle nested x_handle_selection_requests,
- but this is difficult to test, and seems unimportant. */
- x_start_queuing_selection_requests ();
- record_unwind_protect_void (x_stop_queuing_selection_requests);
+ unblock_input ();
TRACE2 ("x_handle_selection_request: selection=%s, target=%s",
SDATA (SYMBOL_NAME (selection_symbol)),
@@ -888,15 +860,17 @@ x_handle_selection_request (struct selection_input_event *event)
DONE:
+ if (pushed)
+ selection_request_stack->converted = true;
+
if (success)
x_reply_selection_request (event, dpyinfo);
else
x_decline_selection_request (event);
- x_selection_current_request = 0;
/* Run the `x-sent-selection-functions' abnormal hook. */
if (!NILP (Vx_sent_selection_functions)
- && !EQ (Vx_sent_selection_functions, Qunbound))
+ && !BASE_EQ (Vx_sent_selection_functions, Qunbound))
CALLN (Frun_hook_with_args, Qx_sent_selection_functions,
selection_symbol, target_symbol, success ? Qt : Qnil);
@@ -917,11 +891,14 @@ x_convert_selection (Lisp_Object selection_symbol,
{
Lisp_Object lisp_selection;
struct selection_data *cs;
+ struct x_selection_request *frame;
lisp_selection
= x_get_local_selection (selection_symbol, target_symbol,
false, dpyinfo);
+ frame = selection_request_stack;
+
/* A nil return value means we can't perform the conversion. */
if (NILP (lisp_selection)
|| (CONSP (lisp_selection) && NILP (XCDR (lisp_selection))))
@@ -929,15 +906,16 @@ x_convert_selection (Lisp_Object selection_symbol,
if (for_multiple)
{
cs = xmalloc (sizeof *cs);
- cs->data = (unsigned char *) &conversion_fail_tag;
+ cs->data = ((unsigned char *)
+ &selection_request_stack->conversion_fail_tag);
cs->size = 1;
cs->format = 32;
cs->type = XA_ATOM;
cs->nofree = true;
cs->property = property;
cs->wait_object = NULL;
- cs->next = converted_selections;
- converted_selections = cs;
+ cs->next = frame->converted_selections;
+ frame->converted_selections = cs;
}
return false;
@@ -949,8 +927,8 @@ x_convert_selection (Lisp_Object selection_symbol,
cs->nofree = true;
cs->property = property;
cs->wait_object = NULL;
- cs->next = converted_selections;
- converted_selections = cs;
+ cs->next = frame->converted_selections;
+ frame->converted_selections = cs;
lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
return true;
}
@@ -1008,6 +986,12 @@ x_handle_selection_clear (struct selection_input_event *event)
/* Run the `x-lost-selection-functions' abnormal hook. */
CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol);
+ /* If Emacs lost ownership of XdndSelection during drag-and-drop,
+ there is no point in continuing the drag-and-drop session. */
+ if (x_dnd_in_progress
+ && EQ (selection_symbol, QXdndSelection))
+ error ("Lost ownership of XdndSelection");
+
redisplay_preserve_echo_area (20);
}
@@ -1017,8 +1001,6 @@ x_handle_selection_event (struct selection_input_event *event)
TRACE0 ("x_handle_selection_event");
if (event->kind != SELECTION_REQUEST_EVENT)
x_handle_selection_clear (event);
- else if (x_queue_selection_requests)
- x_queue_event (event);
else
x_handle_selection_request (event);
}
@@ -1148,8 +1130,13 @@ wait_for_property_change (struct prop_location *location)
intmax_t secs = timeout / 1000;
int nsecs = (timeout % 1000) * 1000000;
TRACE2 (" Waiting %"PRIdMAX" secs, %d nsecs", secs, nsecs);
- wait_reading_process_output (secs, nsecs, 0, false,
- property_change_reply, NULL, 0);
+
+ if (!input_blocked_p ())
+ wait_reading_process_output (secs, nsecs, 0, false,
+ property_change_reply, NULL, 0);
+ else
+ x_wait_for_cell_change (property_change_reply,
+ make_timespec (secs, nsecs));
if (NILP (XCAR (property_change_reply)))
{
@@ -1256,9 +1243,22 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
intmax_t secs = timeout / 1000;
int nsecs = (timeout % 1000) * 1000000;
TRACE1 (" Start waiting %"PRIdMAX" secs for SelectionNotify", secs);
- wait_reading_process_output (secs, nsecs, 0, false,
- reading_selection_reply, NULL, 0);
- TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply)));
+ /* This function can be called with input blocked inside Xt or GTK
+ timeouts run inside popup menus, so use a function that works
+ when input is blocked. Prefer wait_reading_process_output
+ otherwise, or the toolkit might not get some events.
+ (bug#22214) */
+ if (!input_blocked_p ())
+ wait_reading_process_output (secs, nsecs, 0, false,
+ reading_selection_reply, NULL, 0);
+ else
+ x_wait_for_cell_change (reading_selection_reply,
+ make_timespec (secs, nsecs));
+ TRACE1 (" Got event = %s", (!NILP (XCAR (reading_selection_reply))
+ ? (SYMBOLP (XCAR (reading_selection_reply))
+ ? SSDATA (SYMBOL_NAME (XCAR (reading_selection_reply)))
+ : "YES")
+ : "NO"));
if (NILP (XCAR (reading_selection_reply)))
error ("Timed out waiting for reply from selection owner");
@@ -1953,7 +1953,7 @@ x_handle_selection_notify (const XSelectionEvent *event)
if (event->selection != reading_which_selection)
return;
- TRACE0 ("Received SelectionNotify");
+ TRACE1 ("Received SelectionNotify: %d", (int) event->property);
XSETCAR (reading_selection_reply,
(event->property != 0 ? Qt : Qlambda));
}
@@ -2454,28 +2454,29 @@ If the value is 0 or the atom is not known, return the empty string. */)
(Lisp_Object value, Lisp_Object frame)
{
struct frame *f = decode_window_system_frame (frame);
- char *name = 0;
- char empty[] = "";
- Lisp_Object ret = Qnil;
Display *dpy = FRAME_X_DISPLAY (f);
+ struct x_display_info *dpyinfo;
Atom atom;
- bool had_errors_p;
+ bool had_errors_p, need_sync;
+ char *name;
+ Lisp_Object ret;
+ dpyinfo = FRAME_DISPLAY_INFO (f);
CONS_TO_INTEGER (value, Atom, atom);
- block_input ();
x_catch_errors (dpy);
- name = atom ? XGetAtomName (dpy, atom) : empty;
- had_errors_p = x_had_errors_p (dpy);
+ name = x_get_atom_name (dpyinfo, atom, &need_sync);
+ had_errors_p = need_sync && x_had_errors_p (dpy);
x_uncatch_errors_after_check ();
- if (!had_errors_p)
- ret = build_string (name);
+ ret = empty_unibyte_string;
- if (atom && name) XFree (name);
- if (NILP (ret)) ret = empty_unibyte_string;
-
- unblock_input ();
+ if (name)
+ {
+ if (!had_errors_p)
+ ret = build_string (name);
+ xfree (name);
+ }
return ret;
}
@@ -2492,13 +2493,13 @@ FRAME is on. If FRAME is nil, the selected frame is used. */)
ptrdiff_t i;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
-
if (SYMBOLP (atom))
x_atom = symbol_to_x_atom (dpyinfo, atom);
else if (STRINGP (atom))
{
block_input ();
- x_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (atom), False);
+ x_atom = x_intern_cached_atom (dpyinfo, SSDATA (atom),
+ false);
unblock_input ();
}
else
@@ -2521,7 +2522,8 @@ FRAME is on. If FRAME is nil, the selected frame is used. */)
bool
x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
- struct x_display_info *dpyinfo, struct input_event *bufp)
+ struct x_display_info *dpyinfo, struct input_event *bufp,
+ bool root_window_coords, int root_x, int root_y)
{
Lisp_Object vec;
Lisp_Object frame;
@@ -2531,6 +2533,7 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
unsigned char *data = (unsigned char *) event->data.b;
int idata[5];
ptrdiff_t i;
+ Window child_return;
for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
if (dpyinfo->x_dnd_atoms[i] == event->message_type) break;
@@ -2562,7 +2565,15 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
event->format,
size));
- x_relative_mouse_position (f, &x, &y);
+ if (!root_window_coords)
+ x_relative_mouse_position (f, &x, &y);
+ else
+ XTranslateCoordinates (dpyinfo->display,
+ dpyinfo->root_window,
+ FRAME_X_WINDOW (f),
+ root_x, root_y,
+ &x, &y, &child_return);
+
bufp->kind = DRAG_N_DROP_EVENT;
bufp->frame_or_window = frame;
bufp->timestamp = CurrentTime;
@@ -2799,6 +2810,14 @@ A value of 0 means wait as long as necessary. This is initialized from the
\"*selectionTimeout\" resource. */);
x_selection_timeout = 0;
+ DEFVAR_LISP ("x-treat-local-requests-remotely", Vx_treat_local_requests_remotely,
+ doc: /* Whether to treat local selection requests as remote ones.
+
+If non-nil, selection converters for string types (`STRING',
+`UTF8_STRING', `COMPOUND_TEXT', etc) will encode the strings, even
+when Emacs itself is converting the selection. */);
+ Vx_treat_local_requests_remotely = Qnil;
+
/* QPRIMARY is defined in keyboard.c. */
DEFSYM (QSECONDARY, "SECONDARY");
DEFSYM (QSTRING, "STRING");
@@ -2838,6 +2857,4 @@ syms_of_xselect_for_pdumper (void)
property_change_wait_list = 0;
prop_location_identifier = 0;
property_change_reply = Fcons (Qnil, Qnil);
- converted_selections = NULL;
- conversion_fail_tag = None;
}
diff --git a/src/xsettings.c b/src/xsettings.c
index 71d02e61525..c29a844e0a8 100644
--- a/src/xsettings.c
+++ b/src/xsettings.c
@@ -206,6 +206,11 @@ struct xsettings
unsigned seen;
};
+#ifdef HAVE_PGTK
+/* The cairo font_options as obtained using gsettings. */
+static cairo_font_options_t *font_options;
+#endif
+
#ifdef HAVE_GSETTINGS
#define GSETTINGS_SCHEMA "org.gnome.desktop.interface"
#define GSETTINGS_TOOL_BAR_STYLE "toolbar-style"
@@ -215,11 +220,162 @@ struct xsettings
#define GSETTINGS_FONT_NAME "font-name"
#endif
+#ifdef HAVE_PGTK
+#define GSETTINGS_FONT_ANTIALIASING "font-antialiasing"
+#define GSETTINGS_FONT_RGBA_ORDER "font-rgba-order"
+#define GSETTINGS_FONT_HINTING "font-hinting"
+#endif
/* The single GSettings instance, or NULL if not connected to GSettings. */
static GSettings *gsettings_client;
+#if defined HAVE_PGTK && defined HAVE_GSETTINGS
+
+static bool
+xg_settings_key_valid_p (GSettings *settings, const char *key)
+{
+#ifdef GLIB_VERSION_2_32
+ GSettingsSchema *schema;
+ bool rc;
+
+ g_object_get (G_OBJECT (settings),
+ "settings-schema", &schema,
+ NULL);
+
+ if (!schema)
+ return false;
+
+ rc = g_settings_schema_has_key (schema, key);
+ g_settings_schema_unref (schema);
+
+ return rc;
+#else
+ return false;
+#endif
+}
+
+#endif
+
+#ifdef HAVE_PGTK
+/* Store an event for re-rendering of the fonts. */
+static void
+store_font_options_changed (void)
+{
+ if (dpyinfo_valid (first_dpyinfo))
+ store_config_changed_event (Qfont_render,
+ XCAR (first_dpyinfo->name_list_element));
+}
+
+/* Apply changes in the hinting system setting. */
+static void
+apply_gsettings_font_hinting (GSettings *settings)
+{
+ GVariant *val;
+ const char *hinting;
+
+ if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_HINTING))
+ return;
+
+ val = g_settings_get_value (settings, GSETTINGS_FONT_HINTING);
+
+ if (val)
+ {
+ g_variant_ref_sink (val);
+
+ if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+ {
+ hinting = g_variant_get_string (val, NULL);
+
+ if (!strcmp (hinting, "full"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_FULL);
+ else if (!strcmp (hinting, "medium"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_MEDIUM);
+ else if (!strcmp (hinting, "slight"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_SLIGHT);
+ else if (!strcmp (hinting, "none"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_NONE);
+ }
+ g_variant_unref (val);
+ }
+}
+
+/* Apply changes in the antialiasing system setting. */
+static void
+apply_gsettings_font_antialias (GSettings *settings)
+{
+ GVariant *val;
+ const char *antialias;
+
+ if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_ANTIALIASING))
+ return;
+
+ val = g_settings_get_value (settings, GSETTINGS_FONT_ANTIALIASING);
+
+ if (val)
+ {
+ g_variant_ref_sink (val);
+ if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+ {
+ antialias = g_variant_get_string (val, NULL);
+
+ if (!strcmp (antialias, "none"))
+ cairo_font_options_set_antialias (font_options,
+ CAIRO_ANTIALIAS_NONE);
+ else if (!strcmp (antialias, "grayscale"))
+ cairo_font_options_set_antialias (font_options,
+ CAIRO_ANTIALIAS_GRAY);
+ else if (!strcmp (antialias, "rgba"))
+ cairo_font_options_set_antialias (font_options,
+ CAIRO_ANTIALIAS_SUBPIXEL);
+ }
+ g_variant_unref (val);
+ }
+}
+
+/* Apply the settings for the rgb element ordering. */
+static void
+apply_gsettings_font_rgba_order (GSettings *settings)
+{
+ GVariant *val;
+ const char *rgba_order;
+
+ if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_RGBA_ORDER))
+ return;
+
+ val = g_settings_get_value (settings,
+ GSETTINGS_FONT_RGBA_ORDER);
+
+ if (val)
+ {
+ g_variant_ref_sink (val);
+
+ if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+ {
+ rgba_order = g_variant_get_string (val, NULL);
+
+ if (!strcmp (rgba_order, "rgb"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_RGB);
+ else if (!strcmp (rgba_order, "bgr"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_BGR);
+ else if (!strcmp (rgba_order, "vrgb"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_VRGB);
+ else if (!strcmp (rgba_order, "vbgr"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_VBGR);
+ }
+ g_variant_unref (val);
+ }
+}
+#endif /* HAVE_PGTK */
+
/* Callback called when something changed in GSettings. */
static void
@@ -273,6 +429,23 @@ something_changed_gsettingsCB (GSettings *settings,
}
}
#endif /* USE_CAIRO || HAVE_XFT */
+#ifdef HAVE_PGTK
+ else if (!strcmp (key, GSETTINGS_FONT_ANTIALIASING))
+ {
+ apply_gsettings_font_antialias (settings);
+ store_font_options_changed ();
+ }
+ else if (!strcmp (key, GSETTINGS_FONT_HINTING))
+ {
+ apply_gsettings_font_hinting (settings);
+ store_font_options_changed ();
+ }
+ else if (!strcmp (key, GSETTINGS_FONT_RGBA_ORDER))
+ {
+ apply_gsettings_font_rgba_order (settings);
+ store_font_options_changed ();
+ }
+#endif /* HAVE_PGTK */
}
#endif /* HAVE_GSETTINGS */
@@ -900,6 +1073,16 @@ init_gsettings (void)
dupstring (&current_font, g_variant_get_string (val, NULL));
g_variant_unref (val);
}
+
+ /* Only use the gsettings font entries for the Cairo backend
+ running on PGTK. */
+#ifdef HAVE_PGTK
+ font_options = cairo_font_options_create ();
+ apply_gsettings_font_antialias (gsettings_client);
+ apply_gsettings_font_hinting (gsettings_client);
+ apply_gsettings_font_rgba_order (gsettings_client);
+#endif /* HAVE_PGTK */
+
#endif /* USE_CAIRO || HAVE_XFT */
#endif /* HAVE_GSETTINGS */
@@ -1021,6 +1204,21 @@ xsettings_get_system_normal_font (void)
}
#endif
+#ifdef HAVE_PGTK
+/* Return the cairo font options, updated from the gsettings font
+ config entries. The caller should call cairo_font_options_destroy
+ on the result. */
+cairo_font_options_t *
+xsettings_get_font_options (void)
+{
+ if (font_options != NULL)
+ return cairo_font_options_copy (font_options);
+ else
+ /* GSettings is not configured. */
+ return cairo_font_options_create ();
+}
+#endif
+
DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
Sfont_get_system_normal_font,
0, 0, 0,
@@ -1073,6 +1271,10 @@ syms_of_xsettings (void)
gconf_client = NULL;
PDUMPER_IGNORE (gconf_client);
#endif
+#ifdef HAVE_PGTK
+ font_options = NULL;
+ PDUMPER_IGNORE (font_options);
+#endif
DEFSYM (Qmonospace_font_name, "monospace-font-name");
DEFSYM (Qfont_name, "font-name");
diff --git a/src/xsettings.h b/src/xsettings.h
index ccaa36489d0..5e5df37062b 100644
--- a/src/xsettings.h
+++ b/src/xsettings.h
@@ -23,6 +23,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#ifndef HAVE_PGTK
#include "dispextern.h"
#include <X11/Xlib.h>
+#else
+#include <cairo.h>
#endif
struct x_display_info;
@@ -41,5 +43,8 @@ extern const char *xsettings_get_system_font (void);
extern const char *xsettings_get_system_normal_font (void);
#endif
+#ifdef HAVE_PGTK
+extern cairo_font_options_t *xsettings_get_font_options (void);
+#endif
#endif /* XSETTINGS_H */
diff --git a/src/xterm.c b/src/xterm.c
index 2141964c747..2cc17b455da 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -78,7 +78,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
INPUT FOCUS
Under X, the window where keyboard input is sent is not always
- explictly defined. When there is a focus window, it receives what
+ explicitly defined. When there is a focus window, it receives what
is referred to as "explicit focus", but when there is none, it
receives "implicit focus" whenever the pointer enters it, and loses
that focus when the pointer leaves. When the toplevel window of a
@@ -550,6 +550,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
#include <stdlib.h>
#include <math.h>
+#include <signal.h>
#include "lisp.h"
#include "blockinput.h"
@@ -699,6 +700,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#endif
#endif
+#ifdef USE_GTK
+#include <xgselect.h>
+#endif
+
#include "bitmaps/gray.xbm"
#ifdef HAVE_XKB
@@ -784,6 +789,227 @@ static int current_finish;
static struct input_event *current_hold_quit;
#endif
+/* Queue selection requests in `pending_selection_requests' if more
+ than 0. */
+static int x_use_pending_selection_requests;
+
+static void x_push_selection_request (struct selection_input_event *);
+
+/* Defer selection requests. Between this and
+ x_release_selection_requests, any selection requests can be
+ processed by calling `x_handle_pending_selection_requests'.
+
+ Also run through and queue all the selection events already in the
+ keyboard buffer. */
+void
+x_defer_selection_requests (void)
+{
+ union buffered_input_event *event;
+ bool between;
+
+ between = false;
+
+ block_input ();
+ if (!x_use_pending_selection_requests)
+ {
+ event = kbd_fetch_ptr;
+
+ while (event != kbd_store_ptr)
+ {
+ if (event->ie.kind == SELECTION_REQUEST_EVENT
+ || event->ie.kind == SELECTION_CLEAR_EVENT)
+ {
+ x_push_selection_request (&event->sie);
+
+ /* Mark this selection event as invalid. */
+ SELECTION_EVENT_DPYINFO (&event->sie) = NULL;
+
+ /* Move the kbd_fetch_ptr along if doing so would not
+ result in any other events being skipped. This
+ avoids exhausting the keyboard buffer with some
+ over-enthusiastic clipboard managers. */
+ if (!between)
+ kbd_fetch_ptr = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
+ ? kbd_buffer : event + 1);
+ }
+ else
+ between = true;
+
+ event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
+ ? kbd_buffer : event + 1);
+ }
+ }
+
+ x_use_pending_selection_requests++;
+ unblock_input ();
+}
+
+static void
+x_release_selection_requests (void)
+{
+ x_use_pending_selection_requests--;
+}
+
+void
+x_release_selection_requests_and_flush (void)
+{
+ x_release_selection_requests ();
+
+ if (!x_use_pending_selection_requests)
+ x_handle_pending_selection_requests ();
+}
+
+struct x_selection_request_event
+{
+ /* The selection request event. */
+ struct selection_input_event se;
+
+ /* The next unprocessed selection request event. */
+ struct x_selection_request_event *next;
+};
+
+/* Chain of unprocessed selection request events. Used to handle
+ selection requests inside long-lasting modal event loops, such as
+ the drag-and-drop loop. */
+
+struct x_selection_request_event *pending_selection_requests;
+
+/* Compare two request serials A and B with OP, handling
+ wraparound. */
+#define X_COMPARE_SERIALS(a, op ,b) \
+ (((long) (a) - (long) (b)) op 0)
+
+struct x_atom_ref
+{
+ /* Atom name. */
+ const char *name;
+
+ /* Offset of atom in the display info structure. */
+ int offset;
+};
+
+/* List of all atoms that should be interned when connecting to a
+ display. */
+static const struct x_atom_ref x_atom_refs[] =
+ {
+#define ATOM_REFS_INIT(string, member) \
+ { string, offsetof (struct x_display_info, member) },
+ ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
+ ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
+ ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
+ ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
+ ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
+ ATOM_REFS_INIT ("WM_STATE", Xatom_wm_state)
+ ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
+ ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
+ ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
+ ATOM_REFS_INIT ("WM_TRANSIENT_FOR", Xatom_wm_transient_for)
+ ATOM_REFS_INIT ("Editres", Xatom_editres)
+ ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
+ ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
+ ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
+ ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
+ ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
+ ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
+ ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
+ ATOM_REFS_INIT ("INCR", Xatom_INCR)
+ ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
+ ATOM_REFS_INIT ("EMACS_SERVER_TIME_PROP", Xatom_EMACS_SERVER_TIME_PROP)
+ ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
+ ATOM_REFS_INIT ("NULL", Xatom_NULL)
+ ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
+ ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
+ ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
+ ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
+ ATOM_REFS_INIT ("_MOTIF_WM_HINTS", Xatom_MOTIF_WM_HINTS)
+ /* For properties of font. */
+ ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
+ ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
+ ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
+ ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
+ ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
+ /* Ghostscript support. */
+ ATOM_REFS_INIT ("DONE", Xatom_DONE)
+ ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
+ ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
+ ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
+ ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
+ /* EWMH */
+ ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
+ ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
+ ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
+ Xatom_net_wm_state_maximized_horz)
+ ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
+ Xatom_net_wm_state_maximized_vert)
+ ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
+ ATOM_REFS_INIT ("_NET_WM_STATE_SHADED", Xatom_net_wm_state_shaded)
+ ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
+ ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
+ ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
+ Xatom_net_window_type_tooltip)
+ ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
+ ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
+ ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
+ ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
+ ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
+ ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
+ ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
+ ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
+ ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
+ ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
+ ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter)
+ ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
+ ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
+ ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
+ ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking)
+ /* Session management */
+ ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
+ ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
+ ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
+ ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", Xatom_net_wm_state_skip_taskbar)
+ ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
+ ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
+ ATOM_REFS_INIT ("_NET_WM_OPAQUE_REGION", Xatom_net_wm_opaque_region)
+ ATOM_REFS_INIT ("_NET_WM_PING", Xatom_net_wm_ping)
+ ATOM_REFS_INIT ("_NET_WM_PID", Xatom_net_wm_pid)
+#ifdef HAVE_XKB
+ ATOM_REFS_INIT ("Meta", Xatom_Meta)
+ ATOM_REFS_INIT ("Super", Xatom_Super)
+ ATOM_REFS_INIT ("Hyper", Xatom_Hyper)
+ ATOM_REFS_INIT ("ShiftLock", Xatom_ShiftLock)
+ ATOM_REFS_INIT ("Alt", Xatom_Alt)
+#endif
+ /* DND source. */
+ ATOM_REFS_INIT ("XdndAware", Xatom_XdndAware)
+ ATOM_REFS_INIT ("XdndSelection", Xatom_XdndSelection)
+ ATOM_REFS_INIT ("XdndTypeList", Xatom_XdndTypeList)
+ ATOM_REFS_INIT ("XdndActionCopy", Xatom_XdndActionCopy)
+ ATOM_REFS_INIT ("XdndActionMove", Xatom_XdndActionMove)
+ ATOM_REFS_INIT ("XdndActionLink", Xatom_XdndActionLink)
+ ATOM_REFS_INIT ("XdndActionAsk", Xatom_XdndActionAsk)
+ ATOM_REFS_INIT ("XdndActionPrivate", Xatom_XdndActionPrivate)
+ ATOM_REFS_INIT ("XdndActionList", Xatom_XdndActionList)
+ ATOM_REFS_INIT ("XdndActionDescription", Xatom_XdndActionDescription)
+ ATOM_REFS_INIT ("XdndProxy", Xatom_XdndProxy)
+ ATOM_REFS_INIT ("XdndEnter", Xatom_XdndEnter)
+ ATOM_REFS_INIT ("XdndPosition", Xatom_XdndPosition)
+ ATOM_REFS_INIT ("XdndStatus", Xatom_XdndStatus)
+ ATOM_REFS_INIT ("XdndLeave", Xatom_XdndLeave)
+ ATOM_REFS_INIT ("XdndDrop", Xatom_XdndDrop)
+ ATOM_REFS_INIT ("XdndFinished", Xatom_XdndFinished)
+ /* Motif drop protocol support. */
+ ATOM_REFS_INIT ("_MOTIF_DRAG_WINDOW", Xatom_MOTIF_DRAG_WINDOW)
+ ATOM_REFS_INIT ("_MOTIF_DRAG_TARGETS", Xatom_MOTIF_DRAG_TARGETS)
+ ATOM_REFS_INIT ("_MOTIF_DRAG_AND_DROP_MESSAGE",
+ Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
+ ATOM_REFS_INIT ("_MOTIF_DRAG_INITIATOR_INFO",
+ Xatom_MOTIF_DRAG_INITIATOR_INFO)
+ ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO",
+ Xatom_MOTIF_DRAG_RECEIVER_INFO)
+ ATOM_REFS_INIT ("XmTRANSFER_SUCCESS", Xatom_XmTRANSFER_SUCCESS)
+ ATOM_REFS_INIT ("XmTRANSFER_FAILURE", Xatom_XmTRANSFER_FAILURE)
+ };
+
enum
{
X_EVENT_NORMAL,
@@ -863,19 +1089,39 @@ static void x_scroll_bar_end_update (struct x_display_info *, struct scroll_bar
static int x_filter_event (struct x_display_info *, XEvent *);
#endif
+static struct frame *x_tooltip_window_to_frame (struct x_display_info *,
+ Window, bool *);
+static Window x_get_window_below (Display *, Window, int, int, int *, int *);
+
/* Global state maintained during a drag-and-drop operation. */
/* Flag that indicates if a drag-and-drop operation is in progress. */
bool x_dnd_in_progress;
+/* Number that indicates the last "generation" of
+ UNSUPPORTED_DROP_EVENTs handled. */
+unsigned x_dnd_unsupported_event_level;
+
/* The frame where the drag-and-drop operation originated. */
struct frame *x_dnd_frame;
+/* That frame, but set when x_dnd_waiting_for_finish is true. Used to
+ prevent the frame from being deleted inside selection handlers and
+ other callbacks. */
+struct frame *x_dnd_finish_frame;
+
/* Flag that indicates if a drag-and-drop operation is no longer in
progress, but the nested event loop should continue to run, because
handle_one_xevent is waiting for the drop target to return some
important information. */
-static bool x_dnd_waiting_for_finish;
+bool x_dnd_waiting_for_finish;
+
+/* Whether or not to move the tooltip along with the mouse pointer
+ during drag-and-drop. */
+static bool x_dnd_update_tooltip;
+
+/* Monitor attribute list used for updating the tooltip position. */
+static Lisp_Object x_dnd_monitors;
/* The display the drop target that is supposed to send information is
on. */
@@ -916,6 +1162,10 @@ static int x_dnd_waiting_for_finish_proto;
where the drag-and-drop operation originated. */
static bool x_dnd_allow_current_frame;
+/* Whether or not the `XdndTypeList' property has already been set on
+ the drag frame. */
+static bool x_dnd_init_type_lists;
+
/* Whether or not to return a frame from `x_dnd_begin_drag_and_drop'.
0 means to do nothing. 1 means to wait for the mouse to first exit
@@ -943,6 +1193,10 @@ static Window x_dnd_end_window;
did not support XDND. */
static int x_dnd_last_protocol_version;
+/* Whether or not the last seen window is actually one of our
+ frames. */
+static bool x_dnd_last_window_is_frame;
+
/* The Motif drag and drop protocol style of `x_dnd_last_seen_window'.
XM_DRAG_STYLE_NONE means the window does not support the Motif drag
or drop protocol. XM_DRAG_STYLE_DROP_ONLY means the window does
@@ -974,13 +1228,25 @@ static XRectangle x_dnd_mouse_rect;
protocol, this is set to the atom XdndActionPrivate. */
static Atom x_dnd_action;
+/* The symbol to return from `x-begin-drag' if non-nil. Takes
+ precedence over `x_dnd_action`. */
+static Lisp_Object x_dnd_action_symbol;
+
/* The action we want the drop target to perform. The drop target may
elect to perform some different action, which is guaranteed to be
in `x_dnd_action' upon completion of a drop. */
static Atom x_dnd_wanted_action;
+/* The set of optional actions available to a Motif drop target
+ computed at the start of the drag-and-drop operation. */
+static uint8_t x_dnd_motif_operations;
+
+/* The preferred optional action out of that set. Only takes effect
+ if `x_dnd_action' is XdndAsk. */
+static uint8_t x_dnd_first_motif_operation;
+
/* Array of selection targets available to the drop target. */
-static Atom *x_dnd_targets = NULL;
+static Atom *x_dnd_targets;
/* The number of elements in that array. */
static int x_dnd_n_targets;
@@ -1009,42 +1275,86 @@ static unsigned int x_dnd_keyboard_state;
/* jmp_buf that gets us out of the IO error handler if an error occurs
terminating DND as part of the display disconnect handler. */
-static jmp_buf x_dnd_disconnect_handler;
+static sigjmp_buf x_dnd_disconnect_handler;
+
+/* Whether or not the current invocation of handle_one_xevent
+ happened inside the drag_and_drop event loop. */
+static bool x_dnd_inside_handle_one_xevent;
+
+/* The recursive edit depth when the drag-and-drop operation was
+ started. */
+static int x_dnd_recursion_depth;
+/* Structure describing a single window that can be the target of
+ drag-and-drop operations. */
struct x_client_list_window
{
+ /* The window itself. */
Window window;
+
+ /* The display that window is on. */
Display *dpy;
+
+ /* Its X and Y coordinates from the root window. */
int x, y;
+
+ /* The width and height of the window. */
int width, height;
+
+ /* Whether or not the window is mapped. */
bool mapped_p;
+
+ /* A bitmask describing events Emacs was listening for from the
+ window before some extra events were added in
+ `x_dnd_compute_toplevels'. */
long previous_event_mask;
+
+ /* The window manager state of the window. */
unsigned long wm_state;
+ /* The next window in this list. */
struct x_client_list_window *next;
+
+ /* The Motif protocol style of this window, if any. */
uint8_t xm_protocol_style;
+ /* The extents of the frame window in each direction. */
int frame_extents_left;
int frame_extents_right;
int frame_extents_top;
int frame_extents_bottom;
#ifdef HAVE_XSHAPE
+ /* The border width of this window. */
int border_width;
+ /* The rectangles making up the input shape. */
XRectangle *input_rects;
+
+ /* The number of rectangles composing the input shape. */
int n_input_rects;
+ /* The rectangles making up the bounding shape. */
XRectangle *bounding_rects;
+
+ /* The number of rectangles composing the bounding shape. */
int n_bounding_rects;
#endif
};
-static struct x_client_list_window *x_dnd_toplevels = NULL;
+/* List of all toplevels in stacking order, from top to bottom. */
+static struct x_client_list_window *x_dnd_toplevels;
+
+/* Whether or not the window manager supports the required features
+ for `x_dnd_toplevels' to work. */
static bool x_dnd_use_toplevels;
/* Motif drag-and-drop protocol support. */
+/* Pointer to a variable which stores whether or not an X error
+ occured while trying to create the Motif drag window. */
+static volatile bool *xm_drag_window_error;
+
typedef enum xm_byte_order
{
XM_BYTE_ORDER_LSB_FIRST = 'l',
@@ -1078,8 +1388,8 @@ typedef enum xm_byte_order
}
#else
-#define SWAPCARD32(l) bswap_32 (l)
-#define SWAPCARD16(l) bswap_16 (l)
+#define SWAPCARD32(l) ((l) = bswap_32 (l))
+#define SWAPCARD16(l) ((l) = bswap_16 (l))
#endif
typedef struct xm_targets_table_header
@@ -1181,34 +1491,50 @@ typedef struct xm_top_level_leave_message
/* #define XM_DRAG_SIDE_EFFECT_OPERATIONS(effect) (((effect) & 0xf00) >> 8) */
#define XM_DRAG_SIDE_EFFECT_DROP_ACTION(effect) (((effect) & 0xf000) >> 12)
-#define XM_DRAG_NOOP 0
-#define XM_DRAG_MOVE (1L << 0)
-#define XM_DRAG_COPY (1L << 1)
-#define XM_DRAG_LINK (1L << 2)
+enum xm_drag_operation
+ {
+ XM_DRAG_NOOP = 0,
+ XM_DRAG_MOVE = (1L << 0),
+ XM_DRAG_COPY = (1L << 1),
+ XM_DRAG_LINK = (1L << 2),
+ };
-#define XM_DROP_ACTION_DROP 0
-#define XM_DROP_ACTION_DROP_HELP 1
-#define XM_DROP_ACTION_DROP_CANCEL 2
+enum xm_drag_action
+ {
+ XM_DROP_ACTION_DROP = 0,
+ XM_DROP_ACTION_DROP_HELP = 1,
+ XM_DROP_ACTION_DROP_CANCEL = 2,
+ };
#define XM_DRAG_REASON(originator, code) ((code) | ((originator) << 7))
#define XM_DRAG_REASON_ORIGINATOR(reason) (((reason) & 0x80) ? 1 : 0)
#define XM_DRAG_REASON_CODE(reason) ((reason) & 0x7f)
-#define XM_DRAG_REASON_DROP_START 5
-#define XM_DRAG_REASON_TOP_LEVEL_ENTER 0
-#define XM_DRAG_REASON_TOP_LEVEL_LEAVE 1
-#define XM_DRAG_REASON_DRAG_MOTION 2
-#define XM_DRAG_ORIGINATOR_INITIATOR 0
-#define XM_DRAG_ORIGINATOR_RECEIVER 1
-
-#define XM_DRAG_STYLE_NONE 0
+enum xm_drag_reason
+ {
+ XM_DRAG_REASON_DROP_START = 5,
+ XM_DRAG_REASON_TOP_LEVEL_ENTER = 0,
+ XM_DRAG_REASON_TOP_LEVEL_LEAVE = 1,
+ XM_DRAG_REASON_DRAG_MOTION = 2,
+ };
-#define XM_DRAG_STYLE_DROP_ONLY 1
-#define XM_DRAG_STYLE_DROP_ONLY_REC 3
+enum xm_drag_originator
+ {
+ XM_DRAG_ORIGINATOR_INITIATOR = 0,
+ XM_DRAG_ORIGINATOR_RECEIVER = 1,
+ };
-#define XM_DRAG_STYLE_DYNAMIC 5
-#define XM_DRAG_STYLE_DYNAMIC_REC 2
-#define XM_DRAG_STYLE_DYNAMIC_REC1 4
+enum xm_drag_style
+ {
+ /* The values ending with _REC should be treated as equivalent to
+ the ones without in messages from the receiver. */
+ XM_DRAG_STYLE_NONE = 0,
+ XM_DRAG_STYLE_DROP_ONLY = 1,
+ XM_DRAG_STYLE_DROP_ONLY_REC = 3,
+ XM_DRAG_STYLE_DYNAMIC = 5,
+ XM_DRAG_STYLE_DYNAMIC_REC = 2,
+ XM_DRAG_STYLE_DYNAMIC_REC1 = 4,
+ };
#define XM_DRAG_STYLE_IS_DROP_ONLY(n) ((n) == XM_DRAG_STYLE_DROP_ONLY \
|| (n) == XM_DRAG_STYLE_DROP_ONLY_REC)
@@ -1216,9 +1542,16 @@ typedef struct xm_top_level_leave_message
|| (n) == XM_DRAG_STYLE_DYNAMIC_REC \
|| (n) == XM_DRAG_STYLE_DYNAMIC_REC1)
-#define XM_DROP_SITE_VALID 3
-/* #define XM_DROP_SITE_INVALID 2 */
-#define XM_DROP_SITE_NONE 1
+enum xm_drop_site_status
+ {
+ XM_DROP_SITE_VALID = 3,
+ XM_DROP_SITE_INVALID = 2,
+ XM_DROP_SITE_NONE = 1,
+ };
+
+/* The version of the Motif drag-and-drop protocols that Emacs
+ supports. */
+#define XM_DRAG_PROTOCOL_VERSION 0
static uint8_t
xm_side_effect_from_action (struct x_display_info *dpyinfo, Atom action)
@@ -1229,10 +1562,34 @@ xm_side_effect_from_action (struct x_display_info *dpyinfo, Atom action)
return XM_DRAG_MOVE;
else if (action == dpyinfo->Xatom_XdndActionLink)
return XM_DRAG_LINK;
+ else if (action == dpyinfo->Xatom_XdndActionAsk)
+ return x_dnd_first_motif_operation;
return XM_DRAG_NOOP;
}
+static uint8_t
+xm_operations_from_actions (struct x_display_info *dpyinfo,
+ Atom *ask_actions, int n_ask_actions)
+{
+ int i;
+ uint8_t flags;
+
+ flags = 0;
+
+ for (i = 0; i < n_ask_actions; ++i)
+ {
+ if (ask_actions[i] == dpyinfo->Xatom_XdndActionCopy)
+ flags |= XM_DRAG_COPY;
+ else if (ask_actions[i] == dpyinfo->Xatom_XdndActionMove)
+ flags |= XM_DRAG_MOVE;
+ else if (ask_actions[i] == dpyinfo->Xatom_XdndActionLink)
+ flags |= XM_DRAG_LINK;
+ }
+
+ return flags;
+}
+
static int
xm_read_targets_table_header (uint8_t *bytes, ptrdiff_t length,
xm_targets_table_header *header_return,
@@ -1396,6 +1753,9 @@ xm_write_drag_initiator_info (Display *dpy, Window wdesc,
static int
xm_drag_window_error_handler (Display *display, XErrorEvent *event)
{
+ if (xm_drag_window_error)
+ *xm_drag_window_error = true;
+
return 0;
}
@@ -1404,7 +1764,7 @@ xm_drag_window_io_error_handler (Display *dpy)
{
/* DPY isn't created through GDK, so it doesn't matter if we don't
crash here. */
- longjmp (x_dnd_disconnect_handler, 1);
+ siglongjmp (x_dnd_disconnect_handler, 1);
}
static Window
@@ -1418,6 +1778,9 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
XSetWindowAttributes attrs;
Display *temp_display;
void *old_handler, *old_io_handler;
+ /* These are volatile because GCC mistakenly warns about them being
+ clobbered by longjmp. */
+ volatile bool error, created;
drag_window = None;
rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
@@ -1473,6 +1836,9 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
return None;
}
+ error = false;
+ xm_drag_window_error = &error;
+
XGrabServer (temp_display);
XSetCloseDownMode (temp_display, RetainPermanent);
@@ -1483,6 +1849,9 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
_MOTIF_DRAG_WINDOW = XInternAtom (temp_display,
"_MOTIF_DRAG_WINDOW", False);
+ if (error)
+ goto give_up;
+
/* Some other program might've created a drag window between now
and when we first looked. Use that if it exists. */
@@ -1500,8 +1869,12 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
if (tmp_data)
XFree (tmp_data);
+ error = false;
+
if (drag_window == None)
{
+ created = true;
+
attrs.override_redirect = True;
drag_window = XCreateWindow (temp_display, DefaultRootWindow (temp_display),
-1, -1, 1, 1, 0, CopyFromParent, InputOnly,
@@ -1510,8 +1883,41 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
_MOTIF_DRAG_WINDOW, XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &drag_window, 1);
}
+ else
+ created = false;
+
+ /* Handle all errors now. */
+ XSync (temp_display, False);
+ give_up:
+
+ /* Some part of the drag window creation process failed, so
+ punt. */
+ if (error)
+ {
+ /* If the drag window was actually created, delete it now.
+ Probably, a BadAlloc happened during the XChangeProperty
+ request. */
+ if (created)
+ {
+ if (drag_window != None)
+ XDestroyWindow (temp_display, drag_window);
+
+ XDeleteProperty (temp_display, DefaultRootWindow (temp_display),
+ _MOTIF_DRAG_WINDOW);
+ }
+
+ drag_window = None;
+ }
+
+ xm_drag_window_error = NULL;
+
+ /* FIXME: why does XCloseDisplay hang if SIGIO arrives and there
+ are multiple displays? */
+ unrequest_sigio ();
XCloseDisplay (temp_display);
+ request_sigio ();
+
XSetErrorHandler (old_handler);
XSetIOErrorHandler (old_io_handler);
@@ -1633,7 +2039,7 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
if (!rc)
{
header.byte_order = XM_BYTE_ORDER_CUR_FIRST;
- header.protocol = 0;
+ header.protocol = XM_DRAG_PROTOCOL_VERSION;
header.target_list_count = 1;
header.total_data_size = 8 + 2 + ntargets * 4;
@@ -1678,7 +2084,7 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
xfree (recs);
header.byte_order = XM_BYTE_ORDER_CUR_FIRST;
- header.protocol = 0;
+ header.protocol = XM_DRAG_PROTOCOL_VERSION;
header.target_list_count = 1;
header.total_data_size = 8 + 2 + ntargets * 4;
@@ -1715,10 +2121,17 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
data format. To avoid confusing Motif when that happens, set
it back to 0. There will probably be no more updates to the
protocol either. */
- header.protocol = 0;
+ header.protocol = XM_DRAG_PROTOCOL_VERSION;
+
+ x_catch_errors (dpyinfo->display);
xm_write_targets_table (dpyinfo->display, drag_window,
dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
&header, recs);
+ /* Presumably we got a BadAlloc upon writing the targets
+ table. */
+ if (x_had_errors_p (dpyinfo->display))
+ idx = -1;
+ x_uncatch_errors_after_check ();
}
XUngrabServer (dpyinfo->display);
@@ -1745,7 +2158,7 @@ xm_setup_drag_info (struct x_display_info *dpyinfo,
if (idx != -1)
{
drag_initiator_info.byteorder = XM_BYTE_ORDER_CUR_FIRST;
- drag_initiator_info.protocol = 0;
+ drag_initiator_info.protocol = XM_DRAG_PROTOCOL_VERSION;
drag_initiator_info.table_index = idx;
drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
@@ -1862,7 +2275,7 @@ xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source,
mmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
mmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_NONE, XM_DRAG_NOOP,
+ XM_DROP_SITE_NONE, x_dnd_motif_operations,
XM_DROP_ACTION_DROP_CANCEL);
mmsg.timestamp = dmsg->timestamp;
mmsg.x = 65535;
@@ -1927,6 +2340,44 @@ xm_read_drop_start_reply (const XEvent *msg, xm_drop_start_reply *reply)
}
static int
+xm_read_drop_start_message (const XEvent *msg,
+ xm_drop_start_message *dmsg)
+{
+ const uint8_t *data;
+
+ data = (const uint8_t *) &msg->xclient.data.b[0];
+
+ if ((XM_DRAG_REASON_ORIGINATOR (data[0])
+ != XM_DRAG_ORIGINATOR_INITIATOR)
+ || (XM_DRAG_REASON_CODE (data[0])
+ != XM_DRAG_REASON_DROP_START))
+ return 1;
+
+ dmsg->reason = *(data++);
+ dmsg->byte_order = *(data++);
+ dmsg->side_effects = *(uint16_t *) data;
+ dmsg->timestamp = *(uint32_t *) (data + 2);
+ dmsg->x = *(uint16_t *) (data + 6);
+ dmsg->y = *(uint16_t *) (data + 8);
+ dmsg->index_atom = *(uint32_t *) (data + 10);
+ dmsg->source_window = *(uint32_t *) (data + 14);
+
+ if (dmsg->byte_order != XM_BYTE_ORDER_CUR_FIRST)
+ {
+ SWAPCARD16 (dmsg->side_effects);
+ SWAPCARD32 (dmsg->timestamp);
+ SWAPCARD16 (dmsg->x);
+ SWAPCARD16 (dmsg->y);
+ SWAPCARD32 (dmsg->index_atom);
+ SWAPCARD32 (dmsg->source_window);
+ }
+
+ dmsg->byte_order = XM_BYTE_ORDER_CUR_FIRST;
+
+ return 0;
+}
+
+static int
xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
Window wdesc, xm_drag_receiver_info *rec)
{
@@ -1955,6 +2406,9 @@ xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
{
data = (uint8_t *) tmp_data;
+ if (data[1] > XM_DRAG_PROTOCOL_VERSION)
+ return 1;
+
rec->byteorder = data[0];
rec->protocol = data[1];
rec->protocol_style = data[2];
@@ -1979,6 +2433,40 @@ xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
return !rc;
}
+static int
+xm_read_drag_motion_message (const XEvent *msg,
+ xm_drag_motion_message *dmsg)
+{
+ const uint8_t *data;
+
+ data = (const uint8_t *) &msg->xclient.data.b[0];
+
+ if ((XM_DRAG_REASON_CODE (data[0])
+ != XM_DRAG_REASON_DRAG_MOTION)
+ || (XM_DRAG_REASON_ORIGINATOR (data[0])
+ != XM_DRAG_ORIGINATOR_INITIATOR))
+ return 1;
+
+ dmsg->reason = *(data++);
+ dmsg->byteorder = *(data++);
+ dmsg->side_effects = *(uint16_t *) data;
+ dmsg->timestamp = *(uint32_t *) (data + 2);
+ dmsg->x = *(uint16_t *) (data + 6);
+ dmsg->y = *(uint16_t *) (data + 8);
+
+ if (dmsg->byteorder != XM_BYTE_ORDER_CUR_FIRST)
+ {
+ SWAPCARD16 (dmsg->side_effects);
+ SWAPCARD32 (dmsg->timestamp);
+ SWAPCARD16 (dmsg->x);
+ SWAPCARD16 (dmsg->y);
+ }
+
+ dmsg->byteorder = XM_BYTE_ORDER_CUR_FIRST;
+
+ return 0;
+}
+
static void
x_dnd_send_xm_leave_for_drop (struct x_display_info *dpyinfo,
struct frame *f, Window wdesc,
@@ -1999,23 +2487,57 @@ x_dnd_send_xm_leave_for_drop (struct x_display_info *dpyinfo,
}
static void
-x_dnd_free_toplevels (void)
+x_dnd_free_toplevels (bool display_alive)
{
struct x_client_list_window *last;
struct x_client_list_window *tem = x_dnd_toplevels;
+ ptrdiff_t n_windows, i, buffer_size;
+ Window *destroy_windows;
+ unsigned long *prev_masks;
+ specpdl_ref count;
+ Display *dpy;
+
+ if (!x_dnd_toplevels)
+ /* Probably called inside an IO error handler. */
+ return;
+
+ /* Pacify GCC. */
+ prev_masks = NULL;
+ destroy_windows = NULL;
+ if (display_alive)
+ {
+ buffer_size = 1024;
+ destroy_windows = xmalloc (sizeof *destroy_windows
+ * buffer_size);
+ prev_masks = xmalloc (sizeof *prev_masks *
+ buffer_size);
+ n_windows = 0;
+ }
+
+ block_input ();
while (tem)
{
last = tem;
tem = tem->next;
- x_catch_errors (last->dpy);
- XSelectInput (last->dpy, last->window,
- last->previous_event_mask);
-#ifdef HAVE_XSHAPE
- XShapeSelectInput (last->dpy, last->window, None);
-#endif
- x_uncatch_errors ();
+ if (display_alive)
+ {
+ if (++n_windows >= buffer_size)
+ {
+ buffer_size += 1024;
+ destroy_windows
+ = xrealloc (destroy_windows, (sizeof *destroy_windows
+ * buffer_size));
+ prev_masks
+ = xrealloc (prev_masks, (sizeof *prev_masks
+ * buffer_size));
+ }
+
+ dpy = last->dpy;
+ prev_masks[n_windows - 1] = last->previous_event_mask;
+ destroy_windows[n_windows - 1] = last->window;
+ }
#ifdef HAVE_XSHAPE
if (last->n_input_rects != -1)
@@ -2028,6 +2550,34 @@ x_dnd_free_toplevels (void)
}
x_dnd_toplevels = NULL;
+
+ if (!display_alive)
+ {
+ unblock_input ();
+ return;
+ }
+
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (xfree, destroy_windows);
+ record_unwind_protect_ptr (xfree, prev_masks);
+
+ if (display_alive)
+ {
+ x_catch_errors (dpy);
+
+ for (i = 0; i < n_windows; ++i)
+ {
+ XSelectInput (dpy, destroy_windows[i], prev_masks[i]);
+#ifdef HAVE_XSHAPE
+ XShapeSelectInput (dpy, destroy_windows[i], None);
+#endif
+ }
+
+ x_uncatch_errors ();
+ }
+
+ unbind_to (count, Qnil);
+ unblock_input ();
}
static int
@@ -2102,27 +2652,29 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
toplevels = (Window *) data;
#ifdef USE_XCB
+ USE_SAFE_ALLOCA;
+
window_attribute_cookies
- = alloca (sizeof *window_attribute_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *window_attribute_cookies * nitems);
translate_coordinate_cookies
- = alloca (sizeof *translate_coordinate_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *translate_coordinate_cookies * nitems);
get_property_cookies
- = alloca (sizeof *get_property_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *get_property_cookies * nitems);
xm_property_cookies
- = alloca (sizeof *xm_property_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *xm_property_cookies * nitems);
extent_property_cookies
- = alloca (sizeof *extent_property_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *extent_property_cookies * nitems);
get_geometry_cookies
- = alloca (sizeof *get_geometry_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *get_geometry_cookies * nitems);
#ifdef HAVE_XCB_SHAPE
bounding_rect_cookies
- = alloca (sizeof *bounding_rect_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *bounding_rect_cookies * nitems);
#endif
#ifdef HAVE_XCB_SHAPE_INPUT_RECTS
input_rect_cookies
- = alloca (sizeof *input_rect_cookies * nitems);
+ = SAFE_ALLOCA (sizeof *input_rect_cookies * nitems);
#endif
for (i = 0; i < nitems; ++i)
@@ -2353,7 +2905,9 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
&& xcb_get_property_value_length (xm_property_reply) >= 4)
{
xmdata = xcb_get_property_value (xm_property_reply);
- tem->xm_protocol_style = xmdata[2];
+
+ if (xmdata[1] <= XM_DRAG_PROTOCOL_VERSION)
+ tem->xm_protocol_style = xmdata[2];
}
#endif
@@ -2509,7 +3063,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
}
/* And the common case where there is no input rect and the
- bouding rect equals the window dimensions. */
+ bounding rect equals the window dimensions. */
if (tem->n_input_rects == -1
&& tem->n_bounding_rects == 1
@@ -2602,6 +3156,13 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
#endif
}
+#ifdef USE_XCB
+ SAFE_FREE ();
+#endif
+
+ if (data)
+ XFree (data);
+
return 0;
}
@@ -2611,7 +3172,7 @@ x_dnd_io_error_handler (Display *display)
#ifdef USE_GTK
emacs_abort ();
#else
- longjmp (x_dnd_disconnect_handler, 1);
+ siglongjmp (x_dnd_disconnect_handler, 1);
#endif
}
@@ -2978,7 +3539,6 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
int dest_x, dest_y;
Window child_return, child;
- event.xbutton.type = ButtonPress;
event.xbutton.serial = 0;
event.xbutton.send_event = True;
event.xbutton.display = dpyinfo->display;
@@ -2992,39 +3552,37 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
dest_x = root_x;
dest_y = root_y;
- while (XTranslateCoordinates (dpyinfo->display, child,
- child, root_x, root_y, &dest_x,
- &dest_y, &child_return)
- && child_return != None
- && XTranslateCoordinates (dpyinfo->display, child,
- child_return, root_x, root_y,
- &dest_x, &dest_y, &child))
- {
- child = child_return;
- root_x = dest_x;
- root_y = dest_y;
- }
+ while (XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window,
+ child, root_x, root_y, &dest_x, &dest_y,
+ &child_return)
+ && child_return != None)
+ child = child_return;
if (CONSP (value))
x_own_selection (QPRIMARY, Fnth (make_fixnum (1), value),
frame);
else
- x_own_selection (QPRIMARY, Qnil, frame);
+ error ("Lost ownership of XdndSelection");
event.xbutton.window = child;
+ event.xbutton.subwindow = None;
event.xbutton.x = dest_x;
event.xbutton.y = dest_y;
event.xbutton.state = 0;
event.xbutton.button = 2;
event.xbutton.same_screen = True;
- event.xbutton.time = before + 1;
- event.xbutton.time = before + 2;
x_set_pending_dnd_time (before);
+ event.xbutton.type = ButtonPress;
+ event.xbutton.time = before + 1;
+
XSendEvent (dpyinfo->display, child,
True, ButtonPressMask, &event);
+
event.xbutton.type = ButtonRelease;
+ event.xbutton.time = before + 2;
+
XSendEvent (dpyinfo->display, child,
True, ButtonReleaseMask, &event);
@@ -3057,19 +3615,20 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
XFree (atom_names[i - 1]);
}
- name = XGetAtomName (dpyinfo->display,
- x_dnd_wanted_action);
+ name = x_get_atom_name (dpyinfo, x_dnd_wanted_action,
+ NULL);
if (name)
{
arg = intern (name);
- XFree (name);
+ xfree (name);
}
else
arg = Qnil;
ie.kind = UNSUPPORTED_DROP_EVENT;
ie.code = (unsigned) target_window;
+ ie.modifiers = x_dnd_unsupported_event_level;
ie.arg = list3 (assq_no_quit (QXdndSelection,
dpyinfo->terminal->Vselection_alist),
targets, arg);
@@ -3085,16 +3644,20 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
static Window
x_dnd_get_target_window (struct x_display_info *dpyinfo,
int root_x, int root_y, int *proto_out,
- int *motif_out, Window *toplevel_out)
+ int *motif_out, Window *toplevel_out,
+ bool *was_frame)
{
- Window child_return, child, dummy, proxy;
+ Window child_return, child, proxy;
int dest_x_return, dest_y_return, rc, proto, motif;
+ int parent_x, parent_y;
bool extents_p;
#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2)
Window overlay_window;
XWindowAttributes attrs;
#endif
int wmstate;
+ struct frame *tooltip, *f;
+ bool unrelated;
child_return = dpyinfo->root_window;
dest_x_return = root_x;
@@ -3103,6 +3666,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
proto = -1;
*motif_out = XM_DRAG_STYLE_NONE;
*toplevel_out = None;
+ *was_frame = false;
if (x_dnd_use_toplevels)
{
@@ -3115,10 +3679,21 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
&& FRAME_X_WINDOW (x_dnd_frame) == child)
*motif_out = XM_DRAG_STYLE_NONE;
+ f = x_top_window_to_frame (dpyinfo, child);
+
*toplevel_out = child;
if (child != None)
{
+ if (f)
+ {
+ *was_frame = true;
+ *proto_out = -1;
+ *motif_out = XM_DRAG_STYLE_NONE;
+
+ return child;
+ }
+
#ifndef USE_XCB
proxy = x_dnd_get_window_proxy (dpyinfo, child);
#else
@@ -3161,10 +3736,13 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
dpyinfo->Xatom_NET_WM_CM_Sn) != None)
{
x_catch_errors (dpyinfo->display);
+ XGrabServer (dpyinfo->display);
overlay_window = XCompositeGetOverlayWindow (dpyinfo->display,
dpyinfo->root_window);
XCompositeReleaseOverlayWindow (dpyinfo->display,
dpyinfo->root_window);
+ XUngrabServer (dpyinfo->display);
+
if (!x_had_errors_p (dpyinfo->display))
{
XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs);
@@ -3222,13 +3800,13 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
while (child_return != None)
{
child = child_return;
+ parent_x = dest_x_return;
+ parent_y = dest_y_return;
x_catch_errors (dpyinfo->display);
- rc = XTranslateCoordinates (dpyinfo->display,
- child_return, child_return,
- dest_x_return, dest_y_return,
- &dest_x_return, &dest_y_return,
- &child_return);
+ rc = XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window,
+ child_return, root_x, root_y, &dest_x_return,
+ &dest_y_return, &child_return);
if (x_had_errors_p (dpyinfo->display) || !rc)
{
@@ -3238,6 +3816,35 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
if (child_return)
{
+ /* If child_return is a tooltip frame, look beneath it. We
+ never want to drop anything onto a tooltip frame. */
+
+ tooltip = x_tooltip_window_to_frame (dpyinfo, child_return,
+ &unrelated);
+
+ if (tooltip || unrelated)
+ child_return = x_get_window_below (dpyinfo->display, child_return,
+ parent_x, parent_y, &dest_x_return,
+ &dest_y_return);
+
+ if (!child_return)
+ {
+ x_uncatch_errors ();
+ break;
+ }
+
+ f = x_top_window_to_frame (dpyinfo, child_return);
+
+ if (f)
+ {
+ *proto_out = -1;
+ *motif_out = XM_DRAG_STYLE_NONE;
+ *toplevel_out = child_return;
+ *was_frame = true;
+
+ return child_return;
+ }
+
if (x_dnd_get_wm_state_and_proto (dpyinfo, child_return,
&wmstate, &proto, &motif,
&proxy)
@@ -3266,23 +3873,9 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
return proxy;
}
}
-
- rc = XTranslateCoordinates (dpyinfo->display,
- child, child_return,
- dest_x_return, dest_y_return,
- &dest_x_return, &dest_y_return,
- &dummy);
-
- if (x_had_errors_p (dpyinfo->display) || !rc)
- {
- x_uncatch_errors_after_check ();
- *proto_out = -1;
- *toplevel_out = dpyinfo->root_window;
- return None;
- }
}
- x_uncatch_errors_after_check ();
+ x_uncatch_errors ();
}
#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2)
@@ -3319,10 +3912,13 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
dpyinfo->Xatom_NET_WM_CM_Sn) != None)
{
x_catch_errors (dpyinfo->display);
+ XGrabServer (dpyinfo->display);
overlay_window = XCompositeGetOverlayWindow (dpyinfo->display,
dpyinfo->root_window);
XCompositeReleaseOverlayWindow (dpyinfo->display,
dpyinfo->root_window);
+ XUngrabServer (dpyinfo->display);
+
if (!x_had_errors_p (dpyinfo->display))
{
XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs);
@@ -3456,9 +4052,6 @@ x_dnd_send_enter (struct frame *f, Window target, int supported)
int i;
XEvent msg;
- if (x_top_window_to_frame (dpyinfo, target))
- return;
-
msg.xclient.type = ClientMessage;
msg.xclient.message_type = dpyinfo->Xatom_XdndEnter;
msg.xclient.format = 32;
@@ -3474,12 +4067,16 @@ x_dnd_send_enter (struct frame *f, Window target, int supported)
for (i = 0; i < min (3, x_dnd_n_targets); ++i)
msg.xclient.data.l[i + 2] = x_dnd_targets[i];
- if (x_dnd_n_targets > 3)
+ if (x_dnd_n_targets > 3 && !x_dnd_init_type_lists)
XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dpyinfo->Xatom_XdndTypeList, XA_ATOM, 32,
PropModeReplace, (unsigned char *) x_dnd_targets,
x_dnd_n_targets);
+ /* Now record that the type list has already been set (if required),
+ so we don't have to set it again. */
+ x_dnd_init_type_lists = true;
+
x_catch_errors (dpyinfo->display);
XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
x_uncatch_errors ();
@@ -3493,23 +4090,6 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
{
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
XEvent msg;
- struct frame *target_frame;
- int dest_x, dest_y;
- Window child_return;
-
- target_frame = x_top_window_to_frame (dpyinfo, target);
-
- if (target_frame && XTranslateCoordinates (dpyinfo->display,
- dpyinfo->root_window,
- FRAME_X_WINDOW (target_frame),
- root_x, root_y, &dest_x,
- &dest_y, &child_return))
- {
- x_dnd_movement_frame = target_frame;
- x_dnd_movement_x = dest_x;
- x_dnd_movement_y = dest_y;
- return;
- }
if (target == x_dnd_mouse_rect_target
&& x_dnd_mouse_rect.width
@@ -3533,7 +4113,7 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
if (supported >= 5)
{
- if (button >= 4 && button <= 8)
+ if (button >= 4 && button <= 7)
{
msg.xclient.data.l[1] |= (1 << 9);
msg.xclient.data.l[1] |= (button - 4) << 7;
@@ -3567,9 +4147,6 @@ x_dnd_send_leave (struct frame *f, Window target)
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
XEvent msg;
- if (x_top_window_to_frame (dpyinfo, target))
- return;
-
msg.xclient.type = ClientMessage;
msg.xclient.message_type = dpyinfo->Xatom_XdndLeave;
msg.xclient.format = 32;
@@ -3589,74 +4166,17 @@ static bool
x_dnd_send_drop (struct frame *f, Window target, Time timestamp,
int supported)
{
- struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+ struct x_display_info *dpyinfo;
XEvent msg;
- struct input_event ie;
- struct frame *self_frame;
- int root_x, root_y, win_x, win_y, i;
- unsigned int mask;
- Window root, child;
- Lisp_Object lval;
- char **atom_names;
- char *name;
-
- self_frame = x_top_window_to_frame (dpyinfo, target);
- if (self_frame)
- {
- if (!x_dnd_allow_current_frame
- && self_frame == x_dnd_frame)
- return false;
-
- /* Send a special drag-and-drop event when dropping on top of an
- Emacs frame to avoid all the overhead involved with sending
- client events. */
- EVENT_INIT (ie);
-
- if (XQueryPointer (dpyinfo->display, FRAME_X_WINDOW (self_frame),
- &root, &child, &root_x, &root_y, &win_x, &win_y,
- &mask))
- {
- ie.kind = DRAG_N_DROP_EVENT;
- XSETFRAME (ie.frame_or_window, self_frame);
-
- lval = Qnil;
- atom_names = alloca (x_dnd_n_targets * sizeof *atom_names);
- name = XGetAtomName (dpyinfo->display, x_dnd_wanted_action);
-
- if (!XGetAtomNames (dpyinfo->display, x_dnd_targets,
- x_dnd_n_targets, atom_names))
- {
- XFree (name);
- return false;
- }
-
- for (i = x_dnd_n_targets; i != 0; --i)
- {
- lval = Fcons (intern (atom_names[i - 1]), lval);
- XFree (atom_names[i - 1]);
- }
-
- lval = Fcons (intern (name), lval);
- lval = Fcons (QXdndSelection, lval);
- ie.arg = lval;
- ie.timestamp = CurrentTime;
-
- XSETINT (ie.x, win_x);
- XSETINT (ie.y, win_y);
-
- XFree (name);
- kbd_buffer_store_event (&ie);
-
- return false;
- }
- }
- else if (x_dnd_action == None)
+ if (x_dnd_action == None)
{
x_dnd_send_leave (f, target);
return false;
}
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+
msg.xclient.type = ClientMessage;
msg.xclient.message_type = dpyinfo->Xatom_XdndDrop;
msg.xclient.format = 32;
@@ -3676,14 +4196,48 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp,
return true;
}
-void
+static void
x_set_dnd_targets (Atom *targets, int ntargets)
{
if (x_dnd_targets)
xfree (x_dnd_targets);
- x_dnd_targets = targets;
+ block_input ();
+ x_dnd_targets = xmalloc (sizeof *targets * ntargets);
x_dnd_n_targets = ntargets;
+
+ memcpy (x_dnd_targets, targets,
+ sizeof *targets * ntargets);
+ unblock_input ();
+}
+
+static void
+x_free_dnd_targets (void)
+{
+ if (!x_dnd_targets)
+ return;
+
+ xfree (x_dnd_targets);
+ x_dnd_targets = NULL;
+ x_dnd_n_targets = 0;
+}
+
+static void
+x_clear_dnd_monitors (void)
+{
+ x_dnd_monitors = Qnil;
+}
+
+static void
+x_free_dnd_toplevels (void)
+{
+ if (!x_dnd_use_toplevels || !x_dnd_toplevels)
+ return;
+
+ /* If the display is deleted, x_dnd_toplevels will already be
+ NULL, so we can always assume the display is alive here. */
+
+ x_dnd_free_toplevels (true);
}
static void
@@ -3716,9 +4270,7 @@ x_dnd_cleanup_drag_and_drop (void *frame)
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
XM_DROP_ACTION_DROP_CANCEL);
dmsg.x = 0;
dmsg.y = 0;
@@ -3739,12 +4291,8 @@ x_dnd_cleanup_drag_and_drop (void *frame)
x_dnd_in_progress = false;
}
- x_set_dnd_targets (NULL, 0);
x_dnd_waiting_for_finish = false;
- if (x_dnd_use_toplevels)
- x_dnd_free_toplevels ();
-
FRAME_DISPLAY_INFO (f)->grabbed = 0;
#ifdef USE_GTK
current_hold_quit = NULL;
@@ -3768,11 +4316,123 @@ x_dnd_cleanup_drag_and_drop (void *frame)
if (x_dnd_motif_setup_p)
XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+
+ /* Remove any type list set as well. */
+ if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
+ XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
+
unblock_input ();
x_dnd_frame = NULL;
}
+static void
+x_dnd_note_self_position (struct x_display_info *dpyinfo, Window target,
+ unsigned short root_x, unsigned short root_y)
+{
+ struct frame *f;
+ int dest_x, dest_y;
+ Window child_return;
+
+ f = x_top_window_to_frame (dpyinfo, target);
+
+ if (f && XTranslateCoordinates (dpyinfo->display,
+ dpyinfo->root_window,
+ FRAME_X_WINDOW (f),
+ root_x, root_y, &dest_x,
+ &dest_y, &child_return))
+ {
+ x_dnd_movement_frame = f;
+ x_dnd_movement_x = dest_x;
+ x_dnd_movement_y = dest_y;
+
+ return;
+ }
+}
+
+static void
+x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target,
+ unsigned short root_x, unsigned short root_y,
+ Time timestamp)
+{
+ struct input_event ie;
+ struct frame *f;
+ Lisp_Object lval;
+ char **atom_names;
+ char *name;
+ int win_x, win_y, i;
+ Window dummy;
+
+ if (!x_dnd_allow_current_frame
+ && (FRAME_OUTER_WINDOW (x_dnd_frame)
+ == target))
+ return;
+
+ f = x_top_window_to_frame (dpyinfo, target);
+
+ if (!f)
+ return;
+
+ if (NILP (Vx_dnd_native_test_function))
+ return;
+
+ if (!XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window,
+ FRAME_X_WINDOW (f), root_x, root_y,
+ &win_x, &win_y, &dummy))
+ return;
+
+ /* Emacs can't respond to DND events inside the nested event loop,
+ so when dragging items to itself, call the test function
+ manually. */
+
+ XSETFRAME (lval, f);
+ x_dnd_action = None;
+ x_dnd_action_symbol
+ = safe_call2 (Vx_dnd_native_test_function,
+ Fposn_at_x_y (make_fixnum (win_x),
+ make_fixnum (win_y),
+ lval, Qnil),
+ x_atom_to_symbol (dpyinfo,
+ x_dnd_wanted_action));
+
+ if (!SYMBOLP (x_dnd_action_symbol))
+ return;
+
+ EVENT_INIT (ie);
+
+ ie.kind = DRAG_N_DROP_EVENT;
+ XSETFRAME (ie.frame_or_window, f);
+
+ lval = Qnil;
+ atom_names = alloca (x_dnd_n_targets * sizeof *atom_names);
+ name = x_get_atom_name (dpyinfo, x_dnd_wanted_action, NULL);
+
+ if (!XGetAtomNames (dpyinfo->display, x_dnd_targets,
+ x_dnd_n_targets, atom_names))
+ {
+ xfree (name);
+ return;
+ }
+
+ for (i = x_dnd_n_targets; i != 0; --i)
+ {
+ lval = Fcons (intern (atom_names[i - 1]), lval);
+ XFree (atom_names[i - 1]);
+ }
+
+ lval = Fcons (intern (name), lval);
+ lval = Fcons (QXdndSelection, lval);
+ ie.arg = lval;
+ ie.timestamp = timestamp;
+
+ XSETINT (ie.x, win_x);
+ XSETINT (ie.y, win_y);
+
+ xfree (name);
+ kbd_buffer_store_event (&ie);
+}
+
/* Flush display of frame F. */
static void
@@ -3967,11 +4627,16 @@ x_update_opaque_region (struct frame *f, XEvent *configure)
(unsigned char *) &opaque_region, 4);
else
{
- object_class = G_OBJECT_GET_CLASS (FRAME_GTK_OUTER_WIDGET (f));
- class = GTK_WIDGET_CLASS (object_class);
+ /* This causes child frames to not update correctly for an
+ unknown reason. (bug#55779) */
+ if (!FRAME_PARENT_FRAME (f))
+ {
+ object_class = G_OBJECT_GET_CLASS (FRAME_GTK_OUTER_WIDGET (f));
+ class = GTK_WIDGET_CLASS (object_class);
- if (class->style_updated)
- class->style_updated (FRAME_GTK_OUTER_WIDGET (f));
+ if (class->style_updated)
+ class->style_updated (FRAME_GTK_OUTER_WIDGET (f));
+ }
}
#endif
unblock_input ();
@@ -4062,27 +4727,48 @@ x_free_xi_devices (struct x_display_info *dpyinfo)
unblock_input ();
}
+#ifdef HAVE_XINPUT2_1
+struct xi_known_valuator
+{
+ /* The current value of this valuator. */
+ double current_value;
+
+ /* The number of the valuator. */
+ int number;
+
+ /* The next valuator whose value we already know. */
+ struct xi_known_valuator *next;
+};
+#endif
+
static void
xi_populate_device_from_info (struct xi_device_t *xi_device,
XIDeviceInfo *device)
{
#ifdef HAVE_XINPUT2_1
struct xi_scroll_valuator_t *valuator;
+ struct xi_known_valuator *values, *tem;
int actual_valuator_count;
XIScrollClassInfo *info;
+ XIValuatorClassInfo *val_info;
#endif
+ int c;
#ifdef HAVE_XINPUT2_2
XITouchClassInfo *touch_info;
#endif
- int c;
+
+#ifdef HAVE_XINPUT2_1
+ USE_SAFE_ALLOCA;
+#endif
xi_device->device_id = device->deviceid;
xi_device->grab = 0;
#ifdef HAVE_XINPUT2_1
actual_valuator_count = 0;
- xi_device->valuators =
- xmalloc (sizeof *xi_device->valuators * device->num_classes);
+ xi_device->valuators = xmalloc (sizeof *xi_device->valuators
+ * device->num_classes);
+ values = NULL;
#endif
#ifdef HAVE_XINPUT2_2
xi_device->touchpoints = NULL;
@@ -4114,7 +4800,21 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
break;
}
+
+ case XIValuatorClass:
+ {
+ val_info = (XIValuatorClassInfo *) device->classes[c];
+ tem = SAFE_ALLOCA (sizeof *tem);
+
+ tem->next = values;
+ tem->number = val_info->number;
+ tem->current_value = val_info->value;
+
+ values = tem;
+ break;
+ }
#endif
+
#ifdef HAVE_XINPUT2_2
case XITouchClass:
{
@@ -4129,6 +4829,25 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
#ifdef HAVE_XINPUT2_1
xi_device->scroll_valuator_count = actual_valuator_count;
+
+ /* Now look through all the valuators whose values are already known
+ and populate our client-side records with their current
+ values. */
+
+ for (tem = values; values; values = values->next)
+ {
+ for (c = 0; c < xi_device->scroll_valuator_count; ++c)
+ {
+ if (xi_device->valuators[c].number == tem->number)
+ {
+ xi_device->valuators[c].invalid_p = false;
+ xi_device->valuators[c].current_value = tem->current_value;
+ xi_device->valuators[c].pending_enter_reset = true;
+ }
+ }
+ }
+
+ SAFE_FREE ();
#endif
}
@@ -4242,6 +4961,7 @@ x_get_scroll_valuator_delta (struct x_display_info *dpyinfo,
}
}
+ *valuator_return = NULL;
return DBL_MAX;
}
@@ -5305,6 +6025,20 @@ x_set_frame_alpha (struct frame *f)
unsigned long opac;
Window parent;
+#ifndef USE_XCB
+ unsigned char *data = NULL;
+ Atom actual;
+ int rc, format;
+ unsigned long n, left;
+ unsigned long value;
+#else
+ xcb_get_property_cookie_t opacity_cookie;
+ xcb_get_property_reply_t *opacity_reply;
+ xcb_generic_error_t *error;
+ bool rc;
+ uint32_t value;
+#endif
+
if (dpyinfo->highlight_frame == f)
alpha = f->alpha[0];
else
@@ -5343,19 +6077,22 @@ x_set_frame_alpha (struct frame *f)
/* return unless necessary */
{
- unsigned char *data = NULL;
- Atom actual;
- int rc, format;
- unsigned long n, left;
-
+#ifndef USE_XCB
rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
0, 1, False, XA_CARDINAL,
&actual, &format, &n, &left,
&data);
- if (rc == Success && actual != None && data)
+ if (rc == Success && actual != None
+ && n && format == XA_CARDINAL && data)
{
- unsigned long value = *(unsigned long *) data;
+ value = *(unsigned long *) data;
+
+ /* Xlib sign-extends values greater than 0x7fffffff on 64-bit
+ machines. Get the low bits by ourself. */
+
+ value &= 0xffffffff;
+
if (value == opac)
{
x_uncatch_errors ();
@@ -5366,6 +6103,37 @@ x_set_frame_alpha (struct frame *f)
if (data)
XFree (data);
+#else
+ /* Avoid the confusing Xlib sign-extension mess by using XCB
+ instead. */
+ opacity_cookie
+ = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) win,
+ (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity,
+ XCB_ATOM_CARDINAL, 0, 1);
+ opacity_reply
+ = xcb_get_property_reply (dpyinfo->xcb_connection,
+ opacity_cookie, &error);
+
+ rc = opacity_reply;
+
+ if (!opacity_reply)
+ free (error);
+ else
+ {
+ rc = (opacity_reply->format == 32
+ && opacity_reply->type == XCB_ATOM_CARDINAL
+ && (xcb_get_property_value_length (opacity_reply) >= 4));
+
+ if (rc)
+ value = *(uint32_t *) xcb_get_property_value (opacity_reply);
+ }
+
+ if (opacity_reply)
+ free (opacity_reply);
+
+ if (rc && value == opac)
+ return;
+#endif
}
XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
@@ -5504,6 +6272,15 @@ show_back_buffer (struct frame *f)
static void
x_flip_and_flush (struct frame *f)
{
+ /* Flipping buffers requires a working connection to the X server,
+ which isn't always present if `inhibit-redisplay' is t, since
+ this can be called from the IO error handler. */
+ if (!NILP (Vinhibit_redisplay)
+ /* This has to work for tooltip frames, however, and redisplay
+ cannot happen when they are being flushed anyway. (bug#55519) */
+ && !FRAME_TOOLTIP_P (f))
+ return;
+
block_input ();
#ifdef HAVE_XDBE
if (FRAME_X_NEED_BUFFER_FLIP (f))
@@ -5745,7 +6522,8 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
}
static void
-x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)
+x_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
+ struct draw_fringe_bitmap_params *p)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
Display *display = FRAME_X_DISPLAY (f);
@@ -5762,15 +6540,21 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
mono-displays, the fill style may have been changed to
FillSolid in x_draw_glyph_string_background. */
if (face->stipple)
- XSetFillStyle (display, face->gc, FillOpaqueStippled);
- else
- XSetBackground (display, face->gc, face->background);
-
- x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
- true);
+ {
+ XSetFillStyle (display, face->gc, FillOpaqueStippled);
+ x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
+ true);
+ XSetFillStyle (display, face->gc, FillSolid);
- if (!face->stipple)
- XSetForeground (display, face->gc, face->foreground);
+ row->stipple_p = true;
+ }
+ else
+ {
+ XSetBackground (display, face->gc, face->background);
+ x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
+ true);
+ XSetForeground (display, face->gc, face->foreground);
+ }
}
#ifdef USE_CAIRO
@@ -6231,6 +7015,31 @@ x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
x_clear_rectangle (s->f, s->gc, x, y, w, h, s->hl != DRAW_CURSOR);
}
+#ifndef USE_CAIRO
+
+static void
+x_clear_point (struct frame *f, GC gc, int x, int y,
+ bool respect_alpha_background)
+{
+ XGCValues xgcv;
+ Display *dpy;
+
+ dpy = FRAME_X_DISPLAY (f);
+
+ if (f->alpha_background != 1.0
+ && respect_alpha_background)
+ {
+ x_clear_rectangle (f, gc, x, y, 1, 1, true);
+ return;
+ }
+
+ XGetGCValues (dpy, gc, GCBackground | GCForeground, &xgcv);
+ XSetForeground (dpy, gc, xgcv.background);
+ XDrawPoint (dpy, FRAME_X_DRAWABLE (f), gc, x, y);
+ XSetForeground (dpy, gc, xgcv.foreground);
+}
+
+#endif
/* Draw the background of glyph_string S. If S->background_filled_p
is non-zero don't draw it. FORCE_P non-zero means draw the
@@ -6561,6 +7370,10 @@ x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
glyph->ascent + glyph->descent - 1);
x += glyph->pixel_width;
}
+
+ /* Defend against hypothetical bad code elsewhere that uses
+ s->char2b after this function returns. */
+ s->char2b = NULL;
}
#ifdef USE_X_TOOLKIT
@@ -6923,21 +7736,21 @@ x_hash_string_ignore_case (const char *string)
/* On frame F, translate the color name to RGB values. Use cached
information, if possible.
- Note that there is currently no way to clean old entries out of the
- cache. However, it is limited to names in the server's database,
- and names we've actually looked up; list-colors-display is probably
- the most color-intensive case we're likely to hit. */
+ If too many entries are placed in the cache, the least recently
+ used entries are removed. */
Status
x_parse_color (struct frame *f, const char *color_name,
XColor *color)
{
unsigned short r, g, b;
- Display *dpy = FRAME_X_DISPLAY (f);
- Colormap cmap = FRAME_X_COLORMAP (f);
+ Display *dpy;
+ Colormap cmap;
struct x_display_info *dpyinfo;
- struct color_name_cache_entry *cache_entry;
+ struct color_name_cache_entry *cache_entry, *last;
+ struct color_name_cache_entry *next, *color_entry;
unsigned int hash, idx;
+ int rc, i;
/* Don't pass #RGB strings directly to XParseColor, because that
follows the X convention of zero-extending each channel
@@ -6949,37 +7762,94 @@ x_parse_color (struct frame *f, const char *color_name,
color->red = r;
color->green = g;
color->blue = b;
+
return 1;
}
+ /* Some X servers send BadValue on empty color names. */
+ if (!strlen (color_name))
+ return 0;
+
+ cmap = FRAME_X_COLORMAP (f);
+ dpy = FRAME_X_DISPLAY (f);
dpyinfo = FRAME_DISPLAY_INFO (f);
+
hash = x_hash_string_ignore_case (color_name);
idx = hash % dpyinfo->color_names_size;
- for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names[idx];
+ last = NULL;
+
+ for (cache_entry = dpyinfo->color_names[idx];
cache_entry; cache_entry = cache_entry->next)
{
if (!xstrcasecmp (cache_entry->name, color_name))
{
- *color = cache_entry->rgb;
- return 1;
+ /* Move recently used entries to the start of the color
+ cache. */
+
+ if (last)
+ {
+ last->next = cache_entry->next;
+ cache_entry->next = dpyinfo->color_names[idx];
+
+ dpyinfo->color_names[idx] = cache_entry;
+ }
+
+ if (cache_entry->valid)
+ *color = cache_entry->rgb;
+
+ return cache_entry->valid;
}
- }
- /* Some X servers send BadValue on empty color names. */
- if (!strlen (color_name))
- return 0;
+ last = cache_entry;
+ }
- if (XParseColor (dpy, cmap, color_name, color) == 0)
- /* No caching of negative results, currently. */
- return 0;
+ block_input ();
+ rc = XParseColor (dpy, cmap, color_name, color);
+ unblock_input ();
cache_entry = xzalloc (sizeof *cache_entry);
- cache_entry->rgb = *color;
+ dpyinfo->color_names_length[idx] += 1;
+
+ if (rc)
+ cache_entry->rgb = *color;
+
+ cache_entry->valid = rc;
cache_entry->name = xstrdup (color_name);
- cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names[idx];
- FRAME_DISPLAY_INFO (f)->color_names[idx] = cache_entry;
- return 1;
+ cache_entry->next = dpyinfo->color_names[idx];
+
+ dpyinfo->color_names[idx] = cache_entry;
+
+ /* Don't let the color cache become too big. */
+ if (dpyinfo->color_names_length[idx] > (x_color_cache_bucket_size > 0
+ ? x_color_cache_bucket_size : 128))
+ {
+ i = 0;
+
+ for (last = dpyinfo->color_names[idx]; last; last = last->next)
+ {
+ if (++i == (x_color_cache_bucket_size > 0
+ ? x_color_cache_bucket_size : 128))
+ {
+ next = last->next;
+ last->next = NULL;
+
+ for (color_entry = next; color_entry; color_entry = last)
+ {
+ last = color_entry->next;
+
+ xfree (color_entry->name);
+ xfree (color_entry);
+
+ dpyinfo->color_names_length[idx] -= 1;
+ }
+
+ return rc;
+ }
+ }
+ }
+
+ return rc;
}
@@ -7358,20 +8228,62 @@ x_setup_relief_colors (struct glyph_string *s)
}
}
+#ifndef USE_CAIRO
+static void
+x_fill_triangle (struct frame *f, GC gc, XPoint point1,
+ XPoint point2, XPoint point3)
+{
+ XPoint abc[3];
+
+ abc[0] = point1;
+ abc[1] = point2;
+ abc[2] = point3;
+
+ XFillPolygon (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
+ gc, abc, 3, Convex, CoordModeOrigin);
+}
+
+static XPoint
+x_make_point (int x, int y)
+{
+ XPoint pt;
+
+ pt.x = x;
+ pt.y = y;
+
+ return pt;
+}
+
+static bool
+x_inside_rect_p (XRectangle *rects, int nrects, int x, int y)
+{
+ int i;
+
+ for (i = 0; i < nrects; ++i)
+ {
+ if (x >= rects[i].x && y >= rects[i].y
+ && x < rects[i].x + rects[i].width
+ && y < rects[i].y + rects[i].height)
+ return true;
+ }
+
+ return false;
+}
+#endif
/* Draw a relief on frame F inside the rectangle given by LEFT_X,
- TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
- to draw, it must be >= 0. RAISED_P means draw a raised
- relief. LEFT_P means draw a relief on the left side of
- the rectangle. RIGHT_P means draw a relief on the right
- side of the rectangle. CLIP_RECT is the clipping rectangle to use
- when drawing. */
+ TOP_Y, RIGHT_X, and BOTTOM_Y. VWIDTH and HWIDTH are respectively
+ the thickness of the vertical relief (left and right) and
+ horizontal relief (top and bottom) to draw, it must be >= 0.
+ RAISED_P means draw a raised relief. LEFT_P means draw a relief on
+ the left side of the rectangle. RIGHT_P means draw a relief on the
+ right side of the rectangle. CLIP_RECT is the clipping rectangle
+ to use when drawing. */
static void
-x_draw_relief_rect (struct frame *f,
- int left_x, int top_y, int right_x, int bottom_y,
- int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p,
- bool left_p, bool right_p,
+x_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x,
+ int bottom_y, int hwidth, int vwidth, bool raised_p,
+ bool top_p, bool bot_p, bool left_p, bool right_p,
XRectangle *clip_rect)
{
#ifdef USE_CAIRO
@@ -7447,90 +8359,118 @@ x_draw_relief_rect (struct frame *f,
x_reset_clip_rectangles (f, top_left_gc);
x_reset_clip_rectangles (f, bottom_right_gc);
#else
- Display *dpy = FRAME_X_DISPLAY (f);
- Drawable drawable = FRAME_X_DRAWABLE (f);
- int i;
- GC gc;
-
- if (raised_p)
- gc = f->output_data.x->white_relief.gc;
- else
- gc = f->output_data.x->black_relief.gc;
- XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
+ GC gc, white_gc, black_gc, normal_gc;
+ Drawable drawable;
+ Display *dpy;
/* This code is more complicated than it has to be, because of two
minor hacks to make the boxes look nicer: (i) if width > 1, draw
the outermost line using the black relief. (ii) Omit the four
corner pixels. */
- /* Top. */
- if (top_p)
- {
- if (hwidth == 1)
- XDrawLine (dpy, drawable, gc,
- left_x + left_p, top_y,
- right_x + !right_p, top_y);
+ white_gc = f->output_data.x->white_relief.gc;
+ black_gc = f->output_data.x->black_relief.gc;
+ normal_gc = f->output_data.x->normal_gc;
- for (i = 1; i < hwidth; ++i)
- XDrawLine (dpy, drawable, gc,
- left_x + i * left_p, top_y + i,
- right_x + 1 - i * right_p, top_y + i);
- }
+ drawable = FRAME_X_DRAWABLE (f);
+ dpy = FRAME_X_DISPLAY (f);
- /* Left. */
- if (left_p)
- {
- if (vwidth == 1)
- XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y);
+ x_set_clip_rectangles (f, white_gc, clip_rect, 1);
+ x_set_clip_rectangles (f, black_gc, clip_rect, 1);
- for (i = 1; i < vwidth; ++i)
- XDrawLine (dpy, drawable, gc,
- left_x + i, top_y + (i + 1) * top_p,
- left_x + i, bottom_y + 1 - (i + 1) * bot_p);
- }
-
- XSetClipMask (dpy, gc, None);
if (raised_p)
- gc = f->output_data.x->black_relief.gc;
+ gc = white_gc;
else
- gc = f->output_data.x->white_relief.gc;
- XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
+ gc = black_gc;
- /* Outermost top line. */
- if (top_p && hwidth > 1)
- XDrawLine (dpy, drawable, gc,
- left_x + left_p, top_y,
- right_x + !right_p, top_y);
+ /* Draw lines. */
- /* Outermost left line. */
- if (left_p && vwidth > 1)
- XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y);
+ if (top_p)
+ x_fill_rectangle (f, gc, left_x, top_y,
+ right_x - left_x + 1, hwidth,
+ false);
+
+ if (left_p)
+ x_fill_rectangle (f, gc, left_x, top_y, vwidth,
+ bottom_y - top_y + 1, false);
+
+ if (raised_p)
+ gc = black_gc;
+ else
+ gc = white_gc;
- /* Bottom. */
if (bot_p)
+ x_fill_rectangle (f, gc, left_x, bottom_y - hwidth + 1,
+ right_x - left_x + 1, hwidth, false);
+
+ if (right_p)
+ x_fill_rectangle (f, gc, right_x - vwidth + 1, top_y,
+ vwidth, bottom_y - top_y + 1, false);
+
+ /* Draw corners. */
+
+ if (bot_p && left_p)
+ x_fill_triangle (f, raised_p ? white_gc : black_gc,
+ x_make_point (left_x, bottom_y - hwidth),
+ x_make_point (left_x + vwidth, bottom_y - hwidth),
+ x_make_point (left_x, bottom_y));
+
+ if (top_p && right_p)
+ x_fill_triangle (f, raised_p ? white_gc : black_gc,
+ x_make_point (right_x - vwidth, top_y),
+ x_make_point (right_x, top_y),
+ x_make_point (right_x - vwidth, top_y + hwidth));
+
+ /* Draw outer line. */
+
+ if (top_p && left_p && bot_p && right_p
+ && hwidth > 1 && vwidth > 1)
+ x_draw_rectangle (f, black_gc, left_x, top_y,
+ right_x - left_x, bottom_y - top_y);
+ else
{
- if (hwidth >= 1)
- XDrawLine (dpy, drawable, gc,
- left_x + left_p, bottom_y,
- right_x + !right_p, bottom_y);
+ if (top_p && hwidth > 1)
+ XDrawLine (dpy, drawable, black_gc, left_x, top_y,
+ right_x + 1, top_y);
- for (i = 1; i < hwidth; ++i)
- XDrawLine (dpy, drawable, gc,
- left_x + i * left_p, bottom_y - i,
- right_x + 1 - i * right_p, bottom_y - i);
+ if (bot_p && hwidth > 1)
+ XDrawLine (dpy, drawable, black_gc, left_x, bottom_y,
+ right_x + 1, bottom_y);
+
+ if (left_p && vwidth > 1)
+ XDrawLine (dpy, drawable, black_gc, left_x, top_y,
+ left_x, bottom_y + 1);
+
+ if (right_p && vwidth > 1)
+ XDrawLine (dpy, drawable, black_gc, right_x, top_y,
+ right_x, bottom_y + 1);
}
- /* Right. */
- if (right_p)
+ /* Erase corners. */
+
+ if (hwidth > 1 && vwidth > 1)
{
- for (i = 0; i < vwidth; ++i)
- XDrawLine (dpy, drawable, gc,
- right_x - i, top_y + (i + 1) * top_p,
- right_x - i, bottom_y + 1 - (i + 1) * bot_p);
- }
+ if (left_p && top_p && x_inside_rect_p (clip_rect, 1,
+ left_x, top_y))
+ /* This should respect `alpha-background' since it's being
+ cleared with the background color of the frame. */
+ x_clear_point (f, normal_gc, left_x, top_y, true);
- x_reset_clip_rectangles (f, gc);
+ if (left_p && bot_p && x_inside_rect_p (clip_rect, 1,
+ left_x, bottom_y))
+ x_clear_point (f, normal_gc, left_x, bottom_y, true);
+
+ if (right_p && top_p && x_inside_rect_p (clip_rect, 1,
+ right_x, top_y))
+ x_clear_point (f, normal_gc, right_x, top_y, true);
+ if (right_p && bot_p && x_inside_rect_p (clip_rect, 1,
+ right_x, bottom_y))
+ x_clear_point (f, normal_gc, right_x, bottom_y, true);
+ }
+
+ x_reset_clip_rectangles (f, white_gc);
+ x_reset_clip_rectangles (f, black_gc);
#endif
}
@@ -8039,6 +8979,9 @@ x_draw_image_glyph_string (struct glyph_string *s)
|| s->img->pixmap == 0
|| s->width != s->background_width)
{
+ if (s->stippled_p)
+ s->row->stipple_p = true;
+
#ifndef USE_CAIRO
if (s->img->mask)
{
@@ -8219,6 +9162,8 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
XSetFillStyle (display, gc, FillOpaqueStippled);
x_fill_rectangle (s->f, gc, x, y, w, h, true);
XSetFillStyle (display, gc, FillSolid);
+
+ s->row->stipple_p = true;
}
else
{
@@ -8245,8 +9190,13 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
background_width -= text_left_x - x;
x = text_left_x;
}
+
+ if (!s->row->stipple_p)
+ s->row->stipple_p = s->stippled_p;
+
if (background_width > 0)
- x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
+ x_draw_glyph_string_bg_rect (s, x, s->y,
+ background_width, s->height);
}
s->background_filled_p = true;
@@ -8522,13 +9472,13 @@ x_draw_glyph_string (struct glyph_string *s)
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
- = (!(NILP (val) || EQ (val, Qunbound))
+ = (!(NILP (val) || BASE_EQ (val, Qunbound))
|| s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
use_underline_position_properties
- = !(NILP (val) || EQ (val, Qunbound));
+ = !(NILP (val) || BASE_EQ (val, Qunbound));
/* Get the underline thickness. Default is 1 pixel. */
if (font && font->underline_thickness > 0)
@@ -8560,7 +9510,7 @@ x_draw_glyph_string (struct glyph_string *s)
}
/* Ignore minimum_offset if the amount of pixels was
- explictly specified. */
+ explicitly specified. */
if (!s->face->underline_pixels_above_descent_line)
position = max (position, minimum_offset);
}
@@ -8695,6 +9645,14 @@ x_draw_glyph_string (struct glyph_string *s)
/* Reset clipping. */
x_reset_clip_rectangles (s->f, s->gc);
s->num_clips = 0;
+
+ /* Set the stippled flag that tells redisplay whether or not a
+ stipple was actually draw. */
+
+ if (s->first_glyph->type != STRETCH_GLYPH
+ && s->first_glyph->type != IMAGE_GLYPH
+ && !s->row->stipple_p)
+ s->row->stipple_p = s->stippled_p;
}
/* Shift display to make room for inserted glyphs. */
@@ -8724,13 +9682,15 @@ x_delete_glyphs (struct frame *f, int n)
/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
If they are <= 0, this is probably an error. */
-MAYBE_UNUSED static void
+#if defined USE_GTK || !defined USE_CAIRO
+static void
x_clear_area1 (Display *dpy, Window window,
int x, int y, int width, int height, int exposures)
{
eassert (width > 0 && height > 0);
XClearArea (dpy, window, x, y, width, height, exposures);
}
+#endif
void
x_clear_area (struct frame *f, int x, int y, int width, int height)
@@ -9439,8 +10399,24 @@ x_toggle_visible_pointer (struct frame *f, bool invisible)
if (dpyinfo->invisible_cursor == None)
dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
+#ifndef HAVE_XFIXES
if (dpyinfo->invisible_cursor == None)
invisible = false;
+#else
+ /* But if Xfixes is available, try using it instead. */
+ if (dpyinfo->invisible_cursor == None)
+ {
+ if (x_probe_xfixes_extension (dpyinfo))
+ {
+ dpyinfo->fixes_pointer_blanking = true;
+ xfixes_toggle_visible_pointer (f, invisible);
+
+ return;
+ }
+ else
+ invisible = false;
+ }
+#endif
if (invisible)
XDefineCursor (dpyinfo->display, FRAME_X_WINDOW (f),
@@ -9588,6 +10564,67 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
return 0;
}
+/* Like x_any_window_to_frame but only try to find tooltip frames.
+
+ If wdesc is a toolkit tooltip without an associated frame, set
+ UNRELATED_TOOLTIP_P to true. Otherwise, set it to false. */
+static struct frame *
+x_tooltip_window_to_frame (struct x_display_info *dpyinfo,
+ Window wdesc, bool *unrelated_tooltip_p)
+{
+ Lisp_Object tail, frame;
+ struct frame *f;
+#ifdef USE_GTK
+ GtkWidget *widget;
+ GdkWindow *tooltip_window;
+#endif
+
+ *unrelated_tooltip_p = false;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ f = XFRAME (frame);
+
+ if (FRAME_X_P (f) && FRAME_TOOLTIP_P (f)
+ && FRAME_DISPLAY_INFO (f) == dpyinfo
+ && FRAME_X_WINDOW (f) == wdesc)
+ return f;
+
+#ifdef USE_GTK
+ if (!FRAME_X_P (f))
+ continue;
+
+ if (FRAME_X_OUTPUT (f)->ttip_window)
+ widget = GTK_WIDGET (FRAME_X_OUTPUT (f)->ttip_window);
+ else
+ widget = NULL;
+
+ if (widget)
+ tooltip_window = gtk_widget_get_window (widget);
+ else
+ tooltip_window = NULL;
+
+#ifdef HAVE_GTK3
+ if (tooltip_window
+ && (gdk_x11_window_get_xid (tooltip_window) == wdesc))
+ {
+ *unrelated_tooltip_p = true;
+ break;
+ }
+#else
+ if (tooltip_window
+ && (GDK_WINDOW_XID (tooltip_window) == wdesc))
+ {
+ *unrelated_tooltip_p = true;
+ break;
+ }
+#endif
+#endif
+ }
+
+ return NULL;
+}
+
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
/* Like x_window_to_frame but also compares the window with the widget's
@@ -9742,8 +10779,11 @@ static void
x_next_event_from_any_display (XEvent *event)
{
struct x_display_info *dpyinfo;
- fd_set fds;
- int fd, maxfd;
+ fd_set fds, rfds;
+ int fd, maxfd, rc;
+
+ rc = -1;
+ FD_ZERO (&rfds);
while (true)
{
@@ -9753,47 +10793,113 @@ x_next_event_from_any_display (XEvent *event)
for (dpyinfo = x_display_list; dpyinfo;
dpyinfo = dpyinfo->next)
{
- if (XPending (dpyinfo->display))
+ fd = ConnectionNumber (dpyinfo->display);
+
+ if ((rc < 0 || FD_ISSET (fd, &rfds))
+ && XPending (dpyinfo->display))
{
XNextEvent (dpyinfo->display, event);
return;
}
- fd = XConnectionNumber (dpyinfo->display);
-
if (fd > maxfd)
maxfd = fd;
eassert (fd < FD_SETSIZE);
- FD_SET (XConnectionNumber (dpyinfo->display), &fds);
+ FD_SET (fd, &fds);
}
eassert (maxfd >= 0);
- /* We don't have to check the return of pselect, because if an
+ /* Continue to read input even if pselect fails, because if an
error occurs XPending will call the IO error handler, which
then brings us out of this loop. */
- pselect (maxfd, &fds, NULL, NULL, NULL, NULL);
+ rc = pselect (maxfd + 1, &fds, NULL, NULL, NULL, NULL);
+
+ if (rc >= 0)
+ rfds = fds;
}
}
#endif /* USE_X_TOOLKIT || USE_GTK */
static void
-x_clear_dnd_targets (void)
+x_handle_pending_selection_requests_1 (struct x_selection_request_event *tem)
{
- if (x_dnd_unwind_flag)
- x_set_dnd_targets (NULL, 0);
+ specpdl_ref count;
+ struct selection_input_event se;
+
+ count = SPECPDL_INDEX ();
+ se = tem->se;
+
+ record_unwind_protect_ptr (xfree, tem);
+ x_handle_selection_event (&se);
+ unbind_to (count, Qnil);
+}
+
+/* Handle all pending selection request events from modal event
+ loops. */
+void
+x_handle_pending_selection_requests (void)
+{
+ struct x_selection_request_event *tem;
+
+ while (pending_selection_requests)
+ {
+ tem = pending_selection_requests;
+ pending_selection_requests = tem->next;
+
+ x_handle_pending_selection_requests_1 (tem);
+ }
+}
+
+static void
+x_push_selection_request (struct selection_input_event *se)
+{
+ struct x_selection_request_event *tem;
+
+ tem = xmalloc (sizeof *tem);
+ tem->next = pending_selection_requests;
+ tem->se = *se;
+ pending_selection_requests = tem;
+}
+
+bool
+x_detect_pending_selection_requests (void)
+{
+ return pending_selection_requests;
+}
+
+static void
+x_clear_dnd_action (void)
+{
+ x_dnd_action_symbol = Qnil;
}
/* This function is defined far away from the rest of the XDND code so
it can utilize `x_any_window_to_frame'. */
+/* Implementors beware! On most other platforms (where drag-and-drop
+ data is not provided via selections, but some kind of serialization
+ mechanism), it is usually much easier to implement a suitable
+ primitive instead of copying the C code here, and then to build
+ `x-begin-drag' on top of that, by making it a wrapper function in
+ Lisp that converts the list of targets and value of `XdndSelection'
+ to serialized data. Also be sure to update the data types used in
+ dnd.el.
+
+ For examples of how to do this, see `haiku-drag-message' and
+ `x-begin-drag' in haikuselect.c and lisp/term/haiku-win.el, and
+ `ns-begin-drag' and `x-begin-drag' in nsselect.m and
+ lisp/term/ns-win.el. */
+
Lisp_Object
x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
Lisp_Object return_frame, Atom *ask_action_list,
const char **ask_action_names, size_t n_ask_actions,
- bool allow_current_frame)
+ bool allow_current_frame, Atom *target_atoms,
+ int ntargets, Lisp_Object selection_target_list,
+ bool follow_tooltip)
{
#ifndef USE_GTK
XEvent next_event;
@@ -9801,60 +10907,119 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
#endif
XWindowAttributes root_window_attrs;
struct input_event hold_quit;
- struct frame *any;
char *atom_name, *ask_actions;
Lisp_Object action, ltimestamp;
- specpdl_ref ref;
+ specpdl_ref ref, count, base;
ptrdiff_t i, end, fill;
XTextProperty prop;
xm_drop_start_message dmsg;
Lisp_Object frame_object, x, y, frame, local_value;
- bool signals_were_pending;
+ bool signals_were_pending, need_sync;
#ifdef HAVE_XKB
XkbStateRec keyboard_state;
#endif
#ifndef USE_GTK
struct x_display_info *event_display;
#endif
+ union buffered_input_event *events, *event;
+ int n_events;
+ struct frame *event_frame;
- if (!FRAME_VISIBLE_P (f))
+ base = SPECPDL_INDEX ();
+
+ /* Bind this here to avoid juggling bindings and SAFE_FREE in
+ Fx_begin_drag. */
+ specbind (Qx_dnd_targets_list, selection_target_list);
+
+ /* Before starting drag-and-drop, walk through the keyboard buffer
+ to see if there are any UNSUPPORTED_DROP_EVENTs, and run them now
+ if they exist, to prevent race conditions from happening due to
+ multiple unsupported drops running at once. */
+
+ block_input ();
+ events = alloca (sizeof *events * KBD_BUFFER_SIZE);
+ n_events = 0;
+ event = kbd_fetch_ptr;
+
+ while (event != kbd_store_ptr)
{
- x_set_dnd_targets (NULL, 0);
- error ("Frame is invisible");
+ if (event->ie.kind == UNSUPPORTED_DROP_EVENT
+ && event->ie.modifiers < x_dnd_unsupported_event_level)
+ events[n_events++] = *event;
+
+ event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
+ ? kbd_buffer : event + 1);
}
+ x_dnd_unsupported_event_level += 1;
+ unblock_input ();
+
+ for (i = 0; i < n_events; ++i)
+ {
+ maybe_quit ();
+
+ event = &events[i];
+ event_frame = XFRAME (event->ie.frame_or_window);
+
+ if (!FRAME_LIVE_P (event_frame))
+ continue;
+
+ if (!NILP (Vx_dnd_unsupported_drop_function))
+ {
+ if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
+ XCAR (XCDR (event->ie.arg)), event->ie.x,
+ event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
+ make_uint (event->ie.code),
+ event->ie.frame_or_window,
+ make_int (event->ie.timestamp))))
+ continue;
+ }
+
+ /* `x-dnd-unsupported-drop-function' could have deleted the
+ event frame. */
+ if (!FRAME_LIVE_P (event_frame))
+ continue;
+
+ x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (event_frame),
+ event->ie.frame_or_window,
+ XCAR (event->ie.arg),
+ XCAR (XCDR (event->ie.arg)),
+ (Window) event->ie.code,
+ XFIXNUM (event->ie.x),
+ XFIXNUM (event->ie.y),
+ event->ie.timestamp);
+ break;
+ }
+
+ if (!FRAME_VISIBLE_P (f))
+ error ("Frame must be visible");
+
XSETFRAME (frame, f);
local_value = assq_no_quit (QXdndSelection,
FRAME_TERMINAL (f)->Vselection_alist);
if (x_dnd_in_progress || x_dnd_waiting_for_finish)
- {
- x_set_dnd_targets (NULL, 0);
- error ("A drag-and-drop session is already in progress");
- }
+ error ("A drag-and-drop session is already in progress");
- if (CONSP (local_value))
- {
- ref = SPECPDL_INDEX ();
+ DEFER_SELECTIONS;
- record_unwind_protect_void (x_clear_dnd_targets);
- x_dnd_unwind_flag = true;
- x_own_selection (QXdndSelection,
- Fnth (make_fixnum (1), local_value), frame);
- x_dnd_unwind_flag = false;
- unbind_to (ref, Qnil);
- }
+ /* If local_value is nil, then we lost ownership of XdndSelection.
+ Signal a more informative error than args-out-of-range. */
+ if (NILP (local_value))
+ error ("Lost ownership of XdndSelection");
+
+ if (CONSP (local_value))
+ x_own_selection (QXdndSelection,
+ Fnth (make_fixnum (1), local_value), frame);
else
- {
- x_set_dnd_targets (NULL, 0);
- error ("No local value for XdndSelection");
- }
+ error ("No local value for XdndSelection");
if (popup_activated ())
- {
- x_set_dnd_targets (NULL, 0);
- error ("Trying to drag-and-drop from within a menu-entry");
- }
+ error ("Trying to drag-and-drop from within a menu-entry");
+
+ x_set_dnd_targets (target_atoms, ntargets);
+ record_unwind_protect_void (x_free_dnd_targets);
+ record_unwind_protect_void (x_clear_dnd_action);
ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
QXdndSelection);
@@ -9864,10 +11029,24 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
else
x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
+ x_dnd_motif_operations
+ = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), xaction);
+
+ x_dnd_first_motif_operation = XM_DRAG_NOOP;
+
if (n_ask_actions)
{
+ x_dnd_motif_operations
+ = xm_operations_from_actions (FRAME_DISPLAY_INFO (f),
+ ask_action_list,
+ n_ask_actions);
+ x_dnd_first_motif_operation
+ = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ ask_action_list[0]);
+
ask_actions = NULL;
end = 0;
+ count = SPECPDL_INDEX ();
for (i = 0; i < n_ask_actions; ++i)
{
@@ -9889,16 +11068,25 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
prop.format = 8;
prop.nitems = end;
+ record_unwind_protect_ptr (xfree, ask_actions);
+
+ /* This can potentially store a lot of data in window
+ properties, so check for allocation errors. */
block_input ();
+ x_catch_errors (FRAME_X_DISPLAY (f));
XSetTextProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
&prop, FRAME_DISPLAY_INFO (f)->Xatom_XdndActionDescription);
- xfree (ask_actions);
XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
FRAME_DISPLAY_INFO (f)->Xatom_XdndActionList, XA_ATOM, 32,
PropModeReplace, (unsigned char *) ask_action_list,
n_ask_actions);
+ x_check_errors (FRAME_X_DISPLAY (f),
+ "Can't set action descriptions: %s");
+ x_uncatch_errors_after_check ();
unblock_input ();
+
+ unbind_to (count, Qnil);
}
else
{
@@ -9914,14 +11102,45 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
unblock_input ();
}
+ if (follow_tooltip)
+ {
+#if defined HAVE_XRANDR || defined USE_GTK
+ x_dnd_monitors
+ = FRAME_DISPLAY_INFO (f)->last_monitor_attributes_list;
+
+ if (NILP (x_dnd_monitors))
+#endif
+ x_dnd_monitors
+ = Fx_display_monitor_attributes_list (frame);
+
+ record_unwind_protect_void (x_clear_dnd_monitors);
+ }
+
+ x_dnd_update_tooltip = follow_tooltip;
+
+ /* This shouldn't happen. */
+ if (x_dnd_toplevels)
+ x_dnd_free_toplevels (true);
+
+#ifdef USE_GTK
+ /* Prevent GTK+ timeouts from being run, since they can call
+ handle_one_xevent behind our back. */
+ suppress_xg_select ();
+ record_unwind_protect_void (release_xg_select);
+#endif
+
+ /* Initialize most of the state for the drag-and-drop operation. */
x_dnd_in_progress = true;
+ x_dnd_recursion_depth = command_loop_level + minibuf_level;
x_dnd_frame = f;
x_dnd_last_seen_window = None;
x_dnd_last_seen_toplevel = None;
x_dnd_last_protocol_version = -1;
+ x_dnd_last_window_is_frame = false;
x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_mouse_rect_target = None;
x_dnd_action = None;
+ x_dnd_action_symbol = Qnil;
x_dnd_wanted_action = xaction;
x_dnd_return_frame = 0;
x_dnd_waiting_for_finish = false;
@@ -9934,6 +11153,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
x_dnd_toplevels = NULL;
x_dnd_allow_current_frame = allow_current_frame;
x_dnd_movement_frame = NULL;
+ x_dnd_init_type_lists = false;
#ifdef HAVE_XKB
x_dnd_keyboard_state = 0;
@@ -9953,9 +11173,11 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
{
if (x_dnd_compute_toplevels (FRAME_DISPLAY_INFO (f)))
{
- x_dnd_free_toplevels ();
+ x_dnd_free_toplevels (true);
x_dnd_use_toplevels = false;
}
+ else
+ record_unwind_protect_void (x_free_dnd_toplevels);
}
if (!NILP (return_frame))
@@ -9983,14 +11205,17 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
while (x_dnd_in_progress || x_dnd_waiting_for_finish)
{
- hold_quit.kind = NO_EVENT;
+ EVENT_INIT (hold_quit);
+
#ifdef USE_GTK
current_finish = X_EVENT_NORMAL;
current_hold_quit = &hold_quit;
current_count = 0;
+ xg_pending_quit_event.kind = NO_EVENT;
#endif
block_input ();
+ x_dnd_inside_handle_one_xevent = true;
#ifdef USE_GTK
gtk_main_iteration ();
#elif defined USE_X_TOOLKIT
@@ -10027,7 +11252,12 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
&next_event, &finish, &hold_quit);
#endif
}
+#else
+ /* Clear these before the read_socket_hook can be called. */
+ current_count = -1;
+ current_hold_quit = NULL;
#endif
+ x_dnd_inside_handle_one_xevent = false;
/* The unblock_input below might try to read input, but
XTread_socket does nothing inside a drag-and-drop event
@@ -10042,7 +11272,16 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
if (event_display == FRAME_DISPLAY_INFO (f))
{
#endif
- if (x_dnd_movement_frame)
+ if (x_dnd_movement_frame
+ /* FIXME: how come this can end up with movement frames
+ from other displays on GTK builds? */
+ && (FRAME_X_DISPLAY (x_dnd_movement_frame)
+ == FRAME_X_DISPLAY (f))
+ /* If both those variables are false, then F is no
+ longer protected from deletion by Lisp code. This
+ can only happen during the final iteration of the DND
+ event loop. */
+ && (x_dnd_in_progress || x_dnd_waiting_for_finish))
{
XSETFRAME (frame_object, x_dnd_movement_frame);
XSETINT (x, x_dnd_movement_x);
@@ -10050,6 +11289,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
x_dnd_movement_frame = NULL;
if (!NILP (Vx_dnd_movement_function)
+ && FRAME_LIVE_P (XFRAME (frame_object))
&& !FRAME_TOOLTIP_P (XFRAME (frame_object))
&& x_dnd_movement_x >= 0
&& x_dnd_movement_y >= 0
@@ -10071,19 +11311,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
if (hold_quit.kind != NO_EVENT)
{
- if (hold_quit.kind == SELECTION_REQUEST_EVENT)
- {
- x_dnd_old_window_attrs = root_window_attrs;
- x_dnd_unwind_flag = true;
-
- ref = SPECPDL_INDEX ();
- record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
- x_handle_selection_event ((struct selection_input_event *) &hold_quit);
- x_dnd_unwind_flag = false;
- unbind_to (ref, Qnil);
- continue;
- }
-
if (x_dnd_in_progress)
{
if (x_dnd_last_seen_window != None
@@ -10101,9 +11328,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
XM_DROP_ACTION_DROP_CANCEL);
dmsg.x = 0;
dmsg.y = 0;
@@ -10124,19 +11349,107 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
x_dnd_frame = NULL;
}
- x_set_dnd_targets (NULL, 0);
x_dnd_waiting_for_finish = false;
+ x_dnd_return_frame_object = NULL;
+ x_dnd_movement_frame = NULL;
+
+ /* Don't clear dpyinfo->grabbed if we're quitting. */
+
+#ifdef USE_GTK
+ current_hold_quit = NULL;
+#endif
+ /* Restore the old event mask. */
+ XSelectInput (FRAME_X_DISPLAY (f),
+ FRAME_DISPLAY_INFO (f)->root_window,
+ root_window_attrs.your_event_mask);
+#ifdef HAVE_XKB
+ if (FRAME_DISPLAY_INFO (f)->supports_xkb)
+ XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
+ XkbStateNotifyMask, 0);
+#endif
+ /* Delete the Motif drag initiator info if it was set up. */
+ if (x_dnd_motif_setup_p)
+ XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+
+
+ /* Remove any type list set as well. */
+ if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
+ XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
+
+ /* Call kbd_buffer_store event, which calls
+ handle_interrupt and sets `last-event-frame' along
+ with various other things. */
+ kbd_buffer_store_event (&hold_quit);
+ /* Now quit anyway. */
+ quit ();
+ }
+
+ if (pending_selection_requests
+ && (x_dnd_in_progress || x_dnd_waiting_for_finish))
+ {
+ x_dnd_old_window_attrs = root_window_attrs;
+ x_dnd_unwind_flag = true;
+
+ ref = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+ x_handle_pending_selection_requests ();
+ x_dnd_unwind_flag = false;
+ unbind_to (ref, Qnil);
+ }
- if (x_dnd_use_toplevels)
- x_dnd_free_toplevels ();
+#ifdef USE_GTK
+ if (xg_pending_quit_event.kind != NO_EVENT)
+ {
+ xg_pending_quit_event.kind = NO_EVENT;
+ if (x_dnd_in_progress)
+ {
+ if (x_dnd_last_seen_window != None
+ && x_dnd_last_protocol_version != -1)
+ x_dnd_send_leave (f, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
+ dmsg.timestamp = xg_pending_quit_event.timestamp;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
+ XM_DROP_ACTION_DROP_CANCEL);
+ dmsg.x = 0;
+ dmsg.y = 0;
+ dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+ dmsg.source_window = FRAME_X_WINDOW (f);
+
+ x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
+ x_dnd_last_seen_window,
+ xg_pending_quit_event.timestamp);
+ xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+ x_dnd_last_seen_window, &dmsg);
+ }
+
+ x_dnd_end_window = x_dnd_last_seen_window;
+ x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
+ x_dnd_in_progress = false;
+ x_dnd_frame = NULL;
+ }
+
+ x_dnd_waiting_for_finish = false;
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
FRAME_DISPLAY_INFO (f)->grabbed = 0;
-#ifdef USE_GTK
current_hold_quit = NULL;
-#endif
+
+ block_input ();
/* Restore the old event mask. */
XSelectInput (FRAME_X_DISPLAY (f),
FRAME_DISPLAY_INFO (f)->root_window,
@@ -10150,9 +11463,17 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
if (x_dnd_motif_setup_p)
XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+
+
+ /* Remove any type list set as well. */
+ if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
+ XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
+ unblock_input ();
+
quit ();
}
-#ifndef USE_GTK
+#else
}
else
{
@@ -10165,7 +11486,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
#endif
}
- x_set_dnd_targets (NULL, 0);
x_dnd_waiting_for_finish = false;
#ifdef USE_GTK
@@ -10187,6 +11507,11 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
if (x_dnd_motif_setup_p)
XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+
+ /* Remove any type list set as well. */
+ if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
+ XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
unblock_input ();
if (x_dnd_return_frame == 3
@@ -10202,45 +11527,43 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
XSETFRAME (action, x_dnd_return_frame_object);
x_dnd_return_frame_object = NULL;
- return action;
+
+ return unbind_to (base, action);
}
x_dnd_return_frame_object = NULL;
-
- if (x_dnd_use_toplevels)
- x_dnd_free_toplevels ();
FRAME_DISPLAY_INFO (f)->grabbed = 0;
- /* Emacs can't respond to DND events inside the nested event
- loop, so when dragging items to itself, always return
- XdndActionPrivate. */
- if (x_dnd_end_window != None
- && (any = x_any_window_to_frame (FRAME_DISPLAY_INFO (f),
- x_dnd_end_window))
- && (allow_current_frame || any != f))
- return QXdndActionPrivate;
+ if (!NILP (x_dnd_action_symbol))
+ return unbind_to (base, x_dnd_action_symbol);
if (x_dnd_action != None)
{
block_input ();
x_catch_errors (FRAME_X_DISPLAY (f));
- atom_name = XGetAtomName (FRAME_X_DISPLAY (f),
- x_dnd_action);
- x_uncatch_errors ();
+ atom_name = x_get_atom_name (FRAME_DISPLAY_INFO (f),
+ x_dnd_action, &need_sync);
+
+ if (need_sync)
+ x_uncatch_errors ();
+ else
+ /* No protocol request actually happened, so avoid the extra
+ sync by calling x_uncatch_errors_after_check instead. */
+ x_uncatch_errors_after_check ();
if (atom_name)
{
action = intern (atom_name);
- XFree (atom_name);
+ xfree (atom_name);
}
else
action = Qnil;
unblock_input ();
- return action;
+ return unbind_to (base, action);
}
- return Qnil;
+ return unbind_to (base, Qnil);
}
/* The focus may have changed. Figure out if it is a real focus change,
@@ -10780,6 +12103,80 @@ x_note_mouse_movement (struct frame *frame, const XMotionEvent *event,
return false;
}
+/* Get a sibling below WINDOW on DPY at PARENT_X and PARENT_Y. */
+static Window
+x_get_window_below (Display *dpy, Window window,
+ int parent_x, int parent_y,
+ int *inner_x, int *inner_y)
+{
+ int rc, i, cx, cy;
+ XWindowAttributes attrs;
+ unsigned int nchildren;
+ Window root, parent, *children, value;
+ bool window_seen;
+
+ /* TODO: rewrite to have less dependencies. */
+
+ children = NULL;
+ window_seen = false;
+ value = None;
+
+ rc = XQueryTree (dpy, window, &root, &parent,
+ &children, &nchildren);
+
+ if (rc)
+ {
+ if (children)
+ XFree (children);
+
+ rc = XQueryTree (dpy, parent, &root,
+ &parent, &children, &nchildren);
+ }
+
+ if (rc)
+ {
+ for (i = nchildren - 1; i >= 0; --i)
+ {
+ if (children[i] == window)
+ {
+ window_seen = true;
+ continue;
+ }
+
+ if (!window_seen)
+ continue;
+
+ rc = XGetWindowAttributes (dpy, children[i], &attrs);
+
+ if (rc && attrs.map_state != IsViewable)
+ continue;
+
+ if (rc && parent_x >= attrs.x
+ && parent_y >= attrs.y
+ && parent_x < attrs.x + attrs.width
+ && parent_y < attrs.y + attrs.height)
+ {
+ value = children[i];
+ cx = parent_x - attrs.x;
+ cy = parent_y - attrs.y;
+
+ break;
+ }
+ }
+ }
+
+ if (children)
+ XFree (children);
+
+ if (value)
+ {
+ *inner_x = cx;
+ *inner_y = cy;
+ }
+
+ return value;
+}
+
/* Return the current position of the mouse.
*FP should be a frame which indicates which display to ask about.
@@ -10805,8 +12202,9 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
Time *timestamp)
{
- struct frame *f1;
+ struct frame *f1, *maybe_tooltip;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
+ bool unrelated_tooltip;
block_input ();
@@ -10861,9 +12259,11 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
Window first_win = 0;
#endif
int win_x, win_y;
- int parent_x = 0, parent_y = 0;
+ int parent_x, parent_y;
win = root;
+ parent_x = root_x;
+ parent_y = root_y;
/* XTranslateCoordinates can get errors if the window
structure is changing at the same time this function
@@ -10898,6 +12298,22 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
root_x, root_y, &win_x, &win_y,
/* Child of win. */
&child);
+
+ /* If CHILD is a tooltip frame, look below it if
+ track-mouse is drag-source. */
+ if (child != None
+ && (EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping)))
+ {
+ maybe_tooltip = x_tooltip_window_to_frame (dpyinfo, child,
+ &unrelated_tooltip);
+
+ if (maybe_tooltip || unrelated_tooltip)
+ child = x_get_window_below (dpyinfo->display, child,
+ parent_x, parent_y, &win_x,
+ &win_y);
+ }
+
if (child == None || child == win)
{
#ifdef USE_GTK
@@ -13695,6 +15111,13 @@ x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
result = xg_filter_key (f1, event);
unblock_input ();
+ /* Clear `xg_pending_quit_event' so we don't end up reacting to quit
+ events sent outside the main event loop (i.e. those sent from
+ inside a popup menu event loop). */
+
+ if (popup_activated ())
+ xg_pending_quit_event.kind = NO_EVENT;
+
if (result && f1)
/* There will probably be a GDK event generated soon, so
exercise the wire to make pselect return. */
@@ -13900,6 +15323,132 @@ mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
}
}
+static void
+x_dnd_compute_tip_xy (int *root_x, int *root_y, Lisp_Object attributes)
+{
+ Lisp_Object monitor, geometry;
+ int min_x, min_y, max_x, max_y;
+ int width, height;
+
+ width = FRAME_PIXEL_WIDTH (XFRAME (tip_frame));
+ height = FRAME_PIXEL_HEIGHT (XFRAME (tip_frame));
+
+ max_y = -1;
+
+ /* Try to determine the monitor where the mouse pointer is and
+ its geometry. See bug#22549. */
+ while (CONSP (attributes))
+ {
+ monitor = XCAR (attributes);
+ geometry = assq_no_quit (Qgeometry, monitor);
+
+ if (CONSP (geometry))
+ {
+ min_x = XFIXNUM (Fnth (make_fixnum (1), geometry));
+ min_y = XFIXNUM (Fnth (make_fixnum (2), geometry));
+ max_x = min_x + XFIXNUM (Fnth (make_fixnum (3), geometry));
+ max_y = min_y + XFIXNUM (Fnth (make_fixnum (4), geometry));
+
+ if (min_x <= *root_x && *root_x < max_x
+ && min_y <= *root_y && *root_y < max_y)
+ break;
+
+ max_y = -1;
+ }
+
+ attributes = XCDR (attributes);
+ }
+
+ /* It was not possible to determine the monitor's geometry, so we
+ assign some sane defaults here: */
+ if (max_y < 0)
+ {
+ min_x = 0;
+ min_y = 0;
+ max_x = x_display_pixel_width (FRAME_DISPLAY_INFO (x_dnd_frame));
+ max_y = x_display_pixel_height (FRAME_DISPLAY_INFO (x_dnd_frame));
+ }
+
+ if (*root_y + XFIXNUM (tip_dy) <= min_y)
+ *root_y = min_y; /* Can happen for negative dy */
+ else if (*root_y + XFIXNUM (tip_dy) + height <= max_y)
+ /* It fits below the pointer */
+ *root_y += XFIXNUM (tip_dy);
+ else if (height + XFIXNUM (tip_dy) + min_y <= *root_y)
+ /* It fits above the pointer. */
+ *root_y -= height + XFIXNUM (tip_dy);
+ else
+ /* Put it on the top. */
+ *root_y = min_y;
+
+ if (*root_x + XFIXNUM (tip_dx) <= min_x)
+ *root_x = 0; /* Can happen for negative dx */
+ else if (*root_x + XFIXNUM (tip_dx) + width <= max_x)
+ /* It fits to the right of the pointer. */
+ *root_x += XFIXNUM (tip_dx);
+ else if (width + XFIXNUM (tip_dx) + min_x <= *root_x)
+ /* It fits to the left of the pointer. */
+ *root_x -= width + XFIXNUM (tip_dx);
+ else
+ /* Put it left justified on the screen -- it ought to fit that way. */
+ *root_x = min_x;
+}
+
+static void
+x_dnd_update_tooltip_position (int root_x, int root_y)
+{
+ struct frame *tip_f;
+
+ if (!x_dnd_in_progress || !x_dnd_update_tooltip)
+ return;
+
+ if (!FRAMEP (tip_frame))
+ return;
+
+ tip_f = XFRAME (tip_frame);
+
+ if (!FRAME_LIVE_P (tip_f)
+ || !FRAME_VISIBLE_P (tip_f)
+ || (FRAME_X_DISPLAY (tip_f)
+ != FRAME_X_DISPLAY (x_dnd_frame)))
+ return;
+
+ if (tip_window != None
+ && FIXNUMP (tip_dx) && FIXNUMP (tip_dy))
+ {
+ x_dnd_compute_tip_xy (&root_x, &root_y,
+ x_dnd_monitors);
+
+ XMoveWindow (FRAME_X_DISPLAY (x_dnd_frame),
+ tip_window, root_x, root_y);
+ }
+}
+
+static void
+x_dnd_update_tooltip_now (void)
+{
+ int root_x, root_y;
+ Window root, child;
+ int win_x, win_y;
+ unsigned int mask;
+ Bool rc;
+ struct x_display_info *dpyinfo;
+
+ if (!x_dnd_in_progress || !x_dnd_update_tooltip)
+ return;
+
+ dpyinfo = FRAME_DISPLAY_INFO (x_dnd_frame);
+
+ rc = XQueryPointer (dpyinfo->display,
+ dpyinfo->root_window,
+ &root, &child, &root_x,
+ &root_y, &win_x, &win_y,
+ &mask);
+
+ if (rc)
+ x_dnd_update_tooltip_position (root_x, root_y);
+}
+
/* Get the window underneath the pointer, see if it moved, and update
the DND state accordingly. */
static void
@@ -13912,6 +15461,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
xm_top_level_enter_message emsg;
xm_drag_motion_message dmsg;
xm_drop_start_message dsmsg;
+ bool was_frame;
if (XQueryPointer (dpyinfo->display,
dpyinfo->root_window,
@@ -13922,7 +15472,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
{
target = x_dnd_get_target_window (dpyinfo, root_x,
root_y, &target_proto,
- &motif_style, &toplevel);
+ &motif_style, &toplevel,
+ &was_frame);
if (toplevel != x_dnd_last_seen_toplevel)
{
@@ -13939,6 +15490,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -13978,6 +15530,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -13999,11 +15552,13 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
x_dnd_last_motif_style = motif_style;
+ x_dnd_last_window_is_frame = was_frame;
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
- else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -14022,7 +15577,9 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
}
}
- if (x_dnd_last_protocol_version != -1 && target != None)
+ if (x_dnd_last_window_is_frame && target != None)
+ x_dnd_note_self_position (dpyinfo, target, root_x, root_y);
+ else if (x_dnd_last_protocol_version != -1 && target != None)
x_dnd_send_position (x_dnd_frame, target,
x_dnd_last_protocol_version,
root_x, root_y,
@@ -14034,7 +15591,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
0
#endif
);
- else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -14045,9 +15603,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (dpyinfo,
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
(!x_dnd_xm_use_help
? XM_DROP_ACTION_DROP
: XM_DROP_ACTION_DROP_HELP));
@@ -14059,6 +15615,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
xm_send_drag_motion_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
target, &dmsg);
}
+
+ x_dnd_update_tooltip_position (root_x, root_y);
}
/* The pointer moved out of the screen. */
else if (x_dnd_last_protocol_version != -1)
@@ -14079,9 +15637,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
dsmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (dpyinfo,
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
XM_DROP_ACTION_DROP_CANCEL);
dsmsg.x = 0;
dsmsg.y = 0;
@@ -14104,6 +15660,236 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
}
}
+int
+x_display_pixel_height (struct x_display_info *dpyinfo)
+{
+ if (dpyinfo->screen_height)
+ return dpyinfo->screen_height;
+
+ return HeightOfScreen (dpyinfo->screen);
+}
+
+int
+x_display_pixel_width (struct x_display_info *dpyinfo)
+{
+ if (dpyinfo->screen_width)
+ return dpyinfo->screen_width;
+
+ return WidthOfScreen (dpyinfo->screen);
+}
+
+/* Handle events from each display until CELL's car becomes non-nil,
+ or TIMEOUT elapses. */
+void
+x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout)
+{
+ struct x_display_info *dpyinfo;
+ fd_set fds;
+ int fd, maxfd;
+#ifndef USE_GTK
+ int finish, rc;
+ XEvent event;
+ fd_set rfds;
+#endif
+ struct input_event hold_quit;
+ struct timespec current, at;
+
+ at = timespec_add (current_timespec (), timeout);
+
+#ifndef USE_GTK
+ FD_ZERO (&rfds);
+ rc = -1;
+#endif
+
+ while (true)
+ {
+ FD_ZERO (&fds);
+ maxfd = -1;
+
+ for (dpyinfo = x_display_list; dpyinfo;
+ dpyinfo = dpyinfo->next)
+ {
+ fd = ConnectionNumber (dpyinfo->display);
+
+#ifndef USE_GTK
+ if ((rc < 0 || FD_ISSET (fd, &rfds))
+ /* If pselect failed, the erroring display's IO error
+ handler will eventually be called. */
+ && XPending (dpyinfo->display))
+ {
+ while (XPending (dpyinfo->display))
+ {
+ EVENT_INIT (hold_quit);
+
+ XNextEvent (dpyinfo->display, &event);
+ handle_one_xevent (dpyinfo, &event,
+ &finish, &hold_quit);
+
+ if (!NILP (XCAR (cell)))
+ return;
+
+ if (finish == X_EVENT_GOTO_OUT)
+ break;
+
+ /* Make us quit now. */
+ if (hold_quit.kind != NO_EVENT)
+ kbd_buffer_store_event (&hold_quit);
+ }
+ }
+#endif
+
+ if (fd > maxfd)
+ maxfd = fd;
+
+ eassert (fd < FD_SETSIZE);
+ FD_SET (fd, &fds);
+ }
+
+ /* Prevent events from being lost (from GTK's point of view) by
+ using GDK to run the event loop. */
+#ifdef USE_GTK
+ while (gtk_events_pending ())
+ {
+ EVENT_INIT (hold_quit);
+ current_count = 0;
+ current_hold_quit = &hold_quit;
+ current_finish = X_EVENT_NORMAL;
+
+ gtk_main_iteration ();
+
+ current_count = -1;
+ current_hold_quit = NULL;
+
+ /* Make us quit now. */
+ if (hold_quit.kind != NO_EVENT)
+ kbd_buffer_store_event (&hold_quit);
+
+ if (!NILP (XCAR (cell)))
+ return;
+
+ if (current_finish == X_EVENT_GOTO_OUT)
+ break;
+ }
+#endif
+
+ eassert (maxfd >= 0);
+
+ current = current_timespec ();
+
+ if (timespec_cmp (at, current) < 0
+ || !NILP (XCAR (cell)))
+ return;
+
+ timeout = timespec_sub (at, current);
+
+#ifndef USE_GTK
+ rc = pselect (maxfd + 1, &fds, NULL, NULL, &timeout, NULL);
+
+ if (rc >= 0)
+ rfds = fds;
+#else
+ pselect (maxfd + 1, &fds, NULL, NULL, &timeout, NULL);
+#endif
+ }
+}
+
+#ifdef USE_GTK
+static void
+x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data)
+{
+ struct x_display_info *dpyinfo;
+ struct input_event ie;
+ Lisp_Object current_monitors, terminal;
+ GdkDisplay *gdpy;
+ Display *dpy;
+
+ gdpy = gdk_screen_get_display (gscr);
+ dpy = gdk_x11_display_get_xdisplay (gdpy);
+ dpyinfo = x_display_info_for_display (dpy);
+
+ if (!dpyinfo)
+ return;
+
+ XSETTERMINAL (terminal, dpyinfo->terminal);
+
+ current_monitors
+ = Fx_display_monitor_attributes_list (terminal);
+
+ if (NILP (Fequal (current_monitors,
+ dpyinfo->last_monitor_attributes_list)))
+ {
+ EVENT_INIT (ie);
+ ie.kind = MONITORS_CHANGED_EVENT;
+ ie.arg = terminal;
+
+ kbd_buffer_store_event (&ie);
+
+ if (x_dnd_in_progress && x_dnd_update_tooltip)
+ x_dnd_monitors = current_monitors;
+
+ x_dnd_update_tooltip_now ();
+ }
+
+ dpyinfo->last_monitor_attributes_list = current_monitors;
+}
+#endif
+
+/* Extract the root window coordinates from the client message EVENT
+ if it is a message that we already understand. Return false if the
+ event was not understood. */
+static bool
+x_coords_from_dnd_message (struct x_display_info *dpyinfo,
+ XEvent *event, int *x_out, int *y_out)
+{
+ xm_drag_motion_message dmsg;
+ xm_drop_start_message smsg;
+ xm_drop_start_reply reply;
+
+ if (event->type != ClientMessage)
+ return false;
+
+ if (event->xclient.message_type == dpyinfo->Xatom_XdndPosition)
+ {
+ if (event->xclient.format != 32)
+ return false;
+
+ *x_out = (((unsigned long) event->xclient.data.l[2]) >> 16
+ & 0xffff);
+ *y_out = (event->xclient.data.l[2] & 0xffff);
+
+ return true;
+ }
+
+ if ((event->xclient.message_type
+ == dpyinfo->Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
+ && event->xclient.format == 8)
+ {
+ if (!xm_read_drag_motion_message (event, &dmsg))
+ {
+ *x_out = dmsg.x;
+ *y_out = dmsg.y;
+
+ return true;
+ }
+ else if (!xm_read_drop_start_message (event, &smsg))
+ {
+ *x_out = smsg.x;
+ *y_out = smsg.y;
+
+ return true;
+ }
+ else if (!xm_read_drop_start_reply (event, &reply))
+ {
+ *x_out = reply.better_x;
+ *y_out = reply.better_y;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Handles the XEvent EVENT on display DPYINFO.
*FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
@@ -14146,6 +15932,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
GdkEvent *copy = NULL;
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
#endif
+ int dx, dy;
+ USE_SAFE_ALLOCA;
*finish = X_EVENT_NORMAL;
@@ -14176,11 +15964,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
case ClientMessage:
{
+ int rc;
+
if (x_dnd_in_progress
&& FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo
&& event->xclient.message_type == dpyinfo->Xatom_XdndStatus)
{
Window target;
+ unsigned long r1, r2;
target = event->xclient.data.l[0];
@@ -14188,11 +15979,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
&& target == x_dnd_last_seen_window
&& event->xclient.data.l[1] & 2)
{
+ r1 = event->xclient.data.l[2];
+ r2 = event->xclient.data.l[2];
+
x_dnd_mouse_rect_target = target;
- x_dnd_mouse_rect.x = (event->xclient.data.l[2] & 0xffff0000) >> 16;
- x_dnd_mouse_rect.y = (event->xclient.data.l[2] & 0xffff);
- x_dnd_mouse_rect.width = (event->xclient.data.l[3] & 0xffff0000) >> 16;
- x_dnd_mouse_rect.height = (event->xclient.data.l[3] & 0xffff);
+ x_dnd_mouse_rect.x = (r1 & 0xffff0000) >> 16;
+ x_dnd_mouse_rect.y = (r1 & 0xffff);
+ x_dnd_mouse_rect.width = (r2 & 0xffff0000) >> 16;
+ x_dnd_mouse_rect.height = (r2 & 0xffff);
}
else
x_dnd_mouse_rect_target = None;
@@ -14377,25 +16171,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (event->xclient.data.l[0] == dpyinfo->Xatom_net_wm_ping
+ /* Handling window stacking changes during
+ drag-and-drop requires Emacs to select for
+ SubstructureNotifyMask, which in turn causes the
+ message to be sent to Emacs itself using the event
+ mask specified by the EWMH. To avoid an infinite
+ loop, make sure the client message's window is not
+ the root window if DND is in progress. */
+ && (!(x_dnd_in_progress
+ || x_dnd_waiting_for_finish)
+ || event->xclient.window != dpyinfo->root_window)
&& event->xclient.format == 32)
{
XEvent send_event = *event;
send_event.xclient.window = dpyinfo->root_window;
XSendEvent (dpyinfo->display, dpyinfo->root_window, False,
- /* FIXME: handling window stacking changes
- during drag-and-drop requires Emacs to
- select for SubstructureNotifyMask,
- which in turn causes the message to be
- sent to Emacs itself using the event
- mask specified by the EWMH. To avoid
- an infinite loop, just use
- SubstructureRedirectMask when a
- drag-and-drop operation is in
- progress. */
- ((x_dnd_in_progress || x_dnd_waiting_for_finish)
- ? SubstructureRedirectMask
- : SubstructureRedirectMask | SubstructureNotifyMask),
+ SubstructureRedirectMask | SubstructureNotifyMask,
&send_event);
*finish = X_EVENT_DROP;
@@ -14435,17 +16227,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
*finish = X_EVENT_DROP;
#else
widget = FRAME_GTK_OUTER_WIDGET (f);
+ window = gtk_widget_get_window (widget);
+ eassert (window);
+
+ /* This could be a (former) child frame for which
+ frame synchronization was disabled. Enable it
+ now. */
+ gdk_x11_window_set_frame_sync_enabled (window, TRUE);
if (widget && !FRAME_X_OUTPUT (f)->xg_sync_end_pending_p)
{
- window = gtk_widget_get_window (widget);
- eassert (window);
frame_clock = gdk_window_get_frame_clock (window);
eassert (frame_clock);
gdk_frame_clock_request_phase (frame_clock,
GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT);
-
FRAME_X_OUTPUT (f)->xg_sync_end_pending_p = true;
}
#endif
@@ -14503,7 +16299,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
goto OTHER;
#ifndef USE_CAIRO
Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
+ /* FIXME: why does this sometimes generate a BadMatch
+ error? */
+ x_catch_errors (dpyinfo->display);
x_kill_gs_process (pixmap, f);
+ x_uncatch_errors ();
expose_frame (f, 0, 0, 0, 0);
#endif /* !USE_CAIRO */
goto done;
@@ -14542,24 +16342,34 @@ handle_one_xevent (struct x_display_info *dpyinfo,
f = any;
if (!f)
goto OTHER;
- if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie))
+
+ /* These values are always used initialized, but GCC doesn't
+ know that. */
+ dx = 0;
+ dy = 0;
+
+ rc = x_coords_from_dnd_message (dpyinfo, (XEvent *) event,
+ &dx, &dy);
+
+ if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie,
+ rc, dx, dy))
*finish = X_EVENT_DROP;
}
break;
case SelectionNotify:
-#ifdef USE_X_TOOLKIT
- if (! x_window_to_frame (dpyinfo, event->xselection.requestor))
+#if defined USE_X_TOOLKIT || defined USE_GTK
+ if (!x_window_to_frame (dpyinfo, event->xselection.requestor))
goto OTHER;
-#endif /* not USE_X_TOOLKIT */
+#endif /* not USE_X_TOOLKIT and not USE_GTK */
x_handle_selection_notify (&event->xselection);
break;
case SelectionClear: /* Someone has grabbed ownership. */
-#ifdef USE_X_TOOLKIT
- if (! x_window_to_frame (dpyinfo, event->xselectionclear.window))
+#if defined USE_X_TOOLKIT || defined USE_GTK
+ if (!x_window_to_frame (dpyinfo, event->xselectionclear.window))
goto OTHER;
-#endif /* USE_X_TOOLKIT */
+#endif /* not USE_X_TOOLKIT and not USE_GTK */
{
const XSelectionClearEvent *eventp = &event->xselectionclear;
@@ -14567,6 +16377,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
+
+ if (x_use_pending_selection_requests)
+ {
+ x_push_selection_request (&inev.sie);
+ EVENT_INIT (inev.ie);
+ }
}
break;
@@ -14590,11 +16406,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
events immediately, by setting hold_quit to the input
event. */
- if (x_dnd_in_progress || x_dnd_waiting_for_finish)
+ if (x_use_pending_selection_requests)
{
- eassume (hold_quit);
-
- *hold_quit = inev.ie;
+ x_push_selection_request (&inev.sie);
EVENT_INIT (inev.ie);
}
@@ -14604,7 +16418,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
&& eventp->selection == dpyinfo->Xatom_XdndSelection
&& (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS
|| eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE))
- x_dnd_waiting_for_finish = false;
+ {
+ x_dnd_waiting_for_finish = false;
+
+ /* If the transfer failed, then return nil from
+ `x-begin-drag'. */
+ if (eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE)
+ x_dnd_action = None;
+ }
}
break;
@@ -14625,7 +16446,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
unsigned long nitems, bytesafter;
unsigned char *data = NULL;
-
if (event->xproperty.state == PropertyDelete)
{
if (!last)
@@ -14714,6 +16534,107 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
}
+ if (f && FRAME_X_OUTPUT (f)->alpha_identical_p
+ && (event->xproperty.atom
+ == dpyinfo->Xatom_net_wm_window_opacity))
+ {
+#ifndef USE_XCB
+ int rc, actual_format;
+ Atom actual;
+ unsigned char *tmp_data;
+ unsigned long n, left, opacity;
+
+ tmp_data = NULL;
+#else
+ xcb_get_property_cookie_t opacity_cookie;
+ xcb_get_property_reply_t *opacity_reply;
+ xcb_generic_error_t *error;
+ bool rc;
+ uint32_t value;
+#endif
+
+ if (event->xproperty.state == PropertyDelete)
+ {
+ f->alpha[0] = 1.0;
+ f->alpha[1] = 1.0;
+
+ store_frame_param (f, Qalpha, Qnil);
+ }
+ else
+ {
+#ifndef USE_XCB
+ rc = XGetWindowProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+ dpyinfo->Xatom_net_wm_window_opacity,
+ 0, 1, False, AnyPropertyType, &actual,
+ &actual_format, &n, &left, &tmp_data);
+
+ if (rc == Success && actual_format == 32
+ && (actual == XA_CARDINAL
+ /* Some broken programs set the opacity property
+ to those types, but window managers accept
+ them anyway. */
+ || actual == XA_ATOM
+ || actual == XA_WINDOW) && n)
+ {
+ opacity = *(unsigned long *) tmp_data & OPAQUE;
+ f->alpha[0] = (double) opacity / (double) OPAQUE;
+ f->alpha[1] = (double) opacity / (double) OPAQUE;
+
+ store_frame_param (f, Qalpha, make_float (f->alpha[0]));
+ }
+ else
+ {
+ f->alpha[0] = 1.0;
+ f->alpha[1] = 1.0;
+
+ store_frame_param (f, Qalpha, Qnil);
+ }
+#else
+ opacity_cookie
+ = xcb_get_property (dpyinfo->xcb_connection, 0,
+ (xcb_window_t) FRAME_OUTER_WINDOW (f),
+ (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity,
+ XCB_ATOM_CARDINAL, 0, 1);
+ opacity_reply
+ = xcb_get_property_reply (dpyinfo->xcb_connection,
+ opacity_cookie, &error);
+
+ if (!opacity_reply)
+ free (error), rc = false;
+ else
+ rc = (opacity_reply->format == 32
+ && (opacity_reply->type == XCB_ATOM_CARDINAL
+ || opacity_reply->type == XCB_ATOM_ATOM
+ || opacity_reply->type == XCB_ATOM_WINDOW)
+ && (xcb_get_property_value_length (opacity_reply) >= 4));
+
+ if (rc)
+ {
+ value = *(uint32_t *) xcb_get_property_value (opacity_reply);
+
+ f->alpha[0] = (double) value / (double) OPAQUE;
+ f->alpha[1] = (double) value / (double) OPAQUE;
+ store_frame_param (f, Qalpha, make_float (f->alpha[0]));
+ }
+ else
+ {
+ f->alpha[0] = 1.0;
+ f->alpha[1] = 1.0;
+
+ store_frame_param (f, Qalpha, Qnil);
+ }
+
+ if (opacity_reply)
+ free (opacity_reply);
+#endif
+ }
+
+#ifndef USE_XCB
+ if (tmp_data)
+ XFree (tmp_data);
+#endif
+ }
+
if (event->xproperty.window == dpyinfo->root_window
&& (event->xproperty.atom == dpyinfo->Xatom_net_client_list_stacking
|| event->xproperty.atom == dpyinfo->Xatom_net_current_desktop)
@@ -14722,11 +16643,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
if (x_dnd_use_toplevels)
{
- x_dnd_free_toplevels ();
+ x_dnd_free_toplevels (true);
if (x_dnd_compute_toplevels (dpyinfo))
{
- x_dnd_free_toplevels ();
+ x_dnd_free_toplevels (true);
x_dnd_use_toplevels = false;
}
}
@@ -15223,9 +17144,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
memset (&compose_status, 0, sizeof (compose_status));
#ifdef HAVE_XKB
- if (FRAME_DISPLAY_INFO (f)->xkb_desc)
+ if (dpyinfo->xkb_desc)
{
- XkbDescRec *rec = FRAME_DISPLAY_INFO (f)->xkb_desc;
+ XkbDescRec *rec = dpyinfo->xkb_desc;
if (rec->map->modmap && rec->map->modmap[xkey.keycode])
goto done_keysym;
@@ -15256,7 +17177,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (status_return == XBufferOverflow)
{
copy_bufsiz = nbytes + 1;
- copy_bufptr = alloca (copy_bufsiz);
+ copy_bufptr = SAFE_ALLOCA (copy_bufsiz);
nbytes = XmbLookupString (FRAME_XIC (f),
&xkey, (char *) copy_bufptr,
copy_bufsiz, &keysym,
@@ -15594,7 +17515,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (f && x_mouse_click_focus_ignore_position)
{
- ignore_next_mouse_click_timeout = event->xmotion.time + 200;
+ ignore_next_mouse_click_timeout = (event->xmotion.time
+ + x_mouse_click_focus_ignore_time);
mouse_click_timeout_display = dpyinfo;
}
@@ -15693,7 +17615,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
Do it only if there's something to cancel.
Otherwise, the startup message is cleared when
the mouse leaves the frame. */
- if (any_help_event_p)
+ if (any_help_event_p
+ /* But never if `mouse-drag-and-drop-region' is in
+ progress, since that results in the tooltip being
+ dismissed when the mouse moves on top. */
+ && !((EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping))
+ && gui_mouse_grabbed (dpyinfo)))
do_help = -1;
}
#ifdef USE_GTK
@@ -15724,6 +17652,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
if (x_dnd_in_progress
+ /* Handle these events normally if the recursion
+ level is higher than when the drag-and-drop
+ operation was initiated. This is so that mouse
+ input works while we're in the debugger for, say,
+ `x-dnd-movement-function`. */
+ && (command_loop_level + minibuf_level
+ <= x_dnd_recursion_depth)
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
Window target, toplevel;
@@ -15731,6 +17666,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
xm_top_level_leave_message lmsg;
xm_top_level_enter_message emsg;
xm_drag_motion_message dmsg;
+ XRectangle *r;
+ bool was_frame;
+
+ /* Always clear mouse face. */
+ clear_mouse_face (hlinfo);
+ hlinfo->mouse_face_hidden = true;
/* Sometimes the drag-and-drop operation starts with the
pointer of a frame invisible due to input. Since
@@ -15738,13 +17679,35 @@ handle_one_xevent (struct x_display_info *dpyinfo,
visible manually. */
if (f)
- XTtoggle_invisible_pointer (f, false);
+ {
+ XTtoggle_invisible_pointer (f, false);
+
+ r = &dpyinfo->last_mouse_glyph;
+
+ /* Also remember the mouse glyph and set
+ mouse_moved. */
+ if (f != dpyinfo->last_mouse_glyph_frame
+ || event->xmotion.x < r->x
+ || event->xmotion.x >= r->x + r->width
+ || event->xmotion.y < r->y
+ || event->xmotion.y >= r->y + r->height)
+ {
+ f->mouse_moved = true;
+ f->last_mouse_device = Qnil;
+ dpyinfo->last_mouse_scroll_bar = NULL;
+
+ remember_mouse_glyph (f, event->xmotion.x,
+ event->xmotion.y, r);
+ dpyinfo->last_mouse_glyph_frame = f;
+ }
+ }
target = x_dnd_get_target_window (dpyinfo,
event->xmotion.x_root,
event->xmotion.y_root,
&target_proto,
- &motif_style, &toplevel);
+ &motif_style, &toplevel,
+ &was_frame);
if (toplevel != x_dnd_last_seen_toplevel)
{
@@ -15761,6 +17724,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -15800,6 +17764,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -15816,7 +17781,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
dmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_NONE, XM_DRAG_NOOP,
+ XM_DROP_SITE_NONE, x_dnd_motif_operations,
XM_DROP_ACTION_DROP_CANCEL);
dmsg.timestamp = event->xmotion.time;
dmsg.x = event->xmotion.x_root;
@@ -15842,11 +17807,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
x_dnd_last_motif_style = motif_style;
+ x_dnd_last_window_is_frame = was_frame;
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
- else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -15865,7 +17832,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
}
- if (x_dnd_last_protocol_version != -1 && target != None)
+ if (x_dnd_last_window_is_frame && target != None)
+ x_dnd_note_self_position (dpyinfo, target,
+ event->xbutton.x_root,
+ event->xbutton.y_root);
+ else if (x_dnd_last_protocol_version != -1 && target != None)
x_dnd_send_position (x_dnd_frame, target,
x_dnd_last_protocol_version,
event->xmotion.x_root,
@@ -15873,7 +17844,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_selection_timestamp,
x_dnd_wanted_action, 0,
event->xmotion.state);
- else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -15883,9 +17855,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
dmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (dpyinfo,
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
(!x_dnd_xm_use_help
? XM_DROP_ACTION_DROP
: XM_DROP_ACTION_DROP_HELP));
@@ -15898,6 +17868,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
target, &dmsg);
}
+ x_dnd_update_tooltip_position (event->xmotion.x_root,
+ event->xmotion.y_root);
+
goto OTHER;
}
@@ -16000,6 +17973,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
So if this ConfigureNotify is immediately followed by another
for the same window, use the info from the latest update, and
consider the events all handled. */
+
/* Opaque resize may be trickier; ConfigureNotify events are
mixed with Expose events for multiple windows. */
configureEvent = *event;
@@ -16021,6 +17995,36 @@ handle_one_xevent (struct x_display_info *dpyinfo,
configureEvent = next_event;
}
+ /* If we get a ConfigureNotify for the root window, this means
+ the dimensions of the screen it's on changed. */
+
+ if (configureEvent.xconfigure.window == dpyinfo->root_window)
+ {
+#ifdef HAVE_XRANDR
+ /* This function is OK to call even if the X server doesn't
+ support RandR. */
+ XRRUpdateConfiguration (&configureEvent);
+#elif !defined USE_GTK
+ /* Catch screen size changes even if RandR is not available
+ on the client. GTK does this internally. */
+
+ if (configureEvent.xconfigure.width != dpyinfo->screen_width
+ || configureEvent.xconfigure.height != dpyinfo->screen_height)
+ {
+ inev.ie.kind = MONITORS_CHANGED_EVENT;
+ XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
+
+ /* Store this event now since inev.ie.type could be set to
+ MOVE_FRAME_EVENT later. */
+ kbd_buffer_store_event (&inev.ie);
+ inev.ie.kind = NO_EVENT;
+ }
+#endif
+
+ dpyinfo->screen_width = configureEvent.xconfigure.width;
+ dpyinfo->screen_height = configureEvent.xconfigure.height;
+ }
+
if (x_dnd_in_progress && x_dnd_use_toplevels
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
@@ -16182,15 +18186,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#endif
x_net_wm_state (f, configureEvent.xconfigure.window);
-#ifdef USE_X_TOOLKIT
+#if defined USE_X_TOOLKIT || defined USE_GTK
/* Tip frames are pure X window, set size for them. */
if (FRAME_TOOLTIP_P (f))
{
if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height
|| FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width)
- {
- SET_FRAME_GARBAGED (f);
- }
+ SET_FRAME_GARBAGED (f);
+
FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
}
@@ -16317,8 +18320,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
bool dnd_grab = false;
if (x_dnd_in_progress
+ /* Handle these events normally if the recursion
+ level is higher than when the drag-and-drop
+ operation was initiated. This is so that mouse
+ input works while we're in the debugger for, say,
+ `x-dnd-movement-function`. */
+ && (command_loop_level + minibuf_level
+ <= x_dnd_recursion_depth)
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
+ f = mouse_or_wdesc_frame (dpyinfo, event->xbutton.window);
+
+ if (event->type == ButtonPress)
+ {
+ dpyinfo->grabbed |= (1 << event->xbutton.button);
+ dpyinfo->last_mouse_frame = f;
+ if (f && !tab_bar_p)
+ f->last_tab_bar_item = -1;
+#if ! defined (USE_GTK)
+ if (f && !tool_bar_p)
+ f->last_tool_bar_item = -1;
+#endif /* not USE_GTK */
+ }
+ else
+ dpyinfo->grabbed &= ~(1 << event->xbutton.button);
+
if (event->xbutton.type == ButtonPress
&& x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
@@ -16350,7 +18376,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_in_progress = false;
+ if (x_dnd_update_tooltip
+ && FRAMEP (tip_frame)
+ && FRAME_LIVE_P (XFRAME (tip_frame))
+ && (FRAME_X_DISPLAY (XFRAME (tip_frame))
+ == FRAME_X_DISPLAY (x_dnd_frame)))
+ Fx_hide_tip ();
+
+ x_dnd_finish_frame = x_dnd_frame;
+
if (x_dnd_last_seen_window != None
+ && x_dnd_last_window_is_frame)
+ {
+ x_dnd_waiting_for_finish = false;
+ x_dnd_note_self_drop (dpyinfo,
+ x_dnd_last_seen_window,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ event->xbutton.time);
+ }
+ else if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
{
x_dnd_pending_finish_target = x_dnd_last_seen_window;
@@ -16386,9 +18431,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (dpyinfo,
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
(!x_dnd_xm_use_help
? XM_DROP_ACTION_DROP
: XM_DROP_ACTION_DROP_HELP));
@@ -16436,15 +18479,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_last_seen_window = None;
x_dnd_last_seen_toplevel = None;
+ x_dnd_last_window_is_frame = false;
x_dnd_frame = NULL;
- x_set_dnd_targets (NULL, 0);
}
}
goto OTHER;
}
- if (x_dnd_in_progress)
+ if (x_dnd_in_progress
+ && (command_loop_level + minibuf_level
+ <= x_dnd_recursion_depth))
goto OTHER;
memset (&compose_status, 0, sizeof (compose_status));
@@ -16480,7 +18525,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
f = x_any_window_to_frame (dpyinfo, event->xbutton.window);
if (event->xbutton.button > 3
- && event->xbutton.button < 9
+ && event->xbutton.button < 8
&& f)
{
if (ignore_next_mouse_click_timeout
@@ -16794,7 +18839,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
ev.window = enter->event;
ev.time = enter->time;
- x_display_set_last_user_time (dpyinfo, xi_event->time);
+ x_display_set_last_user_time (dpyinfo, enter->time);
#ifdef USE_MOTIF
use_copy = true;
@@ -16852,7 +18897,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (f && x_mouse_click_focus_ignore_position)
{
- ignore_next_mouse_click_timeout = xev->time + 200;
+ ignore_next_mouse_click_timeout = (enter->time
+ + x_mouse_click_focus_ignore_time);
mouse_click_timeout_display = dpyinfo;
}
@@ -16896,7 +18942,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#ifdef USE_X_TOOLKIT
if (popup_activated ()
- && leave->mode == XINotifyPassiveUngrab)
+ && (leave->mode == XINotifyPassiveUngrab
+ || leave->mode == XINotifyUngrab))
any = x_any_window_to_frame (dpyinfo, leave->event);
#endif
@@ -16941,7 +18988,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
leave->deviceid, false);
#endif
- x_display_set_last_user_time (dpyinfo, xi_event->time);
+ x_display_set_last_user_time (dpyinfo, leave->time);
#ifdef HAVE_XWIDGETS
{
@@ -16968,6 +19015,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
masks are set on the frame widget's window. */
f = x_window_to_frame (dpyinfo, leave->event);
+ /* Also do this again here, since the test for `any'
+ above may not have found a frame, as that usually
+ just looks up a top window on Xt builds. */
+
+#ifdef HAVE_XINPUT2_1
+ if (leave->detail != XINotifyInferior && f)
+ xi_reset_scroll_valuators_for_device_id (dpyinfo,
+ leave->deviceid, false);
+#endif
+
if (!f)
f = x_top_window_to_frame (dpyinfo, leave->event);
#endif
@@ -16985,7 +19042,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
Do it only if there's something to cancel.
Otherwise, the startup message is cleared when
the mouse leaves the frame. */
- if (any_help_event_p)
+ if (any_help_event_p
+ /* But never if `mouse-drag-and-drop-region' is
+ in progress, since that results in the
+ tooltip being dismissed when the mouse moves
+ on top. */
+ && !((EQ (track_mouse, Qdrag_source)
+ || EQ (track_mouse, Qdropping))
+ && gui_mouse_grabbed (dpyinfo)))
do_help = -1;
}
#ifdef USE_GTK
@@ -17004,6 +19068,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
XIValuatorState *states;
double *values;
bool found_valuator = false;
+ bool other_valuators_found = false;
#endif
/* A fake XMotionEvent for x_note_mouse_movement. */
XMotionEvent ev;
@@ -17061,6 +19126,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
i, *values, &val);
values++;
+ if (!val)
+ {
+ other_valuators_found = true;
+ continue;
+ }
+
if (delta != DBL_MAX)
{
if (!f)
@@ -17208,12 +19279,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
So instead of that, just ignore XI wheel
events which land on a scroll bar.
- Here we assume anything which isn't the edit
- widget window is a scroll bar. */
+ Here we assume anything which isn't the edit
+ widget window is a scroll bar. */
if (xev->child != None
&& xev->child != FRAME_X_WINDOW (f))
- goto OTHER;
+ goto XI_OTHER;
#endif
if (fabs (total_x) > 0 || fabs (total_y) > 0)
@@ -17249,7 +19320,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (source && !NILP (source->name))
inev.ie.device = source->name;
- goto XI_OTHER;
+ if (!other_valuators_found)
+ goto XI_OTHER;
}
#ifdef HAVE_XWIDGETS
}
@@ -17304,10 +19376,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
f = mouse_or_wdesc_frame (dpyinfo, xev->event);
if (x_dnd_in_progress
+ /* Handle these events normally if the recursion
+ level is higher than when the drag-and-drop
+ operation was initiated. This is so that mouse
+ input works while we're in the debugger for, say,
+ `x-dnd-movement-function`. */
+ && (command_loop_level + minibuf_level
+ <= x_dnd_recursion_depth)
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
Window target, toplevel;
int target_proto, motif_style;
+ XRectangle *r;
+ bool was_frame;
+
+ /* Always clear mouse face. */
+ clear_mouse_face (hlinfo);
+ hlinfo->mouse_face_hidden = true;
/* Sometimes the drag-and-drop operation starts with the
pointer of a frame invisible due to input. Since
@@ -17315,14 +19400,37 @@ handle_one_xevent (struct x_display_info *dpyinfo,
visible manually. */
if (f)
- XTtoggle_invisible_pointer (f, false);
+ {
+ XTtoggle_invisible_pointer (f, false);
+
+ r = &dpyinfo->last_mouse_glyph;
+
+ /* Also remember the mouse glyph and set
+ mouse_moved. */
+ if (f != dpyinfo->last_mouse_glyph_frame
+ || xev->event_x < r->x
+ || xev->event_x >= r->x + r->width
+ || xev->event_y < r->y
+ || xev->event_y >= r->y + r->height)
+ {
+ f->mouse_moved = true;
+ f->last_mouse_device = (source ? source->name
+ : Qnil);
+ dpyinfo->last_mouse_scroll_bar = NULL;
+
+ remember_mouse_glyph (f, xev->event_x,
+ xev->event_y, r);
+ dpyinfo->last_mouse_glyph_frame = f;
+ }
+ }
target = x_dnd_get_target_window (dpyinfo,
xev->root_x,
xev->root_y,
&target_proto,
&motif_style,
- &toplevel);
+ &toplevel,
+ &was_frame);
if (toplevel != x_dnd_last_seen_toplevel)
{
@@ -17339,6 +19447,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -17378,6 +19487,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -17396,7 +19506,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_NONE, XM_DRAG_NOOP,
+ XM_DROP_SITE_NONE, x_dnd_motif_operations,
XM_DROP_ACTION_DROP_CANCEL);
dmsg.timestamp = xev->time;
dmsg.x = lrint (xev->root_x);
@@ -17422,11 +19532,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
x_dnd_last_motif_style = motif_style;
+ x_dnd_last_window_is_frame = was_frame;
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
- else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -17445,7 +19557,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
}
- if (x_dnd_last_protocol_version != -1 && target != None)
+ if (x_dnd_last_window_is_frame && target != None)
+ x_dnd_note_self_position (dpyinfo, target,
+ xev->root_x, xev->root_y);
+ else if (x_dnd_last_protocol_version != -1 && target != None)
{
dnd_state = xev->mods.effective;
@@ -17466,7 +19581,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_wanted_action, 0,
dnd_state);
}
- else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -17477,9 +19593,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (dpyinfo,
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
(!x_dnd_xm_use_help
? XM_DROP_ACTION_DROP
: XM_DROP_ACTION_DROP_HELP));
@@ -17492,6 +19606,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
target, &dmsg);
}
+ x_dnd_update_tooltip_position (xev->root_x, xev->root_y);
+
goto XI_OTHER;
}
@@ -17558,7 +19674,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
#ifndef USE_TOOLKIT_SCROLL_BARS
struct scroll_bar *bar
- = x_window_to_scroll_bar (xi_event->display, xev->event, 2);
+ = x_window_to_scroll_bar (dpyinfo->display, xev->event, 2);
if (bar)
x_scroll_bar_note_movement (bar, &ev);
@@ -17595,8 +19711,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
int dnd_state;
if (x_dnd_in_progress
+ && (command_loop_level + minibuf_level
+ <= x_dnd_recursion_depth)
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
+ f = mouse_or_wdesc_frame (dpyinfo, xev->event);
+
+ if (xev->evtype == XI_ButtonPress)
+ {
+ dpyinfo->grabbed |= (1 << xev->detail);
+ dpyinfo->last_mouse_frame = f;
+ if (f && !tab_bar_p)
+ f->last_tab_bar_item = -1;
+#if ! defined (USE_GTK)
+ if (f && !tool_bar_p)
+ f->last_tool_bar_item = -1;
+#endif /* not USE_GTK */
+ }
+ else
+ dpyinfo->grabbed &= ~(1 << xev->detail);
+
if (xev->evtype == XI_ButtonPress
&& x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
@@ -17634,8 +19768,33 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_in_progress = false;
+ /* If a tooltip that we're following is
+ displayed, hide it now. */
+
+ if (x_dnd_update_tooltip
+ && FRAMEP (tip_frame)
+ && FRAME_LIVE_P (XFRAME (tip_frame))
+ && (FRAME_X_DISPLAY (XFRAME (tip_frame))
+ == FRAME_X_DISPLAY (x_dnd_frame)))
+ Fx_hide_tip ();
+
+ /* This doesn't have to be marked since it
+ is only accessed if
+ x_dnd_waiting_for_finish is true, which
+ is only possible inside the DND event
+ loop where that frame is on the
+ stack. */
+ x_dnd_finish_frame = x_dnd_frame;
+
if (x_dnd_last_seen_window != None
- && x_dnd_last_protocol_version != -1)
+ && x_dnd_last_window_is_frame)
+ {
+ x_dnd_waiting_for_finish = false;
+ x_dnd_note_self_drop (dpyinfo, x_dnd_last_seen_window,
+ xev->root_x, xev->root_y, xev->time);
+ }
+ else if (x_dnd_last_seen_window != None
+ && x_dnd_last_protocol_version != -1)
{
x_dnd_pending_finish_target = x_dnd_last_seen_window;
x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version;
@@ -17670,9 +19829,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
dmsg.side_effects
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (dpyinfo,
- x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
(!x_dnd_xm_use_help
? XM_DROP_ACTION_DROP
: XM_DROP_ACTION_DROP_HELP));
@@ -17727,15 +19884,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_last_seen_window = None;
x_dnd_last_seen_toplevel = None;
+ x_dnd_last_window_is_frame = false;
x_dnd_frame = NULL;
- x_set_dnd_targets (NULL, 0);
goto XI_OTHER;
}
}
}
- if (x_dnd_in_progress)
+ if (x_dnd_in_progress
+ && (command_loop_level + minibuf_level
+ <= x_dnd_recursion_depth))
goto XI_OTHER;
#ifdef USE_MOTIF
@@ -17801,9 +19960,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
g_object_ref (copy->button.window);
- if (popup_activated ()
- && xev->evtype == XI_ButtonRelease)
- goto XI_OTHER;
+ if (popup_activated ())
+ {
+ /* GTK+ popup menus don't respond to core buttons
+ after Button3, so don't dismiss popup menus upon
+ wheel movement here either. */
+ if (xev->detail > 3)
+ *finish = X_EVENT_DROP;
+
+ if (xev->evtype == XI_ButtonRelease)
+ goto XI_OTHER;
+ }
#endif
#ifdef HAVE_XINPUT2_1
@@ -17896,7 +20063,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
f = x_any_window_to_frame (dpyinfo, xev->event);
- if (xev->detail > 3 && xev->detail < 9 && f)
+ if (xev->detail > 3 && xev->detail < 8 && f)
{
if (xev->evtype == XI_ButtonRelease)
{
@@ -17939,7 +20106,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (f)
{
- if (xev->detail >= 4 && xev->detail <= 8)
+ if (xev->detail >= 4 && xev->detail < 8)
{
if (xev->evtype == XI_ButtonRelease)
{
@@ -18260,9 +20427,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
state |= x_emacs_to_x_modifiers (dpyinfo, extra_keyboard_modifiers);
#ifdef HAVE_XKB
- if (FRAME_DISPLAY_INFO (f)->xkb_desc)
+ if (dpyinfo->xkb_desc)
{
- XkbDescRec *rec = FRAME_DISPLAY_INFO (f)->xkb_desc;
+ XkbDescRec *rec = dpyinfo->xkb_desc;
if (rec->map->modmap && rec->map->modmap[xev->detail])
goto xi_done_keysym;
@@ -18352,7 +20519,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (status_return == XBufferOverflow)
{
copy_bufsiz = nbytes + 1;
- copy_bufptr = alloca (copy_bufsiz);
+ copy_bufptr = SAFE_ALLOCA (copy_bufsiz);
nbytes = XmbLookupString (FRAME_XIC (f),
&xkey, (char *) copy_bufptr,
copy_bufsiz, &keysym,
@@ -18384,8 +20551,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
copy_bufsiz, &overflow);
if (overflow)
{
- copy_bufptr = alloca ((copy_bufsiz += overflow)
- * sizeof *copy_bufptr);
+ copy_bufptr = SAFE_ALLOCA ((copy_bufsiz += overflow)
+ * sizeof *copy_bufptr);
overflow = 0;
nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
state & ~mods_rtrn, copy_bufptr,
@@ -18696,7 +20863,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
struct xi_touch_point_t *tem, *last;
#endif
- disabled = alloca (sizeof *disabled * hev->num_info);
+ disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info);
n_disabled = 0;
for (i = 0; i < hev->num_info; ++i)
@@ -18995,6 +21162,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (!menu_bar_p && !tool_bar_p)
{
+ x_catch_errors (dpyinfo->display);
+
if (f && device->direct_p)
{
*finish = X_EVENT_DROP;
@@ -19023,6 +21192,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
xev->detail, xev->event, XIRejectTouch);
#endif
+ x_uncatch_errors ();
}
else
{
@@ -19135,7 +21305,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
device = xi_device_from_id (dpyinfo, pev->deviceid);
source = xi_device_from_id (dpyinfo, pev->sourceid);
- x_display_set_last_user_time (dpyinfo, xi_event->time);
+ x_display_set_last_user_time (dpyinfo, pev->time);
if (!device)
goto XI_OTHER;
@@ -19466,7 +21636,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
/* And the common case where there is no input rect and the
- bouding rect equals the window dimensions. */
+ bounding rect equals the window dimensions. */
if (tem->n_input_rects == -1
&& tem->n_bounding_rects == 1
@@ -19484,6 +21654,75 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
}
#endif
+#if defined HAVE_XRANDR && !defined USE_GTK
+ if (dpyinfo->xrandr_supported_p
+ && (event->type == (dpyinfo->xrandr_event_base
+ + RRScreenChangeNotify)
+ || event->type == (dpyinfo->xrandr_event_base
+ + RRNotify)))
+ {
+ union buffered_input_event *ev;
+ Time timestamp;
+ Lisp_Object current_monitors;
+ XRRScreenChangeNotifyEvent *notify;
+
+ if (event->type == (dpyinfo->xrandr_event_base
+ + RRScreenChangeNotify))
+ XRRUpdateConfiguration (event);
+
+ if (event->type == (dpyinfo->xrandr_event_base
+ + RRScreenChangeNotify))
+ {
+ notify = ((XRRScreenChangeNotifyEvent *) event);
+ timestamp = notify->timestamp;
+
+ /* Don't set screen dimensions if the notification is
+ for a different screen. */
+ if (notify->root == dpyinfo->root_window)
+ {
+ dpyinfo->screen_width = notify->width;
+ dpyinfo->screen_height = notify->height;
+ dpyinfo->screen_mm_width = notify->mwidth;
+ dpyinfo->screen_mm_height = notify->mheight;
+ }
+ }
+ else
+ timestamp = 0;
+
+ ev = (kbd_store_ptr == kbd_buffer
+ ? kbd_buffer + KBD_BUFFER_SIZE - 1
+ : kbd_store_ptr - 1);
+
+ if (kbd_store_ptr != kbd_fetch_ptr
+ && ev->ie.kind == MONITORS_CHANGED_EVENT
+ && XTERMINAL (ev->ie.arg) == dpyinfo->terminal)
+ /* Don't store a MONITORS_CHANGED_EVENT if there is
+ already an undelivered event on the queue. */
+ goto OTHER;
+
+ inev.ie.kind = MONITORS_CHANGED_EVENT;
+ inev.ie.timestamp = timestamp;
+ XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
+
+ /* Also don't do anything if the monitor configuration
+ didn't really change. */
+
+ current_monitors
+ = Fx_display_monitor_attributes_list (inev.ie.arg);
+
+ if (!NILP (Fequal (current_monitors,
+ dpyinfo->last_monitor_attributes_list)))
+ inev.ie.kind = NO_EVENT;
+
+ dpyinfo->last_monitor_attributes_list = current_monitors;
+
+ if (x_dnd_in_progress && x_dnd_update_tooltip)
+ x_dnd_monitors = current_monitors;
+
+ if (inev.ie.kind != NO_EVENT)
+ x_dnd_update_tooltip_now ();
+ }
+#endif
OTHER:
#ifdef USE_X_TOOLKIT
block_input ();
@@ -19566,6 +21805,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (any && any != f)
flush_dirty_back_buffer_on (any);
#endif
+
+ SAFE_FREE ();
return count;
}
@@ -19611,8 +21852,18 @@ XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
/* Don't allow XTread_socket to do anything if drag-and-drop is in
progress. If unblock_input causes XTread_socket to be called and
read X events while the drag-and-drop event loop is in progress,
- things can go wrong very quick. */
- if (x_dnd_in_progress || x_dnd_waiting_for_finish)
+ things can go wrong very quick.
+
+ When x_dnd_unwind_flag is true, the above doesn't apply, since
+ the surrounding code takes special precautions to keep it safe.
+
+ That doesn't matter for events from displays other than the
+ display of the drag-and-drop operation, though. */
+ if (!x_dnd_unwind_flag
+ && ((x_dnd_in_progress
+ && dpyinfo->display == FRAME_X_DISPLAY (x_dnd_frame))
+ || (x_dnd_waiting_for_finish
+ && dpyinfo->display == x_dnd_finish_display)))
return 0;
block_input ();
@@ -20129,70 +22380,131 @@ x_text_icon (struct frame *f, const char *icon_name)
return false;
}
-#define X_ERROR_MESSAGE_SIZE 200
-
-/* If non-nil, this should be a string.
- It means catch X errors and store the error message in this string.
- The reason we use a stack is that x_catch_error/x_uncatch_error can
- be called from a signal handler.
-*/
+struct x_error_message_stack
+{
+ /* Pointer to the error message of any error that was generated, or
+ NULL. */
+ char *string;
-struct x_error_message_stack {
- char string[X_ERROR_MESSAGE_SIZE];
+ /* The display this error handler applies to. */
Display *dpy;
+
+ /* A function to call upon an error if non-NULL. */
x_special_error_handler handler;
+
+ /* Some data to pass to that handler function. */
void *handler_data;
+
+ /* The previous handler in this stack. */
struct x_error_message_stack *prev;
+
+ /* The first request that this error handler applies to. Keeping
+ track of this allows us to avoid an XSync yet still have errors
+ for previously made requests be handled correctly. */
+ unsigned long first_request;
};
+
+/* Stack of X error message handlers. Whenever an error is generated
+ on a display, look in this stack for an appropriate error handler,
+ set its `string' to the error message and call its `handler' with
+ `handler_data'. If no handler applies to the error, don't catch
+ it, and let it crash Emacs instead.
+
+ This used to be a pointer to a string in which any error would be
+ placed before 2006. */
static struct x_error_message_stack *x_error_message;
-/* An X error handler which stores the error message in
- *x_error_message. This is called from x_error_handler if
- x_catch_errors is in effect. */
+/* The amount of items (depth) in that stack. */
+int x_error_message_count;
+
+static struct x_error_message_stack *
+x_find_error_handler (Display *dpy, XErrorEvent *event)
+{
+ struct x_error_message_stack *stack;
+
+ stack = x_error_message;
+
+ while (stack)
+ {
+ if (X_COMPARE_SERIALS (event->serial, >=,
+ stack->first_request)
+ && dpy == stack->dpy)
+ return stack;
+
+ stack = stack->prev;
+ }
+
+ return NULL;
+}
+
+void
+x_unwind_errors_to (int depth)
+{
+ while (x_error_message_count > depth)
+ /* This is safe to call because we check whether or not
+ x_error_message->dpy is still alive before calling XSync. */
+ x_uncatch_errors ();
+}
+
+#define X_ERROR_MESSAGE_SIZE 200
+
+/* An X error handler which stores the error message in the first
+ applicable handler in the x_error_message stack. This is called
+ from *x_error_handler if an x_catch_errors for DISPLAY is in
+ effect. */
static void
-x_error_catcher (Display *display, XErrorEvent *event)
+x_error_catcher (Display *display, XErrorEvent *event,
+ struct x_error_message_stack *stack)
{
+ char buf[X_ERROR_MESSAGE_SIZE];
+
XGetErrorText (display, event->error_code,
- x_error_message->string,
- X_ERROR_MESSAGE_SIZE);
- if (x_error_message->handler)
- x_error_message->handler (display, event, x_error_message->string,
- x_error_message->handler_data);
+ buf, X_ERROR_MESSAGE_SIZE);
+
+ if (stack->string)
+ xfree (stack->string);
+
+ stack->string = xstrdup (buf);
+
+ if (stack->handler)
+ stack->handler (display, event, stack->string,
+ stack->handler_data);
}
-/* Begin trapping X errors for display DPY. Actually we trap X errors
- for all displays, but DPY should be the display you are actually
- operating on.
+/* Begin trapping X errors for display DPY.
- After calling this function, X protocol errors no longer cause
- Emacs to exit; instead, they are recorded in the string
- stored in *x_error_message.
+ After calling this function, X protocol errors generated on DPY no
+ longer cause Emacs to exit; instead, they are recorded in an error
+ handler pushed onto the stack `x_error_message'.
Calling x_check_errors signals an Emacs error if an X error has
occurred since the last call to x_catch_errors or x_check_errors.
- Calling x_uncatch_errors resumes the normal error handling.
- Calling x_uncatch_errors_after_check is similar, but skips an XSync
- to the server, and should be used only immediately after
- x_had_errors_p or x_check_errors. */
+ Calling x_uncatch_errors resumes the normal error handling,
+ skipping an XSync if the last request made is known to have been
+ processed. Calling x_uncatch_errors_after_check is similar, but
+ always skips an XSync to the server, and should be used only
+ immediately after x_had_errors_p or x_check_errors, or when it is
+ known that no requests have been made since the last x_catch_errors
+ call for DPY. */
void
x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
void *handler_data)
{
- struct x_error_message_stack *data = xmalloc (sizeof *data);
-
- /* Make sure any errors from previous requests have been dealt with. */
- XSync (dpy, False);
+ struct x_error_message_stack *data;
+ data = xzalloc (sizeof *data);
data->dpy = dpy;
- data->string[0] = 0;
data->handler = handler;
data->handler_data = handler_data;
data->prev = x_error_message;
+ data->first_request = NextRequest (dpy);
x_error_message = data;
+
+ ++x_error_message_count;
}
void
@@ -20216,12 +22528,14 @@ x_uncatch_errors_after_check (void)
block_input ();
tmp = x_error_message;
x_error_message = x_error_message->prev;
+ --x_error_message_count;
+ if (tmp->string)
+ xfree (tmp->string);
xfree (tmp);
unblock_input ();
}
-/* Undo the last x_catch_errors call.
- DPY should be the display that was passed to x_catch_errors. */
+/* Undo the last x_catch_errors call. */
void
x_uncatch_errors (void)
@@ -20239,11 +22553,22 @@ x_uncatch_errors (void)
/* The display may have been closed before this function is called.
Check if it is still open before calling XSync. */
- if (x_display_info_for_display (x_error_message->dpy) != 0)
+ if (x_display_info_for_display (x_error_message->dpy) != 0
+ /* There is no point in making this extra sync if all requests
+ are known to have been fully processed. */
+ && (LastKnownRequestProcessed (x_error_message->dpy)
+ != NextRequest (x_error_message->dpy) - 1)
+ /* Likewise if no request was made since the trap was
+ installed. */
+ && (NextRequest (x_error_message->dpy)
+ > x_error_message->first_request))
XSync (x_error_message->dpy, False);
tmp = x_error_message;
x_error_message = x_error_message->prev;
+ --x_error_message_count;
+ if (tmp->string)
+ xfree (tmp->string);
xfree (tmp);
unblock_input ();
}
@@ -20255,36 +22580,64 @@ x_uncatch_errors (void)
void
x_check_errors (Display *dpy, const char *format)
{
- /* Make sure to catch any errors incurred so far. */
- XSync (dpy, False);
+ char *string;
+
+ /* This shouldn't happen, since x_check_errors should be called
+ immediately inside an x_catch_errors block. */
+ if (dpy != x_error_message->dpy)
+ emacs_abort ();
- if (x_error_message->string[0])
+ /* There is no point in making this extra sync if all requests
+ are known to have been fully processed. */
+ if ((LastKnownRequestProcessed (dpy)
+ != NextRequest (dpy) - 1)
+ && (NextRequest (dpy)
+ > x_error_message->first_request))
+ XSync (dpy, False);
+
+ if (x_error_message->string)
{
- char string[X_ERROR_MESSAGE_SIZE];
- memcpy (string, x_error_message->string, X_ERROR_MESSAGE_SIZE);
- x_uncatch_errors ();
+ string = alloca (strlen (x_error_message->string) + 1);
+ strcpy (string, x_error_message->string);
+
error (format, string);
}
}
-/* Nonzero if we had any X protocol errors
- since we did x_catch_errors on DPY. */
+/* Nonzero if any X protocol errors were generated since the last call
+ to x_catch_errors on DPY. */
bool
x_had_errors_p (Display *dpy)
{
+ /* This shouldn't happen, since x_check_errors should be called
+ immediately inside an x_catch_errors block. */
+ if (dpy != x_error_message->dpy)
+ emacs_abort ();
+
/* Make sure to catch any errors incurred so far. */
- XSync (dpy, False);
+ if ((LastKnownRequestProcessed (dpy)
+ != NextRequest (dpy) - 1)
+ && (NextRequest (dpy)
+ > x_error_message->first_request))
+ XSync (dpy, False);
- return x_error_message->string[0] != 0;
+ return x_error_message->string;
}
-/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
+/* Forget about any errors we have had, since we did x_catch_errors on
+ DPY. */
void
x_clear_errors (Display *dpy)
{
- x_error_message->string[0] = 0;
+ /* This shouldn't happen, since x_check_errors should be called
+ immediately inside an x_catch_errors block. */
+ if (dpy != x_error_message->dpy)
+ emacs_abort ();
+
+ xfree (x_error_message->string);
+ x_error_message->string = NULL;
}
#if false
@@ -20302,9 +22655,12 @@ x_fully_uncatch_errors (void)
#if false
static unsigned int x_wire_count;
-x_trace_wire (void)
+
+static int
+x_trace_wire (Display *dpy)
{
- fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
+ fprintf (stderr, "Lib call: %u\n", ++x_wire_count);
+ return 0;
}
#endif
@@ -20344,63 +22700,64 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
if (x_dnd_in_progress || x_dnd_waiting_for_finish)
{
- /* Handle display disconnect errors here because this function
- is not reentrant at this particular spot. */
- io_error_handler = XSetIOErrorHandler (x_dnd_io_error_handler);
-
- if (!sigsetjmp (x_dnd_disconnect_handler, 1)
- && x_dnd_in_progress
- && dpy != (x_dnd_waiting_for_finish
- ? x_dnd_finish_display
- : FRAME_X_DISPLAY (x_dnd_frame)))
+ if (!ioerror)
{
- /* Clean up drag and drop if the drag frame's display isn't
- the one being disconnected. */
- f = x_dnd_frame;
-
- if (x_dnd_last_seen_window != None
- && x_dnd_last_protocol_version != -1)
- x_dnd_send_leave (x_dnd_frame,
- x_dnd_last_seen_window);
- else if (x_dnd_last_seen_window != None
- && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
- && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
- && x_dnd_motif_setup_p)
+ /* Handle display disconnect errors here because this function
+ is not reentrant at this particular spot. */
+ io_error_handler = XSetIOErrorHandler (x_dnd_io_error_handler);
+
+ if (!!sigsetjmp (x_dnd_disconnect_handler, 1)
+ && x_dnd_in_progress
+ && dpy == (x_dnd_waiting_for_finish
+ ? x_dnd_finish_display
+ : FRAME_X_DISPLAY (x_dnd_frame)))
{
- dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
- XM_DRAG_REASON_DROP_START);
- dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
- dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time;
- dmsg.side_effects
- = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
- x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
- x_dnd_wanted_action),
- XM_DROP_ACTION_DROP_CANCEL);
- dmsg.x = 0;
- dmsg.y = 0;
- dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
- dmsg.source_window = FRAME_X_WINDOW (f);
-
- x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
- x_dnd_last_seen_window, 0);
- xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
- x_dnd_last_seen_window, &dmsg);
+ /* Clean up drag and drop if the drag frame's display isn't
+ the one being disconnected. */
+ f = x_dnd_frame;
+
+ if (x_dnd_last_seen_window != None
+ && x_dnd_last_protocol_version != -1)
+ x_dnd_send_leave (x_dnd_frame,
+ x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
+ dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID, x_dnd_motif_operations,
+ XM_DROP_ACTION_DROP_CANCEL);
+ dmsg.x = 0;
+ dmsg.y = 0;
+ dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+ dmsg.source_window = FRAME_X_WINDOW (f);
+
+ x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
+ x_dnd_last_seen_window, 0);
+ xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+ x_dnd_last_seen_window, &dmsg);
+ }
}
+
+ XSetIOErrorHandler (io_error_handler);
}
- XSetIOErrorHandler (io_error_handler);
dpyinfo = x_display_info_for_display (dpy);
x_dnd_last_seen_window = None;
x_dnd_last_seen_toplevel = None;
x_dnd_in_progress = false;
- x_set_dnd_targets (NULL, 0);
x_dnd_waiting_for_finish = false;
if (x_dnd_use_toplevels)
- x_dnd_free_toplevels ();
+ x_dnd_free_toplevels (!ioerror);
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
@@ -20417,6 +22774,12 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
dpyinfo->display = 0;
}
+ /* delete_frame can still try to read async input (even though we
+ tell pass `noelisp'), because looking up the `delete-before'
+ parameter calls Fassq which then calls maybe_quit. So block
+ input while deleting frames. */
+ block_input ();
+
/* First delete frames whose mini-buffers are on frames
that are on the dead display. */
FOR_EACH_FRAME (tail, frame)
@@ -20481,6 +22844,8 @@ For details, see etc/PROBLEMS.\n",
}
}
+ unblock_input ();
+
if (terminal_list == 0)
{
fprintf (stderr, "%s\n", error_msg);
@@ -20506,16 +22871,16 @@ static void x_error_quitter (Display *, XErrorEvent *);
static int
x_error_handler (Display *display, XErrorEvent *event)
{
+ struct x_error_message_stack *stack;
#ifdef HAVE_XINPUT2
struct x_display_info *dpyinfo;
#endif
#if defined USE_GTK && defined HAVE_GTK3
- if ((event->error_code == BadMatch || event->error_code == BadWindow)
+ if ((event->error_code == BadMatch
+ || event->error_code == BadWindow)
&& event->request_code == X_SetInputFocus)
- {
- return 0;
- }
+ return 0;
#endif
/* If we try to ungrab or grab a device that doesn't exist anymore
@@ -20536,8 +22901,10 @@ x_error_handler (Display *display, XErrorEvent *event)
return 0;
#endif
- if (x_error_message)
- x_error_catcher (display, event);
+ stack = x_find_error_handler (display, event);
+
+ if (stack)
+ x_error_catcher (display, event, stack);
else
x_error_quitter (display, event);
return 0;
@@ -21043,17 +23410,16 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_gravity)
https://freedesktop.org/wiki/Specifications/wm-spec/. */
bool
-x_wm_supports (struct frame *f, Atom want_atom)
+x_wm_supports_1 (struct x_display_info *dpyinfo, Atom want_atom)
{
Atom actual_type;
unsigned long actual_size, bytes_remaining;
int i, rc, actual_format;
bool ret;
Window wmcheck_window;
- struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Window target_window = dpyinfo->root_window;
int max_len = 65536;
- Display *dpy = FRAME_X_DISPLAY (f);
+ Display *dpy = dpyinfo->display;
unsigned char *tmp_data = NULL;
Atom target_type = XA_WINDOW;
@@ -21127,6 +23493,13 @@ x_wm_supports (struct frame *f, Atom want_atom)
return ret;
}
+bool
+x_wm_supports (struct frame *f, Atom want_atom)
+{
+ return x_wm_supports_1 (FRAME_DISPLAY_INFO (f),
+ want_atom);
+}
+
static void
set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value)
{
@@ -21289,15 +23662,20 @@ x_get_current_wm_state (struct frame *f,
#ifdef USE_XCB
xcb_get_property_cookie_t prop_cookie;
xcb_get_property_reply_t *prop;
- xcb_atom_t *reply_data UNINIT;
+ typedef xcb_atom_t reply_data_object;
#else
Display *dpy = FRAME_X_DISPLAY (f);
unsigned long bytes_remaining;
int rc, actual_format;
Atom actual_type;
unsigned char *tmp_data = NULL;
- Atom *reply_data UNINIT;
+ typedef Atom reply_data_object;
#endif
+ reply_data_object *reply_data;
+# if defined GCC_LINT || defined lint
+ reply_data_object reply_data_dummy;
+ reply_data = &reply_data_dummy;
+# endif
*sticky = false;
*size_state = FULLSCREEN_NONE;
@@ -21648,7 +24026,7 @@ x_check_expected_move (struct frame *f, int expected_left, int expected_top)
int adjusted_left;
int adjusted_top;
- FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
+ FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
@@ -21665,7 +24043,6 @@ x_check_expected_move (struct frame *f, int expected_left, int expected_top)
else
/* It's a "Type B" window manager. We don't have to adjust the
frame's position. */
-
FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
}
@@ -21679,11 +24056,17 @@ x_check_expected_move (struct frame *f, int expected_left, int expected_top)
static void
x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
{
- int count = 0;
+ sigset_t emptyset;
+ int count, current_left, current_top;
+ struct timespec fallback;
+
+ sigemptyset (&emptyset);
+ count = 0;
while (count++ < 50)
{
- int current_left = 0, current_top = 0;
+ current_left = 0;
+ current_top = 0;
/* In theory, this call to XSync only needs to happen once, but in
practice, it doesn't seem to work, hence the need for the surrounding
@@ -21708,7 +24091,14 @@ x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
/* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
will then return up-to-date position info. */
- wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
+ fallback = dtotimespec (0.5);
+
+ /* This will hang if input is blocked, so use pselect to wait
+ instead. */
+ if (input_blocked_p ())
+ pselect (0, NULL, NULL, NULL, &fallback, &emptyset);
+ else
+ wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
}
@@ -22375,6 +24765,18 @@ x_make_frame_visible_invisible (struct frame *f, bool visible)
x_make_frame_invisible (f);
}
+Cursor
+x_create_font_cursor (struct x_display_info *dpyinfo, int glyph)
+{
+ if (glyph <= 65535)
+ return XCreateFontCursor (dpyinfo->display, glyph);
+
+ /* x-pointer-invisible cannot fit in CARD16, and thus cannot be any
+ existing cursor. */
+ return make_invisible_cursor (dpyinfo);
+}
+
+
/* Change window state from mapped to iconified. */
void
@@ -22462,6 +24864,10 @@ x_iconify_frame (struct frame *f)
msg.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_wm_change_state;
msg.xclient.format = 32;
msg.xclient.data.l[0] = IconicState;
+ msg.xclient.data.l[1] = 0;
+ msg.xclient.data.l[2] = 0;
+ msg.xclient.data.l[3] = 0;
+ msg.xclient.data.l[4] = 0;
if (! XSendEvent (FRAME_X_DISPLAY (f),
FRAME_DISPLAY_INFO (f)->root_window,
@@ -22691,7 +25097,6 @@ x_destroy_window (struct frame *f)
x_free_frame_resources (f);
xfree (f->output_data.x->saved_menu_event);
- xfree (f->output_data.x);
#ifdef HAVE_X_I18N
if (f->output_data.x->preedit_chars)
@@ -22703,11 +25108,162 @@ x_destroy_window (struct frame *f)
XFree (f->output_data.x->xi_masks);
#endif
+ xfree (f->output_data.x);
f->output_data.x = NULL;
dpyinfo->reference_count--;
}
+/* Intern NAME in DPYINFO, but check to see if the atom was already
+ interned when the X connection was opened, and use that instead.
+
+ If PREDEFINED_ONLY, return None if the atom was not interned during
+ connection setup or is predefined. */
+Atom
+x_intern_cached_atom (struct x_display_info *dpyinfo,
+ const char *name, bool predefined_only)
+{
+ int i;
+ char *ptr;
+ Atom *atom;
+
+ /* Special atoms that depend on the screen number. */
+ char xsettings_atom_name[sizeof "_XSETTINGS_S%d" - 2
+ + INT_STRLEN_BOUND (int)];
+ char cm_atom_name[sizeof "_NET_WM_CM_S%d" - 2
+ + INT_STRLEN_BOUND (int)];
+
+ sprintf (xsettings_atom_name, "_XSETTINGS_S%d",
+ XScreenNumberOfScreen (dpyinfo->screen));
+ sprintf (cm_atom_name, "_NET_WM_CM_S%d",
+ XScreenNumberOfScreen (dpyinfo->screen));
+
+ if (!strcmp (name, xsettings_atom_name))
+ return dpyinfo->Xatom_xsettings_sel;
+
+ if (!strcmp (name, cm_atom_name))
+ return dpyinfo->Xatom_NET_WM_CM_Sn;
+
+ /* Now do some common predefined atoms. */
+ if (!strcmp (name, "PRIMARY"))
+ return XA_PRIMARY;
+
+ if (!strcmp (name, "SECONDARY"))
+ return XA_SECONDARY;
+
+ if (!strcmp (name, "STRING"))
+ return XA_STRING;
+
+ if (!strcmp (name, "INTEGER"))
+ return XA_INTEGER;
+
+ if (!strcmp (name, "ATOM"))
+ return XA_ATOM;
+
+ if (!strcmp (name, "CARDINAL"))
+ return XA_CARDINAL;
+
+ if (!strcmp (name, "WINDOW"))
+ return XA_WINDOW;
+
+ for (i = 0; i < ARRAYELTS (x_atom_refs); ++i)
+ {
+ ptr = (char *) dpyinfo;
+
+ if (!strcmp (x_atom_refs[i].name, name))
+ {
+ atom = (Atom *) (ptr + x_atom_refs[i].offset);
+
+ return *atom;
+ }
+ }
+
+ if (predefined_only)
+ return None;
+
+ return XInternAtom (dpyinfo->display, name, False);
+}
+
+/* Get the name of ATOM, but try not to make a request to the X
+ server. Whether or not a request to the X server happened is
+ placed in NEED_SYNC. */
+char *
+x_get_atom_name (struct x_display_info *dpyinfo, Atom atom,
+ bool *need_sync)
+{
+ char *dpyinfo_pointer, *name, *value, *buffer;
+ int i;
+ Atom ref_atom;
+
+ dpyinfo_pointer = (char *) dpyinfo;
+ value = NULL;
+
+ if (need_sync)
+ *need_sync = false;
+
+ buffer = alloca (45 + INT_STRLEN_BOUND (int));
+
+ switch (atom)
+ {
+ case XA_PRIMARY:
+ return xstrdup ("PRIMARY");
+
+ case XA_SECONDARY:
+ return xstrdup ("SECONDARY");
+
+ case XA_INTEGER:
+ return xstrdup ("INTEGER");
+
+ case XA_ATOM:
+ return xstrdup ("ATOM");
+
+ case XA_CARDINAL:
+ return xstrdup ("CARDINAL");
+
+ case XA_WINDOW:
+ return xstrdup ("WINDOW");
+
+ default:
+ if (atom == dpyinfo->Xatom_xsettings_sel)
+ {
+ sprintf (buffer, "_XSETTINGS_S%d",
+ XScreenNumberOfScreen (dpyinfo->screen));
+ return xstrdup (buffer);
+ }
+
+ if (atom == dpyinfo->Xatom_NET_WM_CM_Sn)
+ {
+ sprintf (buffer, "_NET_WM_CM_S%d",
+ XScreenNumberOfScreen (dpyinfo->screen));
+ return xstrdup (buffer);
+ }
+
+ for (i = 0; i < ARRAYELTS (x_atom_refs); ++i)
+ {
+ ref_atom = *(Atom *) (dpyinfo_pointer
+ + x_atom_refs[i].offset);
+
+ if (atom == ref_atom)
+ return xstrdup (x_atom_refs[i].name);
+ }
+
+ name = XGetAtomName (dpyinfo->display, atom);
+
+ if (need_sync)
+ *need_sync = true;
+
+ if (name)
+ {
+ value = xstrdup (name);
+ XFree (name);
+ }
+
+ break;
+ }
+
+ return value;
+}
+
/* Setting window manager hints. */
@@ -23152,7 +25708,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
#ifdef USE_XCB
xcb_connection_t *xcb_conn;
#endif
- char *cm_atom_sprintf;
+ static char const cm_atom_fmt[] = "_NET_WM_CM_S%d";
+ char cm_atom_sprintf[sizeof cm_atom_fmt - 2 + INT_STRLEN_BOUND (int)];
+#ifdef USE_GTK
+ GdkDisplay *gdpy;
+ GdkScreen *gscr;
+#endif
block_input ();
@@ -23314,6 +25875,11 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
}
#endif
+ /* Select for structure events on the root window, since this allows
+ us to record changes to the size of the screen. */
+
+ XSelectInput (dpy, DefaultRootWindow (dpy), StructureNotifyMask);
+
/* We have definitely succeeded. Record the new connection. */
dpyinfo = xzalloc (sizeof *dpyinfo);
@@ -23332,7 +25898,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
{
terminal->kboard = allocate_kboard (Qx);
- if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->u.s.function, Qunbound))
+ if (!BASE_EQ (XSYMBOL (Qvendor_specific_keysyms)->u.s.function,
+ Qunbound))
{
char *vendor = ServerVendor (dpy);
@@ -23375,12 +25942,14 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
dpyinfo->color_names_size = 256;
dpyinfo->color_names = xzalloc (dpyinfo->color_names_size
* sizeof *dpyinfo->color_names);
+ dpyinfo->color_names_length = xzalloc (dpyinfo->color_names_size
+ * sizeof *dpyinfo->color_names_length);
/* Set the name of the terminal. */
terminal->name = xlispstrdup (display_name);
#if false
- XSetAfterFunction (x_current_display, x_trace_wire);
+ XSetAfterFunction (dpyinfo->display, x_trace_wire);
#endif
Lisp_Object system_name = Fsystem_name ();
@@ -23754,17 +26323,59 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
;
#endif
+#if defined HAVE_XRANDR || defined USE_GTK
+ Lisp_Object term;
+
+ XSETTERMINAL (term, terminal);
+#endif
+
#ifdef HAVE_XRANDR
- int xrr_event_base, xrr_error_base;
- bool xrr_ok = false;
- xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base);
- if (xrr_ok)
+ dpyinfo->xrandr_supported_p
+ = XRRQueryExtension (dpy, &dpyinfo->xrandr_event_base,
+ &dpyinfo->xrandr_error_base);
+
+#ifndef USE_GTK
+ dpyinfo->last_monitor_attributes_list = Qnil;
+#endif
+
+ if (dpyinfo->xrandr_supported_p)
{
XRRQueryVersion (dpy, &dpyinfo->xrandr_major_version,
&dpyinfo->xrandr_minor_version);
+
+#ifndef USE_GTK
+ if (dpyinfo->xrandr_major_version == 1
+ && dpyinfo->xrandr_minor_version >= 2)
+ {
+ XRRSelectInput (dpyinfo->display,
+ dpyinfo->root_window,
+ (RRScreenChangeNotifyMask
+ | RRCrtcChangeNotifyMask
+ | RROutputChangeNotifyMask
+ /* Emacs doesn't actually need this, but GTK
+ selects for it when the display is
+ initialized. */
+ | RROutputPropertyNotifyMask));
+
+ dpyinfo->last_monitor_attributes_list
+ = Fx_display_monitor_attributes_list (term);
+ }
+#endif
}
#endif
+#ifdef USE_GTK
+ dpyinfo->last_monitor_attributes_list
+ = Fx_display_monitor_attributes_list (term);
+
+ gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+ gscr = gdk_display_get_default_screen (gdpy);
+
+ g_signal_connect (G_OBJECT (gscr), "monitors-changed",
+ G_CALLBACK (x_monitors_changed_cb),
+ NULL);
+#endif
+
#ifdef HAVE_XKB
int xkb_major, xkb_minor, xkb_op, xkb_error_code;
xkb_major = XkbMajorVersion;
@@ -23843,141 +26454,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
}
- {
- int n = snprintf (NULL, 0, "_NET_WM_CM_S%d",
- XScreenNumberOfScreen (dpyinfo->screen));
- cm_atom_sprintf = alloca (n + 1);
-
- snprintf (cm_atom_sprintf, n + 1, "_NET_WM_CM_S%d",
- XScreenNumberOfScreen (dpyinfo->screen));
- }
+ sprintf (cm_atom_sprintf, cm_atom_fmt,
+ XScreenNumberOfScreen (dpyinfo->screen));
{
- static const struct
- {
- const char *name;
- int offset;
- } atom_refs[] = {
-#define ATOM_REFS_INIT(string, member) \
- { string, offsetof (struct x_display_info, member) },
- ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
- ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
- ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
- ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
- ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
- ATOM_REFS_INIT ("WM_STATE", Xatom_wm_state)
- ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
- ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
- ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
- ATOM_REFS_INIT ("WM_TRANSIENT_FOR", Xatom_wm_transient_for)
- ATOM_REFS_INIT ("Editres", Xatom_editres)
- ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
- ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
- ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
- ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
- ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
- ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
- ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
- ATOM_REFS_INIT ("INCR", Xatom_INCR)
- ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
- ATOM_REFS_INIT ("EMACS_SERVER_TIME_PROP", Xatom_EMACS_SERVER_TIME_PROP)
- ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
- ATOM_REFS_INIT ("NULL", Xatom_NULL)
- ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
- ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
- ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
- ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
- ATOM_REFS_INIT ("_MOTIF_WM_HINTS", Xatom_MOTIF_WM_HINTS)
- /* For properties of font. */
- ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
- ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
- ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
- ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
- ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
- /* Ghostscript support. */
- ATOM_REFS_INIT ("DONE", Xatom_DONE)
- ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
- ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
- ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
- ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
- /* EWMH */
- ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
- ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
- ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
- Xatom_net_wm_state_maximized_horz)
- ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
- Xatom_net_wm_state_maximized_vert)
- ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
- ATOM_REFS_INIT ("_NET_WM_STATE_SHADED", Xatom_net_wm_state_shaded)
- ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
- ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
- ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
- Xatom_net_window_type_tooltip)
- ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
- ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
- ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
- ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
- ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
- ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
- ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
- ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
- ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
- ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
- ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter)
- ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
- ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
- ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
- ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking)
- /* Session management */
- ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
- ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
- ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
- ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", Xatom_net_wm_state_skip_taskbar)
- ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
- ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
- ATOM_REFS_INIT ("_NET_WM_OPAQUE_REGION", Xatom_net_wm_opaque_region)
- ATOM_REFS_INIT ("_NET_WM_PING", Xatom_net_wm_ping)
- ATOM_REFS_INIT ("_NET_WM_PID", Xatom_net_wm_pid)
-#ifdef HAVE_XKB
- ATOM_REFS_INIT ("Meta", Xatom_Meta)
- ATOM_REFS_INIT ("Super", Xatom_Super)
- ATOM_REFS_INIT ("Hyper", Xatom_Hyper)
- ATOM_REFS_INIT ("ShiftLock", Xatom_ShiftLock)
- ATOM_REFS_INIT ("Alt", Xatom_Alt)
-#endif
- /* DND source. */
- ATOM_REFS_INIT ("XdndAware", Xatom_XdndAware)
- ATOM_REFS_INIT ("XdndSelection", Xatom_XdndSelection)
- ATOM_REFS_INIT ("XdndTypeList", Xatom_XdndTypeList)
- ATOM_REFS_INIT ("XdndActionCopy", Xatom_XdndActionCopy)
- ATOM_REFS_INIT ("XdndActionMove", Xatom_XdndActionMove)
- ATOM_REFS_INIT ("XdndActionLink", Xatom_XdndActionLink)
- ATOM_REFS_INIT ("XdndActionAsk", Xatom_XdndActionAsk)
- ATOM_REFS_INIT ("XdndActionPrivate", Xatom_XdndActionPrivate)
- ATOM_REFS_INIT ("XdndActionList", Xatom_XdndActionList)
- ATOM_REFS_INIT ("XdndActionDescription", Xatom_XdndActionDescription)
- ATOM_REFS_INIT ("XdndProxy", Xatom_XdndProxy)
- ATOM_REFS_INIT ("XdndEnter", Xatom_XdndEnter)
- ATOM_REFS_INIT ("XdndPosition", Xatom_XdndPosition)
- ATOM_REFS_INIT ("XdndStatus", Xatom_XdndStatus)
- ATOM_REFS_INIT ("XdndLeave", Xatom_XdndLeave)
- ATOM_REFS_INIT ("XdndDrop", Xatom_XdndDrop)
- ATOM_REFS_INIT ("XdndFinished", Xatom_XdndFinished)
- /* Motif drop protocol support. */
- ATOM_REFS_INIT ("_MOTIF_DRAG_WINDOW", Xatom_MOTIF_DRAG_WINDOW)
- ATOM_REFS_INIT ("_MOTIF_DRAG_TARGETS", Xatom_MOTIF_DRAG_TARGETS)
- ATOM_REFS_INIT ("_MOTIF_DRAG_AND_DROP_MESSAGE",
- Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
- ATOM_REFS_INIT ("_MOTIF_DRAG_INITIATOR_INFO",
- Xatom_MOTIF_DRAG_INITIATOR_INFO)
- ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO",
- Xatom_MOTIF_DRAG_RECEIVER_INFO)
- ATOM_REFS_INIT ("XmTRANSFER_SUCCESS", Xatom_XmTRANSFER_SUCCESS)
- ATOM_REFS_INIT ("XmTRANSFER_FAILURE", Xatom_XmTRANSFER_FAILURE)
- };
-
int i;
- enum { atom_count = ARRAYELTS (atom_refs) };
+ enum { atom_count = ARRAYELTS (x_atom_refs) };
/* 1 for _XSETTINGS_SN. */
enum { total_atom_count = 2 + atom_count };
Atom atoms_return[total_atom_count];
@@ -23987,7 +26469,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
+ INT_STRLEN_BOUND (int)];
for (i = 0; i < atom_count; i++)
- atom_names[i] = (char *) atom_refs[i].name;
+ atom_names[i] = (char *) x_atom_refs[i].name;
/* Build _XSETTINGS_SN atom name. */
sprintf (xsettings_atom_name, xsettings_fmt,
@@ -23999,7 +26481,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
False, atoms_return);
for (i = 0; i < atom_count; i++)
- *(Atom *) ((char *) dpyinfo + atom_refs[i].offset) = atoms_return[i];
+ *(Atom *) ((char *) dpyinfo + x_atom_refs[i].offset) = atoms_return[i];
/* Manually copy last two atoms. */
dpyinfo->Xatom_xsettings_sel = atoms_return[i];
@@ -24126,7 +26608,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
/* Only do this for the very first display in the Emacs session.
Ignore X session management when Emacs was first started on a
tty or started as a daemon. */
- if (terminal->id == 1 && ! IS_DAEMON)
+ if (!dpyinfo->next && ! IS_DAEMON)
x_session_initialize (dpyinfo);
#endif
@@ -24154,6 +26636,7 @@ x_delete_display (struct x_display_info *dpyinfo)
struct terminal *t;
struct color_name_cache_entry *color_entry, *next_color_entry;
int i;
+ struct x_selection_request_event *ie, *last, *temp;
/* Close all frames and delete the generic struct terminal for this
X display. */
@@ -24169,6 +26652,30 @@ x_delete_display (struct x_display_info *dpyinfo)
break;
}
+ /* Find any pending selection requests for this display and unchain
+ them. */
+
+ last = NULL;
+
+ for (ie = pending_selection_requests; ie; ie = ie->next)
+ {
+ again:
+
+ if (SELECTION_EVENT_DPYINFO (&ie->se) == dpyinfo)
+ {
+ if (last)
+ last->next = ie->next;
+
+ temp = ie;
+ ie = ie->next;
+ xfree (temp);
+
+ goto again;
+ }
+
+ last = ie;
+ }
+
if (next_noop_dpyinfo == dpyinfo)
next_noop_dpyinfo = dpyinfo->next;
@@ -24199,6 +26706,7 @@ x_delete_display (struct x_display_info *dpyinfo)
}
xfree (dpyinfo->color_names);
+ xfree (dpyinfo->color_names_length);
xfree (dpyinfo->x_id_name);
xfree (dpyinfo->x_dnd_atoms);
xfree (dpyinfo->color_cells);
@@ -24335,11 +26843,12 @@ x_delete_terminal (struct terminal *terminal)
x_dnd_last_seen_window = None;
x_dnd_last_seen_toplevel = None;
x_dnd_in_progress = false;
- x_set_dnd_targets (NULL, 0);
x_dnd_waiting_for_finish = false;
+ /* The display is going away, so there's no point in
+ de-selecting for input on the DND toplevels. */
if (x_dnd_use_toplevels)
- x_dnd_free_toplevels ();
+ x_dnd_free_toplevels (false);
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
@@ -24576,7 +27085,8 @@ mark_xterm (void)
mark_object (val);
}
-#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS
+#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \
+ || defined HAVE_XRANDR || defined USE_GTK
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
{
#ifdef HAVE_XINPUT2
@@ -24587,6 +27097,9 @@ mark_xterm (void)
for (i = 0; i < dpyinfo->n_protected_windows; ++i)
mark_object (dpyinfo->protected_windows[i]);
#endif
+#if defined HAVE_XRANDR || defined USE_GTK
+ mark_object (dpyinfo->last_monitor_attributes_list);
+#endif
}
#endif
}
@@ -24597,9 +27110,16 @@ syms_of_xterm (void)
x_error_message = NULL;
PDUMPER_IGNORE (x_error_message);
+ x_dnd_monitors = Qnil;
+ staticpro (&x_dnd_monitors);
+
+ x_dnd_action_symbol = Qnil;
+ staticpro (&x_dnd_action_symbol);
+
DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
DEFSYM (Qlatin_1, "latin-1");
DEFSYM (Qnow, "now");
+ DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list");
#ifdef USE_GTK
xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
@@ -24637,9 +27157,21 @@ This variable is used only when the window manager requires that you
click on a frame to select it (give it focus). In that case, a value
of nil, means that the selected window and cursor position changes to
reflect the mouse click position, while a non-nil value means that the
-selected window or cursor position is preserved. */);
+selected window or cursor position is preserved.
+
+This option works by ignoring button press events for a given amount
+of time after a frame might've been focused. If it does not work for
+you, try increasing the value of
+`x-mouse-click-focus-ignore-time'. */);
x_mouse_click_focus_ignore_position = false;
+ DEFVAR_INT ("x-mouse-click-focus-ignore-time", x_mouse_click_focus_ignore_time,
+ doc: /* Number of miliseconds for which to ignore buttons after focus change.
+This variable only takes effect if
+`x-mouse-click-focus-ignore-position' is non-nil, and should be
+adjusted if the default value does not work for whatever reason. */);
+ x_mouse_click_focus_ignore_time = 200;
+
DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
doc: /* Which toolkit scroll bars Emacs uses, if any.
A value of nil means Emacs doesn't use toolkit scroll bars.
@@ -24791,6 +27323,13 @@ during a drag-and-drop session, to work around broken implementations
of Motif. */);
x_dnd_fix_motif_leave = true;
+ DEFVAR_BOOL ("x-dnd-disable-motif-drag", x_dnd_disable_motif_drag,
+ doc: /* Disable the Motif drag protocol during DND.
+This reduces network usage, but also means you can no longer scroll
+around inside the Motif window underneath the cursor during
+drag-and-drop. */);
+ x_dnd_disable_motif_drag = false;
+
DEFVAR_LISP ("x-dnd-movement-function", Vx_dnd_movement_function,
doc: /* Function called upon mouse movement on a frame during drag-and-drop.
It should either be nil, or accept two arguments FRAME and POSITION,
@@ -24800,16 +27339,41 @@ mouse position list. */);
DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function,
doc: /* Function called when trying to drop on an unsupported window.
-This function is called whenever the user tries to drop
-something on a window that does not support either the XDND or
-Motif protocols for drag-and-drop. It should return a non-nil
-value if the drop was handled by the function, and nil if it was
-not. It should accept several arguments TARGETS, X, Y, ACTION,
-WINDOW-ID and FRAME, where TARGETS is the list of targets that
-was passed to `x-begin-drag', WINDOW-ID is the numeric XID of
-the window that is being dropped on, X and Y are the root
-window-relative coordinates where the drop happened, ACTION
-is the action that was passed to `x-begin-drag', and FRAME is
-the frame which initiated the drag-and-drop operation. */);
+This function is called whenever the user tries to drop something on a
+window that does not support either the XDND or Motif protocols for
+drag-and-drop. It should return a non-nil value if the drop was
+handled by the function, and nil if it was not. It should accept
+several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME and TIME,
+where TARGETS is the list of targets that was passed to
+`x-begin-drag', WINDOW-ID is the numeric XID of the window that is
+being dropped on, X and Y are the root window-relative coordinates
+where the drop happened, ACTION is the action that was passed to
+`x-begin-drag', FRAME is the frame which initiated the drag-and-drop
+operation, and TIME is the X server time when the drop happened. */);
Vx_dnd_unsupported_drop_function = Qnil;
+
+ DEFVAR_INT ("x-color-cache-bucket-size", x_color_cache_bucket_size,
+ doc: /* Max number of buckets allowed per display in the internal color cache.
+Values less than 1 mean 128. This option is for debugging only. */);
+ x_color_cache_bucket_size = 128;
+
+ DEFVAR_LISP ("x-dnd-targets-list", Vx_dnd_targets_list,
+ doc: /* List of drag-and-drop targets.
+This variable contains the list of drag-and-drop selection targets
+during a drag-and-drop operation, in the same format as the TARGET
+argument to `x-begin-drag'. */);
+ Vx_dnd_targets_list = Qnil;
+
+ DEFVAR_LISP ("x-dnd-native-test-function", Vx_dnd_native_test_function,
+ doc: /* Function that determines return value of drag-and-drop on Emacs frames.
+If the value is a function, `x-begin-drag' will call it with two
+arguments, POS and ACTION, where POS is a mouse position list
+that specifies the location of the drop, and ACTION is the
+action specified by the caller of `x-begin-drag'. The function
+should return a symbol describing what to return from
+`x-begin-drag' if the drop happens on an Emacs frame.
+
+If the value is nil, or the function returns a value that is not
+a symbol, a drop on an Emacs frame will be canceled. */);
+ Vx_dnd_native_test_function = Qnil;
}
diff --git a/src/xterm.h b/src/xterm.h
index 3e06564bee9..82b4308041a 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -196,8 +196,15 @@ extern cairo_pattern_t *x_bitmap_stipple (struct frame *, Pixmap);
struct color_name_cache_entry
{
struct color_name_cache_entry *next;
+
+ /* The color values of the cached color entry. */
XColor rgb;
+
+ /* The name of the cached color. */
char *name;
+
+ /* Whether or not RGB is valid (i.e. the color actually exists). */
+ bool_bf valid : 1;
};
#ifdef HAVE_XINPUT2
@@ -513,6 +520,9 @@ struct x_display_info
/* A cache mapping color names to RGB values. */
struct color_name_cache_entry **color_names;
+ /* The number of buckets for each hash in that hash table. */
+ ptrdiff_t *color_names_length;
+
/* The size of that hash table. */
int color_names_size;
@@ -595,10 +605,19 @@ struct x_display_info
XModifierKeymap *modmap;
#ifdef HAVE_XRANDR
+ bool xrandr_supported_p;
+ int xrandr_event_base;
+ int xrandr_error_base;
int xrandr_major_version;
int xrandr_minor_version;
#endif
+#if defined HAVE_XRANDR || defined USE_GTK
+ /* This is used to determine if the monitor configuration really
+ changed upon receiving a monitor change event. */
+ Lisp_Object last_monitor_attributes_list;
+#endif
+
#if defined USE_CAIRO || defined HAVE_XRENDER
XExtCodes *ext_codes;
#endif
@@ -683,6 +702,17 @@ struct x_display_info
int n_protected_windows;
int protected_windows_max;
#endif
+
+ /* The current dimensions of the screen. This is updated when a
+ ConfigureNotify is received for the root window, and is zero if
+ that didn't happen. */
+ int screen_width;
+ int screen_height;
+
+ /* The mm width and height of the screen. Updated on
+ RRScreenChangeNotify. */
+ int screen_mm_width;
+ int screen_mm_height;
};
#ifdef HAVE_X_I18N
@@ -706,6 +736,9 @@ extern bool x_display_ok (const char *);
extern void select_visual (struct x_display_info *);
extern Window tip_window;
+extern Lisp_Object tip_dx;
+extern Lisp_Object tip_dy;
+extern Lisp_Object tip_frame;
/* Each X frame object points to its own struct x_output object
in the output_data.x field. The x_output structure contains
@@ -925,6 +958,10 @@ struct x_output
false, tell Xt not to wait. */
bool_bf wait_for_wm : 1;
+ /* True if this frame's alpha value is the same for both the active
+ and inactive states. */
+ bool_bf alpha_identical_p : 1;
+
#ifdef HAVE_X_I18N
/* Input context (currently, this means Compose key handler setup). */
XIC xic;
@@ -1352,8 +1389,8 @@ extern const char *x_get_string_resource (void *, const char *, const char *);
/* Defined in xterm.c */
-typedef void (*x_special_error_handler)(Display *, XErrorEvent *, char *,
- void *);
+typedef void (*x_special_error_handler) (Display *, XErrorEvent *, char *,
+ void *);
extern bool x_text_icon (struct frame *, const char *);
extern void x_catch_errors (Display *);
@@ -1362,6 +1399,7 @@ extern void x_catch_errors_with_handler (Display *, x_special_error_handler,
extern void x_check_errors (Display *, const char *)
ATTRIBUTE_FORMAT_PRINTF (2, 0);
extern bool x_had_errors_p (Display *);
+extern void x_unwind_errors_to (int);
extern void x_uncatch_errors (void);
extern void x_uncatch_errors_after_check (void);
extern void x_clear_errors (Display *);
@@ -1372,7 +1410,8 @@ extern void x_iconify_frame (struct frame *f);
extern void x_free_frame_resources (struct frame *);
extern void x_wm_set_size_hint (struct frame *, long, bool);
-extern void x_delete_terminal (struct terminal *terminal);
+extern void x_delete_terminal (struct terminal *);
+extern Cursor x_create_font_cursor (struct x_display_info *, int);
extern unsigned long x_copy_color (struct frame *, unsigned long);
#ifdef USE_X_TOOLKIT
extern XtAppContext Xt_app_con;
@@ -1390,6 +1429,7 @@ extern void x_clear_area (struct frame *f, int, int, int, int);
|| (!defined USE_X_TOOLKIT && !defined USE_GTK)
extern void x_mouse_leave (struct x_display_info *);
#endif
+extern void x_wait_for_cell_change (Lisp_Object, struct timespec);
#ifndef USE_GTK
extern int x_dispatch_event (XEvent *, Display *);
@@ -1419,25 +1459,24 @@ extern void x_xr_reset_ext_clip (struct frame *f);
extern void x_scroll_bar_configure (GdkEvent *);
#endif
+#define DEFER_SELECTIONS \
+ x_defer_selection_requests (); \
+ record_unwind_protect_void (x_release_selection_requests_and_flush)
+
+extern void x_defer_selection_requests (void);
+extern void x_release_selection_requests_and_flush (void);
+extern void x_handle_pending_selection_requests (void);
+extern bool x_detect_pending_selection_requests (void);
extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
Lisp_Object, Atom *, const char **,
- size_t, bool);
+ size_t, bool, Atom *, int,
+ Lisp_Object, bool);
extern void x_dnd_do_unsupported_drop (struct x_display_info *, Lisp_Object,
Lisp_Object, Lisp_Object, Window, int,
int, Time);
-extern void x_set_dnd_targets (Atom *, int);
-
-INLINE int
-x_display_pixel_height (struct x_display_info *dpyinfo)
-{
- return HeightOfScreen (dpyinfo->screen);
-}
-INLINE int
-x_display_pixel_width (struct x_display_info *dpyinfo)
-{
- return WidthOfScreen (dpyinfo->screen);
-}
+extern int x_display_pixel_height (struct x_display_info *);
+extern int x_display_pixel_width (struct x_display_info *);
INLINE unsigned long
x_make_truecolor_pixel (struct x_display_info *dpyinfo, int r, int g, int b)
@@ -1471,6 +1510,7 @@ extern void x_set_shaded (struct frame *, Lisp_Object, Lisp_Object);
extern void x_set_skip_taskbar (struct frame *, Lisp_Object, Lisp_Object);
extern void x_set_z_group (struct frame *, Lisp_Object, Lisp_Object);
extern bool x_wm_supports (struct frame *, Atom);
+extern bool x_wm_supports_1 (struct x_display_info *, Atom);
extern void x_wait_for_event (struct frame *, int);
extern void x_clear_under_internal_border (struct frame *f);
@@ -1495,11 +1535,13 @@ extern void x_handle_property_notify (const XPropertyEvent *);
extern void x_handle_selection_notify (const XSelectionEvent *);
extern void x_handle_selection_event (struct selection_input_event *);
extern void x_clear_frame_selections (struct frame *);
+extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom);
extern bool x_handle_dnd_message (struct frame *,
const XClientMessageEvent *,
struct x_display_info *,
- struct input_event *);
+ struct input_event *,
+ bool, int, int);
extern int x_check_property_data (Lisp_Object);
extern void x_fill_property_data (Display *,
Lisp_Object,
@@ -1518,6 +1560,10 @@ extern Lisp_Object x_timestamp_for_selection (struct x_display_info *,
Lisp_Object);
extern void x_set_pending_dnd_time (Time);
extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object);
+extern Atom x_intern_cached_atom (struct x_display_info *, const char *,
+ bool);
+extern char *x_get_atom_name (struct x_display_info *, Atom, bool *)
+ ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE;
#ifdef USE_GTK
extern bool xg_set_icon (struct frame *, Lisp_Object);
@@ -1578,7 +1624,11 @@ extern struct input_event xg_pending_quit_event;
#endif
extern bool x_dnd_in_progress;
+extern bool x_dnd_waiting_for_finish;
extern struct frame *x_dnd_frame;
+extern struct frame *x_dnd_finish_frame;
+extern unsigned x_dnd_unsupported_event_level;
+extern int x_error_message_count;
#ifdef HAVE_XINPUT2
extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int);